commit 41dc6e7547ff5cd64b6e2db68de6bebad01d2df1 Author: lidy@connor.net.cn Date: Tue Nov 19 16:34:58 2024 +0800 20241119修改前上传备份 diff --git a/.git0/COMMIT_EDITMSG b/.git0/COMMIT_EDITMSG new file mode 100644 index 0000000..8a714f1 --- /dev/null +++ b/.git0/COMMIT_EDITMSG @@ -0,0 +1 @@ +20200706 diff --git a/.git0/HEAD b/.git0/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/.git0/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/.git0/config b/.git0/config new file mode 100644 index 0000000..be3822d --- /dev/null +++ b/.git0/config @@ -0,0 +1,10 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true +[remote "connor"] + url = http://plmserver.cn:3000/CN-TS-00000039/CHINT-PLM-ITK.git + fetch = +refs/heads/*:refs/remotes/connor/* diff --git a/.git0/description b/.git0/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/.git0/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/.git0/hooks/applypatch-msg.sample b/.git0/hooks/applypatch-msg.sample new file mode 100644 index 0000000..a5d7b84 --- /dev/null +++ b/.git0/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/.git0/hooks/commit-msg.sample b/.git0/hooks/commit-msg.sample new file mode 100644 index 0000000..b58d118 --- /dev/null +++ b/.git0/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/.git0/hooks/fsmonitor-watchman.sample b/.git0/hooks/fsmonitor-watchman.sample new file mode 100644 index 0000000..14ed0aa --- /dev/null +++ b/.git0/hooks/fsmonitor-watchman.sample @@ -0,0 +1,173 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IPC::Open2; + +# An example hook script to integrate Watchman +# (https://facebook.github.io/watchman/) with git to speed up detecting +# new and modified files. +# +# The hook is passed a version (currently 2) and last update token +# formatted as a string and outputs to stdout a new update token and +# all files that have been modified since the update token. Paths must +# be relative to the root of the working tree and separated by a single NUL. +# +# To enable this hook, rename this file to "query-watchman" and set +# 'git config core.fsmonitor .git/hooks/query-watchman' +# +my ($version, $last_update_token) = @ARGV; + +# Uncomment for debugging +# print STDERR "$0 $version $last_update_token\n"; + +# Check the hook interface version +if ($version ne 2) { + die "Unsupported query-fsmonitor hook version '$version'.\n" . + "Falling back to scanning...\n"; +} + +my $git_work_tree = get_working_dir(); + +my $retry = 1; + +my $json_pkg; +eval { + require JSON::XS; + $json_pkg = "JSON::XS"; + 1; +} or do { + require JSON::PP; + $json_pkg = "JSON::PP"; +}; + +launch_watchman(); + +sub launch_watchman { + my $o = watchman_query(); + if (is_work_tree_watched($o)) { + output_result($o->{clock}, @{$o->{files}}); + } +} + +sub output_result { + my ($clockid, @files) = @_; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # binmode $fh, ":utf8"; + # print $fh "$clockid\n@files\n"; + # close $fh; + + binmode STDOUT, ":utf8"; + print $clockid; + print "\0"; + local $, = "\0"; + print @files; +} + +sub watchman_clock { + my $response = qx/watchman clock "$git_work_tree"/; + die "Failed to get clock id on '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + + return $json_pkg->new->utf8->decode($response); +} + +sub watchman_query { + my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty') + or die "open2() failed: $!\n" . + "Falling back to scanning...\n"; + + # In the query expression below we're asking for names of files that + # changed since $last_update_token but not from the .git folder. + # + # To accomplish this, we're using the "since" generator to use the + # recency index to select candidate nodes and "fields" to limit the + # output to file names only. Then we're using the "expression" term to + # further constrain the results. + if (substr($last_update_token, 0, 1) eq "c") { + $last_update_token = "\"$last_update_token\""; + } + my $query = <<" END"; + ["query", "$git_work_tree", { + "since": $last_update_token, + "fields": ["name"], + "expression": ["not", ["dirname", ".git"]] + }] + END + + # Uncomment for debugging the watchman query + # open (my $fh, ">", ".git/watchman-query.json"); + # print $fh $query; + # close $fh; + + print CHLD_IN $query; + close CHLD_IN; + my $response = do {local $/; }; + + # Uncomment for debugging the watch response + # open ($fh, ">", ".git/watchman-response.json"); + # print $fh $response; + # close $fh; + + die "Watchman: command returned no output.\n" . + "Falling back to scanning...\n" if $response eq ""; + die "Watchman: command returned invalid output: $response\n" . + "Falling back to scanning...\n" unless $response =~ /^\{/; + + return $json_pkg->new->utf8->decode($response); +} + +sub is_work_tree_watched { + my ($output) = @_; + my $error = $output->{error}; + if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) { + $retry--; + my $response = qx/watchman watch "$git_work_tree"/; + die "Failed to make watchman watch '$git_work_tree'.\n" . + "Falling back to scanning...\n" if $? != 0; + $output = $json_pkg->new->utf8->decode($response); + $error = $output->{error}; + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + # Uncomment for debugging watchman output + # open (my $fh, ">", ".git/watchman-output.out"); + # close $fh; + + # Watchman will always return all files on the first query so + # return the fast "everything is dirty" flag to git and do the + # Watchman query just to get it over with now so we won't pay + # the cost in git to look up each individual file. + my $o = watchman_clock(); + $error = $output->{error}; + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + output_result($o->{clock}, ("/")); + $last_update_token = $o->{clock}; + + eval { launch_watchman() }; + return 0; + } + + die "Watchman: $error.\n" . + "Falling back to scanning...\n" if $error; + + return 1; +} + +sub get_working_dir { + my $working_dir; + if ($^O =~ 'msys' || $^O =~ 'cygwin') { + $working_dir = Win32::GetCwd(); + $working_dir =~ tr/\\/\//; + } else { + require Cwd; + $working_dir = Cwd::cwd(); + } + + return $working_dir; +} diff --git a/.git0/hooks/post-update.sample b/.git0/hooks/post-update.sample new file mode 100644 index 0000000..ec17ec1 --- /dev/null +++ b/.git0/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/.git0/hooks/pre-applypatch.sample b/.git0/hooks/pre-applypatch.sample new file mode 100644 index 0000000..4142082 --- /dev/null +++ b/.git0/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/.git0/hooks/pre-commit.sample b/.git0/hooks/pre-commit.sample new file mode 100644 index 0000000..e144712 --- /dev/null +++ b/.git0/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --type=bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/.git0/hooks/pre-merge-commit.sample b/.git0/hooks/pre-merge-commit.sample new file mode 100644 index 0000000..399eab1 --- /dev/null +++ b/.git0/hooks/pre-merge-commit.sample @@ -0,0 +1,13 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git merge" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message to +# stderr if it wants to stop the merge commit. +# +# To enable this hook, rename this file to "pre-merge-commit". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" +: diff --git a/.git0/hooks/pre-push.sample b/.git0/hooks/pre-push.sample new file mode 100644 index 0000000..6187dbf --- /dev/null +++ b/.git0/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/.git0/hooks/pre-rebase.sample b/.git0/hooks/pre-rebase.sample new file mode 100644 index 0000000..6cbef5c --- /dev/null +++ b/.git0/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/.git0/hooks/pre-receive.sample b/.git0/hooks/pre-receive.sample new file mode 100644 index 0000000..a1fd29e --- /dev/null +++ b/.git0/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/.git0/hooks/prepare-commit-msg.sample b/.git0/hooks/prepare-commit-msg.sample new file mode 100644 index 0000000..10fa14c --- /dev/null +++ b/.git0/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/.git0/hooks/update.sample b/.git0/hooks/update.sample new file mode 100644 index 0000000..5014c4b --- /dev/null +++ b/.git0/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --type=bool hooks.allowunannotated) +allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch) +denycreatebranch=$(git config --type=bool hooks.denycreatebranch) +allowdeletetag=$(git config --type=bool hooks.allowdeletetag) +allowmodifytag=$(git config --type=bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/.git0/index b/.git0/index new file mode 100644 index 0000000..0d7cc19 Binary files /dev/null and b/.git0/index differ diff --git a/.git0/info/exclude b/.git0/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/.git0/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/.git0/logs/HEAD b/.git0/logs/HEAD new file mode 100644 index 0000000..ce28206 --- /dev/null +++ b/.git0/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 05446be6b9d230143be91d57377449b4c404a524 licj 1594004530 +0800 commit (initial): 20200706 diff --git a/.git0/logs/refs/heads/master b/.git0/logs/refs/heads/master new file mode 100644 index 0000000..ce28206 --- /dev/null +++ b/.git0/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 05446be6b9d230143be91d57377449b4c404a524 licj 1594004530 +0800 commit (initial): 20200706 diff --git a/.git0/logs/refs/remotes/connor/master b/.git0/logs/refs/remotes/connor/master new file mode 100644 index 0000000..e26e9f9 --- /dev/null +++ b/.git0/logs/refs/remotes/connor/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 05446be6b9d230143be91d57377449b4c404a524 licj 1594004697 +0800 update by push diff --git a/.git0/ms-persist.xml b/.git0/ms-persist.xml new file mode 100644 index 0000000..547e427 --- /dev/null +++ b/.git0/ms-persist.xml @@ -0,0 +1,11 @@ + + + + + WXom062\easylogging++.h + WXom062\HTTPRequest.hpp + WXom062\SQLAPI.h + + + + \ No newline at end of file diff --git a/.git0/objects/02/86caa66369d417a9716ebcd6049bbe04bb8fef b/.git0/objects/02/86caa66369d417a9716ebcd6049bbe04bb8fef new file mode 100644 index 0000000..81b6cf2 Binary files /dev/null and b/.git0/objects/02/86caa66369d417a9716ebcd6049bbe04bb8fef differ diff --git a/.git0/objects/03/c95fabb9aba1c1de8ef6ea6dde9a3574a359e0 b/.git0/objects/03/c95fabb9aba1c1de8ef6ea6dde9a3574a359e0 new file mode 100644 index 0000000..b914d92 Binary files /dev/null and b/.git0/objects/03/c95fabb9aba1c1de8ef6ea6dde9a3574a359e0 differ diff --git a/.git0/objects/05/446be6b9d230143be91d57377449b4c404a524 b/.git0/objects/05/446be6b9d230143be91d57377449b4c404a524 new file mode 100644 index 0000000..0889917 Binary files /dev/null and b/.git0/objects/05/446be6b9d230143be91d57377449b4c404a524 differ diff --git a/.git0/objects/07/1db255e74253090e7a811c0b3fe9680a663f52 b/.git0/objects/07/1db255e74253090e7a811c0b3fe9680a663f52 new file mode 100644 index 0000000..364b4a7 Binary files /dev/null and b/.git0/objects/07/1db255e74253090e7a811c0b3fe9680a663f52 differ diff --git a/.git0/objects/07/91d39a961bd2b69d1077aec666b7947bb6e530 b/.git0/objects/07/91d39a961bd2b69d1077aec666b7947bb6e530 new file mode 100644 index 0000000..33d1cd5 --- /dev/null +++ b/.git0/objects/07/91d39a961bd2b69d1077aec666b7947bb6e530 @@ -0,0 +1 @@ +xYJ@}gQAQRcMz`7ACJ 7 q4ifd nt߼ٙt6:m|? x|5q F):hᐯyxt]\1m>1p^5DD1`>4 GX Y 1 qKh; qC8qKtY)78ԗp9;|שC1qFԣ>~!Q+Ը"o?$\Rsȩn-\Eфq$~pQDSu]d~UwC?L7N%[%H9fi1 %t#*#]kSy0YU26oHF_Mf fud5Vs6d(fL2l>4kZD-~([L˱Z) LՄynv+Q[8V׿v0TursH5cW^=7_2̭S|>ޱ+zkHMj0fU&Nuls#첻:\;Ku;:ΪS \ No newline at end of file diff --git a/.git0/objects/0a/20e940901e23d1af4ee790399bbd0efb8fe93b b/.git0/objects/0a/20e940901e23d1af4ee790399bbd0efb8fe93b new file mode 100644 index 0000000..614842c Binary files /dev/null and b/.git0/objects/0a/20e940901e23d1af4ee790399bbd0efb8fe93b differ diff --git a/.git0/objects/0a/2520fedf5910064b2b3614aa4c8f7751a024a0 b/.git0/objects/0a/2520fedf5910064b2b3614aa4c8f7751a024a0 new file mode 100644 index 0000000..32ba3a9 --- /dev/null +++ b/.git0/objects/0a/2520fedf5910064b2b3614aa4c8f7751a024a0 @@ -0,0 +1,2 @@ +x +@F)z%#+̰`ag >-ƫ/*Y5X!ߎwF;` IpBb3[L?ww@lO\N{یyU|̦kKלֺenZ翢S&U@Ѱ"e|sF~TTE\f@M P~£_Sk _I= \ No newline at end of file diff --git a/.git0/objects/0f/6e466cb46729af9f6222dcf5d1f3569c6dcfab b/.git0/objects/0f/6e466cb46729af9f6222dcf5d1f3569c6dcfab new file mode 100644 index 0000000..0842e8b Binary files /dev/null and b/.git0/objects/0f/6e466cb46729af9f6222dcf5d1f3569c6dcfab differ diff --git a/.git0/objects/12/f04b16c71f612d03df5afc32c47379152e1abe b/.git0/objects/12/f04b16c71f612d03df5afc32c47379152e1abe new file mode 100644 index 0000000..e108087 --- /dev/null +++ b/.git0/objects/12/f04b16c71f612d03df5afc32c47379152e1abe @@ -0,0 +1,2 @@ +xJ@fbH7I)f!BK,LQl+4N'23n}q)O$Sm H9盛Iy9P7+Qh6OP.^0EшQ +Xvknȱ0F'vӥDžpkuP1$NQ0e iT]˶Cj,h|ƪYI%Bd|uYt5ǻDc%(oqz>qVq>,hvh&7DZ|j;V>OFK6UL9CfU^s2ƬЂiҝ&" }Ƿi-f:]V6}i̺fr{O<n=΃ \ No newline at end of file diff --git a/.git0/objects/13/83ae7f1b7fa853fe232548df6a54f68b6a9e6b b/.git0/objects/13/83ae7f1b7fa853fe232548df6a54f68b6a9e6b new file mode 100644 index 0000000..68463d8 Binary files /dev/null and b/.git0/objects/13/83ae7f1b7fa853fe232548df6a54f68b6a9e6b differ diff --git a/.git0/objects/13/e4b6add533fa9b3373d022dc8e4eaff9a041d9 b/.git0/objects/13/e4b6add533fa9b3373d022dc8e4eaff9a041d9 new file mode 100644 index 0000000..07e9df6 Binary files /dev/null and b/.git0/objects/13/e4b6add533fa9b3373d022dc8e4eaff9a041d9 differ diff --git a/.git0/objects/19/cb20eb11fc695f5c1d9fc53f609228a83d55f6 b/.git0/objects/19/cb20eb11fc695f5c1d9fc53f609228a83d55f6 new file mode 100644 index 0000000..866e7ed Binary files /dev/null and b/.git0/objects/19/cb20eb11fc695f5c1d9fc53f609228a83d55f6 differ diff --git a/.git0/objects/1e/769d4d6ce06682b396590f97fe23d541c509df b/.git0/objects/1e/769d4d6ce06682b396590f97fe23d541c509df new file mode 100644 index 0000000..3de277b --- /dev/null +++ b/.git0/objects/1e/769d4d6ce06682b396590f97fe23d541c509df @@ -0,0 +1,2 @@ +xMN0Ys,aDH%Rأ?=6-+D Mj)曧73ϥveő̿>^˗3y%Sr<E,2BN݈-lZ9>B@ʫ J7$0X;IʒjnBQ,PxvU$d('D+p{%Qf8W\0ѐ@%Uy `bX +(@xng+]ڭup/`Kl6QԾ0 L f RZN@(T+#܃Q \ No newline at end of file diff --git a/.git0/objects/1f/90d4dbfb04ffc2dbd82396728c9cf08b091122 b/.git0/objects/1f/90d4dbfb04ffc2dbd82396728c9cf08b091122 new file mode 100644 index 0000000..def0843 Binary files /dev/null and b/.git0/objects/1f/90d4dbfb04ffc2dbd82396728c9cf08b091122 differ diff --git a/.git0/objects/1f/92dfe237fc91c70dca6b087a5cd08a9e7ed5bf b/.git0/objects/1f/92dfe237fc91c70dca6b087a5cd08a9e7ed5bf new file mode 100644 index 0000000..c0eba96 Binary files /dev/null and b/.git0/objects/1f/92dfe237fc91c70dca6b087a5cd08a9e7ed5bf differ diff --git a/.git0/objects/25/87ba07b2ef49ccad9e54a185647ce42f002a27 b/.git0/objects/25/87ba07b2ef49ccad9e54a185647ce42f002a27 new file mode 100644 index 0000000..a22468b Binary files /dev/null and b/.git0/objects/25/87ba07b2ef49ccad9e54a185647ce42f002a27 differ diff --git a/.git0/objects/29/55f062cb2d0bf2a524eb247abbf34fc7e0c5de b/.git0/objects/29/55f062cb2d0bf2a524eb247abbf34fc7e0c5de new file mode 100644 index 0000000..9dc3c5a Binary files /dev/null and b/.git0/objects/29/55f062cb2d0bf2a524eb247abbf34fc7e0c5de differ diff --git a/.git0/objects/29/b41588516e781ef1897402548f7f7ed251bf01 b/.git0/objects/29/b41588516e781ef1897402548f7f7ed251bf01 new file mode 100644 index 0000000..8797267 --- /dev/null +++ b/.git0/objects/29/b41588516e781ef1897402548f7f7ed251bf01 @@ -0,0 +1,3 @@ +xŕJ@ƿ;䨠EB[چ?%P,&>O)>EO awv7 nMXo7ZTN/N[K]V+1cE:`7gr(UH2;-t\:W3Nך\O͟ +%X"yIca8Ò \ No newline at end of file diff --git a/.git0/objects/2b/6c6656f25d703b04afc006e10aebab1945d599 b/.git0/objects/2b/6c6656f25d703b04afc006e10aebab1945d599 new file mode 100644 index 0000000..401b7bc Binary files /dev/null and b/.git0/objects/2b/6c6656f25d703b04afc006e10aebab1945d599 differ diff --git a/.git0/objects/2f/1b506238986dbb9aacfffe83e6fd36ea0d7386 b/.git0/objects/2f/1b506238986dbb9aacfffe83e6fd36ea0d7386 new file mode 100644 index 0000000..92689b1 Binary files /dev/null and b/.git0/objects/2f/1b506238986dbb9aacfffe83e6fd36ea0d7386 differ diff --git a/.git0/objects/30/e1fe2e983d4ffdb5051a21de64fe3402dd64a4 b/.git0/objects/30/e1fe2e983d4ffdb5051a21de64fe3402dd64a4 new file mode 100644 index 0000000..482fc35 Binary files /dev/null and b/.git0/objects/30/e1fe2e983d4ffdb5051a21de64fe3402dd64a4 differ diff --git a/.git0/objects/34/adcb0b9dca3a595c107f97ddcfa006efcaa4ef b/.git0/objects/34/adcb0b9dca3a595c107f97ddcfa006efcaa4ef new file mode 100644 index 0000000..0ea5bd6 Binary files /dev/null and b/.git0/objects/34/adcb0b9dca3a595c107f97ddcfa006efcaa4ef differ diff --git a/.git0/objects/35/bdf5531d779adde53163206348e4e71cb7a87f b/.git0/objects/35/bdf5531d779adde53163206348e4e71cb7a87f new file mode 100644 index 0000000..ec1b06e Binary files /dev/null and b/.git0/objects/35/bdf5531d779adde53163206348e4e71cb7a87f differ diff --git a/.git0/objects/36/8711c9d6a72f5f0e49a56f5431a4b9d9178027 b/.git0/objects/36/8711c9d6a72f5f0e49a56f5431a4b9d9178027 new file mode 100644 index 0000000..10181d6 Binary files /dev/null and b/.git0/objects/36/8711c9d6a72f5f0e49a56f5431a4b9d9178027 differ diff --git a/.git0/objects/36/9bb50b39531e90124d16e5947f65e660deb608 b/.git0/objects/36/9bb50b39531e90124d16e5947f65e660deb608 new file mode 100644 index 0000000..7e2fab2 Binary files /dev/null and b/.git0/objects/36/9bb50b39531e90124d16e5947f65e660deb608 differ diff --git a/.git0/objects/37/b272718b824eabc86fcafad8fe96d1b449abf9 b/.git0/objects/37/b272718b824eabc86fcafad8fe96d1b449abf9 new file mode 100644 index 0000000..4dba9f6 Binary files /dev/null and b/.git0/objects/37/b272718b824eabc86fcafad8fe96d1b449abf9 differ diff --git a/.git0/objects/40/558fab9bb17ddbfecf0bc3ccae6cae5e3d2be3 b/.git0/objects/40/558fab9bb17ddbfecf0bc3ccae6cae5e3d2be3 new file mode 100644 index 0000000..fead43d Binary files /dev/null and b/.git0/objects/40/558fab9bb17ddbfecf0bc3ccae6cae5e3d2be3 differ diff --git a/.git0/objects/40/8517130a48013eb3d96e5189d3901da797331b b/.git0/objects/40/8517130a48013eb3d96e5189d3901da797331b new file mode 100644 index 0000000..46e9bf2 Binary files /dev/null and b/.git0/objects/40/8517130a48013eb3d96e5189d3901da797331b differ diff --git a/.git0/objects/42/6e1b6bd5d37532e93c0aad7e1b2449b5f13cd9 b/.git0/objects/42/6e1b6bd5d37532e93c0aad7e1b2449b5f13cd9 new file mode 100644 index 0000000..b32f866 Binary files /dev/null and b/.git0/objects/42/6e1b6bd5d37532e93c0aad7e1b2449b5f13cd9 differ diff --git a/.git0/objects/44/775f7bb1a5ca7ad0c72962c9625fc0ef2cc7e4 b/.git0/objects/44/775f7bb1a5ca7ad0c72962c9625fc0ef2cc7e4 new file mode 100644 index 0000000..965e3b0 Binary files /dev/null and b/.git0/objects/44/775f7bb1a5ca7ad0c72962c9625fc0ef2cc7e4 differ diff --git a/.git0/objects/44/e61584c7fcb42dd6d706c759f1e4a27ab1dd34 b/.git0/objects/44/e61584c7fcb42dd6d706c759f1e4a27ab1dd34 new file mode 100644 index 0000000..2334fe6 Binary files /dev/null and b/.git0/objects/44/e61584c7fcb42dd6d706c759f1e4a27ab1dd34 differ diff --git a/.git0/objects/45/835435c0a664abca68b7566b26a22dbe0eada8 b/.git0/objects/45/835435c0a664abca68b7566b26a22dbe0eada8 new file mode 100644 index 0000000..65bcb0e Binary files /dev/null and b/.git0/objects/45/835435c0a664abca68b7566b26a22dbe0eada8 differ diff --git a/.git0/objects/46/b134b197f35e75e0784bedbf94a8dd124693b1 b/.git0/objects/46/b134b197f35e75e0784bedbf94a8dd124693b1 new file mode 100644 index 0000000..2c2f59a Binary files /dev/null and b/.git0/objects/46/b134b197f35e75e0784bedbf94a8dd124693b1 differ diff --git a/.git0/objects/4a/d8b56b16d9e10456fcdc197703c6c7568547d5 b/.git0/objects/4a/d8b56b16d9e10456fcdc197703c6c7568547d5 new file mode 100644 index 0000000..96296db Binary files /dev/null and b/.git0/objects/4a/d8b56b16d9e10456fcdc197703c6c7568547d5 differ diff --git a/.git0/objects/4b/379cc0f751608f66ff4c976707a335d1de1794 b/.git0/objects/4b/379cc0f751608f66ff4c976707a335d1de1794 new file mode 100644 index 0000000..1235743 Binary files /dev/null and b/.git0/objects/4b/379cc0f751608f66ff4c976707a335d1de1794 differ diff --git a/.git0/objects/4d/9df624f96e4a5c605417d198540b37eb27b0e7 b/.git0/objects/4d/9df624f96e4a5c605417d198540b37eb27b0e7 new file mode 100644 index 0000000..b40e8dd Binary files /dev/null and b/.git0/objects/4d/9df624f96e4a5c605417d198540b37eb27b0e7 differ diff --git a/.git0/objects/4f/04f7f8035b3000cef505100a2328e03c2bda2d b/.git0/objects/4f/04f7f8035b3000cef505100a2328e03c2bda2d new file mode 100644 index 0000000..241bfca Binary files /dev/null and b/.git0/objects/4f/04f7f8035b3000cef505100a2328e03c2bda2d differ diff --git a/.git0/objects/50/756570fc231ea9e560c6de287d865693516669 b/.git0/objects/50/756570fc231ea9e560c6de287d865693516669 new file mode 100644 index 0000000..b2f31e1 Binary files /dev/null and b/.git0/objects/50/756570fc231ea9e560c6de287d865693516669 differ diff --git a/.git0/objects/58/853dcdfbb2279e371ee2603b7d0d4aff650787 b/.git0/objects/58/853dcdfbb2279e371ee2603b7d0d4aff650787 new file mode 100644 index 0000000..aa14ca0 Binary files /dev/null and b/.git0/objects/58/853dcdfbb2279e371ee2603b7d0d4aff650787 differ diff --git a/.git0/objects/5b/792f328d6696a3e74e0ce533f94263c42f1419 b/.git0/objects/5b/792f328d6696a3e74e0ce533f94263c42f1419 new file mode 100644 index 0000000..19debb0 Binary files /dev/null and b/.git0/objects/5b/792f328d6696a3e74e0ce533f94263c42f1419 differ diff --git a/.git0/objects/5c/a15fc3cac2de49463dc5ac9e2bbaa2ca3b3581 b/.git0/objects/5c/a15fc3cac2de49463dc5ac9e2bbaa2ca3b3581 new file mode 100644 index 0000000..6897427 --- /dev/null +++ b/.git0/objects/5c/a15fc3cac2de49463dc5ac9e2bbaa2ca3b3581 @@ -0,0 +1,2 @@ +xUOOAQJ⁀'͚T/n&F +I 4lL[i⒲~~9qbLx`‘δ[[bp7f5]72xişhm0c3%3jp 6LU}y4zV(m+ZYvv݃*nol p,~%]\Vroy͎ը9Nx{D]Zmrݪ<2gNv-D+f54۳iz.<-S$CD"Z/fq՞A/ڎ# Me2v8>\|z==FqJh7Gmtu&߈~I8&$.-ٸK+"c 팜YS`Z*J%07CwR&Jڍ{GZq]c,P?!fW`6܃C5qW$_A)& m)PGbRCbw@VxLx@ݑ"E7zyhDD|±#} RɑY-ȑ_"`'!-7Z&=_?í_2'W0U~q?Buj[\FVr'\BhX87΃nh>wǨ\pR9L&Ui0 \ No newline at end of file diff --git a/.git0/objects/66/1f02de847c4cbad891783d67c49976a4770398 b/.git0/objects/66/1f02de847c4cbad891783d67c49976a4770398 new file mode 100644 index 0000000..e709d97 Binary files /dev/null and b/.git0/objects/66/1f02de847c4cbad891783d67c49976a4770398 differ diff --git a/.git0/objects/66/2f297264ca953a4273ae7166c124f011ae1a38 b/.git0/objects/66/2f297264ca953a4273ae7166c124f011ae1a38 new file mode 100644 index 0000000..4212be3 Binary files /dev/null and b/.git0/objects/66/2f297264ca953a4273ae7166c124f011ae1a38 differ diff --git a/.git0/objects/66/4d64bbfbf17fa494fa7df0040869c690ecf73f b/.git0/objects/66/4d64bbfbf17fa494fa7df0040869c690ecf73f new file mode 100644 index 0000000..002ffa1 Binary files /dev/null and b/.git0/objects/66/4d64bbfbf17fa494fa7df0040869c690ecf73f differ diff --git a/.git0/objects/6a/433dbf2f9e44b6a35f45a8e627f1db714eb02c b/.git0/objects/6a/433dbf2f9e44b6a35f45a8e627f1db714eb02c new file mode 100644 index 0000000..fceb2cc Binary files /dev/null and b/.git0/objects/6a/433dbf2f9e44b6a35f45a8e627f1db714eb02c differ diff --git a/.git0/objects/6a/44233918f374e30ec44bd04635e8a88e35423f b/.git0/objects/6a/44233918f374e30ec44bd04635e8a88e35423f new file mode 100644 index 0000000..5de382d Binary files /dev/null and b/.git0/objects/6a/44233918f374e30ec44bd04635e8a88e35423f differ diff --git a/.git0/objects/6c/55f54d16d6c896d7eec49109c8a4c6e63e779e b/.git0/objects/6c/55f54d16d6c896d7eec49109c8a4c6e63e779e new file mode 100644 index 0000000..a3756ef Binary files /dev/null and b/.git0/objects/6c/55f54d16d6c896d7eec49109c8a4c6e63e779e differ diff --git a/.git0/objects/6c/6dff065954a7e89ed25a9bfe3800ad67eb9510 b/.git0/objects/6c/6dff065954a7e89ed25a9bfe3800ad67eb9510 new file mode 100644 index 0000000..a3eae0f Binary files /dev/null and b/.git0/objects/6c/6dff065954a7e89ed25a9bfe3800ad67eb9510 differ diff --git a/.git0/objects/6e/b44c69ff8e3ae5932ed06bf8160b438ebabf74 b/.git0/objects/6e/b44c69ff8e3ae5932ed06bf8160b438ebabf74 new file mode 100644 index 0000000..bc0545a Binary files /dev/null and b/.git0/objects/6e/b44c69ff8e3ae5932ed06bf8160b438ebabf74 differ diff --git a/.git0/objects/6f/7df367eb154add7850df57524880206e688870 b/.git0/objects/6f/7df367eb154add7850df57524880206e688870 new file mode 100644 index 0000000..1606761 Binary files /dev/null and b/.git0/objects/6f/7df367eb154add7850df57524880206e688870 differ diff --git a/.git0/objects/6f/ab5918677b83e2ba07ce30e46e986edc750286 b/.git0/objects/6f/ab5918677b83e2ba07ce30e46e986edc750286 new file mode 100644 index 0000000..1d9ef33 Binary files /dev/null and b/.git0/objects/6f/ab5918677b83e2ba07ce30e46e986edc750286 differ diff --git a/.git0/objects/72/5de966ff50cfc2149d2ac813d757026be84a87 b/.git0/objects/72/5de966ff50cfc2149d2ac813d757026be84a87 new file mode 100644 index 0000000..2e32e33 Binary files /dev/null and b/.git0/objects/72/5de966ff50cfc2149d2ac813d757026be84a87 differ diff --git a/.git0/objects/72/9560494db105ba82108c6853abc800ac309772 b/.git0/objects/72/9560494db105ba82108c6853abc800ac309772 new file mode 100644 index 0000000..bf5b5e5 --- /dev/null +++ b/.git0/objects/72/9560494db105ba82108c6853abc800ac309772 @@ -0,0 +1,2 @@ +xJ@ǽvbPR= :lvv7N +">W0(ޜ~څ&ח'_,Af[&q-$nciGFB<$ L v0?q3nzҚ=VK,ć**\0s_?fO%&_[.HE]GMbsu:6Z8IbMO0߸ha]: \ No newline at end of file diff --git a/.git0/objects/73/6ec3a8142ff1ceb408d1d5dbf4c0f5a1407f47 b/.git0/objects/73/6ec3a8142ff1ceb408d1d5dbf4c0f5a1407f47 new file mode 100644 index 0000000..df8a121 Binary files /dev/null and b/.git0/objects/73/6ec3a8142ff1ceb408d1d5dbf4c0f5a1407f47 differ diff --git a/.git0/objects/74/af57fb3f5b864e67767cdc6de5cc5d8128ed3f b/.git0/objects/74/af57fb3f5b864e67767cdc6de5cc5d8128ed3f new file mode 100644 index 0000000..8bc46d4 Binary files /dev/null and b/.git0/objects/74/af57fb3f5b864e67767cdc6de5cc5d8128ed3f differ diff --git a/.git0/objects/76/7936cc24d9c6375d610728d17068ca6339a83e b/.git0/objects/76/7936cc24d9c6375d610728d17068ca6339a83e new file mode 100644 index 0000000..3e63dd3 Binary files /dev/null and b/.git0/objects/76/7936cc24d9c6375d610728d17068ca6339a83e differ diff --git a/.git0/objects/76/86e8e66ba8f2d021d5b1eaa5b0fec09544929a b/.git0/objects/76/86e8e66ba8f2d021d5b1eaa5b0fec09544929a new file mode 100644 index 0000000..d3c0681 --- /dev/null +++ b/.git0/objects/76/86e8e66ba8f2d021d5b1eaa5b0fec09544929a @@ -0,0 +1,2 @@ +x}R[OQx{(o>H 4h06(^N醅%xI|i⣉9@ΜΜ1]LvwQV0/"(lHmGHI5T[WL1) +pI:(~{8LEcW \ԽNC^]ѵ]k/k q&?<[F[-' ikV;H]t$MK,CvFzYs!Fz2Ie/Gނdgǵ>fhɞ~^ӣyp8Vm(,u9~:[]O?UJ(b?Շ8V^??MNMB/d,K,q0'lF^XNOu?xz_WCG9Z!zc/H7|YjH#Buɣ=l3Bq^YxV`YЄRh,eS5d \ No newline at end of file diff --git a/.git0/objects/78/dd801c1e918c5e873c093724f514a77c56553d b/.git0/objects/78/dd801c1e918c5e873c093724f514a77c56553d new file mode 100644 index 0000000..ee1f9b6 Binary files /dev/null and b/.git0/objects/78/dd801c1e918c5e873c093724f514a77c56553d differ diff --git a/.git0/objects/7c/c2832b0f6f84cdf185e732430cb7aefa5808d8 b/.git0/objects/7c/c2832b0f6f84cdf185e732430cb7aefa5808d8 new file mode 100644 index 0000000..2e3f97c Binary files /dev/null and b/.git0/objects/7c/c2832b0f6f84cdf185e732430cb7aefa5808d8 differ diff --git a/.git0/objects/7e/e158ed37980429e63b13ef58bf5b4422e2c583 b/.git0/objects/7e/e158ed37980429e63b13ef58bf5b4422e2c583 new file mode 100644 index 0000000..9b6715e Binary files /dev/null and b/.git0/objects/7e/e158ed37980429e63b13ef58bf5b4422e2c583 differ diff --git a/.git0/objects/82/65456cf5917bab60a085cfbc523642d94d88eb b/.git0/objects/82/65456cf5917bab60a085cfbc523642d94d88eb new file mode 100644 index 0000000..750d713 Binary files /dev/null and b/.git0/objects/82/65456cf5917bab60a085cfbc523642d94d88eb differ diff --git a/.git0/objects/83/cefd2146c98f08052dab14bd61cd8ab1f9ba75 b/.git0/objects/83/cefd2146c98f08052dab14bd61cd8ab1f9ba75 new file mode 100644 index 0000000..121baee Binary files /dev/null and b/.git0/objects/83/cefd2146c98f08052dab14bd61cd8ab1f9ba75 differ diff --git a/.git0/objects/83/df41096968f6a3507ca73e06a2c6980557288a b/.git0/objects/83/df41096968f6a3507ca73e06a2c6980557288a new file mode 100644 index 0000000..5e5eda4 Binary files /dev/null and b/.git0/objects/83/df41096968f6a3507ca73e06a2c6980557288a differ diff --git a/.git0/objects/86/1afaad4052f7992a25dbcfd6e16a83fa740894 b/.git0/objects/86/1afaad4052f7992a25dbcfd6e16a83fa740894 new file mode 100644 index 0000000..6e6a3bf Binary files /dev/null and b/.git0/objects/86/1afaad4052f7992a25dbcfd6e16a83fa740894 differ diff --git a/.git0/objects/86/43318f06e325a9e325b7e6b0de54a0cf331d7a b/.git0/objects/86/43318f06e325a9e325b7e6b0de54a0cf331d7a new file mode 100644 index 0000000..0866e35 Binary files /dev/null and b/.git0/objects/86/43318f06e325a9e325b7e6b0de54a0cf331d7a differ diff --git a/.git0/objects/89/63c9a53e37d0da65344cc55d274dc5f6742c08 b/.git0/objects/89/63c9a53e37d0da65344cc55d274dc5f6742c08 new file mode 100644 index 0000000..5c63ca9 Binary files /dev/null and b/.git0/objects/89/63c9a53e37d0da65344cc55d274dc5f6742c08 differ diff --git a/.git0/objects/8e/f4642184a8350442c118d11f1c31147d6321c3 b/.git0/objects/8e/f4642184a8350442c118d11f1c31147d6321c3 new file mode 100644 index 0000000..4952edf Binary files /dev/null and b/.git0/objects/8e/f4642184a8350442c118d11f1c31147d6321c3 differ diff --git a/.git0/objects/92/0ac38f342e502be2a0ba52560c8be243eb62d1 b/.git0/objects/92/0ac38f342e502be2a0ba52560c8be243eb62d1 new file mode 100644 index 0000000..a6a7991 Binary files /dev/null and b/.git0/objects/92/0ac38f342e502be2a0ba52560c8be243eb62d1 differ diff --git a/.git0/objects/93/857aa636747ae082708f41a276e772082595ed b/.git0/objects/93/857aa636747ae082708f41a276e772082595ed new file mode 100644 index 0000000..6708c79 Binary files /dev/null and b/.git0/objects/93/857aa636747ae082708f41a276e772082595ed differ diff --git a/.git0/objects/97/e65207a850d0a095be03a327f8e692fb28436c b/.git0/objects/97/e65207a850d0a095be03a327f8e692fb28436c new file mode 100644 index 0000000..b66d41b --- /dev/null +++ b/.git0/objects/97/e65207a850d0a095be03a327f8e692fb28436c @@ -0,0 +1 @@ +xKOR4`PK)MIU)I/I˰BJ/JO.-.E*N-*K-O,)/E@jl" \ No newline at end of file diff --git a/.git0/objects/9c/0c9adf08310f03f51403ec970b232f922023ef b/.git0/objects/9c/0c9adf08310f03f51403ec970b232f922023ef new file mode 100644 index 0000000..a485edb Binary files /dev/null and b/.git0/objects/9c/0c9adf08310f03f51403ec970b232f922023ef differ diff --git a/.git0/objects/9c/548954bd57a3bc026990fe76814ad957ecc47f b/.git0/objects/9c/548954bd57a3bc026990fe76814ad957ecc47f new file mode 100644 index 0000000..de0dc05 Binary files /dev/null and b/.git0/objects/9c/548954bd57a3bc026990fe76814ad957ecc47f differ diff --git a/.git0/objects/9c/99621d56c5db439cf68512f2d136cad805bbbf b/.git0/objects/9c/99621d56c5db439cf68512f2d136cad805bbbf new file mode 100644 index 0000000..6030468 --- /dev/null +++ b/.git0/objects/9c/99621d56c5db439cf68512f2d136cad805bbbf @@ -0,0 +1,2 @@ +xUnQ`PԄ k2&M R:6i֤6L`;qp&@r4>Ucƥ M=g^TK…s{{5V6x_f_m\^-VJ>%Im@t ~ a]A%v^7AC>k{Vk];[-l-|pb'nN;_\#g4EN輖SdK)N٫/hL/|NYquSO/fŜD>MJ|~%[d7-7C +ؤ'EBU;rIm=7$B\I8;ǸB{$Ш<8?Csz#xxnԪ=?3%uUF{F{'qy&6NhyP1aS"?A6:`J' 4.͊Ydd@#+>+pk2FbU_!gΊEG&q|B򯽸s{XXG?IBxI\\GfRu4ISxoWKZ2UZOns^y.d 7sC/9 Ha?lE \ No newline at end of file diff --git a/.git0/objects/9f/6b79ab4f38030ea3a54f9043ffa9a508d95e37 b/.git0/objects/9f/6b79ab4f38030ea3a54f9043ffa9a508d95e37 new file mode 100644 index 0000000..3d51eb7 Binary files /dev/null and b/.git0/objects/9f/6b79ab4f38030ea3a54f9043ffa9a508d95e37 differ diff --git a/.git0/objects/a1/07991d7addcafe6f137b1736ff0d6b997aa7a5 b/.git0/objects/a1/07991d7addcafe6f137b1736ff0d6b997aa7a5 new file mode 100644 index 0000000..6d649f4 Binary files /dev/null and b/.git0/objects/a1/07991d7addcafe6f137b1736ff0d6b997aa7a5 differ diff --git a/.git0/objects/a1/3d66467e985e7e5f875dfb0c75f007f59ee52a b/.git0/objects/a1/3d66467e985e7e5f875dfb0c75f007f59ee52a new file mode 100644 index 0000000..3375267 Binary files /dev/null and b/.git0/objects/a1/3d66467e985e7e5f875dfb0c75f007f59ee52a differ diff --git a/.git0/objects/a4/e040bda7b91dc2bfefd120a03b94b56a886299 b/.git0/objects/a4/e040bda7b91dc2bfefd120a03b94b56a886299 new file mode 100644 index 0000000..69d7c21 Binary files /dev/null and b/.git0/objects/a4/e040bda7b91dc2bfefd120a03b94b56a886299 differ diff --git a/.git0/objects/a5/fc2204b80e7b277448698cead76042b3de16cd b/.git0/objects/a5/fc2204b80e7b277448698cead76042b3de16cd new file mode 100644 index 0000000..49d53ea Binary files /dev/null and b/.git0/objects/a5/fc2204b80e7b277448698cead76042b3de16cd differ diff --git a/.git0/objects/a6/3553e4155393c782ee65569f5586d4746ad763 b/.git0/objects/a6/3553e4155393c782ee65569f5586d4746ad763 new file mode 100644 index 0000000..26f677e Binary files /dev/null and b/.git0/objects/a6/3553e4155393c782ee65569f5586d4746ad763 differ diff --git a/.git0/objects/af/a46b5701e28bf816cacd80e7a691a29b19a793 b/.git0/objects/af/a46b5701e28bf816cacd80e7a691a29b19a793 new file mode 100644 index 0000000..aa07d2a Binary files /dev/null and b/.git0/objects/af/a46b5701e28bf816cacd80e7a691a29b19a793 differ diff --git a/.git0/objects/b9/3046d9f42e80f5294ab836e033ba1723c325a5 b/.git0/objects/b9/3046d9f42e80f5294ab836e033ba1723c325a5 new file mode 100644 index 0000000..c45ab85 Binary files /dev/null and b/.git0/objects/b9/3046d9f42e80f5294ab836e033ba1723c325a5 differ diff --git a/.git0/objects/b9/ee8ac20ffc8e8947a7f3fa95a4e044893baeda b/.git0/objects/b9/ee8ac20ffc8e8947a7f3fa95a4e044893baeda new file mode 100644 index 0000000..e35fa40 Binary files /dev/null and b/.git0/objects/b9/ee8ac20ffc8e8947a7f3fa95a4e044893baeda differ diff --git a/.git0/objects/ba/9152f59d3cd817ae2ce1ab8138f6100be4981c b/.git0/objects/ba/9152f59d3cd817ae2ce1ab8138f6100be4981c new file mode 100644 index 0000000..0bb3e9e --- /dev/null +++ b/.git0/objects/ba/9152f59d3cd817ae2ce1ab8138f6100be4981c @@ -0,0 +1,2 @@ +xnA&J*Z/Bd`CXBU7)O"%]So<,3=3s3sfh2;=/Ϸ!}2} Ђ<<=<:)*1Du4 Dmg7x¿y=0bN9JFevq1xOq\Oax8s^SD5שOXƘe^ngxgƘ!kK?f3j7 o QF9\KQ +Mo[KHL@Mk(̣Chy sk2^:LYwRt0)k|1Tc(`.KjhfU"[aZ٢[]FURu~4.|Qsyϩ-{P_}8V>?f/͙ӈ8߳l}IuThBijY)jR2d*=g)YxX1-0) + { + for(int j=0;j +#include + + +mutex m; + +int bom_zie = 0; + +using namespace std; +using namespace Teamcenter; + +typedef struct threadArg2 +{ + CcemEb_parent parent; + tag_t factoryNo; + tag_t folder; + map map_revs; + char zt2_WBSNo[1024]; +}ThreadArg2; + + +typedef struct threadArg +{ + tag_t folder; //ļ + tag_t factoryNo; // + tag_t copy_rev; // + vector revs; + char object_name[1024]; + char owning_user[1024]; + char zt2_MaterialNo[1024]; + char zt2_WBSNo[1024]; + vector uids; + vector qtys; + vector signs; + int cout_tag; +}ThreadArg ; + +DWORD WINAPI createDYCCBOM5(LPVOID p) +{ + ThreadArg2 *pt = (ThreadArg2*)p; + + CcemEb_parent parent = pt->parent; + map map_revs = pt->map_revs; + tag_t folder = pt->folder; + tag_t factoryNo = pt->factoryNo; + + tag_t copy_rev = map_revs[parent.ebGoodsCode]; + tag_t item, copy_item; + tag_t rev; + tag_t item_type; + POM_AM__set_application_bypass(true); + LINFO << "Ƹ"; + SAFECALL(ITEM_ask_item_of_rev(copy_rev, ©_item)); + SAFECALL(TCTYPE_ask_object_type(copy_item, &item_type)); + LINFO << "ȡID"; + char *id; + logical model = false; + SAFECALL(USER_new_item_id(NULLTAG, item_type, &model, &id)); + stringstream ss; + ss.str(""); + ss << "ID:" << id; + LINFO << ss.str().c_str(); + SAFECALL(ITEM_copy_item(copy_rev, id, NULL, &item, &rev)); + LINFO << "ʼļ"; + SAFECALL(AOM_lock(folder)); + SAFECALL(FL_insert(folder, item, 999)); + SAFECALL(AOM_save(folder)); + SAFECALL(AOM_unlock(folder)); + LINFO << "ļӽ,ʼ޸"; + char *object_name; + string new_name; + SAFECALL(AOM_ask_value_string(rev, "object_name", &object_name)); + new_name = ""; + new_name += object_name; + new_name += " "; + new_name += parent.ebTeRe.c_str(); + parent.item = item; + SAFECALL(AOM_lock(rev)); + SAFECALL(AOM_set_value_string(rev, "object_name", new_name.c_str())); + SAFECALL(AOM_set_value_string(rev, "zt2_MaterialNo", parent.zt2_MaterialNo.c_str())); + SAFECALL(AOM_set_value_string(rev, "zt2_WBSNo", pt->zt2_WBSNo)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_set_value_string(item, "object_name", new_name.c_str())); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + int attr1, attr2, attr3; + BOM_line_look_up_attribute("bl_sequence_no", &attr1); + BOM_line_look_up_attribute("bl_ref_designator", &attr2); + BOM_line_look_up_attribute("bl_quantity", &attr3); + LINFO << "ӳ"; + tag_t relation_type; + GRM_find_relation_type("ZT2_FactoryNumber", &relation_type); + tag_t relation; + SAFECALL(GRM_create_relation(rev, factoryNo, relation_type, NULLTAG, &relation)); + SAFECALL(GRM_save_relation(relation)); + SAFECALL(AOM_unlock(relation)); + LINFO << "ʼBOM"; + tag_t child_BOMView, parent_BOMView, topLine, bvr; + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_lock(rev)); + SAFECALL(PS_create_bom_view(NULLTAG, "", "", item, &parent_BOMView)); + SAFECALL(AOM_save(parent_BOMView)); + SAFECALL(PS_create_bvr(parent_BOMView, "", "", false, rev, &bvr)); + SAFECALL(AOM_save(bvr)); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + tag_t win, line; + BOM_create_window(&win); + BOM_set_window_pack_all(win, false); + SAFECALL(BOM_set_window_top_line(win, NULLTAG, rev, NULLTAG, &topLine)); + string childCode; + int index = 10; + for (auto child = parent.childs.begin(); child != parent.childs.end(); child++) + { + (*child).rev = map_revs[(*child).ebGoodsCode]; + childCode = (*child).ebGoodsCode; + SAFECALL(BOM_line_add(topLine, NULL, map_revs[childCode], NULL, &line)); + SAFECALL(BOM_line_set_attribute_string(line, attr1, format("%d", index).c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attr2, (*child).ebSign.c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attr3, (*child).ebQty.c_str())); + index += 10; + } + BOM_save_window(win); + BOM_close_window(win); + DOFREE(id); + DOFREE(object_name); + LINFO << "BOM"; + POM_AM__set_application_bypass(false); + return 0; + + + +} +DWORD WINAPI testCreate(LPVOID p) +{ + LINFO << "testCreate start"; + ThreadArg *ta = (ThreadArg*)p; + int size1 = ta->revs.size(); + int size2 = ta->qtys.size(); + int size3 = ta->signs.size(); + stringstream ss; + ss.str(""); + ss << "汾:" << size1; + ss << ";:" << size2; + ss << ";λŸ:" << size3; + ss << ";object_name:" << ta->object_name; + ss << ";zt2_MaterialNo:" << ta->zt2_MaterialNo; + ss << ";zt2_WBSNo:" << ta->zt2_WBSNo; + LINFO << ss.str().c_str(); + if (1 == 1) + return 0; + + + + tag_t copy_rev = ta->copy_rev; + tag_t factoryNo = ta->factoryNo; + tag_t folder = ta->folder; + tag_t item, copy_item; + tag_t rev; + tag_t item_type; + POM_AM__set_application_bypass(true); + LINFO << "Ƹ"; + SAFECALL(ITEM_ask_item_of_rev(copy_rev, ©_item)); + SAFECALL(TCTYPE_ask_object_type(copy_item, &item_type)); + LINFO << "ȡID"; + char *id; + logical model = false; + SAFECALL(USER_new_item_id(NULLTAG, item_type, &model, &id)); + ss.str(""); + ss << "ID:" << id; + LINFO << ss.str().c_str(); + SAFECALL(ITEM_copy_item(copy_rev, id, NULL, &item, &rev)); + LINFO << "ʼļ"; + SAFECALL(AOM_lock(folder)); + SAFECALL(FL_insert(folder, item, 999)); + SAFECALL(AOM_save(folder)); + SAFECALL(AOM_unlock(folder)); + LINFO << "ļӽ,ʼ޸"; + SAFECALL(AOM_lock(rev)); + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_set_value_string(rev, "object_name", ta->object_name)); + SAFECALL(AOM_set_value_string(rev, "zt2_MaterialNo", ta->zt2_MaterialNo)); + SAFECALL(AOM_set_value_string(rev, "zt2_WBSNo", ta->zt2_WBSNo)); + SAFECALL(AOM_set_value_string(item, "object_name", ta->object_name)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + int attr1, attr2, attr3; + BOM_line_look_up_attribute("bl_sequence_no", &attr1); + BOM_line_look_up_attribute("bl_ref_designator", &attr2); + BOM_line_look_up_attribute("bl_quantity", &attr3); + LINFO << "ӳ"; + tag_t relation_type; + GRM_find_relation_type("ZT2_FactoryNumber", &relation_type); + tag_t relation; + SAFECALL(GRM_create_relation(rev, factoryNo, relation_type, NULLTAG, &relation)); + SAFECALL(GRM_save_relation(relation)); + SAFECALL(AOM_unlock(relation)); + LINFO << "ʼBOM"; + tag_t child_BOMView, parent_BOMView, topLine, bvr; + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_lock(rev)); + SAFECALL(PS_create_bom_view(NULLTAG, "", "", item, &parent_BOMView)); + SAFECALL(AOM_save(parent_BOMView)); + SAFECALL(PS_create_bvr(parent_BOMView, "", "", false, rev, &bvr)); + SAFECALL(AOM_save(bvr)); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + tag_t win, line; + BOM_create_window(&win); + BOM_set_window_pack_all(win, false); + SAFECALL(BOM_set_window_top_line(win, NULLTAG, rev, NULLTAG, &topLine)); + int index = 10; + vector qtys = ta->qtys; + vector signs = ta->signs; + vector revs = ta->revs; + for (auto i = 3; i < ta->cout_tag; i++) + { + SAFECALL(BOM_line_add(topLine, NULL, revs.at(i), NULL, &line)); + SAFECALL(BOM_line_set_attribute_string(line, attr1, format("%d", index).c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attr2, signs.at(i-3).c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attr3, format("%d", atoi(qtys[i-3].c_str())).c_str())); + index += 10; + } + + BOM_save_window(win); + BOM_close_window(win); + DOFREE(id); + LINFO << "BOM"; + POM_AM__set_application_bypass(false); + return 0; +} + +int DYCreateElectricalBOM3(void *return_data) +{ + + int ifail = ITK_ok; + int cout_tag, cout_qty, cout_sign; + threadArg t; + tag_t *revs; + char **qtys, **signs; + char *zt2_WBSNo, *zt2_MaterialNo, *object_name; + USERARG_get_string_argument(&zt2_WBSNo); + USERARG_get_string_argument(&zt2_MaterialNo); + USERARG_get_string_argument(&object_name); + USERARG_get_tag_array_argument(&cout_tag, &revs); + USERARG_get_string_array_argument(&cout_qty, &qtys); + USERARG_get_string_array_argument(&cout_sign, &signs); + LINFO << "zt2_WBSNo:" << zt2_WBSNo << ";zt2_MaterialNo:" << zt2_MaterialNo << ";object_name:" << object_name; + strcpy(t.zt2_WBSNo, zt2_WBSNo); + strcpy(t.zt2_MaterialNo, zt2_MaterialNo); + strcpy(t.object_name, object_name); + t.copy_rev = revs[0]; + t.factoryNo = revs[1]; + t.folder = revs[2]; + LINFO << "cout_tag:" << cout_tag << ";cout_qty:" << cout_qty << ";cout_sign:" << cout_sign; + /* + for (auto i = 3; i < cout_tag; i++) + { + t.revs.push_back(revs[i]); + t.qtys.push_back(qtys[i-3]); + t.signs.push_back(signs[i - 3]); + } + */ + char *uid; + for (auto i = 0; i < cout_tag; i++) + { + char puid[1024]; + ITK__convert_tag_to_uid(revs[i],&uid); + strcpy(puid,uid); + t.uids.push_back(puid); + } + + for (auto i = 0; i < cout_qty; i++) + { + char puid[1024]; + strcpy(puid, qtys[i]); + t.qtys.push_back(puid); + } + for (auto i = 0; i < cout_sign; i++) + { + char puid[1024]; + strcpy(puid, signs[i]); + t.signs.push_back(puid); + } + DOFREE(signs); + DOFREE(qtys); + DOFREE(revs); + DOFREE(object_name); + DOFREE(zt2_MaterialNo); + DOFREE(zt2_WBSNo); + + + HANDLE hThread; + hThread = CreateThread(NULL, 0, testCreate, (LPVOID)&t, 0, NULL); + + + + return ifail; +} + + + + +/*ȡšļ*/ +void getFolderByProject(tag_t &project, tag_t *folder_factoryNo, tag_t *folder_electrical) +{ + + //LINFO << "getFolderByProject start"; + tag_t *refs; + int ref_cout; + tag_t *refs2; + int ref_cout2; + /*ĿĿִļ*/ + tag_t folder_launch = NULLTAG, folder_execute = NULLTAG; + AOM_ask_value_tags(project,"IMAN_reference",&ref_cout,&refs); + /**/ + char *object_name; + string folder_name; + /* ĿִСĿļ*/ + for (int i = 0; i < ref_cout; i++) + { + if (folder_launch != NULLTAG && folder_execute != NULLTAG) + { + break; + } + AOM_ask_value_string(refs[i],"object_name",&object_name); + //LINFO << i << "--" << object_name; + folder_name.clear(); + folder_name.append(object_name); + //LINFO << "--" << folder_name; + if (folder_name.find("Ŀ") != string::npos) + { + //LINFO << "ҵĿļ"; + AOM_ask_value_tags(refs[i], "contents", &ref_cout2, &refs2); + for (int j = 0; j < ref_cout2; j++) + { + AOM_ask_value_string(refs2[j], "object_name", &object_name); + // LINFO << j << "--" << object_name; + folder_name.clear(); + folder_name.append(object_name); + if (folder_name.find("") != string::npos) + { + *folder_factoryNo = refs2[j]; + break; + } + } + } + else if (folder_name.find("Ŀִ") != string::npos) + { + //folder_execute = refs[i]; + //LINFO << "ҵĿִļ"; + AOM_ask_value_tags(refs[i], "contents", &ref_cout2, &refs2); + for (int j = 0; j < ref_cout2; j++) + { + AOM_ask_value_string(refs2[j], "object_name", &object_name); + //LINFO << j << "--" << object_name; + folder_name.clear(); + folder_name.append(object_name); + if (folder_name.find("") != string::npos) + { + *folder_electrical = refs2[j]; + break; + } + } + } + else + { + //LINFO << i << GBKToUTF8("--ɶҲ"); + } + } + /*Ŀִ->*/ + if (folder_execute != NULLTAG) + { + + } + /*Ŀ->*/ + if (&folder_launch != NULLTAG) + { + + } + //LINFO << "getFolderByProject end"; + DOFREE(object_name); + DOFREE(refs); + DOFREE(refs2); +} +int printfBOM(CcemFactoryBean fn,CcemEb_parent bean) +{ + vector childs = bean.childs; + stringstream ss; + ss.str(""); + ss << "factoryNo:" < parents = bean.boms; + + for (auto it_fn = parents.begin(); it_fn != parents.end(); it_fn++) + { + ss.str(""); + vector childs = (*it_fn).childs; + ss << "[" << (*it_fn).ebGoodsCode << ":child["; + for (auto it = childs.begin(); it != childs.end(); it++) + { + ss << " EbGoodsCode=" << (*it).ebGoodsCode << ", EbQty="<<(*it).ebQty<<", EbSign="<<(*it).ebSign; + } + ss << " ] ]"; + LINFO << "--parent "< map_revs, tag_t folder, const char *zt2_WBSNo) +{ + tag_t copy_rev; + tag_t item, copy_item; + tag_t rev; + tag_t item_type; + char *id; + char *object_naem; + string new_name; + logical model = false; + tag_t relation; + tag_t relation_type; + tag_t win; + tag_t child_BOMView, parent_BOMView, topLine, bvr; + int attr1, attr2, attr3; + BOM_line_look_up_attribute("bl_sequence_no", &attr1); + BOM_line_look_up_attribute("bl_ref_designator", &attr2); + BOM_line_look_up_attribute("bl_quantity", &attr3); + vector attrs; + attrs.push_back(attr1); + attrs.push_back(attr2); + attrs.push_back(attr3); + BOM_create_window(&win); + BOM_set_window_pack_all(win, false); + GRM_find_relation_type("ZT2_FactoryNumber", &relation_type); + vector parents = bean.boms; + { + //lock_guard g1(m); + LINFO << ":" << bean.factoryNo_id.c_str() << "ʼ"; + for (auto it = parents.begin(); it != parents.end(); it++) + { + if ((*it).childs.size() == 0) + continue; + CcemEb_parent parent = (*it); + copy_rev = map_revs[parent.ebGoodsCode]; + SAFECALL(ITEM_ask_item_of_rev(copy_rev, ©_item)); + SAFECALL(TCTYPE_ask_object_type(copy_item, &item_type)); + SAFECALL(USER_new_item_id(NULLTAG, item_type, &model, &id)); + SAFECALL(ITEM_copy_item(copy_rev, id, NULL, &item, &rev)); + SAFECALL(AOM_lock(folder)); + SAFECALL(FL_insert(folder, item, 999)); + SAFECALL(AOM_save(folder)); + SAFECALL(AOM_unlock(folder)); + SAFECALL(AOM_ask_value_string(rev, "object_name", &object_naem)); + new_name = ""; + new_name += object_naem; + new_name += " "; + new_name += parent.ebTeRe.c_str(); + parent.item = item; + SAFECALL(AOM_lock(rev)); + SAFECALL(AOM_set_value_string(rev, "object_name", new_name.c_str())); + SAFECALL(AOM_set_value_string(rev, "zt2_MaterialNo", parent.zt2_MaterialNo.c_str())); + SAFECALL(AOM_set_value_string(rev, "zt2_WBSNo", zt2_WBSNo)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_set_value_string(item, "object_name", new_name.c_str())); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + SAFECALL(GRM_create_relation(rev, bean.factoryNo, relation_type, NULLTAG, &relation)); + SAFECALL(GRM_save_relation(relation)); + SAFECALL(AOM_unlock(relation)); + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_lock(rev)); + SAFECALL(PS_create_bom_view(NULLTAG, "", "", item, &parent_BOMView)); + SAFECALL(AOM_save(parent_BOMView)); + SAFECALL(PS_create_bvr(parent_BOMView, "", "", false, rev, &bvr)); + SAFECALL(AOM_save(bvr)); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(BOM_set_window_top_line(win, NULLTAG, rev, NULLTAG, &topLine)); + string childCode; + tag_t line; + int i = 10; + for (auto child = parent.childs.begin(); child != parent.childs.end(); child++) + { + (*child).rev = map_revs[(*child).ebGoodsCode]; + childCode = (*child).ebGoodsCode; + SAFECALL(BOM_line_add(topLine, NULL, map_revs[childCode], NULL, &line)); + SAFECALL(BOM_line_set_attribute_string(line, attrs.at(0), format("%d", i).c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attrs.at(1), (*child).ebSign.c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attrs.at(2), (*child).ebQty.c_str())); + i += 10; + } + BOM_save_window(win); + + } + + BOM_close_window(win); + + DOFREE(object_naem); + DOFREE(id); + LINFO << ":" << bean.factoryNo_id.c_str() << "end"; + bom_zie--; + } + + + + return 0; +} + +int createDYCCBOM(CcemFactoryBean bean, CcemEb_parent parent, tag_t win, map map_revs, tag_t folder + , const char *zt2_WBSNo + ,vector attrs + , tag_t realtion_type) +{ + if (parent.childs.size() == 0) + { + return 0; + } + tag_t copy_rev = map_revs[parent.ebGoodsCode]; + tag_t item,copy_item; + tag_t rev; + tag_t item_type; + SAFECALL(ITEM_ask_item_of_rev(copy_rev, ©_item)); + SAFECALL(TCTYPE_ask_object_type(copy_item, &item_type)); + char *id; + logical model = false; + SAFECALL(USER_new_item_id(NULLTAG, item_type, &model, &id)); + + stringstream ss; + ss.str(""); + ss << "ID:" << id; + //LINFO << ss.str().c_str(); + SAFECALL(ITEM_copy_item(copy_rev, id, NULL, &item, &rev)); + SAFECALL(AOM_lock(folder)); + SAFECALL(FL_insert(folder, item, 999)); + SAFECALL(AOM_save(folder)); + SAFECALL(AOM_unlock(folder)); + + char *object_naem; + SAFECALL(AOM_ask_value_string(rev, "object_name", &object_naem)); + string new_name = ""; + new_name += object_naem; + new_name += " "; + new_name += parent.ebTeRe.c_str(); + SAFECALL(AOM_lock(rev)); + SAFECALL(AOM_set_value_string(rev, "object_name", new_name.c_str())); + SAFECALL(AOM_set_value_string(rev, "zt2_MaterialNo", parent.zt2_MaterialNo.c_str())); + SAFECALL(AOM_set_value_string(rev, "zt2_WBSNo", zt2_WBSNo)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_set_value_string(item, "object_name", new_name.c_str())); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + tag_t relation; + SAFECALL(GRM_create_relation(rev, bean.factoryNo, realtion_type, NULLTAG, &relation)); + SAFECALL(GRM_save_relation(relation)); + SAFECALL(AOM_unlock(relation)); + + //LINFO << "ӹϵ"; + tag_t child_BOMView, parent_BOMView, topLine, bvr; + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_lock(rev)); + SAFECALL(PS_create_bom_view(NULLTAG, "", "", item, &parent_BOMView)); + SAFECALL(AOM_save(parent_BOMView)); + + SAFECALL(PS_create_bvr(parent_BOMView, "", "", false, rev, &bvr)); + SAFECALL(AOM_save(bvr)); + //SAFECALL(BOM_close_window(bvr)); + //SAFECALL(BOM_close_window(parent_BOMView)); + + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(BOM_set_window_top_line(win, NULLTAG, rev, NULLTAG, &topLine)); + //LINFO << "ʼBOM"; + string childCode; + tag_t line; + int i = 10; + int size = parent.childs.size(); + for (auto it = parent.childs.begin(); it != parent.childs.end(); it++) + { + childCode = (*it).ebGoodsCode; + SAFECALL(BOM_line_add(topLine, NULL, map_revs[childCode], NULL, &line)); + SAFECALL(BOM_line_set_attribute_string(line, attrs.at(0), format("%d", i).c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attrs.at(1), (*it).ebSign.c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attrs.at(2), (*it).ebQty.c_str())); + i += 10; + } + SAFECALL(BOM_save_window(win)); + SAFECALL(BOM_close_window(win)); + DOFREE(id); + DOFREE(object_naem); + //LINFO << "createDYCCBOM end"; + return 0; +} + +/*ȡż*/ +void getFactoryNo(tag_t folder_product, map *map_factoryNos) +{ + //LINFO << "getFactoryNo start"; + tag_t *refs,*factoryNos; + int ref_cout,fn_cout; + SAFECALL(AOM_ask_value_tags(folder_product, "contents", &fn_cout, &factoryNos)); + char * item_id, *object_name,**relations; + int product_cout = 0,*level; + string produce_name; + for (int i = 0; i < fn_cout; i++) + { + product_cout = 0; + //AOM_ask_value_string(ccp[i], "object_name", &object_name); + SAFECALL(WSOM_where_referenced(factoryNos[i], 1, &ref_cout, &level, &refs, &relations)); + for (int j = 0; j < ref_cout; j++) + { + if (product_cout > 0) + { + break; + } + if (isTypeOf(refs[i], "Part Revision")) + { + AOM_ask_value_string(factoryNos[i], "object_name", &object_name); + produce_name.clear(); + produce_name.append(object_name); + /*̶Ԫ/뵥Ԫȡ,Ʒ߿ɼȡ*/ + if (produce_name.find("̶Ԫ") != string::npos || produce_name.find("뵥Ԫ") != string::npos) + { + + LINFO << "̶Ԫ/뵥Ԫ"; + product_cout=1; + break; + } + } + + + } + if (product_cout < 1) + { + SAFECALL(AOM_ask_value_string(factoryNos[i],"item_id",&item_id)); + (*map_factoryNos)[item_id] = factoryNos[i]; + } + } + DOFREE(item_id); + DOFREE(object_name); + DOFREE(level); + DOFREE(refs); + DOFREE(relations); + DOFREE(factoryNos); + //LINFO << "getFactoryNo end"; +} + +void getBOMList(map &map_factoryNos, string zt2_WBSNo,tag_t &folder_electrical,string &error); + + +int DYCreateElectricalBOM2(void *return_data) +{ + + //LINFO << "DYCreateElectricalBOM2 start"; + int ifail = ITK_ok; + int cout_tag,cout_qty,cout_sign; + tag_t *revs; + char **qtys, **signs; + char *zt2_WBSNo, *zt2_MaterialNo,*object_name; + USERARG_get_string_argument(&zt2_WBSNo); + USERARG_get_string_argument(&zt2_MaterialNo); + USERARG_get_string_argument(&object_name); + USERARG_get_tag_array_argument(&cout_tag,&revs); + USERARG_get_string_array_argument(&cout_qty, &qtys); + USERARG_get_string_array_argument(&cout_sign, &signs); + + + tag_t factoryNo = revs[1]; + tag_t copy_rev = revs[0]; + tag_t folder = revs[2]; + tag_t item, copy_item; + tag_t rev; + tag_t item_type; + POM_AM__set_application_bypass(true); + SAFECALL(ITEM_ask_item_of_rev(copy_rev, ©_item)); + SAFECALL(TCTYPE_ask_object_type(copy_item, &item_type)); + char *id; + logical model = false; + SAFECALL(USER_new_item_id(NULLTAG, item_type, &model, &id)); + //string + //stringstream ss; + //ss.str(""); + //ss << "ID:" << id; + SAFECALL(ITEM_copy_item(copy_rev, id, NULL, &item, &rev)); + SAFECALL(AOM_lock(folder)); + SAFECALL(FL_insert(folder, item, 999)); + SAFECALL(AOM_save(folder)); + SAFECALL(AOM_unlock(folder)); + SAFECALL(AOM_lock(rev)); + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_set_value_string(rev, "object_name", object_name)); + SAFECALL(AOM_set_value_string(rev, "zt2_MaterialNo", zt2_MaterialNo)); + SAFECALL(AOM_set_value_string(rev, "zt2_WBSNo", zt2_WBSNo)); + SAFECALL(AOM_set_value_string(item, "object_name", object_name)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + int attr1, attr2, attr3; + BOM_line_look_up_attribute("bl_sequence_no", &attr1); + BOM_line_look_up_attribute("bl_ref_designator", &attr2); + BOM_line_look_up_attribute("bl_quantity", &attr3); + tag_t relation_type; + GRM_find_relation_type("ZT2_FactoryNumber", &relation_type); + tag_t relation; + SAFECALL(GRM_create_relation(rev, factoryNo, relation_type, NULLTAG, &relation)); + SAFECALL(GRM_save_relation(relation)); + SAFECALL(AOM_unlock(relation)); + tag_t child_BOMView, parent_BOMView, topLine, bvr; + SAFECALL(AOM_lock(item)); + SAFECALL(AOM_lock(rev)); + SAFECALL(PS_create_bom_view(NULLTAG, "", "", item, &parent_BOMView)); + SAFECALL(AOM_save(parent_BOMView)); + SAFECALL(PS_create_bvr(parent_BOMView, "", "", false, rev, &bvr)); + SAFECALL(AOM_save(bvr)); + SAFECALL(AOM_save(item)); + SAFECALL(AOM_unlock(item)); + SAFECALL(AOM_save(rev)); + SAFECALL(AOM_unlock(rev)); + tag_t win,line; + BOM_create_window(&win); + BOM_set_window_pack_all(win, false); + SAFECALL(BOM_set_window_top_line(win, NULLTAG, rev, NULLTAG, &topLine)); + int index = 10; + char *item_id; + for (auto i = 3; i < cout_tag; i++) + { + SAFECALL(BOM_line_add(topLine, NULL,revs[i], NULL, &line)); + AOM_ask_value_string(revs[i], "item_id", &item_id); + SAFECALL(BOM_line_set_attribute_string(line, attr1, format("%d", index).c_str())); + SAFECALL(BOM_line_set_attribute_string(line, attr2, signs[i-3])); + SAFECALL(BOM_line_set_attribute_string(line, attr3, format("%d", atoi(qtys[i - 3])).c_str())); + index+= 10; + } + BOM_save_window(win); + BOM_close_window(win); + DOFREE(zt2_MaterialNo); + DOFREE(zt2_WBSNo); + DOFREE(object_name); + DOFREE(id); + DOFREE(qtys); + DOFREE(signs); + DOFREE(revs); + DOFREE(item_id); + //LINFO << "BOM"; + POM_AM__set_application_bypass(false); + //LINFO << "DYCreateElectricalBOM2 end"; + return ifail; +} + + + + + + + + + + + + + +/*ѹϴȡBOM*/ +int DYCreateElectricalBOM(void *return_data) +{ + int ifail = ITK_ok; + stringstream str_message; + str_message.str(""); + //Ŀ + tag_t project=NULLTAG; + tag_t folder_factoryNo = NULLTAG, folder_electrical = NULLTAG; + USERARG_get_tag_argument(&project); + getFolderByProject(project, &folder_factoryNo, &folder_electrical); + //LINFO << "ļлȡ"; + char ** stringarray = nullptr; + stringarray = (char **)MEM_alloc(3 * sizeof(char*)); + stringarray[0] = "success"; + stringarray[1] = "field"; + stringarray[2] = "BOMȡɹ"; + if (folder_factoryNo != NULLTAG && folder_electrical != NULLTAG) + { + map map_factoryNos; + char *zt2_WBSNo; + string error = ""; + getFactoryNo(folder_factoryNo,&map_factoryNos); + int size_factoryNo = map_factoryNos.size(); + LINFO << "Ÿ:" << size_factoryNo; + if (size_factoryNo == 0) + { + error.append("ڷij,Ŀݡ"); + stringarray[1] = (char *)MEM_alloc((strlen(error.c_str()) + 1) * sizeof(char)); + strcpy(stringarray[1], error.c_str()); + } + else + { + map::iterator it_fn; + int cout = 1; + AOM_ask_value_string(project, "zt2_WBSNo", &zt2_WBSNo); + getBOMList(map_factoryNos, zt2_WBSNo, folder_electrical, error); + stringarray[1] = (char *)MEM_alloc((strlen(error.c_str()) + 1) * sizeof(char)); + strcpy(stringarray[1], error.c_str()); + DOFREE(zt2_WBSNo); + } + } + + + + + USERSERVICE_array_t arrayStruct; + USERSERVICE_return_string_array((const char**)stringarray, 3, + &arrayStruct); + *(USERSERVICE_array_t*)return_data = arrayStruct; + return ifail; +} + +struct rev_MaterialNo_sort{ + tag_t rev; + string zt2_MaterialNo; +}; +bool sort_by_rev_MaterialNo(const rev_MaterialNo_sort &a, const rev_MaterialNo_sort &b) +{ + return a.zt2_MaterialNo > b.zt2_MaterialNo; +} +int list_all_parts(vector vecs) +{ + vector rev_vec; + for (auto it = vecs.begin(); it != vecs.end(); it++) + { + rev_MaterialNo_sort sort; + char *zt2_MaterialNo; + AOM_ask_value_string((*it), "zt2_MaterialNo", &zt2_MaterialNo); + sort.rev = (*it); + sort.zt2_MaterialNo = zt2_MaterialNo; + rev_vec.push_back(sort); + } + sort(rev_vec.begin(), rev_vec.end(), sort_by_rev_MaterialNo); + return 0; +} + +//ȡˮ +int getTypeNumber(vector vecs,int *num) +{ + *num = 1; + if (vecs.size() == 0) + { + return 0; + } + vector rev_vec; + char *MaterialNo; + for (auto it = vecs.begin(); it != vecs.end(); it++) + { + rev_MaterialNo_sort sort; + + AOM_ask_value_string((*it), "zt2_MaterialNo", &MaterialNo); + sort.rev = (*it); + sort.zt2_MaterialNo = MaterialNo; + rev_vec.push_back(sort); + + } + sort(rev_vec.begin(), rev_vec.end(), sort_by_rev_MaterialNo); + string zt2_MaterialNo = rev_vec.at(0).zt2_MaterialNo; + zt2_MaterialNo.erase(0, zt2_MaterialNo.find_last_of("-")); + if (zt2_MaterialNo.find("-") != string::npos) + { + zt2_MaterialNo.erase(0, zt2_MaterialNo.find_last_of("-") + 1); + *num = atoi(zt2_MaterialNo.c_str()) + 1; + } + DOFREE(MaterialNo); + return 0; +} + + + +void getBOMList(map &map_factoryNos, string zt2_WBSNo, tag_t &folder_electrical + ,string &error) +{ + SAConnection conn; + SACommand command; + tag_t win; + try{ + dbProperties_CC db_CC; + conn.Connect("10.128.10.135@CHINT_DB", "PLMUser", "PLMUser", SA_SQLServer_Client); + command.setConnection(&conn); + stringstream sql; + stringstream fields; + sql.str(""); + fields.str(""); + sql<<"select t.FnCode,t.FnCnCode from CcemFn t where t.FnCode in ("; + int cout = 1; + for (auto it_fn = map_factoryNos.begin(); it_fn != map_factoryNos.end(); it_fn++) + { + if (it_fn == map_factoryNos.begin()) + { + sql << " \'" << it_fn->first.c_str() << " \'"; + } + else + { + sql << " ,\'" << it_fn->first.c_str() << "\'"; + } + cout++; + fields << it_fn->first.c_str(); + } + sql << ')'; + command.setCommandText(sql.str().c_str()); + command.Execute(); + string fnCode = "", fnCnCode = ""; + vector beans; + map map_beans; + while (command.FetchNext()) + { + fnCode = command.Field(1).asString().GetMultiByteChars(); + fnCnCode = command.Field(2).asString().GetMultiByteChars(); + if (!isEmpty(fnCnCode)) + { + if (map_beans.find(fnCode) != map_beans.end()) + { + map_beans[fnCode].list_FnCnCodes.push_back(fnCnCode); + } + else + { + CcemFactoryBean bean; + bean.factoryNo = map_factoryNos[fnCode]; + bean.factoryNo_id = fnCode; + bean.list_FnCnCodes.push_back(fnCnCode); + map_beans[fnCode] = bean; + beans.push_back(bean); + } + } + } + stringstream str_error; + str_error.str(""); + stringstream str_err; + + if (map_beans.empty() || map_beans.size() == 0) + { + string value = "δȡĿӦĹ淶Ϣ"; + error.append(value.c_str()); + conn.Disconnect(); + return; + } + int size_fn = map_beans.size(); + //LINFO << ":" << size_fn; + /*ѯǷBOMظֵ*/ + for (auto it_fn = beans.begin(); it_fn != beans.end(); it_fn++) + { + vector list_FnCnCodes = (*it_fn).list_FnCnCodes; + str_err.str(""); + for (auto it = list_FnCnCodes.begin(); it != list_FnCnCodes.end(); it++) + { + command.setCommandText("SELECT EbGoodsCode,EbCnCode,EbTeRe,EbId,EbQty,EbUpperId,COUNT(*) FROM CcemEb where EbUpperId='0' and EbCnCode =:1 GROUP BY EbGoodsCode,EbCnCode,EbTeRe,EbId,EbQty,EbUpperId HAVING COUNT(*)> 1"); + command << (*it).c_str(); + command.Execute(); + if (command.FetchNext()) + { + str_err << (*it).c_str() << " ,"; + } + } + if (!str_err.str().empty()) + { + str_error << "\n[" << (*it_fn).factoryNo_id << "]з[" << str_err.str().c_str() << "]BOMظֵ;"; + } + } + if (str_error.str().length() > 0) + { + //string value = str_error.str(); + //error.append(value.c_str()); + //conn.Disconnect(); + //return; + } + str_error.str(""); + str_err.str(""); + //LINFO << "ż,ظֵ"; + sql.str(""); + sql << " select t1.EbGoodsCode parentCode,t2.EbGoodsCode childCode,t1.EbTeRe parentTeRe,t1.EbId parentEbLine,t2.EbQty childQty,t1.EbSign from"; + sql << " (select EbGoodsCode,EbCnCode,EbTeRe,EbId,EbQty,EbUpperId,EbSign from CcemEb where EbCnCode= :1 and EbUpperId='0' and EbTeRe !='') t1"; + sql << " LEFT JOIN CcemEb t2 on t1.EbCnCode = t2.EbCnCode and t1.EbId = t2.EbUpperId ORDER BY t1.EbTeRe "; + map parents; + string parentCode; + string childCode; + string parentTeRe; + string parentEbLine; + string childEbQty; + string ebSign; + string key; + map type_indexs; + map map_revs; + int size_bom = 0; + for (auto it_fn = beans.begin(); it_fn != beans.end(); it_fn++) + { + + vector list_FnCnCodes = (*it_fn).list_FnCnCodes; + vector vec_parents; + for (auto it = list_FnCnCodes.begin(); it != list_FnCnCodes.end(); it++) + { + parents.clear(); + command.setCommandText(sql.str().c_str()); + command << (*it).c_str(); + command.Execute(); + while (command.FetchNext()) + { + parentCode = command.Field(1).asString().GetMultiByteChars(); + childCode = command.Field(2).asString().GetMultiByteChars(); + parentTeRe = command.Field(3).asString().GetMultiByteChars(); + parentEbLine = command.Field(4).asString().GetMultiByteChars(); + childEbQty = command.Field(5).asString().GetMultiByteChars(); + ebSign = command.Field(6).asString().GetMultiByteChars(); + int qty = atoi(childEbQty.c_str()); + qty = qty > 0 ? qty : 1; + key.clear(); + key.append(parentCode).append("-").append(parentEbLine); + CcemEb_parent parent; + if (parents.find(key) == parents.end()) + { + parent.ebGoodsCode = parentCode; + parent.ebTeRe = parentTeRe; + vec_parents.push_back(parent); + parents[key] = parent; + type_indexs[parentCode] = 1; + map_revs[parentCode] = NULLTAG; + size_bom++; + } + if (!isEmpty(childCode)) + { + CcemEb_child child; + child.ebGoodsCode = childCode; + child.ebQty = format("%d",qty); + child.ebSign = ebSign; + parents[key].childs.push_back(child); + map_revs[childCode] = NULLTAG; + } + } + for (auto it_p = parents.begin(); it_p != parents.end(); it_p++) + { + (*it_fn).boms.push_back(it_p->second); + } + CcemEb_parent parent; + command.setCommandText("SELECT EbGoodsCode,EbQty,EbSign FROM [dbo].[CcemEb] where EbUpperId='0' and (EbTeRe='' or EbTeRe is null)and EbCnCode =:1 "); + command << (*it).c_str(); + command.Execute(); + while (command.FetchNext()) + { + childCode = command.Field(1).asString().GetMultiByteChars(); + childEbQty = command.Field(2).asString().GetMultiByteChars(); + ebSign = command.Field(3).asString().GetMultiByteChars(); + CcemEb_child child; + child.ebGoodsCode = childCode; + int qty = atoi(childEbQty.c_str()); + qty = qty > 0 ? qty : 1; + child.ebQty = format("%d", qty); + child.ebSign = ebSign; + parent.childs.push_back(child); + map_revs[childCode] = NULLTAG; + } + parent.ebTeRe = (*it); + parent.ebTeRe.append("(ԭ)"); + parent.ebGoodsCode = "9900000135"; + if (parent.childs.size() > 0) + { + vec_parents.push_back(parent); + (*it_fn).boms.push_back(parent); + size_bom++; + } + + } + } + + conn.Disconnect(); + //clock_t end2= clock(); + //double duration2 = (end2 - end1)/((double)CLOCKS_PER_SEC); + //LINFO << "BOMȡʱ:" << duration2<<"s"; + type_indexs["9900000135"] = 1; + //LINFO << "һ" << size_bom << "BOM"; + vector vec_query; + map field; + //LINFO << "ϼ鿪ʼ"; + for (auto it = map_revs.begin(); it != map_revs.end(); it++) + { + //vec_query.clear(); + vec_query.swap(vector()); + field["ID"] = it->first.c_str(); + SAFECALL(queryResult("chint_query_item", field, &vec_query)); + if (vec_query.size() > 0) + { + map_revs[it->first] = vec_query.at(0); + } + else + { + str_err << it->first << ","; + } + } + if (str_err.str().length() > 0) + { + str_error << "BOM[" << str_err.str().c_str() << "]δͬTC"; + error.append(str_error.str().c_str()); + return; + } + LINFO << "ϼ,ʼ˳Ųѯ"; + field.clear(); + field["WBS"] = zt2_WBSNo; + string materialno; + int num; + for (auto it = type_indexs.begin(); it != type_indexs.end(); it++) + { + materialno.clear(); + materialno.append(it->first).append("-*"); + field["materialno"] = materialno; + vec_query.swap(vector()); + int size = vec_query.size(); + SAFECALL(queryResult("chint_query_material", field, &vec_query)); + int size2 = vec_query.size(); + SAFECALL(getTypeNumber(vec_query, &num)); + type_indexs[it->first] = num; + } + //LINFO << "ˮȡ"; + clock_t end3 = clock(); + //double duration3 = (end3 - end2) / ((double)CLOCKS_PER_SEC); + //LINFO << "ݼʱ:" << duration3 << "s"; + + /* + int attr1, attr2, attr3; + BOM_line_look_up_attribute("bl_sequence_no", &attr1); + BOM_line_look_up_attribute("bl_ref_designator", &attr2); + BOM_line_look_up_attribute("bl_quantity", &attr3); + vector vec_attrs; + vec_attrs.push_back(attr1); + vec_attrs.push_back(attr2); + vec_attrs.push_back(attr3); + BOM_create_window(&win); + BOM_set_window_pack_all(win, false); + tag_t relation_type; + GRM_find_relation_type("ZT2_FactoryNumber", &relation_type); + POM_AM__set_application_bypass(true); + for (auto it_fn = beans.begin(); it_fn != beans.end(); it_fn++) + { + vector vec_parents = (*it_fn).boms; + for (auto it = vec_parents.begin(); it != vec_parents.end(); it++) + { + string goodCode = (*it).ebGoodsCode; + int index = type_indexs[goodCode]; + type_indexs[goodCode] = index + 1; + goodCode.append("-").append(format("%05d", index)); + (*it).zt2_MaterialNo = goodCode; + int size = (*it).childs.size(); + try{ + ITKCALL(createDYCCBOM((*it_fn), (*it), win, map_revs, folder_electrical, zt2_WBSNo.c_str(), vec_attrs, relation_type)); + } + catch (exception e) + { + LINFO << "BOM[" << goodCode.c_str() << "]ʧ:" << e.what(); + } + catch (...) + { + LINFO << "쳣..." << "BOM[" << goodCode.c_str() << "]ʧ:"; + } + SAFECALL(BOM_save_window(win)); + } + } + SAFECALL(BOM_close_window(win)); + */ + bom_zie = beans.size(); + if (bom_zie > 0) + { + clock_t end4 = clock(); + //std::thread wait([]{ + // while (bom_zie < 1); + //}); + + LINFO << "ִпʼ"; + POM_AM__set_application_bypass(true); + for (auto it_fn = beans.begin(); it_fn != beans.end(); it_fn++) + { + //std::thread th(createDYCCBOM4, (*it_fn), map_revs, folder_electrical, zt2_WBSNo.c_str()); + //th.join(); + + int t_size = (*it_fn).boms.size(); + if (t_size > 0) + { + DWORD ThreadID; + HANDLE hThread[30]; + for (auto it = (*it_fn).boms.begin(); it != (*it_fn).boms.end(); it++) + { + ThreadArg2 t; + strcpy(t.zt2_WBSNo,zt2_WBSNo.c_str()); + t.factoryNo = (*it_fn).factoryNo; + t.folder = folder_electrical; + t.map_revs = map_revs; + CreateThread(NULL, 0, createDYCCBOM5, (LPVOID)&t, 0, &ThreadID); + //createDYCCBOM4 + } + } + } + //wait.join(); + clock_t end5 = clock(); + double duration4 = (end5 - end4) / ((double)CLOCKS_PER_SEC); + LINFO << "ݼʱ:" << duration4 << "s"; + LINFO << "ִн"; + } + + + POM_AM__set_application_bypass(false); + } + catch (SAException e) + { + POM_AM__set_application_bypass(false); + if (win != NULLTAG) + { + SAFECALL(BOM_close_window(win)); + } + e.ErrMessage(); + LINFO << "SAError:"< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(__CYGWIN__) +# pragma push_macro("WIN32_LEAN_AND_MEAN") +# pragma push_macro("NOMINMAX") +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif // WIN32_LEAN_AND_MEAN +# ifndef NOMINMAX +# define NOMINMAX +# endif // NOMINMAX +# include +# if _WIN32_WINNT < _WIN32_WINNT_WINXP +extern "C" char *_strdup(const char *strSource); +# define strdup _strdup +# include +# endif // _WIN32_WINNT < _WIN32_WINNT_WINXP +# include +# pragma pop_macro("WIN32_LEAN_AND_MEAN") +# pragma pop_macro("NOMINMAX") +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined(_WIN32) || defined(__CYGWIN__) + +namespace http +{ + class RequestError final: public std::logic_error + { + public: + using std::logic_error::logic_error; + }; + + class ResponseError final: public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + }; + + enum class InternetProtocol: std::uint8_t + { + V4, + V6 + }; + + struct Uri final + { + std::string scheme; + std::string user; + std::string password; + std::string host; + std::string port; + std::string path; + std::string query; + std::string fragment; + }; + + struct HttpVersion final + { + uint16_t major; + uint16_t minor; + }; + + struct Status final + { + // RFC 7231, 6. Response Status Codes + enum Code: std::uint16_t + { + Continue = 100, + SwitchingProtocol = 101, + Processing = 102, + EarlyHints = 103, + + Ok = 200, + Created = 201, + Accepted = 202, + NonAuthoritativeInformation = 203, + NoContent = 204, + ResetContent = 205, + PartialContent = 206, + MultiStatus = 207, + AlreadyReported = 208, + ImUsed = 226, + + MultipleChoice = 300, + MovedPermanently = 301, + Found = 302, + SeeOther = 303, + NotModified = 304, + UseProxy = 305, + TemporaryRedirect = 307, + PermanentRedirect = 308, + + BadRequest = 400, + Unauthorized = 401, + PaymentRequired = 402, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + ProxyAuthenticationRequired = 407, + RequestTimeout = 408, + Conflict = 409, + Gone = 410, + LengthRequired = 411, + PreconditionFailed = 412, + PayloadTooLarge = 413, + UriTooLong = 414, + UnsupportedMediaType = 415, + RangeNotSatisfiable = 416, + ExpectationFailed = 417, + MisdirectedRequest = 421, + UnprocessableEntity = 422, + Locked = 423, + FailedDependency = 424, + TooEarly = 425, + UpgradeRequired = 426, + PreconditionRequired = 428, + TooManyRequests = 429, + RequestHeaderFieldsTooLarge = 431, + UnavailableForLegalReasons = 451, + + InternalServerError = 500, + NotImplemented = 501, + BadGateway = 502, + ServiceUnavailable = 503, + GatewayTimeout = 504, + HttpVersionNotSupported = 505, + VariantAlsoNegotiates = 506, + InsufficientStorage = 507, + LoopDetected = 508, + NotExtended = 510, + NetworkAuthenticationRequired = 511 + }; + + HttpVersion httpVersion; + std::uint16_t code; + std::string reason; + }; + + using HeaderField = std::pair; + using HeaderFields = std::vector; + + struct Response final + { + Status status; + HeaderFields headerFields; + std::vector body; + }; + + inline namespace detail + { +#if defined(_WIN32) || defined(__CYGWIN__) + class WinSock final + { + public: + WinSock() + { + WSADATA wsaData; + const auto error = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (error != 0) + throw std::system_error{error, std::system_category(), "WSAStartup failed"}; + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) + { + WSACleanup(); + throw std::runtime_error{"Invalid WinSock version"}; + } + + started = true; + } + + ~WinSock() + { + if (started) WSACleanup(); + } + + WinSock(WinSock&& other) noexcept: + started{other.started} + { + other.started = false; + } + + WinSock& operator=(WinSock&& other) noexcept + { + if (&other == this) return *this; + if (started) WSACleanup(); + started = other.started; + other.started = false; + return *this; + } + + private: + bool started = false; + }; +#endif // defined(_WIN32) || defined(__CYGWIN__) + + inline int getLastError() noexcept + { +#if defined(_WIN32) || defined(__CYGWIN__) + return WSAGetLastError(); +#else + return errno; +#endif // defined(_WIN32) || defined(__CYGWIN__) + } + + constexpr int getAddressFamily(const InternetProtocol internetProtocol) + { + return (internetProtocol == InternetProtocol::V4) ? AF_INET : + (internetProtocol == InternetProtocol::V6) ? AF_INET6 : + throw RequestError{"Unsupported protocol"}; + } + + class Socket final + { + public: +#if defined(_WIN32) || defined(__CYGWIN__) + using Type = SOCKET; + static constexpr Type invalid = INVALID_SOCKET; +#else + using Type = int; + static constexpr Type invalid = -1; +#endif // defined(_WIN32) || defined(__CYGWIN__) + + explicit Socket(const InternetProtocol internetProtocol): + endpoint{socket(getAddressFamily(internetProtocol), SOCK_STREAM, IPPROTO_TCP)} + { + if (endpoint == invalid) + throw std::system_error{getLastError(), std::system_category(), "Failed to create socket"}; + +#if defined(_WIN32) || defined(__CYGWIN__) + ULONG mode = 1; + if (ioctlsocket(endpoint, FIONBIO, &mode) != 0) + { + close(); + throw std::system_error{WSAGetLastError(), std::system_category(), "Failed to get socket flags"}; + } +#else + const auto flags = fcntl(endpoint, F_GETFL); + if (flags == -1) + { + close(); + throw std::system_error{errno, std::system_category(), "Failed to get socket flags"}; + } + + if (fcntl(endpoint, F_SETFL, flags | O_NONBLOCK) == -1) + { + close(); + throw std::system_error{errno, std::system_category(), "Failed to set socket flags"}; + } +#endif // defined(_WIN32) || defined(__CYGWIN__) + +#ifdef __APPLE__ + const int value = 1; + if (setsockopt(endpoint, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)) == -1) + { + close(); + throw std::system_error{errno, std::system_category(), "Failed to set socket option"}; + } +#endif // __APPLE__ + } + + ~Socket() + { + if (endpoint != invalid) close(); + } + + Socket(Socket&& other) noexcept: + endpoint{other.endpoint} + { + other.endpoint = invalid; + } + + Socket& operator=(Socket&& other) noexcept + { + if (&other == this) return *this; + if (endpoint != invalid) close(); + endpoint = other.endpoint; + other.endpoint = invalid; + return *this; + } + + void connect(const struct sockaddr* address, const socklen_t addressSize, const std::int64_t timeout) + { +#if defined(_WIN32) || defined(__CYGWIN__) + auto result = ::connect(endpoint, address, addressSize); + while (result == -1 && WSAGetLastError() == WSAEINTR) + result = ::connect(endpoint, address, addressSize); + + if (result == -1) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) + { + select(SelectType::write, timeout); + + char socketErrorPointer[sizeof(int)]; + socklen_t optionLength = sizeof(socketErrorPointer); + if (getsockopt(endpoint, SOL_SOCKET, SO_ERROR, socketErrorPointer, &optionLength) == -1) + throw std::system_error{WSAGetLastError(), std::system_category(), "Failed to get socket option"}; + + int socketError; + std::memcpy(&socketError, socketErrorPointer, sizeof(socketErrorPointer)); + + if (socketError != 0) + throw std::system_error{socketError, std::system_category(), "Failed to connect"}; + } + else + throw std::system_error{WSAGetLastError(), std::system_category(), "Failed to connect"}; + } +#else + auto result = ::connect(endpoint, address, addressSize); + while (result == -1 && errno == EINTR) + result = ::connect(endpoint, address, addressSize); + + if (result == -1) + { + if (errno == EINPROGRESS) + { + select(SelectType::write, timeout); + + int socketError; + socklen_t optionLength = sizeof(socketError); + if (getsockopt(endpoint, SOL_SOCKET, SO_ERROR, &socketError, &optionLength) == -1) + throw std::system_error{errno, std::system_category(), "Failed to get socket option"}; + + if (socketError != 0) + throw std::system_error{socketError, std::system_category(), "Failed to connect"}; + } + else + throw std::system_error{errno, std::system_category(), "Failed to connect"}; + } +#endif // defined(_WIN32) || defined(__CYGWIN__) + } + + std::size_t send(const void* buffer, const std::size_t length, const std::int64_t timeout) + { + select(SelectType::write, timeout); +#if defined(_WIN32) || defined(__CYGWIN__) + auto result = ::send(endpoint, reinterpret_cast(buffer), + static_cast(length), 0); + + while (result == -1 && WSAGetLastError() == WSAEINTR) + result = ::send(endpoint, reinterpret_cast(buffer), + static_cast(length), 0); + + if (result == -1) + throw std::system_error{WSAGetLastError(), std::system_category(), "Failed to send data"}; +#else + auto result = ::send(endpoint, reinterpret_cast(buffer), + length, noSignal); + + while (result == -1 && errno == EINTR) + result = ::send(endpoint, reinterpret_cast(buffer), + length, noSignal); + + if (result == -1) + throw std::system_error{errno, std::system_category(), "Failed to send data"}; +#endif // defined(_WIN32) || defined(__CYGWIN__) + return static_cast(result); + } + + std::size_t recv(void* buffer, const std::size_t length, const std::int64_t timeout) + { + select(SelectType::read, timeout); +#if defined(_WIN32) || defined(__CYGWIN__) + auto result = ::recv(endpoint, reinterpret_cast(buffer), + static_cast(length), 0); + + while (result == -1 && WSAGetLastError() == WSAEINTR) + result = ::recv(endpoint, reinterpret_cast(buffer), + static_cast(length), 0); + + if (result == -1) + throw std::system_error{WSAGetLastError(), std::system_category(), "Failed to read data"}; +#else + auto result = ::recv(endpoint, reinterpret_cast(buffer), + length, noSignal); + + while (result == -1 && errno == EINTR) + result = ::recv(endpoint, reinterpret_cast(buffer), + length, noSignal); + + if (result == -1) + throw std::system_error{errno, std::system_category(), "Failed to read data"}; +#endif // defined(_WIN32) || defined(__CYGWIN__) + return static_cast(result); + } + + private: + enum class SelectType + { + read, + write + }; + + void select(const SelectType type, const std::int64_t timeout) + { + fd_set descriptorSet; + FD_ZERO(&descriptorSet); + FD_SET(endpoint, &descriptorSet); + +#if defined(_WIN32) || defined(__CYGWIN__) + TIMEVAL selectTimeout{ + static_cast(timeout / 1000), + static_cast((timeout % 1000) * 1000) + }; + auto count = ::select(0, + (type == SelectType::read) ? &descriptorSet : nullptr, + (type == SelectType::write) ? &descriptorSet : nullptr, + nullptr, + (timeout >= 0) ? &selectTimeout : nullptr); + + while (count == -1 && WSAGetLastError() == WSAEINTR) + count = ::select(0, + (type == SelectType::read) ? &descriptorSet : nullptr, + (type == SelectType::write) ? &descriptorSet : nullptr, + nullptr, + (timeout >= 0) ? &selectTimeout : nullptr); + + if (count == -1) + throw std::system_error{WSAGetLastError(), std::system_category(), "Failed to select socket"}; + else if (count == 0) + throw ResponseError{"Request timed out"}; +#else + timeval selectTimeout{ + static_cast(timeout / 1000), + static_cast((timeout % 1000) * 1000) + }; + auto count = ::select(endpoint + 1, + (type == SelectType::read) ? &descriptorSet : nullptr, + (type == SelectType::write) ? &descriptorSet : nullptr, + nullptr, + (timeout >= 0) ? &selectTimeout : nullptr); + + while (count == -1 && errno == EINTR) + count = ::select(endpoint + 1, + (type == SelectType::read) ? &descriptorSet : nullptr, + (type == SelectType::write) ? &descriptorSet : nullptr, + nullptr, + (timeout >= 0) ? &selectTimeout : nullptr); + + if (count == -1) + throw std::system_error{errno, std::system_category(), "Failed to select socket"}; + else if (count == 0) + throw ResponseError{"Request timed out"}; +#endif // defined(_WIN32) || defined(__CYGWIN__) + } + + void close() noexcept + { +#if defined(_WIN32) || defined(__CYGWIN__) + closesocket(endpoint); +#else + ::close(endpoint); +#endif // defined(_WIN32) || defined(__CYGWIN__) + } + +#if defined(__unix__) && !defined(__APPLE__) && !defined(__CYGWIN__) + static constexpr int noSignal = MSG_NOSIGNAL; +#else + static constexpr int noSignal = 0; +#endif // defined(__unix__) && !defined(__APPLE__) + + Type endpoint = invalid; + }; + + // RFC 7230, 3.2.3. WhiteSpace + template + constexpr bool isWhiteSpaceChar(const C c) noexcept + { + return c == 0x20 || c == 0x09; // space or tab + }; + + // RFC 5234, Appendix B.1. Core Rules + template + constexpr bool isDigitChar(const C c) noexcept + { + return c >= 0x30 && c <= 0x39; // 0 - 9 + } + + // RFC 5234, Appendix B.1. Core Rules + template + constexpr bool isAlphaChar(const C c) noexcept + { + return + (c >= 0x61 && c <= 0x7A) || // a - z + (c >= 0x41 && c <= 0x5A); // A - Z + } + + // RFC 7230, 3.2.6. Field Value Components + template + constexpr bool isTokenChar(const C c) noexcept + { + return c == 0x21 || // ! + c == 0x23 || // # + c == 0x24 || // $ + c == 0x25 || // % + c == 0x26 || // & + c == 0x27 || // ' + c == 0x2A || // * + c == 0x2B || // + + c == 0x2D || // - + c == 0x2E || // . + c == 0x5E || // ^ + c == 0x5F || // _ + c == 0x60 || // ` + c == 0x7C || // | + c == 0x7E || // ~ + isDigitChar(c) || + isAlphaChar(c); + }; + // RFC 5234, Appendix B.1. Core Rules + template + constexpr bool isVisibleChar(const C c) noexcept + { + return c >= 0x21 && c <= 0x7E; + } + // RFC 7230, Appendix B. Collected ABNF + template + constexpr bool isObsoleteTextChar(const C c) noexcept + { + return static_cast(c) >= 0x80 && + static_cast(c) <= 0xFF; + } + template + Iterator skipWhiteSpaces(const Iterator begin, const Iterator end) + { + auto i = begin; + for (i = begin; i != end; ++i) + if (!isWhiteSpaceChar(*i)) + break; + return i; + } + // RFC 5234, Appendix B.1. Core Rules + template ::value>::type* = nullptr> + constexpr T digitToUint(const C c) + { + // DIGIT + return (c >= 0x30 && c <= 0x39) ? static_cast(c - 0x30) : // 0 - 9 + throw ResponseError{"Invalid digit"}; + } + // RFC 5234, Appendix B.1. Core Rules + template ::value>::type* = nullptr> + constexpr T hexDigitToUint(const C c) + { + // HEXDIG + return (c >= 0x30 && c <= 0x39) ? static_cast(c - 0x30) : // 0 - 9 + (c >= 0x41 && c <= 0x46) ? static_cast(c - 0x41) + T(10) : // A - Z + (c >= 0x61 && c <= 0x66) ? static_cast(c - 0x61) + T(10) : // a - z, some services send lower-case hex digits + throw ResponseError{"Invalid hex digit"}; + } + // RFC 3986, 3. Syntax Components + template + Uri parseUri(const Iterator begin, const Iterator end) + { + Uri result; + // RFC 3986, 3.1. Scheme + auto i = begin; + if (i == end || !isAlphaChar(*begin)) + throw RequestError{"Invalid scheme"}; + result.scheme.push_back(*i++); + for (; i != end && (isAlphaChar(*i) || isDigitChar(*i) || *i == '+' || *i == '-' || *i == '.'); ++i) + result.scheme.push_back(*i); + if (i == end || *i++ != ':') + throw RequestError{"Invalid scheme"}; + if (i == end || *i++ != '/') + throw RequestError{"Invalid scheme"}; + if (i == end || *i++ != '/') + throw RequestError{"Invalid scheme"}; + // RFC 3986, 3.2. Authority + std::string authority = std::string(i, end); + // RFC 3986, 3.5. Fragment + const auto fragmentPosition = authority.find('#'); + if (fragmentPosition != std::string::npos) + { + result.fragment = authority.substr(fragmentPosition + 1); + authority.resize(fragmentPosition); // remove the fragment part + } + // RFC 3986, 3.4. Query + const auto queryPosition = authority.find('?'); + if (queryPosition != std::string::npos) + { + result.query = authority.substr(queryPosition + 1); + authority.resize(queryPosition); // remove the query part + } + // RFC 3986, 3.3. Path + const auto pathPosition = authority.find('/'); + if (pathPosition != std::string::npos) + { + // RFC 3986, 3.3. Path + result.path = authority.substr(pathPosition); + authority.resize(pathPosition); + } + else + result.path = "/"; + // RFC 3986, 3.2.1. User Information + std::string userinfo; + const auto hostPosition = authority.find('@'); + if (hostPosition != std::string::npos) + { + userinfo = authority.substr(0, hostPosition); + const auto passwordPosition = userinfo.find(':'); + if (passwordPosition != std::string::npos) + { + result.user = userinfo.substr(0, passwordPosition); + result.password = userinfo.substr(passwordPosition + 1); + } + else + result.user = userinfo; + result.host = authority.substr(hostPosition + 1); + } + else + result.host = authority; + // RFC 3986, 3.2.2. Host + const auto portPosition = result.host.find(':'); + if (portPosition != std::string::npos) + { + // RFC 3986, 3.2.3. Port + result.port = result.host.substr(portPosition + 1); + result.host.resize(portPosition); + } + return result; + } + // RFC 7230, 2.6. Protocol Versioning + template + std::pair parseHttpVersion(const Iterator begin, const Iterator end) + { + auto i = begin; + if (i == end || *i++ != 'H') + throw ResponseError{"Invalid HTTP version"}; + if (i == end || *i++ != 'T') + throw ResponseError{"Invalid HTTP version"}; + if (i == end || *i++ != 'T') + throw ResponseError{"Invalid HTTP version"}; + if (i == end || *i++ != 'P') + throw ResponseError{"Invalid HTTP version"}; + if (i == end || *i++ != '/') + throw ResponseError{"Invalid HTTP version"}; + if (i == end) + throw ResponseError{"Invalid HTTP version"}; + const auto majorVersion = digitToUint(*i++); + if (i == end || *i++ != '.') + throw ResponseError{"Invalid HTTP version"}; + if (i == end) + throw ResponseError{"Invalid HTTP version"}; + const auto minorVersion = digitToUint(*i++); + return {i, HttpVersion{majorVersion, minorVersion}}; + } + // RFC 7230, 3.1.2. Status Line + template + std::pair parseStatusCode(const Iterator begin, const Iterator end) + { + std::uint16_t result = 0; + auto i = begin; + while (i != end && isDigitChar(*i)) + result = static_cast(result * 10U) + digitToUint(*i++); + if (std::distance(begin, i) != 3) + throw ResponseError{"Invalid status code"}; + return {i, result}; + } + // RFC 7230, 3.1.2. Status Line + template + std::pair parseReasonPhrase(const Iterator begin, const Iterator end) + { + std::string result; + auto i = begin; + for (; i != end && (isWhiteSpaceChar(*i) || isVisibleChar(*i) || isObsoleteTextChar(*i)); ++i) + result.push_back(static_cast(*i)); + return {i, std::move(result)}; + } + // RFC 7230, 3.2.6. Field Value Components + template + std::pair parseToken(const Iterator begin, const Iterator end) + { + std::string result; + auto i = begin; + for (; i != end && isTokenChar(*i); ++i) + result.push_back(static_cast(*i)); + if (result.empty()) + throw ResponseError{"Invalid token"}; + return {i, std::move(result)}; + } + // RFC 7230, 3.2. Header Fields + template + std::pair parseFieldValue(const Iterator begin, const Iterator end) + { + std::string result; + auto i = begin; + for (; i != end && (isWhiteSpaceChar(*i) || isVisibleChar(*i) || isObsoleteTextChar(*i)); ++i) + result.push_back(static_cast(*i)); + // trim white spaces + result.erase(std::find_if(result.rbegin(), result.rend(), [](const char c) noexcept { + return !isWhiteSpaceChar(c); + }).base(), result.end()); + return {i, std::move(result)}; + } + // RFC 7230, 3.2. Header Fields + template + std::pair parseFieldContent(const Iterator begin, const Iterator end) + { + std::string result; + auto i = begin; + for (;;) + { + const auto fieldValueResult = parseFieldValue(i, end); + i = fieldValueResult.first; + result += fieldValueResult.second; + // Handle obsolete fold as per RFC 7230, 3.2.4. Field Parsing + // Obsolete folding is known as linear white space (LWS) in RFC 2616, 2.2 Basic Rules + auto obsoleteFoldIterator = i; + if (obsoleteFoldIterator == end || *obsoleteFoldIterator++ != '\r') + break; + if (obsoleteFoldIterator == end || *obsoleteFoldIterator++ != '\n') + break; + if (obsoleteFoldIterator == end || !isWhiteSpaceChar(*obsoleteFoldIterator++)) + break; + result.push_back(' '); + i = obsoleteFoldIterator; + } + return {i, std::move(result)}; + } + // RFC 7230, 3.2. Header Fields + template + std::pair parseHeaderField(const Iterator begin, const Iterator end) + { + auto tokenResult = parseToken(begin, end); + auto i = tokenResult.first; + auto fieldName = std::move(tokenResult.second); + if (i == end || *i++ != ':') + throw ResponseError{"Invalid header"}; + i = skipWhiteSpaces(i, end); + auto valueResult = parseFieldContent(i, end); + i = valueResult.first; + auto fieldValue = std::move(valueResult.second); + if (i == end || *i++ != '\r') + throw ResponseError{"Invalid header"}; + if (i == end || *i++ != '\n') + throw ResponseError{"Invalid header"}; + return {i, {std::move(fieldName), std::move(fieldValue)}}; + } + // RFC 7230, 3.1.2. Status Line + template + std::pair parseStatusLine(const Iterator begin, const Iterator end) + { + const auto httpVersionResult = parseHttpVersion(begin, end); + auto i = httpVersionResult.first; + if (i == end || *i++ != ' ') + throw ResponseError{"Invalid status line"}; + const auto statusCodeResult = parseStatusCode(i, end); + i = statusCodeResult.first; + if (i == end || *i++ != ' ') + throw ResponseError{"Invalid status line"}; + auto reasonPhraseResult = parseReasonPhrase(i, end); + i = reasonPhraseResult.first; + if (i == end || *i++ != '\r') + throw ResponseError{"Invalid status line"}; + if (i == end || *i++ != '\n') + throw ResponseError{"Invalid status line"}; + return {i, Status{ + httpVersionResult.second, + statusCodeResult.second, + std::move(reasonPhraseResult.second) + }}; + } + // RFC 7230, 4.1. Chunked Transfer Coding + template ::value>::type* = nullptr> + T stringToUint(const Iterator begin, const Iterator end) + { + T result = 0; + for (auto i = begin; i != end; ++i) + result = T(10U) * result + digitToUint(*i); + return result; + } + template ::value>::type* = nullptr> + T hexStringToUint(const Iterator begin, const Iterator end) + { + T result = 0; + for (auto i = begin; i != end; ++i) + result = T(16U) * result + hexDigitToUint(*i); + return result; + } + // RFC 7230, 3.1.1. Request Line + inline std::string encodeRequestLine(const std::string& method, const std::string& target) + { + return method + " " + target + " HTTP/1.1\r\n"; + } + // RFC 7230, 3.2. Header Fields + inline std::string encodeHeaderFields(const HeaderFields& headerFields) + { + std::string result; + for (const auto& headerField : headerFields) + { + if (headerField.first.empty()) + throw RequestError{"Invalid header field name"}; + for (const auto c : headerField.first) + if (!isTokenChar(c)) + throw RequestError{"Invalid header field name"}; + for (const auto c : headerField.second) + if (!isWhiteSpaceChar(c) && !isVisibleChar(c) && !isObsoleteTextChar(c)) + throw RequestError{"Invalid header field value"}; + result += headerField.first + ": " + headerField.second + "\r\n"; + } + return result; + } + // RFC 4648, 4. Base 64 Encoding + template + std::string encodeBase64(const Iterator begin, const Iterator end) + { + constexpr std::array chars{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + std::string result; + std::size_t c = 0; + std::array charArray; + for (auto i = begin; i != end; ++i) + { + charArray[c++] = static_cast(*i); + if (c == 3) + { + result += chars[static_cast((charArray[0] & 0xFC) >> 2)]; + result += chars[static_cast(((charArray[0] & 0x03) << 4) + ((charArray[1] & 0xF0) >> 4))]; + result += chars[static_cast(((charArray[1] & 0x0F) << 2) + ((charArray[2] & 0xC0) >> 6))]; + result += chars[static_cast(charArray[2] & 0x3f)]; + c = 0; + } + } + if (c) + { + result += chars[static_cast((charArray[0] & 0xFC) >> 2)]; + if (c == 1) + result += chars[static_cast((charArray[0] & 0x03) << 4)]; + else // c == 2 + { + result += chars[static_cast(((charArray[0] & 0x03) << 4) + ((charArray[1] & 0xF0) >> 4))]; + result += chars[static_cast((charArray[1] & 0x0F) << 2)]; + } + while (++c < 4) result += '='; // padding + } + return result; + } + inline std::vector encodeHtml(const Uri& uri, + const std::string& method, + const std::vector& body, + HeaderFields headerFields) + { + if (uri.scheme != "http") + throw RequestError{"Only HTTP scheme is supported"}; + // RFC 7230, 5.3. Request Target + const std::string requestTarget = uri.path + (uri.query.empty() ? "" : '?' + uri.query); + // RFC 7230, 5.4. Host + headerFields.push_back({"Host", uri.host}); + // RFC 7230, 3.3.2. Content-Length + headerFields.push_back({"Content-Length", std::to_string(body.size())}); + // RFC 7617, 2. The 'Basic' Authentication Scheme + if (!uri.user.empty() || !uri.password.empty()) + { + std::string userinfo = uri.user + ':' + uri.password; + headerFields.push_back({"Authorization", "Basic " + encodeBase64(userinfo.begin(), userinfo.end())}); + } + const auto headerData = encodeRequestLine(method, requestTarget) + + encodeHeaderFields(headerFields) + + "\r\n"; + std::vector result(headerData.begin(), headerData.end()); + result.insert(result.end(), body.begin(), body.end()); + return result; + } + } + class Request final + { + public: + explicit Request(const std::string& uriString, + const InternetProtocol protocol = InternetProtocol::V4): + internetProtocol{protocol}, + uri{parseUri(uriString.begin(), uriString.end())} + { + } + Response send(const std::string& method = "GET", + const std::string& body = "", + const HeaderFields& headerFields = {}, + const std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) + { + return send(method, + std::vector(body.begin(), body.end()), + headerFields, + timeout); + } + Response send(const std::string& method, + const std::vector& body, + const HeaderFields& headerFields = {}, + const std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) + { + const auto stopTime = std::chrono::steady_clock::now() + timeout; + if (uri.scheme != "http") + throw RequestError{"Only HTTP scheme is supported"}; + addrinfo hints = {}; + hints.ai_family = getAddressFamily(internetProtocol); + hints.ai_socktype = SOCK_STREAM; + const char* port = uri.port.empty() ? "80" : uri.port.c_str(); + addrinfo* info; + if (getaddrinfo(uri.host.c_str(), port, &hints, &info) != 0) + throw std::system_error{getLastError(), std::system_category(), "Failed to get address info of " + uri.host}; + const std::unique_ptr addressInfo{info, freeaddrinfo}; + const auto requestData = encodeHtml(uri, method, body, headerFields); + Socket socket{internetProtocol}; + const auto getRemainingMilliseconds = [](const std::chrono::steady_clock::time_point time) noexcept -> std::int64_t { + const auto now = std::chrono::steady_clock::now(); + const auto remainingTime = std::chrono::duration_cast(time - now); + return (remainingTime.count() > 0) ? remainingTime.count() : 0; + }; + // take the first address from the list + socket.connect(addressInfo->ai_addr, static_cast(addressInfo->ai_addrlen), + (timeout.count() >= 0) ? getRemainingMilliseconds(stopTime) : -1); + auto remaining = requestData.size(); + auto sendData = requestData.data(); + // send the request + while (remaining > 0) + { + const auto size = socket.send(sendData, remaining, + (timeout.count() >= 0) ? getRemainingMilliseconds(stopTime) : -1); + remaining -= size; + sendData += size; + } + std::array tempBuffer; + constexpr std::array crlf = {'\r', '\n'}; + constexpr std::array headerEnd = {'\r', '\n', '\r', '\n'}; + Response response; + std::vector responseData; + bool parsingBody = false; + bool contentLengthReceived = false; + std::size_t contentLength = 0U; + bool chunkedResponse = false; + std::size_t expectedChunkSize = 0U; + bool removeCrlfAfterChunk = false; + // read the response + for (;;) + { + const auto size = socket.recv(tempBuffer.data(), tempBuffer.size(), + (timeout.count() >= 0) ? getRemainingMilliseconds(stopTime) : -1); + if (size == 0) // disconnected + return response; + responseData.insert(responseData.end(), tempBuffer.begin(), tempBuffer.begin() + size); + if (!parsingBody) + { + // RFC 7230, 3. Message Format + // Empty line indicates the end of the header section (RFC 7230, 2.1. Client/Server Messaging) + const auto endIterator = std::search(responseData.cbegin(), responseData.cend(), + headerEnd.cbegin(), headerEnd.cend()); + if (endIterator == responseData.cend()) break; // two consecutive CRLFs not found + const auto headerBeginIterator = responseData.cbegin(); + const auto headerEndIterator = endIterator + 2; + auto statusLineResult = parseStatusLine(headerBeginIterator, headerEndIterator); + auto i = statusLineResult.first; + response.status = std::move(statusLineResult.second); + for (;;) + { + auto headerFieldResult = parseHeaderField(i, headerEndIterator); + i = headerFieldResult.first; + auto fieldName = std::move(headerFieldResult.second.first); + const auto toLower = [](const char c) noexcept { + return (c >= 'A' && c <= 'Z') ? c - ('A' - 'a') : c; + }; + std::transform(fieldName.begin(), fieldName.end(), fieldName.begin(), toLower); + auto fieldValue = std::move(headerFieldResult.second.second); + if (fieldName == "transfer-encoding") + { + // RFC 7230, 3.3.1. Transfer-Encoding + if (fieldValue == "chunked") + chunkedResponse = true; + else + throw ResponseError{"Unsupported transfer encoding: " + fieldValue}; + } + else if (fieldName == "content-length") + { + // RFC 7230, 3.3.2. Content-Length + contentLength = stringToUint(fieldValue.cbegin(), fieldValue.cend()); + contentLengthReceived = true; + response.body.reserve(contentLength); + } + response.headerFields.push_back({std::move(fieldName), std::move(fieldValue)}); + if (i == headerEndIterator) + break; + } + responseData.erase(responseData.cbegin(), headerEndIterator + 2); + parsingBody = true; + } + if (parsingBody) + { + // Content-Length must be ignored if Transfer-Encoding is received (RFC 7230, 3.2. Content-Length) + if (chunkedResponse) + { + // RFC 7230, 4.1. Chunked Transfer Coding + for (;;) + { + if (expectedChunkSize > 0) + { + const auto toWrite = (std::min)(expectedChunkSize, responseData.size()); + response.body.insert(response.body.end(), responseData.begin(), + responseData.begin() + static_cast(toWrite)); + responseData.erase(responseData.begin(), + responseData.begin() + static_cast(toWrite)); + expectedChunkSize -= toWrite; + if (expectedChunkSize == 0) removeCrlfAfterChunk = true; + if (responseData.empty()) break; + } + else + { + if (removeCrlfAfterChunk) + { + if (responseData.size() < 2) break; + + if (!std::equal(crlf.begin(), crlf.end(), responseData.begin())) + throw ResponseError{"Invalid chunk"}; + removeCrlfAfterChunk = false; + responseData.erase(responseData.begin(), responseData.begin() + 2); + } + const auto i = std::search(responseData.begin(), responseData.end(), + crlf.begin(), crlf.end()); + if (i == responseData.end()) break; + expectedChunkSize = detail::hexStringToUint(responseData.begin(), i); + responseData.erase(responseData.begin(), i + 2); + if (expectedChunkSize == 0) + return response; + } + } + } + else + { + response.body.insert(response.body.end(), responseData.begin(), responseData.end()); + responseData.clear(); + // got the whole content + if (contentLengthReceived && response.body.size() >= contentLength) + return response; + } + } + } + return response; + } + private: +#if defined(_WIN32) || defined(__CYGWIN__) + WinSock winSock; +#endif // defined(_WIN32) || defined(__CYGWIN__) + InternetProtocol internetProtocol; + Uri uri; + }; +} +#endif // HTTPREQUEST_HPP \ No newline at end of file diff --git a/WXom062/Release/CL.read.1.tlog b/WXom062/Release/CL.read.1.tlog new file mode 100644 index 0000000..6c55f54 Binary files /dev/null and b/WXom062/Release/CL.read.1.tlog differ diff --git a/WXom062/Release/CL.write.1.tlog b/WXom062/Release/CL.write.1.tlog new file mode 100644 index 0000000..30e1fe2 Binary files /dev/null and b/WXom062/Release/CL.write.1.tlog differ diff --git a/WXom062/Release/WXom062.Build.CppClean.log b/WXom062/Release/WXom062.Build.CppClean.log new file mode 100644 index 0000000..d31ff7f --- /dev/null +++ b/WXom062/Release/WXom062.Build.CppClean.log @@ -0,0 +1,22 @@ +F:\VS\WXOM062\WXOM062\RELEASE\WX_REGISTRY.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\WX_METHOD.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\WX_MAIN.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\WX_HANDLER.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\TC_UTIL.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\TC_LOG.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\STRING_UTILS.OBJ +F:\VS\WXOM062\WXOM062\RELEASE\VC110.PDB +F:\VS\WXom062\WXom062\Release\string_utils.obj +F:\VS\WXom062\WXom062\Release\tc_log.obj +F:\VS\WXom062\WXom062\Release\tc_util.obj +F:\VS\WXom062\WXom062\Release\wx_Handler.obj +F:\VS\WXom062\WXom062\Release\wx_main.obj +F:\VS\WXom062\WXom062\Release\wx_method.obj +F:\VS\WXom062\WXom062\Release\wx_registry.obj +F:\VS\WXom062\WXom062\Release\cl.command.1.tlog +F:\VS\WXom062\WXom062\Release\CL.read.1.tlog +F:\VS\WXom062\WXom062\Release\CL.write.1.tlog +F:\VS\WXom062\WXom062\Release\link.command.1.tlog +F:\VS\WXom062\WXom062\Release\link.read.1.tlog +F:\VS\WXom062\WXom062\Release\link.write.1.tlog +F:\VS\WXom062\WXom062\Release\vc110.pdb diff --git a/WXom062/Release/WXom062.lastbuildstate b/WXom062/Release/WXom062.lastbuildstate new file mode 100644 index 0000000..9c0c9ad --- /dev/null +++ b/WXom062/Release/WXom062.lastbuildstate @@ -0,0 +1,2 @@ +#v4.0:v110:false +Release|Win32|F:\VS\WXom062\| diff --git a/WXom062/Release/WXom062.log b/WXom062/Release/WXom062.log new file mode 100644 index 0000000..661f02d --- /dev/null +++ b/WXom062/Release/WXom062.log @@ -0,0 +1,168 @@ +生成启动时间为 2019/3/21 17:37:31。 + 1>项目“F:\VS\WXom062\WXom062\WXom062.vcxproj”在节点 2 上(Rebuild 个目标)。 + 1>ClCompile: + C:\VS2012\VC\bin\CL.exe /c /IF:\Siemen\include_cpp /IF:\Siemen\include /IF:\Siemen\lib /Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D WIN32 /D NDEBUG /D _WINDOWS /D _USRDLL /D WXOM062_EXPORTS /D IPLIB=none /D _WINDLL /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Release\\" /Fd"Release\vc110.pdb" /Gd /TP /analyze- /errorReport:prompt string_utils.cxx tc_log.cxx tc_util.cpp wx_Handler.cpp wx_main.cpp wx_method.cpp wx_registry.cpp + string_utils.cxx + tc_log.cxx + 1>tc_log.cxx(58): warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + C:\VS2012\VC\include\stdio.h(357) : 参见“sprintf”的声明 + 1>tc_log.cxx(63): warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + C:\VS2012\VC\include\stdio.h(218) : 参见“fopen”的声明 + 1>tc_log.cxx(77): warning C4996: 'localtime': This function or variable may be unsafe. Consider using localtime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + C:\VS2012\VC\include\time.inl(112) : 参见“localtime”的声明 + 1>tc_log.cxx(87): warning C4996: 'vsprintf': This function or variable may be unsafe. Consider using vsprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + C:\VS2012\VC\include\stdio.h(357) : 参见“vsprintf”的声明 + tc_util.cpp + 1>F:\Siemen\include\tc/preferences.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\tc/preferences.h(562): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\schmgt\schmgt_bridge_itk.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>tc_util.cpp(12): warning C4996: 'localtime': This function or variable may be unsafe. Consider using localtime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + C:\VS2012\VC\include\time.inl(112) : 参见“localtime”的声明 + wx_Handler.cpp + 1>F:\Siemen\include\tc/preferences.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\tc/preferences.h(562): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\schmgt\schmgt_bridge_itk.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include_cpp\Error_Exception.hxx(295): warning C4251: “UGS::Error::Exception::m_sFileName”: class“std::basic_string<_Elem,_Traits,_Alloc>”需要有 dll 接口由 class“UGS::Error::Exception”的客户端使用 + with + [ + _Elem=char, + _Traits=std::char_traits, + _Alloc=std::allocator + ] + 1>F:\Siemen\include_cpp\Error_Exception.hxx(302): warning C4251: “UGS::Error::Exception::m_sSyslogText”: class“std::basic_string<_Elem,_Traits,_Alloc>”需要有 dll 接口由 class“UGS::Error::Exception”的客户端使用 + with + [ + _Elem=char, + _Traits=std::char_traits, + _Alloc=std::allocator + ] + 1>F:\Siemen\include_cpp\base_utils/IFail.hxx(114): warning C4251: “IFail::m_message”: class“std::basic_string<_Elem,_Traits,_Alloc>”需要有 dll 接口由 class“IFail”的客户端使用 + with + [ + _Elem=char, + _Traits=std::char_traits, + _Alloc=std::allocator + ] + 1>F:\Siemen\include_cpp\mld/logging/Logger.hxx(526): warning C4251: “Teamcenter::Logging::Logger::loggerName”: class“std::basic_string<_Elem,_Traits,_Alloc>”需要有 dll 接口由 class“Teamcenter::Logging::Logger”的客户端使用 + with + [ + _Elem=char, + _Traits=std::char_traits, + _Alloc=std::allocator + ] + 1>wx_Handler.cpp(42): warning C4101: “count”: 未引用的局部变量 + 1>wx_Handler.cpp(33): warning C4101: “personname”: 未引用的局部变量 + 1>wx_Handler.cpp(31): warning C4101: “owner”: 未引用的局部变量 + 1>wx_Handler.cpp(117): warning C4018: “<”: 有符号/无符号不匹配 + 1>wx_Handler.cpp(186): warning C4018: “<”: 有符号/无符号不匹配 + 1>wx_Handler.cpp(158): warning C4101: “psr”: 未引用的局部变量 + 1>wx_Handler.cpp(162): warning C4101: “parent_name”: 未引用的局部变量 + 1>wx_Handler.cpp(188): warning C4101: “count”: 未引用的局部变量 + 1>wx_Handler.cpp(193): warning C4101: “user_count”: 未引用的局部变量 + 1>wx_Handler.cpp(189): warning C4101: “tag_members”: 未引用的局部变量 + 1>wx_Handler.cpp(192): warning C4101: “users”: 未引用的局部变量 + 1>wx_Handler.cpp(191): warning C4101: “member_type”: 未引用的局部变量 + 1>wx_Handler.cpp(190): warning C4101: “member_tag”: 未引用的局部变量 + 1>wx_Handler.cpp(283): warning C4018: “<”: 有符号/无符号不匹配 + 1>wx_Handler.cpp(255): warning C4101: “psr”: 未引用的局部变量 + 1>wx_Handler.cpp(259): warning C4101: “parent_name”: 未引用的局部变量 + 1>wx_Handler.cpp(285): warning C4101: “count”: 未引用的局部变量 + 1>wx_Handler.cpp(290): warning C4101: “user_count”: 未引用的局部变量 + 1>wx_Handler.cpp(286): warning C4101: “tag_members”: 未引用的局部变量 + 1>wx_Handler.cpp(289): warning C4101: “users”: 未引用的局部变量 + 1>wx_Handler.cpp(288): warning C4101: “member_type”: 未引用的局部变量 + 1>wx_Handler.cpp(287): warning C4101: “member_tag”: 未引用的局部变量 + 1>wx_Handler.cpp(345): warning C4101: “tem_task”: 未引用的局部变量 + 1>wx_Handler.cpp(408): warning C4101: “count”: 未引用的局部变量 + 1>wx_Handler.cpp(442): warning C4101: “count”: 未引用的局部变量 + 1>wx_Handler.cpp(447): warning C4101: “user_count”: 未引用的局部变量 + 1>wx_Handler.cpp(443): warning C4101: “tag_members”: 未引用的局部变量 + 1>wx_Handler.cpp(446): warning C4101: “users”: 未引用的局部变量 + 1>wx_Handler.cpp(445): warning C4101: “member_type”: 未引用的局部变量 + 1>wx_Handler.cpp(444): warning C4101: “member_tag”: 未引用的局部变量 + wx_main.cpp + 1>F:\Siemen\include\tc/preferences.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\tc/preferences.h(562): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\schmgt\schmgt_bridge_itk.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + wx_method.cpp + 1>F:\Siemen\include\tc/preferences.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\tc/preferences.h(562): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\schmgt\schmgt_bridge_itk.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>wx_method.cpp(56): warning C4018: “<”: 有符号/无符号不匹配 + 1>wx_method.cpp(70): warning C4018: “<”: 有符号/无符号不匹配 + 1>wx_method.cpp(85): warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. + C:\VS2012\VC\include\stdio.h(357) : 参见“sprintf”的声明 + 1>wx_method.cpp(14): warning C4101: “col_cnt”: 未引用的局部变量 + 1>wx_method.cpp(16): warning C4101: “arg”: 未引用的局部变量 + 1>wx_method.cpp(16): warning C4101: “output”: 未引用的局部变量 + 1>wx_method.cpp(14): warning C4101: “val_cnt”: 未引用的局部变量 + wx_registry.cpp + 1>F:\Siemen\include\tc/preferences.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\tc/preferences.h(562): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>F:\Siemen\include\schmgt\schmgt_bridge_itk.h : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + Link: + C:\VS2012\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"F:\VS\WXom062\Release\WXom062.dll" /INCREMENTAL:NO /NOLOGO "F:\Siemen\lib\*.lib" kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NODEFAULTLIB:libuser_exits.ar.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG /PDB:"F:\VS\WXom062\Release\WXom062.pdb" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"F:\VS\WXom062\Release\WXom062.lib" /MACHINE:X86 /SAFESEH /DLL Release\string_utils.obj + Release\tc_log.obj + Release\tc_util.obj + Release\wx_Handler.obj + Release\wx_main.obj + Release\wx_method.obj + Release\wx_registry.obj + 正在创建库 F:\VS\WXom062\Release\WXom062.lib 和对象 F:\VS\WXom062\Release\WXom062.exp + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__MEM_alloc + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__tc_strncpy + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__tc_strcat + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__STRNG_replace_str + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__tc_strstr + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__tc_strcpy + 1>string_utils.obj : error LNK2001: 无法解析的外部符号 __imp__tc_strlen + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__EMH_ask_error_text + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__MEM_free + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__TCTYPE_ask_object_type + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__TC_write_syslog + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__TCTYPE_is_type_of + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__PREF_set_search_scope + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__TCTYPE_find_type + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__PREF_ask_search_scope + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__TC_printf + 1>tc_util.obj : error LNK2001: 无法解析的外部符号 __imp__PREF_ask_char_values + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_name2 + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_set_adhoc_signoff_selection_done + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__AOM_ask_owner + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_remove_signoffs + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__SA_find_user + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_create_adhoc_signoff + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_parent_task + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_root_task + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_state + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__AOM_get_value_string + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__POM_get_user_id + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__SA_ask_user_login_group + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_sub_tasks + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__AOM_ask_value_string + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__SA_find_groupmembers + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_attachments + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__TCTYPE_ask_class_name + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__ITK_ask_argument_named_value + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_name + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__SA_ask_user_person_name2 + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_set_task_result + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 _POM_AM__set_application_bypass + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_sub_task + 1>wx_Handler.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_ask_task_reviewers_group_member + 1>wx_main.obj : error LNK2001: 无法解析的外部符号 __imp__CUSTOM_register_exit + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 __imp__AOM_ask_value_tags + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 __imp__GRM_find_relation_type + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 _USERARG_get_tag_argument + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 _USERSERVICE_return_string_array + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 __imp__ITEM_ask_latest_rev + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 __imp__AOM_UIF_ask_value + 1>wx_method.obj : error LNK2001: 无法解析的外部符号 __imp__GRM_list_secondary_objects_only + 1>wx_registry.obj : error LNK2001: 无法解析的外部符号 _USERSERVICE_register_method + 1>wx_registry.obj : error LNK2001: 无法解析的外部符号 __imp__EPM_register_action_handler + 1>F:\VS\WXom062\Release\WXom062.dll : fatal error LNK1120: 51 个无法解析的外部命令 + 1>已完成生成项目“F:\VS\WXom062\WXom062\WXom062.vcxproj”(Rebuild 个目标)的操作 - 失败。 + +生成失败。 + +已用时间 00:00:07.22 diff --git a/WXom062/Release/WXom062.unsuccessfulbuild b/WXom062/Release/WXom062.unsuccessfulbuild new file mode 100644 index 0000000..e69de29 diff --git a/WXom062/Release/cl.command.1.tlog b/WXom062/Release/cl.command.1.tlog new file mode 100644 index 0000000..4ad8b56 Binary files /dev/null and b/WXom062/Release/cl.command.1.tlog differ diff --git a/WXom062/Release/link.command.1.tlog b/WXom062/Release/link.command.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/WXom062/Release/link.command.1.tlog @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/WXom062/Release/link.read.1.tlog b/WXom062/Release/link.read.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/WXom062/Release/link.read.1.tlog @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/WXom062/Release/link.write.1.tlog b/WXom062/Release/link.write.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/WXom062/Release/link.write.1.tlog @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/WXom062/Release/string_utils.obj b/WXom062/Release/string_utils.obj new file mode 100644 index 0000000..74af57f Binary files /dev/null and b/WXom062/Release/string_utils.obj differ diff --git a/WXom062/Release/tc_log.obj b/WXom062/Release/tc_log.obj new file mode 100644 index 0000000..8265456 Binary files /dev/null and b/WXom062/Release/tc_log.obj differ diff --git a/WXom062/Release/tc_util.obj b/WXom062/Release/tc_util.obj new file mode 100644 index 0000000..2587ba0 Binary files /dev/null and b/WXom062/Release/tc_util.obj differ diff --git a/WXom062/Release/vc110.pdb b/WXom062/Release/vc110.pdb new file mode 100644 index 0000000..7cc2832 Binary files /dev/null and b/WXom062/Release/vc110.pdb differ diff --git a/WXom062/Release/wx_Handler.obj b/WXom062/Release/wx_Handler.obj new file mode 100644 index 0000000..9c54895 Binary files /dev/null and b/WXom062/Release/wx_Handler.obj differ diff --git a/WXom062/Release/wx_main.obj b/WXom062/Release/wx_main.obj new file mode 100644 index 0000000..fef8910 Binary files /dev/null and b/WXom062/Release/wx_main.obj differ diff --git a/WXom062/Release/wx_method.obj b/WXom062/Release/wx_method.obj new file mode 100644 index 0000000..369bb50 Binary files /dev/null and b/WXom062/Release/wx_method.obj differ diff --git a/WXom062/Release/wx_registry.obj b/WXom062/Release/wx_registry.obj new file mode 100644 index 0000000..1f92dfe Binary files /dev/null and b/WXom062/Release/wx_registry.obj differ diff --git a/WXom062/SQLAPI.h b/WXom062/SQLAPI.h new file mode 100644 index 0000000..2dc8cc3 --- /dev/null +++ b/WXom062/SQLAPI.h @@ -0,0 +1,1606 @@ +#if !defined(__SQLAPI_H__) +#define __SQLAPI_H__ + +#ifdef SQLAPI_EXPORTS +#define SQLAPI_API __declspec(dllexport) +#else +#define SQLAPI_API +#endif + +#ifdef SQLAPI_DECL_THROW +#define SQLAPI_THROW(x) throw(x) +#else +#define SQLAPI_THROW(x) +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(_WINDOWS) || defined(_WINDOWS_) +#define SQLAPI_WINDOWS +#include +#endif + +#if !defined(SQLAPI_WINDOWS) || defined (CYGWIN) +#include +#include +#endif + +#ifndef SQLAPI_WINDOWS +#include +#endif + +#ifdef UNDER_CE +#include +#else +#include +#include +#endif +#include +#include +#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__BORLANDC__) && __BORLANDC__ >= 0x0630) || defined(__GNUC__) || defined(__SUNPRO_C) +#define SA_HAVE_STDINT_H +#include +#endif +#include + +#ifndef SIZE_MAX +#define SIZE_MAX ULONG_MAX +#endif + +#ifdef SQLAPI_WINDOWS +// 64-bit integer +typedef __int64 sa_int64_t; +typedef unsigned __int64 sa_uint64_t; +// SQLAPI callback naming +#define SQLAPI_CALLBACK __cdecl +#else +// 64-bit integer +typedef long long int sa_int64_t; +typedef unsigned long long int sa_uint64_t; +// SQLAPI callback naming +#define SQLAPI_CALLBACK +#endif // ! SQLAPI_WINDOWS + +#ifdef SA_USE_STL +#include +#include +#endif + +class ISAClient; +class ISAConnection; +class ISACursor; + +class SAMutex; + +class SAConnection; +class SACommand; +struct sa_Commands; +class saOptions; +class SAParam; +class SAField; + +class SAException; + +class saPlaceHolder; + +class SABytes; +class SALongBinary; +class SALongChar; +class SABLob; +class SACLob; +class SAValueRead; + +//! \addtogroup enums SQLAPI++ defined enums +//! \{ + +typedef + enum eSAClient +{ + //! DBMS client is not specified + SA_Client_NotSpecified, + //! ODBC + SA_ODBC_Client, + //! Oracle + SA_Oracle_Client, + //! Microsoft SQL Server + SA_SQLServer_Client, + //! InterBase or Firebird + SA_InterBase_Client, + //! SQLBase + SA_SQLBase_Client, + //! IBM DB2 + SA_DB2_Client, + //! Informix + SA_Informix_Client, + //! Sybase ASE + SA_Sybase_Client, + //! MySQL + SA_MySQL_Client, + //! PostgreSQL + SA_PostgreSQL_Client, + //! SQLite + SA_SQLite_Client, + //! SQL Anywere + SA_SQLAnywhere_Client, + _SA_Client_Reserverd = (int)(((unsigned int)(-1))/2) +} SAClient_t; + +typedef + enum eSAErrorClass +{ + //! no error occurred + SA_No_Error, + //! user-generated error + SA_UserGenerated_Error, + //! the Library-generated error + SA_Library_Error, + //! DBMS API error occurred + SA_DBMS_API_Error, + _SA_ErrorClass_Reserved = (int)(((unsigned int)(-1))/2) +} SAErrorClass_t; + +typedef +enum eSALibraryErrorType +{ + SA_Library_Error_Nomem, + SA_Library_Error_ClientNotSet, + SA_Library_Error_ClientNotSupported, + SA_Library_Error_LoadLibraryFails, + SA_Library_Error_GetLibraryVersionFails, + SA_Library_Error_ClienVersionOld, + SA_Library_Error_ClientInitFails, + SA_Library_Error_BindVarNotFound, + SA_Library_Error_FieldNotFound, + SA_Library_Error_UnknownDataType, + SA_Library_Error_UnknownParameterType, + SA_Library_Error_UnknownColumnType, + SA_Library_Error_WrongConversion, + SA_Library_Error_WrongDatetime, + _SA_Library_Error_Reserved = (int)(((unsigned int)(-1)) / 2) +} SALibraryErrorType_t; + +typedef + enum eSAIsolationLevel +{ + //! the default(unknown) isolation level + SA_LevelUnknown = -1, + //! standard ANSI isolation level 0 + SA_ANSILevel0, + //! standard ANSI isolation level 1 + SA_ANSILevel1, + //! standard ANSI isolation level 2 + SA_ANSILevel2, + //! standard ANSI isolation level 3 + SA_ANSILevel3, + //! isolation level 'Read Uncommitted' + SA_ReadUncommitted = SA_ANSILevel0, + //! isolation level 'Read Committed' + SA_ReadCommitted = SA_ANSILevel1, + //! isolation level 'Repeatable Read' + SA_RepeatableRead = SA_ANSILevel2, + //! isolation level 'Serializable' + SA_Serializable = SA_ANSILevel3, + _SA_IsolationLevel_Reserved = (int)(((unsigned int)(-1))/2) +} SAIsolationLevel_t; + +typedef + enum eSAAutoCommit +{ + //! the default(unknown) auto-commit mode + SA_AutoCommitUnknown = -1, + //! auto-commit mode is off + SA_AutoCommitOff, + //! auto-commit mode is on + SA_AutoCommitOn, + _SA_AutoCommit_Reserved = (int)(((unsigned int)(-1))/2) +} SAAutoCommit_t; + +typedef + enum eSADataType +{ + SA_dtUnknown, + SA_dtBool, + SA_dtShort, + SA_dtUShort, + SA_dtLong, + SA_dtULong, + SA_dtDouble, + SA_dtNumeric, + SA_dtDateTime, + SA_dtInterval, + SA_dtString, + SA_dtBytes, + SA_dtLongBinary, + SA_dtLongChar, + SA_dtBLob, + SA_dtCLob, + SA_dtCursor, + SA_dtSpecificToDBMS, + _SA_DataType_Reserved = (int)(((unsigned int)(-1))/2) +} SADataType_t; + +typedef + enum eSACommandType +{ + //! command type is not defined + SA_CmdUnknown, + //! command is an SQL statement (with or without parameters) + SA_CmdSQLStmt, + //! command is a raw SQL statement and not interpreted by SQLAPI++ + SA_CmdSQLStmtRaw, + //! command is a stored procedure or a function + SA_CmdStoredProc, + _SA_Cmd_Reserved = (int)(((unsigned int)(-1))/2) +} SACommandType_t; + +typedef + enum eSAParamDirType +{ + SA_ParamInput, + SA_ParamInputOutput, + SA_ParamOutput, + SA_ParamReturn, + _SA_ParamDirType_Reserved = (int)(((unsigned int)(-1))/2) +} SAParamDirType_t; + +typedef + enum eSALongOrLobReaderModes +{ + SA_LongOrLobReaderDefault, + SA_LongOrLobReaderManual, + _SA_LongOrLobReaderModes_Reserved = (int)(((unsigned int)(-1))/2) +} SALongOrLobReaderModes_t; + +typedef + enum eSAPieceType +{ + SA_FirstPiece = 1, + SA_NextPiece = 2, + SA_LastPiece = 3, + SA_OnePiece = 4, + _SA_Reserved_PieceType = (int)(((unsigned int)(-1))/2) +} SAPieceType_t; + +typedef + enum eSAConnectionHandlerType +{ + //! The handles is called after DBMS connection structures is allocated + SA_PreConnectHandler, + //! The handles is called after DBMS connection is esteblished + SA_PostConnectHandler +} SAConnectionHandlerType_t; + +//! \} + +//! \addtogroup typedefs SQLAPI++ defined types +//! \{ + +//! Callback for exception pre-handling +typedef bool (SQLAPI_CALLBACK *PreHandleException_t)(SAException &x, void* pAddlData); + +//! Long or LOB writer callback, use for parameter binding +typedef size_t (SQLAPI_CALLBACK *saLongOrLobWriter_t)(SAPieceType_t &ePieceType, void *pBuf, size_t nLen, void *pAddlData); + +//! Long or LOB reader callback, use for field fetching +typedef void (SQLAPI_CALLBACK *saLongOrLobReader_t)(SAPieceType_t ePieceType, void *pBuf, size_t nLen, size_t nBlobSize, void *pAddlData); + +//! DBMS connection handling callback +typedef void (SQLAPI_CALLBACK *saConnectionHandler_t)(SAConnection &con, SAConnectionHandlerType_t eHandlerType); + +//! \} + +typedef void (SQLAPI_CALLBACK *EnumCursors_t)(ISACursor *, void *); + +class SQLAPI_API saAPI +{ +protected: + saAPI(); +public: + virtual ~saAPI(); +}; + +class SQLAPI_API saConnectionHandles +{ +protected: + saConnectionHandles(); +public: + virtual ~saConnectionHandles(); +}; + +class SQLAPI_API saCommandHandles +{ +protected: + saCommandHandles(); +public: + virtual ~saCommandHandles(); +}; + +#if defined(SA_UNICODE) +#define _TSA(x) L ## x +typedef wchar_t SAChar; +#else +typedef char SAChar; +#define _TSA(x) x +#endif + +struct SAStringData; + +//! Provides support for manipulating character values +class SQLAPI_API SAString +{ +public: + // Constructors + //! Constructs an empty SAString + SAString(); + //! Copy constructor + SAString(const SAString &stringSrc); + //! Initializes SAString from a single character + SAString(SAChar ch, size_t nRepeat = 1); + //! Initializes SAString from an ANSI (multibyte) string (converts to SAChar) + SAString(const char *lpsz); + //! Initializes SAString from a UNICODE string (converts to SAChar) + SAString(const wchar_t *lpsz); + //! Initializes SAString from subset of characters from an ANSI (multibyte) string (converts to SAChar) + SAString(const char *lpch, size_t nLength); + //! Initializes SAString from subset of characters from a UNICODE string (converts to SAChar) + SAString(const wchar_t *lpch, size_t nLength); + //! Initializes SAString from unsigned characters (converts to SAChar) + SAString(const unsigned char *psz); + //! Special constructor for binary data (no conversion to SAChar) + SAString(const void *pBuffer, size_t nLengthInBytes); + + // Attributes & Operations + + //! Get the data length (in characters). + size_t GetLength() const; + //! True if zero length + bool IsEmpty() const; + //! Clear contents to empty + void Empty(); + + //! Return pointer to const string + operator const SAChar *() const; + + // overloaded assignment + + //! Ref-counted copy from another SAString + const SAString &operator =(const SAString &sSrc); + //! Set string content to single character + const SAString &operator=(SAChar ch); +#ifdef SA_UNICODE + const SAString &operator=(char ch); +#endif + //! Copy string content from ANSI (multibyte) string (converts to SAChar) + const SAString &operator=(const char *lpsz); + //! Copy string content from UNICODE string (converts to SAChar) + const SAString &operator=(const wchar_t *lpsz); + //! Copy string content from unsigned chars + const SAString &operator=(const unsigned char *psz); + + // string concatenation + + //! Concatenate from another SAString + const SAString &operator+=(const SAString &string); + //! Concatenate a single character + const SAString &operator+=(SAChar ch); +#ifdef SA_UNICODE + // concatenate an ANSI character after converting it to SAChar + const SAString &operator+=(char ch); +#endif + //! Concatenate from a SAChar string + const SAString &operator+=(const SAChar *lpsz); + + friend SAString SQLAPI_API operator+(const SAString &string1, const SAString &string2); + friend SAString SQLAPI_API operator+(const SAString &string, SAChar ch); + friend SAString SQLAPI_API operator+(SAChar ch, const SAString &string); +#ifdef SA_UNICODE + friend SAString SQLAPI_API operator+(const SAString &string, char ch); + friend SAString SQLAPI_API operator+(char ch, const SAString &string); +#endif + friend SAString SQLAPI_API operator+(const SAString &string, const SAChar *lpsz); + friend SAString SQLAPI_API operator+(const SAChar *lpsz, const SAString &string); + + // string comparison + + //! Straight character comparison + int Compare(const SAChar *lpsz) const; + //! Compare ignoring case + int CompareNoCase(const SAChar *lpsz) const; +#ifndef UNDER_CE + //! NLS aware comparison, case sensitive + int Collate(const SAChar *lpsz) const; +#endif + + //! Convert the object to an uppercase + void MakeUpper(); + //! Convert the object to an lowercase + void MakeLower(); + + // simple sub-string extraction + + //! Return all characters starting at zero-based nFirst + SAString Mid(size_t nFirst) const; + //! Return nCount characters starting at zero-based nFirst + SAString Mid(size_t nFirst, size_t nCount) const; + //! Return first nCount characters in string + SAString Left(size_t nCount) const; + //! Return nCount characters from end of string + SAString Right(size_t nCount) const; + //! Return the character at the specified string position + SAChar GetAt(size_t nPos) const; + + // trimming whitespace (either side) + + //! Remove whitespace starting from right edge + void TrimRight(); + //! Remove whitespace starting from left side + void TrimLeft(); + + // trimming anything (either side) + + //! Remove continuous occurrences of chTarget starting from right + void TrimRight(SAChar chTarget); + //! Remove continuous occurrences of characters in passed string, + // starting from right + void TrimRight(const SAChar *lpszTargets); + //! Remove continuous occurrences of chTarget starting from left + void TrimLeft(SAChar chTarget); + //! Remove continuous occurrences of characters in + // passed string, starting from left + void TrimLeft(const SAChar *lpszTargets); + + // advanced manipulation + + // replace occurrences of substring lpszOld with lpszNew; + // empty lpszNew removes instances of lpszOld + size_t Replace(const SAChar *lpszOld, const SAChar *lpszNew); + // insert character at zero-based index; concatenates + // if index is past end of string + size_t Insert(size_t nIndex, SAChar ch); + // insert substring at zero-based index; concatenates + // if index is past end of string + size_t Insert(size_t nIndex, const SAChar *pstr); + // delete nCount characters starting at zero-based index + size_t Delete(size_t nIndex, size_t nCount = 1); + + // searching + + // find character starting at left, SIZ if not found + size_t Find(SAChar ch) const; + // find character starting at right + size_t ReverseFind(SAChar ch) const; + // find character starting at zero-based index and going right + size_t Find(SAChar ch, size_t nStart) const; + // find first instance of any character in passed string + size_t FindOneOf(const SAChar *lpszCharSet) const; + // find first instance of substring + size_t Find(const SAChar *lpszSub) const; + // find first instance of substring starting at zero-based index + size_t Find(const SAChar *lpszSub, size_t nStart) const; + + // simple formatting + + // printf-like formatting using passed string + void Format(const SAChar *lpszFormat, ...); + // printf-like formatting using variable arguments parameter + void FormatV(const SAChar *, va_list argList); + + // Access to string implementation buffer as "C" character array + + // get pointer to modifiable buffer at least as long as nMinBufLength + SAChar *GetBuffer(size_t nMinBufLength); + // release buffer, setting length to nNewLength (or to first null if SIZE_MAX) + void ReleaseBuffer(size_t nNewLength = SIZE_MAX); + + // Use LockBuffer/UnlockBuffer to turn refcounting off + + // turn refcounting off + SAChar *LockBuffer(); + // turn refcounting back on + void UnlockBuffer(); + + // Special buffer access routines to manipulate binary data + + // get binary data length (in bytes) + size_t GetBinaryLength() const; + // return pointer to const binary data buffer + operator const void *() const; + // get pointer to modifiable binary data buffer at least as long as nMinBufLengthInBytes + void *GetBinaryBuffer(size_t nMinBufLengthInBytes); + // release buffer, setting length to nNewLength (or to first nul if -1) + void ReleaseBinaryBuffer(size_t nNewLengthInBytes); + + // return pointer to const Unicode string, convert if needed + const wchar_t *GetWideChars() const; + // get string length (in Unicode characters) + size_t GetWideCharsLength() const; + // return pointer to const multibyte string, convert if needed + const char *GetMultiByteChars() const; + // get string length (in multibyte characters) + size_t GetMultiByteCharsLength() const; + + // Special conversion functions (multibyte <-> Unicode) +#ifdef SA_UNICODE + // return pointer to const UTF8 string + const char *GetUTF8Chars() const; + // get string length (in UTF8 characters) + size_t GetUTF8CharsLength() const; + // assign UTF8 data + void SetUTF8Chars(const char* szSrc, size_t nSrcLen = SIZE_MAX); +#endif // SA_UNICODE + // return pointer to const UTF16 string + const void *GetUTF16Chars() const; + // get string length (in UTF16 characters) + size_t GetUTF16CharsLength() const; + // assign UTF16 data + void SetUTF16Chars(const void* szSrc, size_t nSrcLen = SIZE_MAX); + + // Implementation +public: + ~SAString(); + +protected: + SAChar *m_pchData; // pointer to ref counted string data + + // implementation helpers + SAStringData *GetData() const; + void Init(); + void AllocBuffer(size_t nLen); +#ifdef SA_UNICODE + void AssignBinaryCopy(size_t nSrcLenInBytes, const void *pSrcData); + void ConcatBinaryCopy(size_t nSrc1LenInBytes, const void *pSrc1Data, size_t nSrc2LenInBytes, const void *pSrc2Data); + void ConcatBinaryInPlace(size_t nSrcLen, const void *pData); +#endif // SA_UNICODE + void AssignCopy(size_t nSrcLen, const SAChar *lpszSrcData); + void ConcatCopy(size_t nSrc1Len, const SAChar *lpszSrc1Data, size_t nSrc2Len, const SAChar *lpszSrc2Data); + void ConcatInPlace(size_t nSrcLen, const SAChar *lpszSrcData); + + void CopyBeforeWrite(); + void AllocBeforeWrite(size_t nLen); + void Release(); + static void Release(SAStringData *pData); + static size_t SafeStrlen(const SAChar *lpsz); + static void FreeData(SAStringData *pData); + +#ifdef SA_USE_STL +public: + SAString(const std::string &stringSrc); + SAString(const std::wstring &stringSrc); +#endif +}; + +// Compare helpers +bool SQLAPI_API operator==(const SAString &s1, const SAString &s2); +bool SQLAPI_API operator==(const SAString &s1, const SAChar *s2); +bool SQLAPI_API operator==(const SAChar *s1, const SAString &s2); +bool SQLAPI_API operator!=(const SAString &s1, const SAString &s2); +bool SQLAPI_API operator!=(const SAString &s1, const SAChar *s2); +bool SQLAPI_API operator!=(const SAChar *s1, const SAString &s2); +bool SQLAPI_API operator<(const SAString &s1, const SAString &s2); +bool SQLAPI_API operator<(const SAString &s1, const SAChar *s2); +bool SQLAPI_API operator<(const SAChar *s1, const SAString &s2); +bool SQLAPI_API operator>(const SAString &s1, const SAString &s2); +bool SQLAPI_API operator>(const SAString &s1, const SAChar *s2); +bool SQLAPI_API operator>(const SAChar *s1, const SAString &s2); +bool SQLAPI_API operator<=(const SAString &s1, const SAString &s2); +bool SQLAPI_API operator<=(const SAString &s1, const SAChar *s2); +bool SQLAPI_API operator<=(const SAChar *s1, const SAString &s2); +bool SQLAPI_API operator>=(const SAString &s1, const SAString &s2); +bool SQLAPI_API operator>=(const SAString &s1, const SAChar *s2); +bool SQLAPI_API operator>=(const SAChar *s1, const SAString &s2); + + +class SQLAPI_API SANull +{ +}; + +#define SA_NUMERIC_MANTISSA_SIZE 32 +class SQLAPI_API SANumeric +{ + void InitZero(); + bool setFromPlainString(const SAChar *sVal); + bool setFromExpString(const SAString &sVal); + +public: + SANumeric(); // default constructor, initializes to zero + + SANumeric(double dVal); // initializes from double + SANumeric &operator=(double); // reinitializes from double + operator double() const; // converts to double + + SANumeric(sa_int64_t iVal); // initializes from 64-bit integer + SANumeric(sa_uint64_t iVal); + SANumeric &operator=(sa_int64_t); // reinitializes from 64-bit integer + SANumeric &operator=(sa_uint64_t); + operator sa_int64_t() const; // converts to 64-bit integer + operator sa_uint64_t() const; + + SANumeric &operator=(const SAChar *sVal); // reinitializes from string + operator SAString() const; // converts to string + +public: + unsigned char precision; // the maximum number of digits in base 10 + unsigned char scale; // the number of digits to the right of the decimal point + unsigned char sign; // the sign: 1 for positive numbers, 0 for negative numbers + + // a number stored as SA_NUMERIC_MANTISSA_SIZE-byte scaled integer, with the least-significant byte on the left + unsigned char val[SA_NUMERIC_MANTISSA_SIZE]; +}; + +class SQLAPI_API SAInterval +{ +public: + SAInterval(); + SAInterval(double dVal); + SAInterval(long nDays, int nHours, int nMins, int nSecs); + SAInterval(long nDays, int nHours, int nMins, int nSecs, unsigned int nNanoSeconds); + + double GetTotalDays() const; + double GetTotalHours() const; + double GetTotalMinutes() const; + double GetTotalSeconds() const; + + long GetDays() const; + long GetHours() const; + long GetMinutes() const; + long GetSeconds() const; + + unsigned int Fraction() const; + + SAInterval& operator=(double dVal); + + SAInterval operator+(const SAInterval& interval) const; + SAInterval operator-(const SAInterval& interval) const; + SAInterval& operator+=(const SAInterval interval); + SAInterval& operator-=(const SAInterval interval); + SAInterval operator-() const; + + operator double() const; + + operator SAString() const; + + void SetInterval(long nDays, int nHours, int nMins, int nSecs, unsigned int nNanoSeconds); + +private: + double m_interval; + //unsigned int m_nFraction; // 0..999999999 +}; + +//! Provides support for manipulating date/time values +class SQLAPI_API SADateTime +{ + friend class SAValueRead; + + static int m_saMonthDays[13]; + +protected: + static bool DateFromTm( + unsigned short wYear, unsigned short wMonth, unsigned short wDay, + unsigned short wHour, unsigned short wMinute, unsigned short wSecond, + unsigned int nNanoSecond, + double &dtDest); + static bool TmFromDate( + double dtSrc, + struct tm &tmDest, unsigned int &nNanoSecond); + +protected: + void Init_Tm(); + void Init(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, unsigned int nFraction, const SAChar* timezone); + struct tm m_tm; + unsigned int m_nFraction; // 0..999999999 + SAString m_timezone; + +public: + SADateTime(); + SADateTime(int nYear, int nMonth, int nDay); + SADateTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec); + SADateTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, unsigned int nFraction); + SADateTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, const SAChar* timezone); + SADateTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec, unsigned int nFraction, const SAChar* timezone); + SADateTime(int nHour, int nMin, int nSec, unsigned int nFraction); + SADateTime(const struct tm &tmValue); + SADateTime(double dt); +#ifndef UNDER_CE + SADateTime(const struct timeb &tmbValue); + SADateTime(const struct timeval &tmvValue); +#endif +#ifdef SQLAPI_WINDOWS + SADateTime(SYSTEMTIME &st); +#endif + SADateTime(const SADateTime &other); + + operator struct tm &(); + operator struct tm() const; + operator double() const; + operator SAString() const; + + int GetYear() const; // year, f.ex., 1999, 2000 + int GetMonth() const; // 1..12 + int GetDay() const; // 1..31 + int GetHour() const; // 0..23 + int GetMinute() const; // 0..59 + int GetSecond() const; // 0..59 + int GetDayOfWeek() const; // 1..7, 1=Sunday, 2=Monday, and so on + int GetDayOfYear() const; // 1..366, where January 1 = 1 + + unsigned int &Fraction(); + unsigned int Fraction() const; + + SAString& Timezone(); + const SAChar* Timezone() const; + +#ifndef UNDER_CE + void GetTimeValue(struct timeb &tmv); + void GetTimeValue(struct timeval &tmv); +#endif +#ifdef SQLAPI_WINDOWS + void GetTimeValue(SYSTEMTIME &st); +#endif + + //! Return the current date/time value + static SADateTime SQLAPI_CALLBACK currentDateTime(); + static SADateTime SQLAPI_CALLBACK currentDateTimeWithFraction(); + + SADateTime operator+(SAInterval interval) const; + SADateTime operator-(SAInterval interval) const; + SADateTime& operator+=(SAInterval interval); + SADateTime& operator-=(SAInterval interval); + + SAInterval operator-(const SADateTime& dt) const; +}; + +class SQLAPI_API SAPos +{ + friend class SACommand; + + SAString m_sName; + +public: + SAPos(int nByID); + SAPos(const SAString& sByName); +}; + +class SQLAPI_API saOptions +{ +#ifdef SA_USE_STL + std::hash_map *m_pOptions; +#else + int m_nOptionCount; + SAParam **m_ppOptions; +#endif + +private: + // disable copy constructor + saOptions(const saOptions &); + // disable assignment operator + saOptions &operator = (const saOptions &); + +public: + saOptions(); + virtual ~saOptions(); + + SAString &operator[](const SAString &sOptionName); + SAString operator[](const SAString &sOptionName) const; +}; + +//! Represents an unique session with a data source +class SQLAPI_API SAConnection +{ + friend class SACommand; + friend class SAField; + friend class SAParam; + friend class ISAConnection; + friend class Iora7Connection; + friend class Iora8Connection; + friend class ora8ExternalConnection; + +private: + // disable copy constructor + SAConnection(const SAConnection &); + // disable assignment operator + SAConnection &operator = (const SAConnection &); + + SAClient_t m_eSAClient; + ISAConnection *m_pISAConnection; + SAMutex *m_pCommandsMutex; + sa_Commands *m_pCommands; + + SAIsolationLevel_t m_eIsolationLevel; + SAAutoCommit_t m_eAutoCommit; + + saOptions m_Options; + + int nReserved; + +protected: + void EnumCursors(EnumCursors_t fn, void *pAddlData); + void RegisterCommand(SACommand *pCommand); + void UnRegisterCommand(SACommand *pCommand); + ISACursor *GetISACursor(SACommand *pCommand); + +public: + SAConnection(); + virtual ~SAConnection(); + + void setClient(SAClient_t eSAClient) SQLAPI_THROW(SAException); + SAClient_t Client() const; + long ClientVersion() const SQLAPI_THROW(SAException); + long ServerVersion() const SQLAPI_THROW(SAException); + SAString ServerVersionString() const SQLAPI_THROW(SAException); + + bool isConnected() const; + bool isAlive() const; + void Connect( + const SAString &sDBString, + const SAString &sUserID, + const SAString &sPassword, + SAClient_t eSAClient = SA_Client_NotSpecified, + saConnectionHandler_t fHandler = NULL) SQLAPI_THROW(SAException); + void Disconnect() SQLAPI_THROW(SAException); + void Destroy(); + void Reset(); + + void setIsolationLevel(SAIsolationLevel_t eIsolationLevel) SQLAPI_THROW(SAException); + SAIsolationLevel_t IsolationLevel() const; + void setAutoCommit(SAAutoCommit_t eAutoCommit) SQLAPI_THROW(SAException); + SAAutoCommit_t AutoCommit() const; + void Commit() SQLAPI_THROW(SAException); + void Rollback() SQLAPI_THROW(SAException); + + SAString &setOption(const SAString &sOptionName); + SAString Option(const SAString &sOptionName) const; + + saAPI *NativeAPI() const SQLAPI_THROW(SAException); + saConnectionHandles *NativeHandles() SQLAPI_THROW(SAException); +}; + +// SAConnection options (common for at least several DBMS-es) +// Worksattion ID +#define SACON_OPTION_WSID _TSA("WSID") +// Application Name +#define SACON_OPTION_APPNAME _TSA("APPNAME") + +//! Defines a specific command that you intend to execute against a data source. +class SQLAPI_API SACommand +{ + friend class SAConnection; + friend class IibCursor; + friend class IsybCursor; + friend class IssDBLibCursor; + friend class IsbCursor; + friend class ImyCursor; + friend class IpgCursor; + friend class Iora8Connection; + friend class Iora8Cursor; + friend class Iora7Connection; + friend class Iora7Cursor; + +private: + // disable copy constructor + SACommand(const SACommand &); + // disable assignment operator + SACommand &operator = (const SACommand &); + + SAConnection *m_pConnection; + + SACommandType_t m_eCmdType; + SAString m_sCmd; + bool m_bPrepared; + bool m_bExecuted; + bool m_bFieldsDescribed; + bool m_bSelectBuffersSet; + + bool m_bParamsKnown; + int m_nPlaceHolderCount; + saPlaceHolder **m_ppPlaceHolders; + int m_nParamCount; + SAParam **m_ppParams; + int m_nMaxParamID; + SAParam **m_ppParamsID; + int m_nCurParamID; + SAString m_sCurParamName; + + int m_nFieldCount; + SAField **m_ppFields; + + saOptions m_Options; + + int nReserved; + + void Init(); + + static int CompareIdentifier( + const SAString &sIdentifier1, + const SAString &sIdentifier2); + SAParam &CreateParam( + const SAString &sName, + SADataType_t eParamType, + int nNativeType, + size_t nParamSize, + int nParamPrecision, + int nParamScale, + SAParamDirType_t eDirType, + const SAString &sFullName, + size_t nStart, // param position in SQL statement + size_t nEnd); // param end position in SQL statemen + void GetParamsSP(); + void UnDescribeParams(); + void ParseInputMarkers( + SAString &sCmd, + bool *pbSpacesInCmd); + + void DescribeFields() SQLAPI_THROW(SAException); + void CreateField( + const SAString &sName, + SADataType_t eFieldType, + int nNativeType, + size_t nFieldSize, + int nFieldPrecision, + int nFieldScale, + bool bFieldRequired, + int nTotalFieldCount); + void DestroyFields(); + + // parses sql statement and create bind parameters array if any (In) + // also cancels previous stsement if any + void ParseCmd( + const SAString &sSQL, + SACommandType_t eCmdType); + + void UnSetCommandText(); + void UnPrepare(); + void UnExecute(); + +public: + //! Construct command with no associated connection and SQL + SACommand(); + //! Construct command based on the given connection and SQL + SACommand( + SAConnection *pConnection, + const SAString &sCmd = SAString(), + SACommandType_t eCmdType = SA_CmdUnknown); + + virtual ~SACommand(); + + SAConnection *Connection() const; + void setConnection(SAConnection *pConnection); + + virtual void Open() SQLAPI_THROW(SAException); + virtual bool isOpened(); + virtual bool isExecuted(); + virtual void Close() SQLAPI_THROW(SAException); + virtual void Destroy(); + virtual void Reset(); + + void setCommandText( + const SAString &sSQL, + SACommandType_t eCmdType = SA_CmdUnknown); + SAString CommandText() const; + SACommandType_t CommandType() const; + virtual void Prepare() SQLAPI_THROW(SAException); + virtual void Execute() SQLAPI_THROW(SAException); + bool isResultSet() SQLAPI_THROW(SAException); + long RowsAffected() SQLAPI_THROW(SAException); // returns number of rows affected by last DML operation + bool FetchNext() SQLAPI_THROW(SAException); // returns true if new row is fetched + bool FetchPrior() SQLAPI_THROW(SAException); + bool FetchFirst() SQLAPI_THROW(SAException); + bool FetchLast() SQLAPI_THROW(SAException); + bool FetchPos(int offset, bool Relative = false) SQLAPI_THROW(SAException); + void Cancel() SQLAPI_THROW(SAException); + + SAParam &CreateParam( + const SAString &sName, + SADataType_t eParamType, + SAParamDirType_t eDirType = SA_ParamInput); + SAParam &CreateParam( + const SAString &sName, + SADataType_t eParamType, + int nNativeType, + size_t nParamSize, + int nParamPrecision, + int nParamScale, + SAParamDirType_t eDirType); + void DestroyParams(); + int ParamCount(); + SAParam &ParamByIndex(int i); // zero based index of C array + SAParam &Param(int nParamByID); // id in SQL statement, not in C array + SAParam &Param(const SAString& sParamByName); + SACommand &operator << (const SAPos &pos); + SACommand &operator << (const SANull &null); + SACommand &operator << (bool Value); + SACommand &operator << (short Value); + SACommand &operator << (unsigned short Value); + SACommand &operator << (long Value); + SACommand &operator << (unsigned long Value); + SACommand &operator << (double Value); + SACommand &operator << (const SANumeric &Value); + SACommand &operator << (sa_int64_t Value); + SACommand &operator << (sa_uint64_t Value); + SACommand &operator << (const SADateTime &Value); + SACommand &operator << (const SAChar *Value); // special overload for string constants + SACommand &operator << (const SAString &Value); + SACommand &operator << (const SABytes &Value); + SACommand &operator << (const SALongBinary &Value); + SACommand &operator << (const SALongChar &Value); + SACommand &operator << (const SABLob &Value); + SACommand &operator << (const SACLob &Value); + SACommand &operator << (const SAValueRead &Value); + + int FieldCount() SQLAPI_THROW(SAException); + SAField &Field(int nField) SQLAPI_THROW(SAException); // 1-based field number in result set + SAField &Field(const SAString &sField) SQLAPI_THROW(SAException); + SAField &operator[](int nField) SQLAPI_THROW(SAException); // 1-based field number in result set + SAField &operator[](const SAString &sField) SQLAPI_THROW(SAException); + + SAString &setOption(const SAString &sOptionName); + SAString Option(const SAString &sOptionName) const; + + saCommandHandles *NativeHandles() SQLAPI_THROW(SAException); + void setBatchExceptionPreHandler(PreHandleException_t fnHandler, void* pAddlData); +}; + +// SACommand options (common for at least several DBMS-es) +// Prefertching rows +#define SACMD_PREFETCH_ROWS _TSA("PreFetchRows") +// Using scrollable cursor +#define SACMD_SCROLLABLE _TSA("Scrollable") +// Option values +#define SAOPT_TRUE _TSA("1") + +class SQLAPI_API SAValueRead +{ + friend class ISACursor; + friend class IibCursor; + friend class Iora7Cursor; + friend class Iora8Cursor; + friend class IsbCursor; + friend class IodbcCursor; + friend class IssDBLibCursor; + friend class IssOleDbCursor; + friend class Idb2Cursor; + friend class IinfCursor; + friend class IsybCursor; + friend class ImyCursor; + friend class IpgCursor; + friend class Isl3Cursor; + friend class IssNCliCursor; + friend class IasaCursor; + +protected: + SALongOrLobReaderModes_t m_eReaderMode; + + saLongOrLobReader_t m_fnReader; + size_t m_nReaderWantedPieceSize; + void *m_pReaderAddlData; + + unsigned char *m_pReaderBuf; + size_t m_nReaderAlloc; + size_t m_nExpectedSizeMax; + size_t m_nReaderRead; + size_t m_nPieceSize; + + size_t PrepareReader( + size_t nExpectedSizeMax, // to optimaze buf allocation for internal buffer, 0 = unknown + size_t nCallerMaxSize, // max Piece that can be proceeced by API + unsigned char *&pBuf, + saLongOrLobReader_t fnReader, + size_t nReaderWantedPieceSize, + void *pReaderAddlData, + bool bAddSpaceForNull = false); + void InvokeReader( + SAPieceType_t ePieceType, + unsigned char *&pBuf, + size_t nPieceLen); + SAString asLongOrLob() const; + +protected: + SADataType_t m_eDataType; + + // null indicator + bool *m_pbNull; + // scalar types + void *m_pScalar; + // an exact numeric value with a fixed precision and scale + SANumeric *m_pNumeric; + // Date time + SADateTime *m_pDateTime; + // Time interval + SAInterval *m_pInterval; + // variable length types (string, bytes, Longs and Lobs) + SAString *m_pString; + // Cursor + SACommand *m_pCursor; +private: + // null indicator + bool m_bInternalNull; + // scalar types + union uScalars + { + bool m_Bool; + short m_Short; + unsigned short m_uShort; + long m_Long; + unsigned long m_uLong; + double m_Double; + } m_InternalScalar; + SANumeric m_InternalNumeric; + SADateTime m_InternalDateTime; + SAInterval m_InternalInterval; + // variable length types (string, bytes, Longs and Lobs) + SAString m_InternalString; + // Cursor + SACommand m_InternalCursor; + +public: + SAValueRead(SADataType_t eDataType); + SAValueRead(const SAValueRead &vr); + virtual ~SAValueRead(); + + SAValueRead &operator =(const SAValueRead &vr); + +public: + SADataType_t DataType() const; + + // Null type + bool isNull() const; + + // scalar types + bool asBool() const; + short asShort() const; + unsigned short asUShort() const; + long asLong() const; + unsigned long asULong() const; + double asDouble() const; + + // numeric + SANumeric asNumeric() const; + + // date/time + SADateTime asDateTime() const; + + // Interval + SAInterval asInterval() const; + + // variable length types + SAString asString() const; + SAString asBytes() const; + SAString asLongBinary() const; + SAString asLongChar() const; + SAString asBLob() const; + SAString asCLob() const; + + // cursor + SACommand *asCursor() const; + + void setLongOrLobReaderMode(SALongOrLobReaderModes_t eMode); + SALongOrLobReaderModes_t LongOrLobReaderMode() const; + + // operators for quick accessing values + // do not inline to prevent varnings + operator bool() const; + operator short() const; + operator unsigned short() const; + operator long() const; + operator unsigned long() const; + operator double() const; + operator SANumeric() const; + operator SADateTime() const; + operator SAInterval() const; + operator SAString() const; + operator SACommand *() const; + + // data and indicator storage +public: + void setIndicatorStorage(bool *pStorage); + void setDataStorage(void *pStorage, SADataType_t eDataType); +}; + +class SQLAPI_API SAValue : public SAValueRead +{ + friend class ISACursor; + friend class IibCursor; + friend class IssDBLibCursor; + friend class Iora7Cursor; + friend class Iora8Cursor; + friend class IsbCursor; + friend class IodbcCursor; + friend class Idb2Cursor; + friend class IinfCursor; + friend class IsybCursor; + friend class ImyCursor; + friend class IpgCursor; + friend class Isl3Cursor; + friend class IssNCliCursor; + friend class IasaCursor; + +private: + bool m_bInternalUseDefault; + +protected: + bool *m_pbUseDefault; + + saLongOrLobWriter_t m_fnWriter; + size_t m_nWriterSize; + void *m_pWriterAddlData; + void *m_pWriterBuf; + size_t m_nWriterAlloc; + size_t m_nWriterWritten; + + size_t InvokeWriter( + SAPieceType_t &ePieceType, + size_t nCallerMaxSize, + void *&pBuf); + +public: + SAValue(SADataType_t eDataType); + virtual ~SAValue(); + + // Sets NULL value + void setAsNull(); + // Sets a flag to use default value + void setAsDefault(); + // queries if "default value" flag is set + bool isDefault() const; + + void setAsUnknown(); + + // scalar types + bool &setAsBool(); + short &setAsShort(); + unsigned short &setAsUShort(); + long &setAsLong(); + unsigned long &setAsULong(); + double &setAsDouble(); + + // numeric + SANumeric &setAsNumeric(); + + // date/time + SADateTime &setAsDateTime(); + + // interval + SAInterval &setAsInterval(); + + // variable length types + SAString &setAsString(); + SAString &setAsBytes(); + SAString &setAsLongBinary( + saLongOrLobWriter_t fnWriter = NULL, + size_t nWriterSize = 0, void *pAddlData = NULL); + SAString &setAsLongChar( + saLongOrLobWriter_t fnWriter = NULL, + size_t nWriterSize = 0, void *pAddlData = NULL); + SAString &setAsBLob( + saLongOrLobWriter_t fnWriter = NULL, + size_t nWriterSize = 0, void *pAddlData = NULL); + SAString &setAsCLob( + saLongOrLobWriter_t fnWriter = NULL, + size_t nWriterSize = 0, void *pAddlData = NULL); + + // cursor + SACommand *&setAsCursor(); + + // special set function(s) + SAValueRead &setAsValueRead(); +}; + +class SQLAPI_API SAParam : public SAValue +{ + friend class SACommand; + friend class saPlaceHolder; + friend class saOptions; + + SACommand *m_pCommand; + + SAString m_sName; + SADataType_t m_eParamType; + int m_nNativeType; + size_t m_nParamSize; + int m_nParamPrecision; + int m_nParamScale; + SAParamDirType_t m_eDirType; + + saOptions m_Options; + +private: + // disable copy constructor + SAParam(const SAParam &); + // disable assignment operator + SAParam &operator = (const SAParam &); + +protected: + SAParam( + SACommand *pCommand, + const SAString &sName, + SADataType_t eParamType, + int nNativeType, + size_t nParamSize, + int nParamPrecision, + int nParamScale, + SAParamDirType_t eDirType); + virtual ~SAParam(); + +public: + const SAString &Name() const; + SADataType_t ParamType() const; + void setParamType(SADataType_t eParamType); + int ParamNativeType() const; + void setParamNativeType(int nNativeType); + size_t ParamSize() const; + void setParamSize(size_t nParamSize); + SAParamDirType_t ParamDirType() const; + void setParamDirType(SAParamDirType_t eParamDirType); + int ParamPrecision() const; + void setParamPrecision(int nParamPrecision); + int ParamScale() const; + void setParamScale(int nParamScale); + + void ReadLongOrLob( + saLongOrLobReader_t fnReader, + size_t nReaderWantedSize, + void *pAddlData); + + SAString &setOption(const SAString &sOptionName); + SAString Option(const SAString &sOptionName) const; +}; + +class SQLAPI_API saPlaceHolder +{ + friend class SACommand; + + SAString m_sFullName; + size_t m_nStart; + size_t m_nEnd; + + SAParam *m_pParamRef; + +private: + saPlaceHolder( + const SAString &sFullName, + size_t nStart, + size_t nEnd, + SAParam *pParamRef); + virtual ~saPlaceHolder(); + +public: + const SAString &getFullName() const; + size_t& getStart(); + size_t& getEnd(); + SAParam *getParam() const; +}; + +class SQLAPI_API SABytes : public SAString +{ +public: + SABytes(const SAString &sData); +}; + +class SQLAPI_API SALongOrLob : public SAString +{ + friend class SACommand; + +protected: + saLongOrLobWriter_t m_fnWriter; + size_t m_nWriterPieceSize; + void *m_pAddlData; + + SALongOrLob(const SAString &sData); + SALongOrLob( + saLongOrLobWriter_t fnWriter, + size_t nWriterPieceSize, + void *pAddlData); +}; + +class SQLAPI_API SALongBinary : public SALongOrLob +{ +public: + SALongBinary(const SAString &sData); + SALongBinary( + saLongOrLobWriter_t fnWriter, + size_t nWriterPieceSize, + void *pAddlData); +}; + +class SQLAPI_API SALongChar : public SALongOrLob +{ +public: + SALongChar(const SAString &sData); + SALongChar( + saLongOrLobWriter_t fnWriter, + size_t nWriterPieceSize, + void *pAddlData); +}; + +class SQLAPI_API SABLob : public SALongOrLob +{ +public: + SABLob(const SAString &sData); + SABLob( + saLongOrLobWriter_t fnWriter, + size_t nWriterPieceSize, + void *pAddlData); +}; + +class SQLAPI_API SACLob : public SALongOrLob +{ +public: + SACLob(const SAString &sData); + SACLob( + saLongOrLobWriter_t fnWriter, + unsigned int nWriterPieceSize, + void *pAddlData); +}; + +class SQLAPI_API SAField : public SAValueRead +{ + friend class SACommand; + + SACommand *m_pCommand; + + // as reported by describe API + int m_nPos; // 1-based + SAString m_sName; + SADataType_t m_eFieldType; + int m_nNativeType; + size_t m_nFieldSize; + int m_nFieldPrecision; + int m_nFieldScale; + bool m_bFieldRequired; + + saOptions m_Options; + +private: + // disable copy constructor + SAField(const SAField &); + // disable assignment operator + SAField &operator = (const SAField &); + +protected: + SAField( + SACommand *pCommand, + int nPos, // 1-based + const SAString &sName, + SADataType_t eFieldType, + int nNativeType, + size_t nFieldSize, + int nFieldPrecision, + int nFieldScale, + bool bFieldRequired); + virtual ~SAField(); + +public: + int Pos() const; + const SAString &Name() const; + SADataType_t FieldType() const; + int FieldNativeType() const; + size_t FieldSize() const; + int FieldPrecision() const; + int FieldScale() const; + bool isFieldRequired() const; + + // !!! + void setFieldSize(int nSize); + void setFieldType(SADataType_t eType); + + void ReadLongOrLob( + saLongOrLobReader_t fnReader, + size_t nReaderWantedSize, + void *pAddlData); + + SAString &setOption(const SAString &sOptionName); + SAString Option(const SAString &sOptionName) const; +}; + +class SQLAPI_API SAException +#ifdef SQLAPI_EXCEPTION_DELIVERED_FROM + : public SQLAPI_EXCEPTION_DELIVERED_FROM +#endif +{ + friend class SAConnection; + friend class SACommand; + +public: + SAException( + SAException* pNested, + SAErrorClass_t eError, + int nNativeError, + int nErrPos, + const SAString &sMsg); + SAException( + SAException* pNested, + SAErrorClass_t eError, + int nNativeError, + int nErrPos, + const SAChar *lpszFormat, ...); + + SAException( + SAErrorClass_t eError, + int nNativeError, + int nErrPos, + const SAString &sMsg); + SAException( + SAErrorClass_t eError, + int nNativeError, + int nErrPos, + const SAChar *lpszFormat, ...); + + SAException(const SAException &other); + +public: + virtual ~SAException(); + + static void SQLAPI_CALLBACK throwUserException( + int nUserCode, const SAChar *lpszFormat, ...); + + SAErrorClass_t ErrClass() const; + int ErrNativeCode() const; + int ErrPos() const; + SAString ErrMessage() const; + SAString ErrText() const; + const SAException* NestedException() const; + +#ifdef SQLAPI_EXCEPTION_HAS_CUSTOM_MEMBERS + SQLAPI_EXCEPTION_HAS_CUSTOM_MEMBERS +#endif + +public: + SAException& operator=(const SAException &other); + +protected: + SAErrorClass_t m_eErrorClass; + int m_nNativeError; + int m_nErrPos; + SAString m_sMsg; + SAException* m_pNested; + + int nReserved; +}; + +class SQLAPI_API SAUserException : public SAException +{ + friend class SAException; + +protected: + SAUserException(int nUserCode, const SAString &sMsg); + +public: + virtual ~SAUserException(); +}; + +typedef enum eSATraceInfo +{ + SA_Trace_None = 0, + SA_Trace_QueryText = 1 //! trace real DBMS API query text SQLAPI++ sends +} SATraceInfo_t; + +//! Callback for tracing +typedef void (SQLAPI_CALLBACK *SATraceFunction_t)( + SATraceInfo_t traceInfo, //! tracing into label + SAConnection* pCon, //! related SAConnection or NULL + SACommand* pCmd, //! related SACommand or NULL + const SAChar* szTraceInfo, //! tracing text + void* pData); //! user provided data + +//! Global SQLAPI++ settings +class SQLAPI_API SAGlobals +{ +public: + static char * SQLAPI_CALLBACK setlocale(int category, const char *locale); + + static int GetVersionMajor(); + static int GetVersionMinor(); + static int GetVersionBuild(); + + static bool& UnloadAPI(); + + static const SAChar* ClientToString(SAClient_t eSAClient); + static SAClient_t StringToClient(const SAChar* szClientName); + + static void SetTraceFunction(SATraceInfo_t traceInfo, SATraceFunction_t traceFunc, void* pData); +}; + +#define SQLAPI_VER_MAJOR 4 +#define SQLAPI_VER_MINOR 1 +#define SQLAPI_VER_BUILD 11 + +#endif // !defined(__SQLAPI_H__) + + diff --git a/WXom062/WXom062.vcxproj b/WXom062/WXom062.vcxproj new file mode 100644 index 0000000..f2c7d40 --- /dev/null +++ b/WXom062/WXom062.vcxproj @@ -0,0 +1,192 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {CA332F54-429B-4AE3-984B-526BD0D9F2A1} + Win32Proj + WXom062 + chint + 8.1 + + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + true + v141 + Unicode + + + DynamicLibrary + false + v141 + true + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + $(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;WXOM062_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;WXOM062_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WXOM062_EXPORTS;IPLIB=none;%(PreprocessorDefinitions) + F:\Siemen\include_cpp;F:\Siemen\include;F:\Siemen\lib;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + F:\Siemen\lib\*.lib;F:\Siemen\lib\itk_main.obj;%(AdditionalDependencies) + libuser_exits.ar.lib;%(IgnoreSpecificDefaultLibraries) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WXOM062_EXPORTS;IPLIB=none;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + Z:\TC_install\YSR\c\TC11.6\include;Z:\TC_install\YSR\c\TC11.6\include_cpp;D:\Siemens\HTTPRequest-master\include;Z:\TC_install\ZhengTai\c\libxl\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + Z:\TC_install\YSR\c\TC11.6\lib\*.lib;C:\Program Files (x86)\Windows Kits\8.0\Lib\win8\um\x64\ws2_32.Lib;Wininet.lib;Z:\TC_install\ZhengTai\c\libxl\lib\*.lib;%(AdditionalDependencies) + libuser_exits.ar.lib;%(IgnoreSpecificDefaultLibraries) + /force:multiple %(AdditionalOptions) + + + + + + \ No newline at end of file diff --git a/WXom062/WXom062.vcxproj.filters b/WXom062/WXom062.vcxproj.filters new file mode 100644 index 0000000..d1311cc --- /dev/null +++ b/WXom062/WXom062.vcxproj.filters @@ -0,0 +1,126 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + \ No newline at end of file diff --git a/WXom062/WXom062.vcxproj.user b/WXom062/WXom062.vcxproj.user new file mode 100644 index 0000000..ef5ff2a --- /dev/null +++ b/WXom062/WXom062.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/WXom062/chintProperty.cpp b/WXom062/chintProperty.cpp new file mode 100644 index 0000000..37b2727 --- /dev/null +++ b/WXom062/chintProperty.cpp @@ -0,0 +1,725 @@ +#pragma warning (disable: 4996) +#pragma warning (disable: 4819) + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +// #include +#include +#include "error_handling.h" +#include "common_itk_util.h" +#include "epm_handler_common.h" +#include +#include +#include "tc_util.h" +using namespace std; +//̽ڵϢ +struct TXFLOWNODEINFOS +{ + char taskname[128]; + char username[128]; + char timeinfo[128]; + //2019.12.2עͣעֻУû + char commentsinfo[256]; + char group[128]; +}flownode_s[64]; + +//ԱϢ +struct TXUSERINFOS +{ + char taskname[128]; + char propertyname[128]; + char group[128]; +}userinfo_s[64]; +//ѾϢ +struct TXCOMMENTSINFOS +{ + char taskname[128]; + char propertyname[128]; + char group[128]; +}commentsinfo_s[64]; +//Ϣ +struct TXTIMEINFOS +{ + char taskname[128]; + char propertyname[128]; + char group[128]; +}timeinfo_s[64]; + + + +int txnodecount = 0; +int txuserinfoscount = 0; +int txtimeinfoscount = 0; +int txcommentsinfoscount = 0; + +typedef struct{ + string TaskUserName; + string TaskTimeName; + string UserName; + string TimeStr; + string GroupName; + string PropUserName; + string PropTimeName; +}TXNOTICE_NODE; +void txSplitUserInfo(char *userinfo) +{ + char* token = NULL, *ptr = NULL, temp[512] = ""; + + token = strtok( userinfo, ";"); + while( token != NULL ) + { + /* While there are tokens in "string" */ + strcpy(temp,token); + ECHO( "token=%s\n", token ); + ptr = strstr(temp, "="); + if (ptr != NULL) + { + strcpy(userinfo_s[txuserinfoscount].propertyname, ptr +1); + strcpy(ptr,"\0"); + strcpy(userinfo_s[txuserinfoscount].taskname ,temp); + ECHO("\nuserinfo_s[userinfoscount].taskname=%s,userinfo_s[userinfoscount].propertyname=%s\n", + userinfo_s[txuserinfoscount].taskname,userinfo_s[txuserinfoscount].propertyname); + } + txuserinfoscount ++; + /* Get next token: */ + token = strtok( NULL, ";"); + } +} +void txSplitCommentsInfo(char *commentsInfo) +{ + char* token = NULL, *ptr = NULL, temp[512] = ""; + + token = strtok( commentsInfo, ";"); + while( token != NULL ) + { + /* While there are tokens in "string" */ + strcpy(temp,token); + ECHO( "token=%s\n", token ); + ptr = strstr(temp, "="); + if (ptr != NULL) + { + strcpy(commentsinfo_s[txcommentsinfoscount].propertyname, ptr +1); + strcpy(ptr,"\0"); + strcpy(commentsinfo_s[txcommentsinfoscount].taskname ,temp); + ECHO("\ncommentsinfo_s[userinfoscount].taskname=%s,commentsinfo_s[userinfoscount].propertyname=%s\n", + commentsinfo_s[txcommentsinfoscount].taskname,commentsinfo_s[txcommentsinfoscount].propertyname); + } + txcommentsinfoscount ++; + /* Get next token: */ + token = strtok( NULL, ";"); + } +} +void txSplitTimeInfo(char *userinfo) +{ + char* token = NULL, *ptr = NULL, temp[512] = ""; + + token = strtok( userinfo, ";"); + while( token != NULL ) + { + /* While there are tokens in "string" */ + strcpy(temp,token); + ECHO( "token=%s\n", token ); + ptr = strstr(temp, "="); + if (ptr != NULL) + { + strcpy(timeinfo_s[txtimeinfoscount].propertyname, ptr +1); + strcpy(ptr,"\0"); + strcpy(timeinfo_s[txtimeinfoscount].taskname ,temp); + ECHO("\ntimeinfo_s[txtimeinfoscount].taskname=%s,timeinfo_s[txtimeinfoscount].propertyname=%s\n",timeinfo_s[txtimeinfoscount].taskname,timeinfo_s[txtimeinfoscount].propertyname); + + } + txtimeinfoscount ++; + /* Get next token: */ + token = strtok( NULL, ";"); + } +} +int tx_ORIGIN_ask_sign_info(tag_t task_node, char *output_str,char *task_name,char *arg3value,char *arg4value) +{ + int ifail = ITK_ok; + tag_t cur_perform_task = NULLTAG,tempTask = NULLTAG; + char cur_task_name[WSO_name_size_c+1]="",buf[128] = ""; + //жϱ + int s = 0; + EPM_decision_t decision = EPM_nogo; + char* userName; + char *timeinfo1 = "",person_name[SA_name_size_c+1]="",*prop_name = "last_mod_date"; + tag_t aUserTag = NULLTAG,responsibleParty = NULLTAG; + date_t decision_date; + //ڵ + int perform_count = 0; + int *attach_type; + tag_t *perform_attaches = NULLTAG; + tag_t memberTag = NULLTAG; + SIGNOFF_TYPE_t memberType; + CR_signoff_decision_t signoff_decision; + EPM_signoff_decision_t dec; + char *timeinfo="",*group_full_name = NULL; + tag_t user_tag=NULLTAG, group_tag = NULLTAG; + //ѭжϱ + int i=0; + + EPM_ask_name( task_node, cur_task_name ) ; + ECHO("cur_task_name = %s\n",cur_task_name); + if ( stricmp( cur_task_name, "perform-signoffs" ) == 0 ) + { + cur_perform_task = task_node; + //õڵ + EPM_ask_parent_task( cur_perform_task, &tempTask ); + EPM_ask_name( tempTask, cur_task_name ); + } + else if( strcmp( cur_task_name, "" ) == 0 || strcmp( cur_task_name, "" ) == 0) + { + cur_perform_task = task_node; + } + else + { + EPM_ask_sub_task(task_node, "perform-signoffs", &cur_perform_task) ; + if ( cur_perform_task != NULLTAG ) + { + EPM_ask_name( task_node, cur_task_name ); + + ECHO( "---------> cur_task_name = %s\n" , cur_task_name ); + + } + } + + if(cur_perform_task != NULLTAG ) + { + char type[WSO_name_size_c+1] = ""; + WSOM_ask_object_type(cur_perform_task,type); + ECHO("current task type = %s\n", type); + cout<<"type--------"< ans; + //if( d_value != NULL ) + //{ + // Split(d_value, ' ', ans); + // if(ans.size() > 1) + // strcat(output_str,ans[0].c_str()); + //} + strcat(output_str,d_value); + //DOFREE(timeinfo); + strcat(output_str, "|"); + strcpy(flownode_s[txnodecount].taskname,""); + strcpy(flownode_s[txnodecount].username,person_name); + //if(ans.size() > 1) + strcpy(flownode_s[txnodecount].timeinfo,d_value); + txnodecount = txnodecount + 1;*/ + ECHO("output_str=%s",output_str); + EPM_ask_all_attachments(cur_perform_task,&perform_count,&perform_attaches,&attach_type); + ECHO("EPM_signoff_attachment Counts = %d", perform_count); + + for(i=0;i 0) + { + for (i=0;i type_vec; + + //Split(exclude_type,";",type_vec); + + ECHO("1%d\n",txuserinfoscount); + cout< +#include "epm_handler_common.h" + +#include +#include +#include +#include +#include +#include +#include +#include "ps/ps.h"; +#include "ps/vrule.h" +#include "sstream" +#include +#include "epm/epm.h" +#include "sa/sa.h" +#include "libxl.h" +#include +#include "epm/signoff.h" +#include +#include +#include +#include +#include "ae/dataset.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include "hx_custom.h" +#include "tc_log.h" +// #include "jk_custom.h" +#include "chint_Handler.h" +#include "util.h" + +void get_current_time(char *date_time) +{ + time_t the_time; + struct tm *time_ptr; + char *time_format = "%Y-%m-%d %H-%M-%S "; + + the_time = time((time_t *)0); + time_ptr = localtime(&the_time); + strftime(date_time, 128, time_format, time_ptr); +} +// char *תΪTCHAR *WCHAR * +TCHAR convertTemp3[256] = { 0 }; +TCHAR convertTemp4[256] = { 0 }; +bool convertBufferSwitch2(false); +TCHAR* Char2Tchar(const char* str, int len) +{ +#ifdef _UNICODE + TCHAR* temp = convertBufferSwitch2 ? convertTemp3 : convertTemp4; + convertBufferSwitch2 = !convertBufferSwitch2; + memset(temp, 0, sizeof(convertTemp3)); + MultiByteToWideChar(CP_UTF8, 0, str, len, temp, 256); + return temp; +#else + return str; +#endif +} +int create_dataset(char *type_name, const char *name, tag_t excelTag) +{ + + // cout<<"------------------"<setKey(L"Halil Kural", L"windows-2723210a07c4e90162b26966a8jcdboe");//˸ÿ⣬Ӧkeyûй + // book->setKey(L"TommoT", L"windows-2421220b07c2e10a6eb96768a2p7r6gc");//° + int n_refs = 0; + tag_t* refs = NULL; + + ifail = AE_ask_all_dataset_named_refs(excelTag, "excel", &n_refs, &refs); + if (ifail != ITK_ok) { /* your error logic here */ } + + char current_date_time_str[128 + 1] = { "\0" }; + get_current_time(current_date_time_str); + + + string time_now = current_date_time_str; + string sGuid = GenerateGuid(); + string datasetName = time_now; + datasetName = datasetName.append(sGuid); + datasetName = datasetName.append(".xls"); + time_now = getenv("temp"); + time_now = time_now.append("\\").append(datasetName); + + cout << "ļ·----------" << time_now << endl; + cout << "-------1----------" << endl; + ifail = AE_export_named_ref(excelTag, "excel", time_now.c_str()); + cout << "--------2---------" << endl; + if (ifail != ITK_ok) { /* your error logic here */ } + //ǷڵԪΪxxxx + wstringstream excel_path; + + // excel_path<<"C:\\TEMP\\export_text.xls"; + excel_path << time_now.c_str(); + cout << "--------3---------" << endl; + libxl::Sheet* sheet = NULL; + cout << "---------4--------" << endl; + if (book->load(excel_path.str().c_str())) + { + sheet = book->getSheet(0);//õ1sheetҳ + + } + + cout << "--------5---------" << endl; + //д + TCHAR array2[100]; + cout << "---------6--------" << endl; + cout << "---------page--------" <writeStr(21, 8, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_DesignTime, -1, array2, 100); + sheet->writeStr(22, 8, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Proofread, -1, array2, 100); + sheet->writeStr(21, 9, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_ProofreadTime, -1, array2, 100); + sheet->writeStr(22, 9, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Normalization, -1, array2, 100); + sheet->writeStr(21, 10, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_NormalizationTime, -1, array2, 100); + sheet->writeStr(22, 10, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Review, -1, array2, 100); + sheet->writeStr(21, 12, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_ReviewTime, -1, array2, 100); + sheet->writeStr(22, 12, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Approve, -1, array2, 100); + sheet->writeStr(21, 14, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_ApproveTime, -1, array2, 100); + sheet->writeStr(22, 14, array2); + } + cout << "-------7----------" << endl; + for (int i = 0; i0--------" << endl; + MultiByteToWideChar(CP_ACP, 0, zt2_Design, -1, array2, 100); + sheet->writeStr(i * 23 + 21, 8, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_DesignTime, -1, array2, 100); + sheet->writeStr(i * 23 + 22, 8, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Proofread, -1, array2, 100); + sheet->writeStr(i * 23 + 21, 9, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_ProofreadTime, -1, array2, 100); + sheet->writeStr(i * 23 + 22, 9, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Normalization, -1, array2, 100); + sheet->writeStr(i * 23 + 21, 10, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_NormalizationTime, -1, array2, 100); + sheet->writeStr(i * 23 + 22, 10, array2); + + MultiByteToWideChar(CP_ACP, 0, zt2_Review, -1, array2, 100); + sheet->writeStr(i * 23 + 21, 12, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_ReviewTime, -1, array2, 100); + sheet->writeStr(i * 23 + 22, 12, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_Approve, -1, array2, 100); + sheet->writeStr(i * 23 + 21, 14, array2); + MultiByteToWideChar(CP_ACP, 0, zt2_ApproveTime, -1, array2, 100); + sheet->writeStr(i * 23 + 22, 14, array2); + } + cout << "---------8--------" << endl; + if (book->save(excel_path.str().c_str()))//浽example.xls + { + //..... + } + else + { + std::cout << book->errorMessage() << std::endl; + } + book->release();//ͷŶ󣡣 + //ݼҵ汾Ĺ淶ϵ + cout << "---------9--------" << endl; + create_dataset("MSExcel", datasetName.c_str(), excelTag);//ݼ(object_type)ݼƣ汾 + return 0; +} + +wstring StringToWString(const string s) +{ + setlocale(LC_ALL, "chs"); + const char* _Source = s.c_str(); + size_t _Dsize = s.size() + 1; + wchar_t *_Dest = new wchar_t[_Dsize]; + wmemset(_Dest, 0, _Dsize); + mbstowcs(_Dest, _Source, _Dsize); + wstring result = _Dest; + delete[]_Dest; + setlocale(LC_ALL, "C"); + return result; +} + +wchar_t* c2w(const char *str) +{ + int length = strlen(str) + 1; + wchar_t *t = (wchar_t*)malloc(sizeof(wchar_t)*length); + memset(t, 0, length*sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, str, strlen(str), t, length); + return t; +} +string WStringToString(const wstring& ws) +{ + + string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C"; + setlocale(LC_ALL, "chs"); + const wchar_t* _Source = ws.c_str(); + size_t _Dsize = 2 * ws.size() + 1; + char *_Dest = new char[_Dsize]; + memset(_Dest, 0, _Dsize); + wcstombs(_Dest, _Source, _Dsize); + string result = _Dest; + delete[]_Dest; + setlocale(LC_ALL, curLocale.c_str()); + return result; + +} + +//ȡexcelԪ +string get_excel_data(libxl::Sheet *sheet, int row, int col) +{ + string result; + double temp; + try + { + libxl::CellType cell_type = sheet->cellType(row, col); + switch (cell_type) + { + case libxl::CELLTYPE_STRING: + result = WStringToString(sheet->readStr(row, col)); + break; + case libxl::CELLTYPE_BLANK: + result = ""; + break; + case libxl::CELLTYPE_EMPTY: + result = ""; + break; + case libxl::CELLTYPE_NUMBER: + temp = sheet->readNum(row, col); + result = temp == (int)temp ? to_string((int)temp) : to_string(temp); + break; + case libxl::CELLTYPE_BOOLEAN: + result = to_string(sheet->readBool(row, col)); + break; + case libxl::CELLTYPE_ERROR: + result = ""; + break; + } + + } + catch (exception e) + { + // LERROR<<"col num"<setKey(L"Halil Kural", L"windows-2723210a07c4e90162b26966a8jcdboe");//˸ÿ⣬Ӧkeyûй + // book->setKey(L"TommoT", L"windows-2421220b07c2e10a6eb96768a2p7r6gc");//° + int n_refs = 0; + tag_t* refs = NULL; + + ifail = AE_ask_all_dataset_named_refs(excelTag, "excel", &n_refs, &refs); + if (ifail != ITK_ok) { /* your error logic here */ } + + char current_date_time_str[128 + 1] = { "\0" }; + get_current_time(current_date_time_str); + + + string time_now = current_date_time_str; + string sGuid = GenerateGuid(); + string datasetName = time_now; + datasetName = datasetName.append(sGuid); + datasetName = datasetName.append(".xls"); + time_now = getenv("temp"); + time_now = time_now.append("\\").append(datasetName); + + cout << "ļ·----------" << time_now << endl; + cout << "-------1----------" << endl; + ifail = AE_export_named_ref(excelTag, "excel", time_now.c_str()); + cout << "--------2---------" << endl; + if (ifail != ITK_ok) { /* your error logic here */ } + //ǷڵԪΪxxxx + wstringstream excel_path; + + // excel_path<<"C:\\TEMP\\export_text.xls"; + excel_path << time_now.c_str(); + cout << "--------3---------" << endl; + libxl::Sheet* sheet = NULL; + cout << "---------4--------" << endl; + if (book->load(excel_path.str().c_str())) + { + sheet = book->getSheet(0);//õ1sheetҳ + cout << "--------ȡexcel---------" << endl; + if (sheet) + { + cout << "--------ȡsheet0---------" << endl; + } + else + { + cout << "--------δȡsheet0---------" << endl; + } + } + else + { + cout << "--------δȡexcel--------" << endl; + } + cout << "--------5---------" << endl; + //д + TCHAR array2[100]; + cout << "---------6--------" << endl; + + if (page == 0) + { + cout << "---------page=0--------" << endl; + // + MultiByteToWideChar(CP_ACP, 0, zt2_Design, -1, array2, 100); + ITKCALL(sheet->writeStr(23, 9, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_DesignTime, -1, array2, 100); + ITKCALL(sheet->writeStr(24, 9, array2)); + //У + MultiByteToWideChar(CP_ACP, 0, zt2_Proofread, -1, array2, 100); + ITKCALL(sheet->writeStr(23, 10, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_ProofreadTime, -1, array2, 100); + ITKCALL(sheet->writeStr(24, 10, array2)); + // + MultiByteToWideChar(CP_ACP, 0, zt2_Technology, -1, array2, 100); + ITKCALL(sheet->writeStr(23, 12, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_TechnologyTime, -1, array2, 100); + ITKCALL(sheet->writeStr(24, 12, array2)); + // + MultiByteToWideChar(CP_ACP, 0, zt2_Review, -1, array2, 100); + ITKCALL(sheet->writeStr(23, 14, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_ReviewTime, -1, array2, 100); + ITKCALL(sheet->writeStr(24, 14, array2)); + } + cout << "-------7----------" << endl; + int rowNum = sheet->lastRow(); + int colNum = sheet->lastCol(); + cout << "lastRow:" << rowNum << endl; + cout << "lastCol:" << colNum << endl; + for (int i = 0; iwriteStr(i * 24 + 23, 9, array2)); + //ITKCALL(sheet->writeStr(i * 23 + 22, 8, c2w(zt2_Design))); + cout << "-------7-3----------" << endl; + MultiByteToWideChar(CP_ACP, 0, zt2_DesignTime, -1, array2, 100); + cout << "-------7-4----------" << endl; + ITKCALL(sheet->writeStr(i * 24 + 24, 9, array2)); + cout << "-------7-5----------" << endl; + MultiByteToWideChar(CP_ACP, 0, zt2_Proofread, -1, array2, 100); + cout << "-------7-6----------" << endl; + ITKCALL(sheet->writeStr(i * 24 + 23, 10, array2)); + cout << "-------7-7----------" << endl; + MultiByteToWideChar(CP_ACP, 0, zt2_ProofreadTime, -1, array2, 100); + cout << "-------7-8----------" << endl; + ITKCALL(sheet->writeStr(i * 24 + 24, 10, array2)); + cout << "-------7-8----------" << endl; + MultiByteToWideChar(CP_ACP, 0, zt2_Technology, -1, array2, 100); + cout << "-------7-9----------" << endl; + ITKCALL(sheet->writeStr(i * 24 + 23, 12, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_TechnologyTime, -1, array2, 100); + ITKCALL(sheet->writeStr(i * 24 + 24, 12, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_Review, -1, array2, 100); + ITKCALL(sheet->writeStr(i * 24 + 23, 14, array2)); + MultiByteToWideChar(CP_ACP, 0, zt2_ReviewTime, -1, array2, 100); + ITKCALL(sheet->writeStr(i * 24 + 24, 14, array2)); + } + cout << "---------8--------" << endl; + if (book->save(excel_path.str().c_str()))//浽example.xls + { + //..... + } + else + { + std::cout << book->errorMessage() << std::endl; + } + book->release();//ͷŶ󣡣 + //ݼҵ汾Ĺ淶ϵ + cout << "---------9--------" << endl; + create_dataset("MSExcel", datasetName.c_str(), excelTag);//ݼ(object_type)ݼƣ汾 + cout << "writeToExcel2 end" << endl; + return 0; +} +int chintSignChange(EPM_action_message_t msg) +{ + + cout << "chintSignChange start" << endl; + //20200113 + POM_AM__set_application_bypass(true); + + EPM_decision_t decision = EPM_go; + int ifail = ITK_ok, arg_cnt = 0, i = 0, att_cnt = 0; + tag_t task_tag = NULLTAG, rootTask_tag = NULLTAG, *attachments = NULL; + // char * ref_type=NULL; + // int actualNum=0; + //ȡǰ + task_tag = msg.task; + //ȡ̽ڵ + ifail = EPM_ask_root_task(task_tag, &rootTask_tag); + //ȡĿö + ifail = EPM_ask_attachments(rootTask_tag, EPM_target_attachment, &att_cnt, &attachments); + int reference_count = 0; tag_t * reference_attachment = NULLTAG; + ifail = EPM_ask_attachments(rootTask_tag, EPM_reference_attachment, &reference_count, &reference_attachment); + map rev_map; + char *zt2_Design = NULL; + char *zt2_DesignTime = NULL; + char *zt2_Proofread = NULL; + char *zt2_ProofreadTime = NULL; + char *zt2_Normalization = NULL; + char *zt2_NormalizationTime = NULL; + char *zt2_Review = NULL; + char *zt2_ReviewTime = NULL; + char *zt2_Approve = NULL; + char *zt2_ApproveTime = NULL; + char *zt2_Technology = NULL; + char *zt2_TechnologyTime = NULL; + char *zt2_Countersign = NULL; + char *zt2_CountersignTime = NULL; + int eCount = 0; + tag_t *eTag = NULLTAG; + // vector.clear();//Ԫ + //ѭĿ + for (i = 0; i < att_cnt; i++) + { + tag_t targetTag = attachments[i]; + //ǰ汾͵ľͲϲ + char * object_type = NULL; + ITKCALL(ifail = AOM_ask_value_string(targetTag, "object_type", &object_type)); + cout << i << "--object_type:" << object_type << endl; + if (strstr(object_type, "ZT2_Change") != NULL) + { + //ȡǩ + + AOM_ask_value_string(targetTag, "zt2_Design", &zt2_Design); + AOM_ask_value_string(targetTag, "zt2_DesignTime", &zt2_DesignTime); + AOM_ask_value_string(targetTag, "zt2_Proofread", &zt2_Proofread); + AOM_ask_value_string(targetTag, "zt2_ProofreadTime", &zt2_ProofreadTime); + AOM_ask_value_string(targetTag, "zt2_Normalization", &zt2_Normalization); + AOM_ask_value_string(targetTag, "zt2_NormalizationTime", &zt2_NormalizationTime); + AOM_ask_value_string(targetTag, "zt2_Review", &zt2_Review); + AOM_ask_value_string(targetTag, "zt2_ReviewTime", &zt2_ReviewTime); + AOM_ask_value_string(targetTag, "zt2_Approve", &zt2_Approve); + AOM_ask_value_string(targetTag, "zt2_ApproveTime", &zt2_ApproveTime); + AOM_ask_value_string(targetTag, "zt2_Countersign", &zt2_Countersign); + AOM_ask_value_string(targetTag, "zt2_CountersignTime", &zt2_CountersignTime); + //ȡݼ + + AOM_ask_value_tags(targetTag, "IMAN_reference", &eCount, &eTag); + for (int j = 0; j0) + { + page = delivery + 1; + } + else + { + page = delivery; + } + writeToExcel(page, eTag[j], zt2_Design, zt2_DesignTime, zt2_Proofread, zt2_ProofreadTime, zt2_Normalization, zt2_NormalizationTime, zt2_Review, zt2_ReviewTime, zt2_Approve, zt2_ApproveTime); + if (values != NULL) + { + for (int t = 0; t0) + { + page=delivery+1; + }else + { + page=delivery; + } + */ + + writeToExcel2(1, eTag[j], zt2_Design, zt2_DesignTime, zt2_Proofread, zt2_ProofreadTime, + zt2_Normalization, zt2_NormalizationTime, zt2_Review, zt2_ReviewTime, + zt2_Approve, zt2_ApproveTime, zt2_Technology, zt2_TechnologyTime); + if (values != NULL) + { + for (int t = 0; t vecs); +void getSch(tag_t task, bool *flag, tag_t *sch, int level); + +int chint_Design_Task(EPM_action_message_t msg) +{ + tag_t root_task; + int t_cnt; + tag_t *t_tag; + POM_AM__set_application_bypass(true); + EPM_ask_root_task(msg.task, &root_task); + TC_argument_list_t * arguments = msg.arguments; + int arg_cnt = TC_number_of_arguments(arguments); + char *temp_key, *temp_val; + map texts; + vector vec_tags; + for (int i = 0; i < arg_cnt; i++) + { + SAFECALL(ITK_ask_argument_named_value(TC_next_argument(arguments), &temp_key, &temp_val)); + if (temp_key == NULL || temp_key == "") + continue; + //vec_tags.push_back() + texts[temp_key] = temp_val; + LINFO << "ʱ=[" << temp_key << "]=[" << temp_val; + printf(":%s,ֵ:%s\r\n",temp_key,temp_val); + } + tag_t *s_tasks; //ʱ + int s_cnt=0; + SAFECALL(AOM_ask_value_tags(root_task,"fnd0RootScheduleTask",&s_cnt,&s_tasks)); + if (s_cnt < 1) + { + LINFO << "δʱ"; + return 0; + } + LINFO << "ǰ̹ʱ:" << s_cnt; + printf("ǰһ%dʱ\r\n",s_cnt); + tag_t sch_task; + char *s_name;//ʱ + bool flag = false; + for (auto i = 0; i < s_cnt; i++) + { + SAFECALL(AOM_ask_value_string(s_tasks[i], "object_name", &s_name)); + LINFO << "ʱ:" << s_name; + if (texts.find(s_name) == texts.end()) + continue; + string task_name = texts[s_name]; + getSch(s_tasks[i], &flag, &sch_task, 0); + if (sch_task != NULL) + { + int cnt; + int *levels; + char**relations; + tag_t folder, *refs; + char *folder_Name, *object_type; + tag_t pro_Folder; + bool flag2 = true; + ITKCALL(WSOM_where_referenced2(sch_task, 1, &cnt, &levels, &refs, &relations)); + for (auto i = 0; i < cnt; i++) + { + ITKCALL(AOM_ask_value_string(refs[i], "object_name", &folder_Name)); + ITKCALL(AOM_ask_value_string(refs[i], "object_type", &object_type)); + printf("object_name:%s|object_type:%s\r\n", folder_Name, object_type); + if (isTypeOf(refs[i], "Folder") && strcmp("Ŀƻ", folder_Name) == 0) + { + printf("ҵĿƻļ\r\n"); + folder = refs[i]; + ITKCALL(WSOM_where_referenced2(folder, 1, &cnt, &levels, &refs, &relations)); + for (auto j = 0; j < cnt; j++) + { + if (isTypeOf(refs[j], "ZT2_ProjectItem")) + { + pro_Folder = refs[j]; + flag2 = false; + break; + } + } + break; + } + } + if (flag2) + { + printf("ҲĿ"); + continue; + } + date_t ISDD, IEDD; + AOM_ask_value_date(s_tasks[i], "actual_start_date", &ISDD); + AOM_ask_value_date(s_tasks[i], "actual_finish_date", &IEDD); + char *item_id; + AOM_ask_value_string(pro_Folder, "item_id", &item_id); + Item *item = BusinessObjectRef(pro_Folder); + vector tasks_vec; + vector tasks_cnt; + item->getTagArray("zt2_Tasks", tasks_vec, tasks_cnt); + vector vecs; + for (auto j = 0; j < tasks_cnt.size(); j++) + { + char *acName, *acNo, *plansEnd, *planStart; + SAFECALL(AOM_ask_value_string(tasks_vec[j],"zt2_activeName", &acName)); + LINFO << ":" << acName; + if (strcmp(acName, task_name.c_str()) != 0) + { + continue; + } + SAFECALL(AOM_ask_value_string(tasks_vec[j], "zt2_activeNo", &acNo)); + vecs.push_back(item_id); + vecs.push_back(acNo); + vecs.push_back(acName); + vecs.push_back(getYMD(ISDD)); + vecs.push_back(getYMD(IEDD)); + } + AccessDesignTask(vecs); + + } + } + return 0; +} + +void getSch(tag_t task, bool *flag, tag_t *sch, int level) +{ + char *folder_Name, *object_type; + ITKCALL(AOM_ask_value_string(task, "object_name", &folder_Name)); + + ITKCALL(AOM_ask_value_string(task, "object_type", &object_type)); + //printf("%dobject_name:%s|object_type:%s|flag:%d \r\n",level,folder_Name,object_type,*flag); + if (*flag) + return; + tag_t *refs; + int cnt = 0, *levels; + char **relations; + ITKCALL(WSOM_where_referenced2(task, 1, &cnt, &levels, &refs, &relations)); + //printf("level:%d|cnt:%d\r\n",level,cnt); + if (cnt == 0) + return; + for (auto i = 0; i vecs) +{ + printf("vecs size:%d\r\n", vecs.size()); + if (vecs.size() % 5 != 0 || vecs.size()==0) + { + printf("IJȷ"); + return; + } + string AUFNR = vecs[0]; // + string VORNR = vecs[1]; // + string LTXA1 = vecs[2]; // + string ISDD = vecs[3]; //ʵʿʼʱ + string IEDD = vecs[4]; //ʵʱ + printf("[AUFNR=%s;VORNR=%s;LTXA1=%s;ISDD=%s;IEDD=%s]\r\n", AUFNR, VORNR, LTXA1, ISDD, IEDD); + vector isRep; + + string filesStr; + filesStr.append("\""); + for (int i = 0; i +#include "string_utils.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace Teamcenter; +using Teamcenter::Main::logger; + +int chint_MES_notice(EPM_action_message_t msg) +{ + tag_t root_task; + int t_cnt; + tag_t *t_tag; + //POM_AM__set_application_bypass(true); + //LINFO<<"ͼֽMESʼ-----"; + EPM_ask_root_task(msg.task, &root_task); + EPM_ask_attachments(root_task, EPM_target_attachment, &t_cnt, &t_tag); + char *item_id, *wl_bm; + for (auto i = 0; i < t_cnt; i++) + { + if (isNeedNotice(t_tag[i])) + continue; + AOM_ask_value_string(t_tag[i], "item_id", &item_id); + //LINFO << "̹-->" << item_id; + + int w_cnt; + tag_t *wls; + AOM_ask_value_tags(t_tag[i], "representation_for", &w_cnt, &wls); + for (auto j = 0; j < w_cnt;j++){ + char* wl_bm; + AOM_ask_value_string(wls[j], "zt2_MaterialNo", &wl_bm); + string bm = wl_bm; + if (bm.size() == 0) + continue; + printf("ϱ->%s\r\n",wl_bm); + //LINFO << "ϱ--"< + +int chint_Design_Task(EPM_action_message_t msg); +int ChintSendMessage(EPM_action_message_t msg); +int chint_set_prop(EPM_action_message_t msg); +int chintProperty(EPM_action_message_t msg); +int chintSignChange(EPM_action_message_t msg); +int chint_standard(EPM_action_message_t msg); +int chint_MES_notice(EPM_action_message_t msg); +int CHINT_BOMEC2SAP(EPM_action_message_t msg); diff --git a/WXom062/chint_MaterialTCMCheck.cpp b/WXom062/chint_MaterialTCMCheck.cpp new file mode 100644 index 0000000..58853dc --- /dev/null +++ b/WXom062/chint_MaterialTCMCheck.cpp @@ -0,0 +1,8 @@ +#include "util.h" + + + +int chint_MaterialTCMCheck() +{ + +} \ No newline at end of file diff --git a/WXom062/chint_main.cpp b/WXom062/chint_main.cpp new file mode 100644 index 0000000..12f04b1 --- /dev/null +++ b/WXom062/chint_main.cpp @@ -0,0 +1,31 @@ +#include "chint_main.h" +#include "chint_registry.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + + /** + * @fn extern "C" DLLAPI int liborigin_register_callbacks + * @return usually return ITK_ok + * @brief liborigin customization entry + */ + DLLAPI int chint_register_callbacks() + { + int ifail = ITK_ok; + ITKCALL(ifail = CUSTOM_register_exit( + "chint", + "USER_gs_shell_init_module", + (CUSTOM_EXIT_ftn_t)chint_Handler)); + //עUserserviceMethod + ITKCALL(ifail = CUSTOM_register_exit( + "chint", + "USERSERVICE_register_methods", + (CUSTOM_EXIT_ftn_t)chint_Method)); + return ifail; + } +#ifdef __cplusplus +} +#endif diff --git a/WXom062/chint_main.h b/WXom062/chint_main.h new file mode 100644 index 0000000..97e6520 --- /dev/null +++ b/WXom062/chint_main.h @@ -0,0 +1,3 @@ +#include +#include +#include diff --git a/WXom062/chint_method.cpp b/WXom062/chint_method.cpp new file mode 100644 index 0000000..7073208 --- /dev/null +++ b/WXom062/chint_method.cpp @@ -0,0 +1,165 @@ +#include "chint_method.h" +#include +#include +#include +#include +#include "tc_util.h" +#include +#define CUST_PROP_ERROR_NO 38600 +#include "util.h" + +#include +#include +using namespace std; + +int CHINT_set_bypass(void *returnValue) +{ + POM_AM__set_application_bypass(true); + return 0; +} + +int CHINT_close_bypass(void *returnValue) +{ + POM_AM__set_application_bypass(false); + return 0; +} + +int sapStateMonitor(METHOD_message_t *msg,va_list args) +{ + int ifail = ITK_ok; + tag_t pro_tag = va_arg(args,tag_t); + char *values = va_arg(args,char*); + char *sapState = NULL, + *item_id = NULL, + *userID = NULL; + + SAFECALL(AOM_ask_value_string(pro_tag, "item_id", &item_id)); + //ask_user + SAFECALL(PROP_ask_name(pro_tag,&sapState)); + char *before = NULL; + + LINFO <<"用户["<<""<< "]修改图纸[" << "" << "]SAP状态为" << sapState; + + if (sapState != NULL){ + MEM_free(sapState); + sapState = NULL; + } + if (item_id != NULL){ + MEM_free(item_id); + item_id = NULL; + } + + + return 0; +} + +void deletesub(string &str, const string &sub, int n) +{ + int m, flag = 0, num = 0; //num是子串出现的次数 + while (flag == 0) + { + m = str.find(sub); + if (m<0) + flag = 1; + else + { + str.erase(m, n); //删除子串 + num++; + } + } + // cout< vec; + vec.push_back(".dwg"); + vec.push_back(".prt"); + vec.push_back(".asm"); + string sts = ""; + int n = 0; + + if (isTypeOf(save_rev, "Dataset")) + { + AOM_ask_value_string(save_rev, "object_name", &datasetName); + cout << "object_name:" << object_name << endl; + for (auto it = vec.begin(); it != vec.end(); it++) + { + object_name = datasetName; + if (strstr(datasetName, (*it).c_str()) != NULL) + { + n = (*it).size(); + deletesub(object_name, (*it).c_str(), n); + cout << "object_name:" << object_name << endl; + AOM_lock(save_rev); + AOM_set_value_string(save_rev, "object_name", object_name.c_str()); + AOM_save(save_rev); + AOM_unlock(save_rev); + } + } + } + + + + + cout << "Dataser_saveAs_post end" << endl; + + + return ITK_ok; +} + +int Dataser_create_post(METHOD_message_t* msg, va_list args){ + tag_t save_rev = va_arg(args, tag_t); + char *datasetName, *type; + std::string object_name; + //ITKCALL(AOM_ask_value_string(save_rev, "object_type", &type)); + + vector vec; + vec.push_back(".dwg"); + vec.push_back(".prt"); + vec.push_back(".asm"); + + + int n = 0; + AOM_ask_value_string(save_rev, "object_name", &datasetName); + cout << "object_name:" << object_name << endl; + for (auto it = vec.begin(); it != vec.end(); it++) + { + object_name = datasetName; + if (strstr(datasetName, (*it).c_str()) != NULL) + { + n = (*it).size(); + deletesub(object_name, (*it).c_str(), n); + cout << "object_name:" << object_name << endl; + AOM_lock(save_rev); + AOM_set_value_string(save_rev, "object_name", object_name.c_str()); + AOM_save(save_rev); + AOM_unlock(save_rev); + } + } + + + + + + //cout << "操作:" << operation << endl; + cout << "rev_type:" << type << endl; + + + + return ITK_ok; + +} \ No newline at end of file diff --git a/WXom062/chint_method.h b/WXom062/chint_method.h new file mode 100644 index 0000000..4cd1a79 --- /dev/null +++ b/WXom062/chint_method.h @@ -0,0 +1,7 @@ +#include "tc_log.h" +#include "tc_util.h" + +int CHINT_set_bypass(void *returnValue); +int CHINT_close_bypass(void *returnValue); +int Dataser_saveAs_post(METHOD_message_t* msg, va_list args); +int Dataser_create_post(METHOD_message_t* msg, va_list args); diff --git a/WXom062/chint_registry.cpp b/WXom062/chint_registry.cpp new file mode 100644 index 0000000..8ab7fa1 --- /dev/null +++ b/WXom062/chint_registry.cpp @@ -0,0 +1,161 @@ +#include "chint_registry.h" +#include "chint_Handler.h" +#include "chint_method.h" +#include +#include +#include + + +extern DLLAPI int chint_Handler(int *decision, va_list args) +{ + int ifail = ITK_ok; + //עActionHandler1handlerƣ2handler3Ӧľĺָ + ifail = EPM_register_action_handler("chint_Design_Task", "ش", (EPM_action_handler_t)chint_Design_Task); + ifail = EPM_register_action_handler("ChintSendMessage", "PLM-AM ", (EPM_action_handler_t)ChintSendMessage); + ifail = EPM_register_action_handler("chint_set_prop", "޸Ŀ", (EPM_action_handler_t)chint_set_prop); + //ifail = EPM_register_action_handler("chintProperty", "chintProperty ", (EPM_action_handler_t)chintProperty); + //ifail = EPM_register_action_handler("chintSignChange", "chintSignChange", (EPM_action_handler_t)chintSignChange); + ifail = EPM_register_action_handler("chint_standard", "chint_standard", (EPM_action_handler_t)chint_standard); + ifail = EPM_register_action_handler("chint_MES_notice", "ͼֽ", (EPM_action_handler_t)chint_MES_notice); + ifail = EPM_register_action_handler("CHINT_BOMEC2SAP", "BOM", (EPM_action_handler_t)CHINT_BOMEC2SAP); + //ifail = EPM_register_action_handler("chintSignSCXXCDTZD", "chintSignSCXXCDTZD", (EPM_action_handler_t)chintSignSCXXCDTZD); + return 0; +} + + +extern DLLAPI int chint_Method() +{ + + int ifail = ITK_ok; + int + status = ITK_ok, + numberOfArguments = 0, + returnValueType = USERARG_STRING_TYPE, + *argumentList = NULL; + USER_function_t functionPtr; + + numberOfArguments = 1; + functionPtr = CHINT_set_bypass; + argumentList = (int*)MEM_alloc(numberOfArguments * sizeof(int)); + argumentList[0] = USERARG_STRING_TYPE; + returnValueType = USERARG_VOID_TYPE; + ITKCALL(status = USERSERVICE_register_method("CONNOR_open_bypass", functionPtr, numberOfArguments, + argumentList, returnValueType)); + MEM_free(argumentList); + printf("ע᷽\r\n"); + if (status == ITK_ok) + { + printf("ע᷽ɹCONNOR_open_bypass\r\n"); + } + else + { + printf("ע᷽ʧ[%d]CONNOR_open_bypass\r\n",status); + } + + numberOfArguments = 1; + functionPtr = CHINT_close_bypass; + argumentList = (int*)MEM_alloc(numberOfArguments * sizeof(int)); + argumentList[0] = USERARG_STRING_TYPE; + returnValueType = USERARG_VOID_TYPE; + ITKCALL(status = USERSERVICE_register_method("CONNOR_close_bypass", functionPtr, numberOfArguments, + argumentList, returnValueType)); + MEM_free(argumentList); + if (status == ITK_ok) + { + printf("ע᷽ɹCONNOR_close_bypass\n"); + } + else + { + printf("ע᷽ʧ[%d]CONNOR_close_bypass\r\n", status); + } + /* + METHOD_id_t mth_tag; + METHOD_find_method("Dataset", AE_save_dataset_msg, &mth_tag); + if (mth_tag.id != NULLTAG) + { + + + ITKCALL(ifail = METHOD_add_action(mth_tag, METHOD_post_action_type, (METHOD_function_t)Dataser_create_post, NULL)) + if (ifail == ITK_ok) + { + printf("Dataser_create_postעɹ\r\n"); + } + else + { + printf("Dataser_create_postעʧ\r\n"); + } + } + */ + int n_input_args = 1; + int input_args[1] = { USERARG_TAG_TYPE }; + + + //serverһ飨akaǩ) + int return_data = USERARG_STRING_TYPE + USERARG_ARRAY_TYPE; + USER_function_t function_ptr = DYCreateElectricalBOM; + ifail = USERSERVICE_register_method("DYCreateElectricalBOM", function_ptr, + n_input_args, input_args, return_data); + { + int numberOfArguments = 6; + argumentList = (int*)MEM_alloc(numberOfArguments * sizeof(int)); + argumentList[0] = USERARG_STRING_TYPE; + argumentList[1] = USERARG_STRING_TYPE; + argumentList[2] = USERARG_STRING_TYPE; + argumentList[3] = USERARG_TAG_TYPE + USERARG_ARRAY_TYPE; + argumentList[4] = USERARG_STRING_TYPE + USERARG_ARRAY_TYPE; + argumentList[5] = USERARG_STRING_TYPE + USERARG_ARRAY_TYPE; + return_data = USERARG_VOID_TYPE; + + function_ptr = DYCreateElectricalBOM2; + ITKCALL(ifail = USERSERVICE_register_method("DYCreateElectricalBOM2", function_ptr, + numberOfArguments, argumentList, return_data)); + MEM_free(argumentList); + if (status == ITK_ok) + { + printf("ע᷽ɹDYCreateElectricalBOM2\n"); + } + else + { + printf("ע᷽ʧ[%d]DYCreateElectricalBOM2\r\n", status); + } + + + numberOfArguments = 6; + argumentList = (int*)MEM_alloc(numberOfArguments * sizeof(int)); + argumentList[0] = USERARG_STRING_TYPE; + argumentList[1] = USERARG_STRING_TYPE; + argumentList[2] = USERARG_STRING_TYPE; + argumentList[3] = USERARG_TAG_TYPE + USERARG_ARRAY_TYPE; + argumentList[4] = USERARG_STRING_TYPE + USERARG_ARRAY_TYPE; + argumentList[5] = USERARG_STRING_TYPE + USERARG_ARRAY_TYPE; + return_data = USERARG_VOID_TYPE; + + function_ptr = DYCreateElectricalBOM3; + ITKCALL(ifail = USERSERVICE_register_method("DYCreateElectricalBOM3", function_ptr, + numberOfArguments, argumentList, return_data)); + MEM_free(argumentList); + if (status == ITK_ok) + { + printf("ע᷽ɹDYCreateElectricalBOM3\n"); + } + else + { + printf("ע᷽ʧ[%d]DYCreateElectricalBOM3\r\n", status); + } + //DOFREE(argumentList); + } + + + + + + + + + + return 0; + + +} + + diff --git a/WXom062/chint_registry.h b/WXom062/chint_registry.h new file mode 100644 index 0000000..0071a7c --- /dev/null +++ b/WXom062/chint_registry.h @@ -0,0 +1,11 @@ +#include "tc_log.h" +#include "tc_util.h" +#include + + + +int DYCreateElectricalBOM(void * return_data); +int DYCreateElectricalBOM2(void *return_data); +int DYCreateElectricalBOM3(void *return_data); +extern DLLAPI int chint_Handler(int *decision, va_list args); +extern DLLAPI int chint_Method(); diff --git a/WXom062/chint_set_prop.cpp b/WXom062/chint_set_prop.cpp new file mode 100644 index 0000000..4583543 --- /dev/null +++ b/WXom062/chint_set_prop.cpp @@ -0,0 +1,65 @@ +#include "tc_util.h" +#include "chint_Handler.h" +#include "util.h" + + +int chint_set_prop(EPM_action_message_t msg) +{ + LINFO << " chint_set_prop begin"; + tag_t root_task, *att, *ref; + TC_argument_list_t * arguments = msg.arguments; + int arg_cnt = TC_number_of_arguments(arguments); + + map val_map1; + map val_map2; + int n_cnt, n_ref; + EPM_ask_root_task(msg.task, &root_task); + EPM_ask_attachments(root_task, EPM_target_attachment, &n_cnt, &att); + //AOM_ask_value_tags(root_task,"root_reference_attachments",&n_ref,&ref); + EPM_ask_attachments(root_task, EPM_reference_attachment, &n_ref, &ref); + map > prop_map; + for (auto i = 0; i < arg_cnt; i++) + { + int index_key1; + char *temp_key, *temp_val; + SAFECALL(ITK_ask_argument_named_value(TC_next_argument(arguments), &temp_key, &temp_val)); + printf("key:%s | value:%s\r\n",temp_key,temp_val); + string temp_k(temp_key); + string temp_v(temp_val); + index_key1 = temp_k.find('.'); + if (index_key1 == -1) + continue; + string type = temp_k.substr(0,index_key1); + string prop = temp_k.substr(index_key1+1); + printf(":%s :%s ֵ:%s\r\n", type, prop, temp_v); + prop_map[type][prop] = temp_v; + + } + POM_AM__set_application_bypass(true); + for (auto i = 0; i < n_cnt; i++) + { + for (auto it = prop_map.begin(); it != prop_map.end(); it++) + { + string type = it->first; + //item_ask_type + + if (isTypeOf(att[i], type.c_str())) + { + map prop_vals = it->second; + SAFECALL(AOM_lock(att[i])); + for (auto it2 = prop_vals.begin(); it2 != prop_vals.end(); it2++) + { + SAFECALL(AOM_set_value_string(att[i], it2->first.c_str(), it2->second.c_str())); + } + SAFECALL(AOM_save(att[i])); + SAFECALL(AOM_unlock(att[i])); + break; + } + } + } + POM_AM__set_application_bypass(false); + LINFO << " chint_set_prop end"; + + return 0; +} + diff --git a/WXom062/chint_standard.cpp b/WXom062/chint_standard.cpp new file mode 100644 index 0000000..a63553e --- /dev/null +++ b/WXom062/chint_standard.cpp @@ -0,0 +1,72 @@ +#include "tc_util.h" +#include "chint_Handler.h" +#include "util.h" +#define CUST_PROP_ERROR_NO 38600 + +using namespace std; +int chint_standard(EPM_action_message_t msg) +{ + + ECHO("chint_standard start\n"); + tag_t root_task, *att = NULLTAG, *factorys = NULLTAG; + int ifail = ITK_ok; + int n_cnt,f_cnt; + EPM_ask_root_task(msg.task, &root_task); + EPM_ask_attachments(root_task, EPM_target_attachment, &n_cnt, &att); + stringstream errMess; + vector vecs; + vecs.push_back("9900000191"); + vecs.push_back("9900000192"); + vecs.push_back("9900000193"); + errMess.str(""); + char *materialNo = NULL, *object_string = NULL; + ECHO("%dĿ\n",n_cnt); + + for (auto i = 0; i < n_cnt; i++) + { + if (isTypeOf(att[i], "Part Revision")) + { + SAFECALL(AOM_ask_value_string(att[i], "zt2_MaterialNo", &materialNo)); + SAFECALL(AOM_ask_value_string(att[i], "object_string", &object_string)); + string temp = materialNo; + ECHO("%s,ϱ[%s]\n", object_string, materialNo); + for (auto j = 0; j < vecs.size(); j++) + { + if (strstr(materialNo,vecs[j].c_str()) != NULL) + { + ECHO("-------%d\n", 0); + ITKCALL(AOM_ask_value_tags(att[i], "ZT2_FactoryNumber", &f_cnt, &factorys)); + ECHO("%d\n",f_cnt); + if (f_cnt == 0) + { + if (errMess.str().length()>0) + { + errMess << "" << object_string; + } + else + { + errMess << object_string; + } + } + } + } + } + } + if (errMess.str().length() > 0) + { + errMess << "δţִз"; + int tmp = 0; + ECHO("ʾ:%s\n",errMess.str().c_str()); + ITKCALL(EMH_store_error_s1(EMH_severity_error, CUST_PROP_ERROR_NO, errMess.str().c_str())); + ifail = -1; + } + DOFREE(att); + DOFREE(factorys); + DOFREE(materialNo); + DOFREE(object_string); + + + ECHO("chint_standard end\n"); + //return CUST_PROP_ERROR_NO; + return ifail; +} \ No newline at end of file diff --git a/WXom062/common_itk_util.c b/WXom062/common_itk_util.c new file mode 100644 index 0000000..426e1b6 --- /dev/null +++ b/WXom062/common_itk_util.c @@ -0,0 +1,612 @@ +/** +* @file common_itk_util.cpp +* @brief itk warpper utility function +* @author James +* @history +* =================================================================================== +* Date Name Description of Change +* 18-July-2008 James +*/ + +#pragma warning (disable: 4996) +#pragma warning (disable: 4819) +#pragma warning(disable: 4995 ) +#pragma warning (disable: 4013) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "error_handling.h" +#include "common_itk_util.h" + +#ifdef WIN32 +#include +#include +#else +#include +#endif + + +#define ARGS_LENGTH 200 +#define ARGS_NAME_DEBUG "-debug" +#define DEBUG "-debug=" +#define MAX_PRINTLINE_LENGTH 2000 +#define MAX_PATH_LENGTH 2000 +#define MAX_ARGUMENT_LENGTH 400 +#define MAX_PARAMNAME_LENGTH 50 +#define MAX_FILE_EXT_LENGTH 10 +#define TRUE_FLAG 1 +#define FALSE_FLAG 0 +#define DETAILLOG 1 + + +void ECHO(char *format, ...) +{ + //if( !YFJC_OPT_DEBUG ) + // return; + + char msg[1024]; + va_list args; + + va_start(args, format); + vsprintf(msg, format, args); + va_end(args); + + printf(msg); + TC_write_syslog(msg); +} + +FILE* logFile = NULL; + +void set_bypass(logical bypass) +{ + //AM__set_application_bypass(bypass); + POM_AM__set_application_bypass(bypass); +} + +int ORIGIN_set_bypass(void *returnValue) +{ + POM_AM__set_application_bypass(true); + return 0; +} + +int ORIGIN_close_bypass(void *returnValue) +{ + POM_AM__set_application_bypass(false); + return 0; +} + +int GetLocalizedType(void * return_data) { + + int ifail = ITK_ok; + char *uid = NULL, *nl = NULL; + char* flag = ""; + tag_t type_tag=NULLTAG; + tag_t release_stat = NULLTAG; + char server_string[10]; + ITKCALL(ifail = USERARG_get_string_argument(&uid)); + ITKCALL(ifail = USERARG_get_string_argument(&nl)); + ECHO("ѯ %s ػ = %s \n", uid, nl); + ITKCALL(ifail = POM_string_to_tag(uid, &type_tag)); + if (type_tag != NULLTAG) { + char localization_status; + logical master; + ITKCALL(ifail = AOM_UIF_ask_localized_value_string(type_tag, "type_name", nl, &flag, &localization_status, &master)); + ECHO("ͣ%s %c\n", flag, localization_status); + if (ifail == ITK_ok&&localization_status=='A') { + strcpy(server_string, flag); + *((char **)return_data) = + (char *)MEM_alloc((strlen(server_string) + 1) * sizeof(char)); + strcpy(*((char **)return_data), server_string); + } + DOFREE(flag); + } + MEM_free(uid); + MEM_free(nl); + return ITK_ok; +} + +/*=============================================================================* + * FUNCTION: current_time + * PURPOSE : get the current datetime + * INPUT: + * date_t* date_tag // current date time tag + * + * RETURN: + * void + *============================================================================*/ +void current_time(date_t * date_tag) +{ + time_t ltime; + struct tm *today; + + // Set time zone from TZ environment variable. If TZ is not set, + // the operating system is queried to obtain the default value + // for the variable. + // + //_tzset(); + + // Get UNIX-style time and display as number and string. + time(<ime); + + today = localtime(<ime); + date_tag->year = today->tm_year + 1900; + date_tag->month = today->tm_mon; + date_tag->day = today->tm_mday; + date_tag->hour = today->tm_hour; + date_tag->minute = today->tm_min; + date_tag->second = today->tm_sec; +} +/*=============================================================================* + * FUNCTION: CreateLogFile + * PURPOSE : create log file + * INPUT: + * char* FunctionName // the funtion which need to create log file + * FILE** logFile // out: the log file pointer + * + * RETURN: + * void + *============================================================================*/ + +void initUserDir(char *userId){ + char logFileDir[MAX_PATH_LENGTH]; + memset(logFileDir, 0, sizeof(logFileDir)); + sprintf(logFileDir, "%s", getenv("TEMP")); + strcat(logFileDir, "\\tc_"); + strcat(logFileDir, userId); + if (chdir(logFileDir) != ITK_ok) { + printf(">> ½·%s\n",logFileDir); + mkdir(logFileDir); + } +} + + +//void initUserDir(char *userId,char **dir) { +// char logFileDir[MAX_PATH_LENGTH]; +// memset(logFileDir, 0, sizeof(logFileDir)); +// sprintf(logFileDir, "%s", getenv("TEMP")); +// strcat(logFileDir, "\\tc_"); +// strcat(logFileDir, userId); +// if (chdir(logFileDir) != ITK_ok) { +// printf(">> ½·%s\n", logFileDir); +// mkdir(logFileDir); +// } +// sprintf(*dir, "%s", logFileDir); +//} + +void CreateTempFileName(char*preFix,const char* FunctionName,char *ext, char *userId, char **fullname,char **fileName) +{ + int ifail = ITK_ok; + //date_t status_now; + //char* date_string = NULL; + char date_string[MAX_PATH_LENGTH]; + char logFileDir[MAX_PATH_LENGTH]; + char logFileName[MAX_PATH_LENGTH]; + //char* session_uid = NULL; + //tag_t session_tag = NULLTAG; + + time_t now; + struct tm *p; + + time(&now); + + //logFile = NULL; + //current_time(&status_now); + p = localtime(&now); + + memset(date_string, 0, sizeof(date_string)); + sprintf(date_string, "%4d%02d%02d%02d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); + //sprintf(date_string, "%4d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday); + //if( DATE_date_to_string( status_now, "%Y%m%d%H%M%S", &date_string) != ITK_ok ) + //ifail = ITK_date_to_string (status_now, &date_string ); + //if (ifail) + //{ + // printf("!*ERROR*!: Failed to get current date time\n"); + // goto CLEANUP; + //} + + memset(logFileDir, 0, sizeof(logFileDir)); + memset(logFileName, 0, sizeof(logFileName)); + //get log dir + sprintf(logFileDir, "%s", getenv("TEMP")); + strcat(logFileDir, "\\tc_"); + strcat(logFileDir, userId); + //printf("\n log file dir: %s\n", logFileDir); + //try to change dir to TC_USER_LOG_DIR + + //get session_uid to make sure the log file name unique + //POM_ask_session(&session_tag); + //ITK__convert_tag_to_uid(session_tag, &session_uid); + //get logFileName + sprintf(logFileName, "%s_%s_%s.%s", preFix,FunctionName, date_string,ext); + //printf("log file name: %s\n", logFileName); + + *fullname = (char *)MEM_alloc(sizeof(char) * 512); + sprintf(*fullname, "%s\\%s", logFileDir, logFileName); + *fileName = (char *)MEM_alloc(sizeof(char) * 512); + sprintf(*fileName, "%s", logFileName); + //for(i = 0; _access((char *)logFileName, 4) == 0; i++) + /*{ + memset(logFileName, 0, sizeof(logFileName)); + sprintf(logFileName, "%s_%s_%s_%d.log", FunctionName, session_uid, date_string, i); + } + printf("final log file name: %s\n", logFileName);*/ + + //create log file + //logFile = fopen(logFileName, "a"); + +CLEANUP:; + //DOFREE(date_string); + /*if(session_uid!=NULL){ + MEM_free(session_uid); + session_uid=NULL; + }*/ +} + +void CreateFileName(char* FunctionName, char *userId, char **fullname) +{ + int ifail = ITK_ok; + //date_t status_now; + //char* date_string = NULL; + char date_string[MAX_PATH_LENGTH]; + char logFileDir[MAX_PATH_LENGTH]; + char logFileName[MAX_PATH_LENGTH]; + //char* session_uid = NULL; + //tag_t session_tag = NULLTAG; + + time_t now; + struct tm *p; + + time(&now); + + //logFile = NULL; + //current_time(&status_now); + p = localtime(&now); + + memset(date_string, 0, sizeof(date_string)); + sprintf(date_string,"%4d%02d%02d%02d%02d%02d",1900+p->tm_year,p->tm_mon+1 ,p->tm_mday ,p->tm_hour,p->tm_min ,p->tm_sec ); + //sprintf(date_string, "%4d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday); + //if( DATE_date_to_string( status_now, "%Y%m%d%H%M%S", &date_string) != ITK_ok ) + //ifail = ITK_date_to_string (status_now, &date_string ); + //if (ifail) + //{ + // printf("!*ERROR*!: Failed to get current date time\n"); + // goto CLEANUP; + //} + + memset(logFileDir, 0, sizeof(logFileDir)); + memset(logFileName, 0, sizeof(logFileName)); + //get log dir + sprintf(logFileDir, "%s", getenv("TEMP")); + strcat(logFileDir, "\\tc_"); + strcat(logFileDir, userId); + //printf("\n log file dir: %s\n", logFileDir); + //try to change dir to TC_USER_LOG_DIR + + //get session_uid to make sure the log file name unique + //POM_ask_session(&session_tag); + //ITK__convert_tag_to_uid(session_tag, &session_uid); + //get logFileName + sprintf(logFileName, "%s_%s_%s.log", FunctionName, userId, date_string); + //printf("log file name: %s\n", logFileName); + + *fullname = (char *)MEM_alloc(sizeof(char) * 512); + sprintf(*fullname, "%s\\%s", logFileDir, logFileName); + + //for(i = 0; _access((char *)logFileName, 4) == 0; i++) + /*{ + memset(logFileName, 0, sizeof(logFileName)); + sprintf(logFileName, "%s_%s_%s_%d.log", FunctionName, session_uid, date_string, i); + } + printf("final log file name: %s\n", logFileName);*/ + + //create log file + //logFile = fopen(logFileName, "a"); + +CLEANUP:; + //DOFREE(date_string); + /*if(session_uid!=NULL){ + MEM_free(session_uid); + session_uid=NULL; + }*/ +} + +void KCreateLogFile(char* FunctionName, char *userId, char **fullname) +{ + int ifail = ITK_ok; + //date_t status_now; + //char* date_string = NULL; + char date_string[MAX_PATH_LENGTH]; + char logFileDir[MAX_PATH_LENGTH]; + char logFileName[MAX_PATH_LENGTH]; + //char* session_uid = NULL; + //tag_t session_tag = NULLTAG; + + time_t now; + struct tm *p; + + time(&now); + + logFile = NULL; + //current_time(&status_now); + p = localtime(&now); + + memset(date_string, 0, sizeof(date_string)); + //sprintf(date_string,"%4d%02d%02d%02d%02d%02d",1900+p->tm_year,p->tm_mon+1 ,p->tm_mday ,p->tm_hour,p->tm_min ,p->tm_sec ); + sprintf(date_string, "%4d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday); + //if( DATE_date_to_string( status_now, "%Y%m%d%H%M%S", &date_string) != ITK_ok ) + //ifail = ITK_date_to_string (status_now, &date_string ); + //if (ifail) + //{ + // printf("!*ERROR*!: Failed to get current date time\n"); + // goto CLEANUP; + //} + + memset(logFileDir, 0, sizeof(logFileDir)); + memset(logFileName, 0, sizeof(logFileName)); + //get log dir + sprintf(logFileDir, "%s", getenv("TEMP")); + strcat(logFileDir, "\\tc_"); + strcat(logFileDir, userId); + //printf("\n log file dir: %s\n", logFileDir); + //try to change dir to TC_USER_LOG_DIR + if (chdir(logFileDir) != ITK_ok) + { + //not set TC_USER_LOG_DIR + //log in to default TC_LOG + memset(logFileDir, 0, sizeof(logFileDir)); + sprintf(logFileDir, "%s", getenv("TC_LOG")); + printf("\n TC_USER_LOG_DIR invalide, log file dir: %s\n", logFileDir); + if (chdir(logFileDir) != ITK_ok) + { + //still can not change to log dir + printf("!*ERROR*!: Failed to change dir to TC_USER_LOG_DIR\n"); + goto CLEANUP; + } + } + + //get session_uid to make sure the log file name unique + //POM_ask_session(&session_tag); + //ITK__convert_tag_to_uid(session_tag, &session_uid); + //get logFileName + sprintf(logFileName, "%s_%s_%s.log", FunctionName, userId, date_string); + //printf("log file name: %s\n", logFileName); + + *fullname = (char *)MEM_alloc(sizeof(char) * 512); + sprintf(*fullname, "%s\\%s", logFileDir, logFileName); + + //for(i = 0; _access((char *)logFileName, 4) == 0; i++) + /*{ + memset(logFileName, 0, sizeof(logFileName)); + sprintf(logFileName, "%s_%s_%s_%d.log", FunctionName, session_uid, date_string, i); + } + printf("final log file name: %s\n", logFileName);*/ + + //create log file + logFile = fopen(logFileName, "a"); + +CLEANUP:; + //DOFREE(date_string); + /*if(session_uid!=NULL){ + MEM_free(session_uid); + session_uid=NULL; + }*/ +} + +int CreateUserFile(logical debug,char* FunctionName, char *userId, char **fullname,FILE **file) +{ + int ifail = ITK_ok; + //date_t status_now; + //char* date_string = NULL; + char date_string[MAX_PATH_LENGTH]; + char logFileDir[MAX_PATH_LENGTH]; + char logFileName[MAX_PATH_LENGTH]; + //char* session_uid = NULL; + //tag_t session_tag = NULLTAG; + + time_t now; + struct tm *p; + + time(&now); + + //logFile = NULL; + //current_time(&status_now); + p = localtime(&now); + + memset(date_string, 0, sizeof(date_string)); + sprintf(date_string,"%4d%02d%02d%02d%02d%02d",1900+p->tm_year,p->tm_mon+1 ,p->tm_mday ,p->tm_hour,p->tm_min ,p->tm_sec ); + //sprintf(date_string, "%4d%02d%02d", 1900 + p->tm_year, p->tm_mon + 1, p->tm_mday); + //if( DATE_date_to_string( status_now, "%Y%m%d%H%M%S", &date_string) != ITK_ok ) + //ifail = ITK_date_to_string (status_now, &date_string ); + //if (ifail) + //{ + // printf("!*ERROR*!: Failed to get current date time\n"); + // goto CLEANUP; + //} + + memset(logFileDir, 0, sizeof(logFileDir)); + memset(logFileName, 0, sizeof(logFileName)); + //get log dir + sprintf(logFileDir, "%s", getenv("TEMP")); + strcat(logFileDir, "\\tc_"); + strcat(logFileDir, userId); + //printf("\n log file dir: %s\n", logFileDir); + //try to change dir to TC_USER_LOG_DIR + if (chdir(logFileDir) != ITK_ok) + { + //not set TC_USER_LOG_DIR + //log in to default TC_LOG + memset(logFileDir, 0, sizeof(logFileDir)); + sprintf(logFileDir, "%s", getenv("TC_LOG")); + KWriteLog(debug, "TC_USER_LOG_DIR invalide, log file dir: %s",logFileDir); + //printf("\n TC_USER_LOG_DIR invalide, log file dir: %s\n", logFileDir); + if (chdir(logFileDir) != ITK_ok) + { + //still can not change to log dir + KWriteLog(debug, "!*ERROR*!: Failed to change dir to TC_USER_LOG_DIR"); + //printf("!*ERROR*!: Failed to change dir to TC_USER_LOG_DIR\n"); + return -1; + } + } + + //get session_uid to make sure the log file name unique + //POM_ask_session(&session_tag); + //ITK__convert_tag_to_uid(session_tag, &session_uid); + //get logFileName + sprintf(logFileName, "%s_%s_%s.txt", FunctionName, userId, date_string); + //printf("log file name: %s\n", logFileName); + + *fullname = (char *)MEM_alloc(sizeof(char) * 512); + sprintf(*fullname, "%s\\%s", logFileDir, logFileName); + + //for(i = 0; _access((char *)logFileName, 4) == 0; i++) + /*{ + memset(logFileName, 0, sizeof(logFileName)); + sprintf(logFileName, "%s_%s_%s_%d.log", FunctionName, session_uid, date_string, i); + } + printf("final log file name: %s\n", logFileName);*/ + + //create log file + *file = fopen(logFileName, "a"); + return ITK_ok; +//CLEANUP:; + //DOFREE(date_string); + /*if(session_uid!=NULL){ + MEM_free(session_uid); + session_uid=NULL; + }*/ +} + + + +/*=============================================================================* + * FUNCTION: KWriteLog + * PURPOSE : write log, if debug log File not null, write log message to log File + * INPUT: + * const char* format // debug message string + * + * RETURN: + * void + *============================================================================*/ +#define MAX_LOG_LENGTH 8000 +void KWriteLog(logical debug, const char* format, ...) +{ + va_list arg; + char tmp[MAX_LOG_LENGTH]; + char date_string[MAX_LOG_LENGTH]; + time_t now; + struct tm *p; + //get the message + memset(tmp, 0, sizeof(tmp)); + va_start(arg, format); + vsprintf(tmp, format, arg); + va_end(arg); + //printf("%s\n", tmp); + printf("%s\n", tmp); + //print message to log file + if (!debug) { + return; + } + if (logFile) + { + time(&now); + //current_time(&status_now); + p = localtime(&now); + memset(date_string, 0, sizeof(date_string)); + sprintf(date_string, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); + fprintf(logFile, "[%s] %s\n", date_string, tmp); + fflush(logFile); + } + else + { + ECHO("*!Error!*: Log File Not Exist\n"); + } +} + +int WriteToFile(logical debug,FILE* file, const char* format, ...) +{ + va_list arg; + char tmp[MAX_PRINTLINE_LENGTH]; + + //get the message + memset(tmp, 0, sizeof(tmp)); + va_start(arg, format); + vsprintf(tmp, format, arg); + va_end(arg); + //print message to log file + KWriteLog(debug, "дݣ%s", tmp); + if (file) + { + fprintf(file, "%s", tmp); + fflush(file); + return ITK_ok; + } + else + { + KWriteLog(debug,"дļʧܣļ"); + return -1; + } +} + + +void KWriteLog1(const char* txt) +{ + char date_string[MAX_PATH_LENGTH]; + time_t now; + struct tm *p; + time(&now); + //current_time(&status_now); + p = localtime(&now); + memset(date_string, 0, sizeof(date_string)); + sprintf(date_string, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); + + if (logFile) + { + printf("%s\n", txt); + //print message to log file + fprintf(logFile, "[%s] %s\n", date_string, txt); + fflush(logFile); + } + else + { + printf("*!Error!*: Log File Not Exist\n"); + } +} + +void KCloseLog(void) +{ + if (logFile) + { + fclose(logFile); + logFile = NULL; + } +} diff --git a/WXom062/common_itk_util.h b/WXom062/common_itk_util.h new file mode 100644 index 0000000..6a433db --- /dev/null +++ b/WXom062/common_itk_util.h @@ -0,0 +1,36 @@ +#ifndef COMMON_ITK_UTIL +#define COMMON_ITK_UTIL + +#ifdef __cplusplus +extern "C" { +#endif + +#define DOFREE(obj) \ +{ \ + if(obj) \ + { \ + MEM_free(obj); \ + obj = NULL; \ + } \ +} + void ECHO(char *format, ...); + void KCreateLogFile(char* FunctionName, char *userId, char **fullname); + void CreateFileName(char* FunctionName, char *userId, char **fullname); + void CreateTempFileName(char*preFix, const char* FunctionName, char *ext, char *userId, char **fullname, char **fileName); + void KWriteLog(logical debug,const char* format, ...); + void KWriteLog1(const char* txt); + void initUserDir(char *userId); + //void initUserDir(char *userId,char **dir); + void KCloseLog(void); + void set_bypass(logical bypass); + int ORIGIN_close_bypass(void *returnValue); + int ORIGIN_set_bypass(void *returnValue); + int GetLocalizedType(void * return_data); + int WriteToFile(logical debug, FILE* file, const char* format, ...); + int CreateUserFile(logical debug, char* FunctionName, char *userId, char **fullname, FILE **file); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/WXom062/easylogging++.h b/WXom062/easylogging++.h new file mode 100644 index 0000000..31f0454 --- /dev/null +++ b/WXom062/easylogging++.h @@ -0,0 +1,4002 @@ +/////////////////////////////////////////////////////////////////////////////////// +// // +// easylogging++.h - Core of EasyLogging++ // +// // +// EasyLogging++ v8.91 // +// Cross platform logging made easy for C++ applications // +// Author Majid Khan // +// http://www.icplusplus.com/tools/easylogging // +// https://github.com/mkhan3189/EasyLoggingPP // +// // +// Copyright (c) 2012-2013 Majid Khan // +// // +// 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 // +// // +// PLEASE NOTE: THIS FILE MAY BE CHANGED. TO GET ORIGINAL VERSION // +// EITHER DOWNLOAD IT FROM http://www.icplusplus.com/tools/easylogging/ // +// OR PULL IT FROM https://github.com/mkhan3189/EasyLoggingPP (master branch) // +// // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef EASYLOGGINGPP_H +#define EASYLOGGINGPP_H +#include +#include +// +// Log location macros +// +#if !defined(__FILE__) +# define __FILE__ "" +#endif // !defined(__FILE__) +#if !defined(__LINE__) +# define __LINE__ 0 +#endif // !defined(__LINE__) +// Appropriate function macro +#if defined(__func__) +# undef __func__ +#endif // defined(__func__) +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# define __func__ __FUNCSIG__ +#elif defined(__GNUC__) && (__GNUC__ >= 2) +# define __func__ __PRETTY_FUNCTION__ +#elif defined(__clang__) && (__clang__ == 1) +# define __func__ __PRETTY_FUNCTION__ +#else +# define __func__ "" +#endif // defined(_MSC_VER) && (_MSC_VER >= 1020) +// +// Compiler evaluation +// http://isocpp.org/blog/2013/05/gcc-4.8.1-released-c11-feature-complete +// http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx +// +// GNU +#if defined(__GNUC__) +# define _ELPP_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define _ELPP_CXX0X 1 +# elif (_ELPP_GCC_VERSION >= 40801) +# define _ELPP_CXX11 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +#endif // defined(__GNUC__) +// VC++ +#if defined(_MSC_VER) +# if (_MSC_VER >= 1400) // VC++ 8.0 +# define _ELPP_CRT_DBG_WARNINGS 1 +# else +# define _ELPP_CRT_DBG_WARNINGS 0 +# endif // (_MSC_VER >= 1400) +# if (_MSC_VER == 1600) +# define _ELPP_CXX0X 1 +# elif (_MSC_VER == 1700) +# define _ELPP_CXX11 1 +# endif // (_MSC_VER == 1600) +#else +# define _ELPP_CRT_DBG_WARNINGS 0 +#endif // defined(_MSC_VER) +// Clang +#if defined(__clang__) && (__clang__ == 1) +# define _ELPP_CLANG_VERSION (__clang_major__ * 10000 \ + + __clang_minor__ * 100 \ + + __clang_patchlevel__) +# if (_ELPP_CLANG_VERSION >= 30300) +# define _ELPP_CXX11 1 +# endif // (_ELPP_CLANG_VERSION >= 30300) +#endif // defined(__clang__) && (__clang__ == 1) +// MinGW +#if defined(__MINGW32__) || defined(__MINGW64__) +# define _ELPP_MINGW 1 +#else +# define _ELPP_MINGW 0 +#endif // defined(__MINGW32__) || defined(__MINGW64__) +#if defined(__ANDROID__) +# define _ELPP_NDK 1 +#else +# define _ELPP_NDK 0 +#endif // defined(__ANDROID__) +// Some special functions that are special for VC++ +// This is to prevent CRT security warnings and to override deprecated methods but at the same time +// MinGW does not support some functions, so we need to make sure that proper function is used. +#if _ELPP_CRT_DBG_WARNINGS +# define SPRINTF sprintf_s +# define STRTOK(a,b,c) strtok_s(a,b,c) +#else +# define SPRINTF sprintf +# define STRTOK(a,b,c) strtok(a,b) +#endif +// std::thread availablity +#if defined(__GNUC__) && (!_ELPP_NDK) && (_ELPP_CXX0X || _ELPP_CXX11) +# define _ELPP_STD_THREAD_AVAILABLE 1 +#elif defined(_MSC_VER) && (!_ELPP_NDK) && (_ELPP_CXX11) +# define _ELPP_STD_THREAD_AVAILABLE 1 +#elif defined(__clang__) && (!_ELPP_NDK) && (__clang__ == 1) && (_ELPP_CXX11) +# define _ELPP_STD_THREAD_AVAILABLE 1 +#else +# define _ELPP_STD_THREAD_AVAILABLE 0 +#endif // defined(__GNUC__) && (_ELPP_CXX0X || _ELPP_CXX11) +// Qt +#if defined(QT_CORE_LIB) +# if (defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +# define _ELPP_QT_5 1 +# else +# define _ELPP_QT_5 0 +# endif // (defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#endif // defined(QT_CORE_LIB) +// +// High-level log evaluation +// +#if (defined(_DISABLE_LOGS)) +# define _ENABLE_EASYLOGGING 0 +#else +# define _ENABLE_EASYLOGGING 1 +#endif // (!defined(_DISABLE_LOGS)) +// +// OS evaluation +// +// Windows +#if defined(_WIN32) || defined(_WIN64) +# define _ELPP_OS_WINDOWS 1 +#else +# define _ELPP_OS_WINDOWS 0 +#endif // defined(_WIN32) || defined(_WIN64) +// Linux +#if (defined(__linux) || defined(__linux__)) +# define _ELPP_OS_LINUX 1 +#else +# define _ELPP_OS_LINUX 0 +#endif // (defined(__linux) || defined(__linux__)) +// Mac +#if defined(__APPLE__) +# define _ELPP_OS_MAC 1 +#else +# define _ELPP_OS_MAC 0 +#endif // defined(__APPLE__) +// Unix +#define _ELPP_OS_UNIX ((_ELPP_OS_LINUX || _ELPP_OS_MAC) && (!_ELPP_OS_WINDOWS)) +// Assembly +#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \ + (defined(_MSC_VER) && (defined(_M_IX86))) +# define _ELPP_ASSEMBLY_SUPPORTED 1 +#else +# define _ELPP_ASSEMBLY_SUPPORTED 0 +#endif +#if (!defined(_DISABLE_ELPP_ASSERT)) +# if (defined(_STOP_ON_FIRST_ELPP_ASSERTION)) +# define __EASYLOGGINGPP_ASSERT(expr, msg) if (!(expr)) { std::cerr << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] with message \"" << msg << "\"" << std::endl; exit(1); } +# else +# define __EASYLOGGINGPP_ASSERT(expr, msg) if (!(expr)) { std::cerr << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] with message \"" << msg << "\"" << std::endl; } +# endif // (defined(_STOP_ON_FIRST_ELPP_ASSERTION)) +#else +# define __EASYLOGGINGPP_ASSERT(x, y) +#endif // (!defined(_DISABLE_ELPP_ASSERT)) +#define __EASYLOGGINGPP_SUPPRESS_UNSED(x) (void)x; +#if _ELPP_OS_UNIX +// Log file permissions for unix-based systems +# define _LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH +#endif // _ELPP_OS_UNIX +#if (!defined(_DISABLE_MUTEX) && (_ENABLE_EASYLOGGING)) +# define _ELPP_ENABLE_MUTEX 1 +#else +# define _ELPP_ENABLE_MUTEX 0 +#endif // (!defined(_DISABLE_MUTEX) && (_ENABLE_EASYLOGGING)) +#if (!defined(_DISABLE_DEBUG_LOGS) && (_ENABLE_EASYLOGGING) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) +# define _ELPP_DEBUG_LOG 1 +#else +# define _ELPP_DEBUG_LOG 0 +#endif // (!defined(_DISABLE_DEBUG_LOGS) && (_ENABLE_EASYLOGGING) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) +#if (!defined(_DISABLE_INFO_LOGS) && (_ENABLE_EASYLOGGING)) +# define _ELPP_INFO_LOG 1 +#else +# define _ELPP_INFO_LOG 0 +#endif // (!defined(_DISABLE_INFO_LOGS) && (_ENABLE_EASYLOGGING)) +#if (!defined(_DISABLE_WARNING_LOGS) && (_ENABLE_EASYLOGGING)) +# define _ELPP_WARNING_LOG 1 +#else +# define _ELPP_WARNING_LOG 0 +#endif // (!defined(_DISABLE_WARNING_LOGS) && (_ENABLE_EASYLOGGING)) +#if (!defined(_DISABLE_ERROR_LOGS) && (_ENABLE_EASYLOGGING)) +# define _ELPP_ERROR_LOG 1 +#else +# define _ELPP_ERROR_LOG 0 +#endif // (!defined(_DISABLE_ERROR_LOGS) && (_ENABLE_EASYLOGGING)) +#if (!defined(_DISABLE_FATAL_LOGS) && (_ENABLE_EASYLOGGING)) +# define _ELPP_FATAL_LOG 1 +#else +# define _ELPP_FATAL_LOG 0 +#endif // (!defined(_DISABLE_FATAL_LOGS) && (_ENABLE_EASYLOGGING)) +#if (defined(_QUALITY_ASSURANCE) && (_ENABLE_EASYLOGGING)) +# define _ELPP_QA_LOG 1 +#else +# define _ELPP_QA_LOG 0 +#endif // (defined(_QUALITY_ASSURANCE) && (_ENABLE_EASYLOGGING)) +#if (!defined(_DISABLE_TRACE_LOGS) && (_ENABLE_EASYLOGGING)) +# define _ELPP_TRACE_LOG 1 +#else +# define _ELPP_TRACE_LOG 0 +#endif // (!defined(_DISABLE_TRACE_LOGS) && (_ENABLE_EASYLOGGING)) +#if (!defined(_DISABLE_VERBOSE_LOGS) && (_ENABLE_EASYLOGGING)) +# define _ELPP_VERBOSE_LOG 1 +#else +# define _ELPP_VERBOSE_LOG 0 +#endif // (!defined(_DISABLE_VERBOSE_LOGS) && (_ENABLE_EASYLOGGING)) +#define ELPP_FOR_EACH(variableName, initialValue, operation, limit) unsigned int variableName = initialValue; \ + do { \ + operation \ + variableName = variableName << 1; \ + if (variableName == 0) { ++variableName; } \ + } while (variableName <= limit) +#define ELPP_FOR_EACH_LEVEL(variableName, initialValue, operation) \ + ELPP_FOR_EACH(variableName, initialValue, operation, easyloggingpp::Level::kMaxValid) +#define ELPP_FOR_EACH_CONFIGURATION(variableName, initialValue, operation) \ + ELPP_FOR_EACH(variableName, initialValue, operation, easyloggingpp::ConfigurationType::kMaxValid) +// Includes +#include +#include +#include +#include +#include +#if _ELPP_NDK +# include +#endif // _ELPP_NDK +#if _ELPP_OS_UNIX +# include +# include +# if (_ELPP_ENABLE_MUTEX) +# if (_ELPP_ASSEMBLY_SUPPORTED) +# include +# else +# include +# endif // (_ELPP_ASSEMBLY_SUPPORTED) +# endif // (_ELPP_ENABLE_MUTEX) +#elif _ELPP_OS_WINDOWS +# include +# include +#endif // _ELPP_OS_UNIX +#include +#include +#include +#include +#include +#include +#include +#include +#if (_ELPP_STD_THREAD_AVAILABLE) +# include +#endif // _ELPP_STD_THREAD_AVAILABLE +#if defined(_ELPP_STL_LOGGING) +// For logging STL based templates +# include +# include +# include +# include +# include +# include +# include +#endif // defined(_ELPP_STL_LOGGING) +#if defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) +// For logging Qt based classes & templates +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) +namespace easyloggingpp { +namespace internal { + +class NoCopy { +protected: + NoCopy(void) {} +private: + NoCopy(const NoCopy&); + NoCopy& operator=(const NoCopy&); +}; + +class StaticClass { +private: + StaticClass(void); + StaticClass(const StaticClass&); + StaticClass& operator=(const StaticClass&); +}; +} // namespace internal + +struct Level : private internal::StaticClass { +public: + enum { + All = 0, Debug = 1, Info = 2, Warning = 4, Error = 8, + Fatal = 16, Verbose = 32, QA = 64, Trace = 128, Unknown = 1010 + }; + + static const unsigned int kMinValid = All; + static const unsigned int kMaxValid = Trace; + + static std::string convertToString(unsigned int level_) { + switch (level_) { + case All: + return std::string("ALL"); + case Debug: + return std::string("DEBUG"); + case Info: + return std::string("INFO"); + case Warning: + return std::string("WARNING"); + case Error: + return std::string("ERROR"); + case Fatal: + return std::string("FATAL"); + case QA: + return std::string("QA"); + case Verbose: + return std::string("VERBOSE"); + case Trace: + return std::string("TRACE"); + default: + return std::string("UNKNOWN"); + } + } + + static unsigned int convertFromString(const std::string& levelStr) { + if (levelStr == "all" || levelStr == "ALL") return Level::All; + if (levelStr == "debug" || levelStr == "DEBUG") return Level::Debug; + if (levelStr == "info" || levelStr == "INFO") return Level::Info; + if (levelStr == "warning" || levelStr == "WARNING") return Level::Warning; + if (levelStr == "error" || levelStr == "ERROR") return Level::Error; + if (levelStr == "fatal" || levelStr == "FATAL") return Level::Fatal; + if (levelStr == "qa" || levelStr == "QA") return Level::QA; + if (levelStr == "verbose" || levelStr == "VERBOSE") return Level::Verbose; + if (levelStr == "trace" || levelStr == "TRACE") return Level::Trace; + return Level::Unknown; + } +}; + +struct ConfigurationType : private internal::StaticClass { +public: + enum { + Enabled = 0, ToFile = 1, ToStandardOutput = 2, Format = 4, Filename = 8, + MillisecondsWidth = 16, PerformanceTracking = 32, RollOutSize = 64, Unknown = 1010 + }; + + static const unsigned int kMinValid = Enabled; + static const unsigned int kMaxValid = RollOutSize; + + static std::string convertToString(unsigned int configurationType_) { + switch (configurationType_) { + case Enabled: + return std::string("ENABLED"); + case Filename: + return std::string("FILENAME"); + case Format: + return std::string("FORMAT"); + case ToFile: + return std::string("TO_FILE"); + case ToStandardOutput: + return std::string("TO_STANDARD_OUTPUT"); + case MillisecondsWidth: + return std::string("MILLISECONDS_WIDTH"); + case PerformanceTracking: + return std::string("PERFORMANCE_TRACKING"); + case RollOutSize: + return std::string("ROLL_OUT_SIZE"); + default: return std::string("UNKNOWN"); + } + } + + static unsigned int convertFromString(const std::string& configStr) { + if (configStr == "enabled" || configStr == "ENABLED") return ConfigurationType::Enabled; + if (configStr == "to_file" || configStr == "TO_FILE") return ConfigurationType::ToFile; + if (configStr == "to_standard_output" || configStr == "TO_STANDARD_OUTPUT") return ConfigurationType::ToStandardOutput; + if (configStr == "format" || configStr == "FORMAT") return ConfigurationType::Format; + if (configStr == "filename" || configStr == "FILENAME") return ConfigurationType::Filename; + if (configStr == "milliseconds_width" || configStr == "MILLISECONDS_WIDTH") return ConfigurationType::MillisecondsWidth; + if (configStr == "performance_tracking" || configStr == "PERFORMANCE_TRACKING") return ConfigurationType::PerformanceTracking; + if (configStr == "roll_out_size" || configStr == "ROLL_OUT_SIZE") return ConfigurationType::RollOutSize; + return ConfigurationType::Unknown; + } +}; + +namespace internal { +struct Aspect : private internal::StaticClass { +public: + enum { + Normal = 0, Conditional = 1, Interval = 2 + }; +}; + +//! +//! Used internally. You should not need this class. +//! +class Constants : private internal::NoCopy { +public: + Constants (void) : + // + // Log level name outputs + // + LOG_INFO_LEVEL_VALUE ("INFO") , + LOG_DEBUG_LEVEL_VALUE ("DEBUG"), + LOG_WARNING_LEVEL_VALUE("WARN"), + LOG_ERROR_LEVEL_VALUE ("ERROR"), + LOG_FATAL_LEVEL_VALUE ("FATAL"), + LOG_VERBOSE_LEVEL_VALUE("VER"), + LOG_QA_LEVEL_VALUE ("QA"), + LOG_TRACE_LEVEL_VALUE ("TRACE"), + // + // Format specifiers + // + APP_NAME_FORMAT_SPECIFIER ("%app"), + LOGGER_ID_FORMAT_SPECIFIER ("%logger"), + THREAD_ID_FORMAT_SPECIFIER ("%thread"), + LEVEL_FORMAT_SPECIFIER ("%level"), + DATE_ONLY_FORMAT_SPECIFIER ("%date"), + TIME_ONLY_FORMAT_SPECIFIER ("%time"), + DATE_TIME_FORMAT_SPECIFIER ("%datetime"), + LOCATION_FORMAT_SPECIFIER ("%loc"), + FUNCTION_FORMAT_SPECIFIER ("%func"), + USER_FORMAT_SPECIFIER ("%user"), + HOST_FORMAT_SPECIFIER ("%host"), + LOG_MESSAGE_FORMAT_SPECIFIER ("%log"), + VERBOSE_LEVEL_FORMAT_SPECIFIER ("%vlevel"), + // + // Others + // + NULL_POINTER ("nullptr"), + FORMAT_SPECIFIER_ESCAPE_CHAR ('E'), + MAX_LOG_PER_CONTAINER (100), + MAX_LOG_PER_COUNTER (100000), + DEFAULT_MILLISECOND_OFFSET (1000), + MAX_VERBOSE_LEVEL (9), + CURRENT_VERBOSE_LEVEL (0), // Set dynamically from registeredLoggers +#if _ELPP_OS_UNIX + PATH_SLASH ("/"), +#elif _ELPP_OS_WINDOWS + PATH_SLASH ("\\"), +#endif // _ELPP_OS_UNIX, + DEFAULT_LOG_FILENAME ("myeasylog.log") + { + // Trivial logger configuration - only to set format (difference: not using %logger) + //C:/logs/unv8TestLogs.log\n + //C:/logs/CCtest.log\n + std::stringstream ss; + ss << " * ALL:\n"; + ss << " FORMAT = %datetime %level %log\n"; + ss << " FILENAME = C:/log/CCtest.log\n"; + ss << " ENABLED = true\n"; + ss << " TO_FILE = true\n"; + ss << " TO_STANDARD_OUTPUT = false\n"; + ss << " MILLISECONDS_WIDTH = 3\n"; + ss << " PERFORMANCE_TRACKING = false\n"; + ss << " ROLL_OUT_SIZE = 2097152\n"; + + DEFAULT_LOGGER_CONFIGURATION = ss.str(); + } // C'tor + // + // Log level name outputs + // + const std::string LOG_INFO_LEVEL_VALUE; + const std::string LOG_DEBUG_LEVEL_VALUE; + const std::string LOG_WARNING_LEVEL_VALUE; + const std::string LOG_ERROR_LEVEL_VALUE; + const std::string LOG_FATAL_LEVEL_VALUE; + const std::string LOG_VERBOSE_LEVEL_VALUE; + const std::string LOG_QA_LEVEL_VALUE; + const std::string LOG_TRACE_LEVEL_VALUE; + // + // Format specifiers + // + const std::string APP_NAME_FORMAT_SPECIFIER; + const std::string LOGGER_ID_FORMAT_SPECIFIER; + const std::string THREAD_ID_FORMAT_SPECIFIER; + const std::string LEVEL_FORMAT_SPECIFIER; + const std::string DATE_ONLY_FORMAT_SPECIFIER; + const std::string TIME_ONLY_FORMAT_SPECIFIER; + const std::string DATE_TIME_FORMAT_SPECIFIER; + const std::string LOCATION_FORMAT_SPECIFIER; + const std::string FUNCTION_FORMAT_SPECIFIER; + const std::string USER_FORMAT_SPECIFIER; + const std::string HOST_FORMAT_SPECIFIER; + const std::string LOG_MESSAGE_FORMAT_SPECIFIER; + const std::string VERBOSE_LEVEL_FORMAT_SPECIFIER; + // + // Others + // + const std::string NULL_POINTER; + const char FORMAT_SPECIFIER_ESCAPE_CHAR; + const unsigned int MAX_LOG_PER_CONTAINER; + const unsigned int MAX_LOG_PER_COUNTER; + const unsigned int DEFAULT_MILLISECOND_OFFSET; + const int MAX_VERBOSE_LEVEL; + int CURRENT_VERBOSE_LEVEL; + const std::string PATH_SLASH; + const std::string DEFAULT_LOG_FILENAME; + std::string DEFAULT_LOGGER_CONFIGURATION; + + enum kFormatFlags { + kDateOnly = 2, + kTimeOnly = 4, + kDateTime = 8, + kLoggerId = 16, + kLocation = 32, + kFunction = 64, + kUser = 128, + kHost = 256, + kLogMessage = 512, + kVerboseLevel = 1024, + kAppName = 2048, + kThreadId = 4096 + }; +}; // class Constants +namespace threading { + +//! +//! To take care of shared resources in multi-threaded application. Used internally, you should not need it. +//! +class Mutex { +public: +#if _ELPP_ASSEMBLY_SUPPORTED +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# define _ELPP_MUTEX_LOCK_GNU_ASM(lf_, old_) "movl $1,%%eax\n" \ + "\txchg %%eax,%0\n" \ + "\tmovl %%eax,%1\n" \ + "\t" : "=m" (lf_), "=m" (old_) : : "%eax", "memory" +# define _ELPP_MUTEX_UNLOCK_GNU_ASM(lf_) "movl $0,%%eax\n" \ + "\txchg %%eax,%0\n" \ + "\t" : "=m" (lf_) : : "%eax", "memory" +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + Mutex(void) : lockerFlag_(0) { + } +#else + Mutex(void) { +# if _ELPP_OS_UNIX + pthread_mutex_init(&underlyingMutex_, NULL); +# elif _ELPP_OS_WINDOWS + InitializeCriticalSection(&underlyingMutex_); +# endif // _ELPP_OS_UNIX + } + + virtual ~Mutex(void) { +# if _ELPP_OS_UNIX + pthread_mutex_destroy(&underlyingMutex_); +# elif _ELPP_OS_WINDOWS + DeleteCriticalSection(&underlyingMutex_); +# endif // _ELPP_OS_UNIX + } +#endif // _ELPP_ASSEMBLY_SUPPORTED + + inline void lock(void) { +#if _ELPP_ASSEMBLY_SUPPORTED + bool locked = false; + while (!locked) { + locked = tryLock(); + if (!locked) { +# if _ELPP_OS_UNIX + sched_yield(); +# elif _ELPP_OS_WINDOWS + Sleep(0); +# endif + } + } +#else +# if _ELPP_OS_UNIX + pthread_mutex_lock(&underlyingMutex_); +# elif _ELPP_OS_WINDOWS + EnterCriticalSection(&underlyingMutex_); +# endif // _ELPP_OS_UNIX +#endif // _ELPP_ASSEMBLY_SUPPORTED + } + + inline bool tryLock(void) { +#if _ELPP_ASSEMBLY_SUPPORTED + int oldLock_; +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + asm volatile (_ELPP_MUTEX_LOCK_GNU_ASM(lockerFlag_, oldLock_)); +# elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + int *ptrLock = &lockerFlag_; + __asm { + mov eax,1 + mov ecx,ptrLock + xchg eax,[ecx] + mov oldLock_,eax + } +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + return (oldLock_ == 0); +#else +# if _ELPP_OS_UNIX + return (pthread_mutex_trylock(&underlyingMutex_) == 0) ? true : false; +# elif _ELPP_OS_WINDOWS + return TryEnterCriticalSection(&underlyingMutex_) ? true : false; +# endif // _ELPP_OS_UNIX +#endif // _ELPP_ASSEMBLY_SUPPORTED + } + + inline void unlock(void) { +#if _ELPP_ASSEMBLY_SUPPORTED +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + asm volatile (_ELPP_MUTEX_UNLOCK_GNU_ASM(lockerFlag_)); +# elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + int *ptrLock = &lockerFlag_; + __asm { + mov eax,0 + mov ecx,ptrLock + xchg eax,[ecx] + } +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#else +# if _ELPP_OS_UNIX + pthread_mutex_unlock(&underlyingMutex_); +# elif _ELPP_OS_WINDOWS + LeaveCriticalSection(&underlyingMutex_); +# endif // _ELPP_OS_UNIX +#endif // _ELPP_ASSEMBLY_SUPPORTED + } +private: +#if _ELPP_ASSEMBLY_SUPPORTED + int lockerFlag_; +#else +# if _ELPP_OS_UNIX + pthread_mutex_t underlyingMutex_; +# elif _ELPP_OS_WINDOWS + CRITICAL_SECTION underlyingMutex_; +# endif // _ELPP_OS_UNIX +#endif // _ELPP_ASSEMBLY_SUPPORTED +}; // class Mutex +//! +//! Scoped mutex that works same as C++11 std::lock_guard. Used internally, you should not use it. +//! +class ScopedLock : private internal::NoCopy { +public: + explicit ScopedLock(Mutex& m_) { + mutex_ = &m_; + mutex_->lock(); + } + + virtual ~ScopedLock(void) { + mutex_->unlock(); + } +private: + Mutex* mutex_; + ScopedLock(void); +}; // class ScopedLock + +//! +//! \return ID of current thread. If std::thread is available it uses get_id() otherwise if on windows it uses +//! GetCurrentThreadId() otherwise empty string. Used internally, you should not use it. +//! +inline std::string getCurrentThreadId(void) { + std::stringstream ss; +#if (_ELPP_STD_THREAD_AVAILABLE) + ss << std::this_thread::get_id(); +#else +# if (_ELPP_OS_WINDOWS) + ss << GetCurrentThreadId(); +# endif // (_ELPP_OS_WINDOWS) +#endif + return ss.str(); +} + +} // namespace threading +namespace utilities { + +template +inline void safeDelete(T*& pointer, bool checkNullity = true) { + if (checkNullity && pointer == NULL) return; + delete pointer; + pointer = NULL; +} + +//! +//! String utilities class used internally. You should not use it. +//! +class StringUtils : private internal::StaticClass { +public: + static inline std::string trim(const std::string &str) { + std::size_t s = str.find_first_not_of(" \n\r\t"); + std::size_t e = str.find_last_not_of(" \n\r\t"); + if ((s == std::string::npos) || (e == std::string::npos)) { + return ""; + } + else { + return str.substr(s, e - s + 1); + } + } + + static inline bool startsWith(const std::string& str, const std::string& start) { + return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0); + } + + static inline bool endsWith(const std::string& str, const std::string& end) { + return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0); + } + + static inline std::vector& split(const std::string& s, char delim, std::vector& elems) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } + return elems; + } + + static inline std::string replaceAll(const std::string& str, const std::string& replaceWhat, const std::string& replaceWith) { + if (replaceWhat == replaceWith) + return str; + std::string result = str; + std::size_t foundAt = std::string::npos; + while ((foundAt = result.find(replaceWhat)) != std::string::npos) { + result.replace(foundAt, replaceWhat.length(), replaceWith); + } + return result; + } + + static inline std::string stripAllWhiteSpaces(const std::string& str) { + std::string result = replaceAll(str, " ", ""); + result = replaceAll(result, "\n", ""); + result = replaceAll(result, "\r", ""); + result = replaceAll(result, "\t", ""); + return result; + } + + static inline void tolower(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + } +}; + +//! +//! Operating System utilities class used internally. You should not use it. +//! +class OSUtils : private internal::StaticClass { +public: +#if _ELPP_OS_WINDOWS + static const char* getWindowsEnvironmentVariable(const char* variableName) { + const DWORD bufferLen = 50; + static char buffer[bufferLen]; + if (GetEnvironmentVariableA(variableName, buffer, bufferLen)) { + return buffer; + } + return NULL; + } +#endif // _ELPP_OS_WINDOWS +#if _ELPP_NDK + static std::string getProperty(const char* prop) { + char propVal[PROP_VALUE_MAX + 1]; + __system_property_get(prop, propVal); + return std::string(propVal); + } + + static std::string getDeviceName(void) { + std::stringstream ss; + std::string manufacturer = getProperty("ro.product.manufacturer"); + std::string model = getProperty("ro.product.model"); + if (manufacturer.empty() && model.empty()) { + return std::string(); + } + ss << manufacturer << " " << model; + return ss.str(); + } +#endif // _ELPP_NDK + // Runs command on terminal and returns the output. + // This is applicable only on linux and mac, for all other OS, an empty string is returned. + static const std::string getBashOutput(const char* command_) { + if (command_ == NULL) { + return std::string(); + } +#if _ELPP_OS_UNIX && !_ELPP_NDK + FILE* proc = NULL; + if ((proc = popen(command_, "r")) == NULL) { + std::cerr << "\nUnable to run command [" << command_ << "]" << std::endl; + return std::string(); + } + char hBuff[4096]; + if (fgets(hBuff, sizeof(hBuff), proc) != NULL) { + pclose(proc); + if (hBuff[strlen(hBuff) - 1] == '\n') { + hBuff[strlen(hBuff) - 1] = '\0'; + } + return std::string(hBuff); + } + return std::string(); +#else + return std::string(); +#endif // _ELPP_OS_UNIX + } + + static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, const char* alternativeBashCommand = NULL) { +#if _ELPP_OS_UNIX + const char* val = getenv(variableName); +#elif _ELPP_OS_WINDOWS + const char* val = getWindowsEnvironmentVariable(variableName); +#endif // _ELPP_OS_UNIX + if ((val == NULL) || ((strcmp(val, "") == 0))) { +#if _ELPP_OS_UNIX + // Try harder on unix-based systems + std::string valBash = internal::utilities::OSUtils::getBashOutput(alternativeBashCommand); + if (valBash.empty()) { + return std::string(defaultVal); + } else { + return valBash; + } +#elif _ELPP_OS_WINDOWS + return std::string(defaultVal); +#endif // _ELPP_OS_WINDOWS + } + return std::string(val); + } + + // Gets current username. + static const std::string currentUser(void) { +#if _ELPP_OS_UNIX && !_ELPP_NDK + return getEnvironmentVariable("USER", "user", "whoami"); +#elif _ELPP_OS_WINDOWS + return getEnvironmentVariable("USERNAME", "user"); +#elif _ELPP_NDK + return std::string("android"); +#else + return std::string(); +#endif // _ELPP_OS_UNIX + } + + // Gets current host name or computer name. + static const std::string currentHost(void) { +#if _ELPP_OS_UNIX && !_ELPP_NDK + return getEnvironmentVariable("HOSTNAME", "unknown-host", "hostname"); +#elif _ELPP_OS_WINDOWS + return getEnvironmentVariable("COMPUTERNAME", "unknown-host"); +#elif _ELPP_NDK + return getDeviceName(); +#else + return std::string(); +#endif // _ELPP_OS_UNIX + } + + // Determines whether or not provided path_ exist in current file system + static inline bool pathExists(const char* path_) { + if (path_ == NULL) { + return false; + } +#if _ELPP_OS_UNIX + struct stat st; + return (stat(path_, &st) == 0); +#elif _ELPP_OS_WINDOWS + DWORD fileType = GetFileAttributesA(path_); + if (fileType == INVALID_FILE_ATTRIBUTES) { + return false; + } + return (fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true; +#endif // _ELPP_OS_UNIX + } + + // Creates path as specified + static bool createPath(const std::string& path_) { + if (path_.empty()) { + return false; + } + if (internal::utilities::OSUtils::pathExists(path_.c_str())) { + return true; + } +#if _ELPP_OS_UNIX + const char* pathDelim_ = "/"; +#elif _ELPP_OS_WINDOWS + char pathDelim_[] = "\\"; +#endif // _ELPP_OS_UNIX + int status = -1; + + char* currPath_ = const_cast(path_.c_str()); + std::string buildingPath_ = std::string(); +#if _ELPP_OS_UNIX + if (path_[0] == '/') { + buildingPath_ = "/"; + } + currPath_ = STRTOK(currPath_, pathDelim_, 0); +#elif _ELPP_OS_WINDOWS + // Use secure functions API + char* nextTok_; + currPath_ = STRTOK(currPath_, pathDelim_, &nextTok_); +#endif // _ELPP_OS_UNIX + while (currPath_ != NULL) { + buildingPath_.append(currPath_); + buildingPath_.append(pathDelim_); +#if _ELPP_OS_UNIX + status = mkdir(buildingPath_.c_str(), _LOG_PERMS); + currPath_ = STRTOK(NULL, pathDelim_, 0); +#elif _ELPP_OS_WINDOWS + status = _mkdir(buildingPath_.c_str()); + currPath_ = STRTOK(NULL, pathDelim_, &nextTok_); +#endif // _ELPP_OS_UNIX + } + if (status == -1) { + return false; + } + return true; + } + + static std::string getPathFromFilename(const std::string& fullPath_, internal::Constants* constants_) { + if (fullPath_ == "" || fullPath_.find(constants_->PATH_SLASH) == std::string::npos) { + return fullPath_; + } + std::size_t lastSlashAt = fullPath_.find_last_of(constants_->PATH_SLASH); + if (lastSlashAt == 0) { + return constants_->PATH_SLASH; + } + return fullPath_.substr(0, lastSlashAt + 1); + } +}; // class OSUtils + +//! +//! Contains static functions related to log manipulation used internally. You should not use it. +//! +class LogManipulator : private internal::StaticClass { +public: + // Updates the formatSpecifier_ for currentFormat_ to value_ provided + static void updateFormatValue(const std::string& formatSpecifier_, + const std::string& value_, std::string& currentFormat_, + internal::Constants* constants_) { + std::size_t foundAt = std::string::npos; + while ((foundAt = currentFormat_.find(formatSpecifier_, foundAt + 1)) != std::string::npos){ + if (currentFormat_[foundAt > 0 ? foundAt - 1 : 0] == constants_->FORMAT_SPECIFIER_ESCAPE_CHAR) { + currentFormat_.erase(foundAt > 0 ? foundAt - 1 : 0, 1); + ++foundAt; + } else { + currentFormat_ = currentFormat_.replace(foundAt, formatSpecifier_.size(), value_); + return; + } + } + } +}; // class LogManipulator + +//! +//! Contains utility functions related to date/time used internally. You should not use it. +//! +class DateUtils : private internal::StaticClass { +public: +#if _ELPP_OS_WINDOWS + static void gettimeofday(struct timeval *tv) { + if (tv != NULL) { +# if defined(_MSC_EXTENSIONS) + const unsigned __int64 delta_ = 11644473600000000Ui64; +# else + const unsigned __int64 delta_ = 11644473600000000ULL; +# endif // defined(_MSC_EXTENSIONS) + const double secOffSet = 0.000001; + const unsigned long usecOffSet = 1000000; + FILETIME fileTime_; + GetSystemTimeAsFileTime(&fileTime_); + unsigned __int64 present_ = 0; + present_ |= fileTime_.dwHighDateTime; + present_ = present_ << 32; + present_ |= fileTime_.dwLowDateTime; + present_ /= 10; // mic-sec + // Subtract the difference + present_ -= delta_; + tv->tv_sec = static_cast(present_ * secOffSet); + tv->tv_usec = static_cast(present_ % usecOffSet); + } + } +#endif // _ELPP_OS_WINDOWS + + // Gets current date and time with milliseconds. + static std::string getDateTime(const std::string& bufferFormat_, unsigned int type_, internal::Constants* constants_, std::size_t milliSecondOffset_ = 1000) { + long milliSeconds = 0; + const int kDateBuffSize_ = 30; + char dateBuffer_[kDateBuffSize_] = ""; + char dateBufferOut_[kDateBuffSize_] = ""; +#if _ELPP_OS_UNIX + bool hasTime_ = ((type_ & constants_->kDateTime) || (type_ & constants_->kTimeOnly)); + timeval currTime; + gettimeofday(&currTime, NULL); + if (hasTime_) { + milliSeconds = currTime.tv_usec / milliSecondOffset_ ; + } + struct tm * timeInfo = localtime(&currTime.tv_sec); + strftime(dateBuffer_, sizeof(dateBuffer_), bufferFormat_.c_str(), timeInfo); + if (hasTime_) { + SPRINTF(dateBufferOut_, "%s.%03ld", dateBuffer_, milliSeconds); + } else { + SPRINTF(dateBufferOut_, "%s", dateBuffer_); + } +#elif _ELPP_OS_WINDOWS + const char* kTimeFormatLocal_ = "HH':'mm':'ss"; + const char* kDateFormatLocal_ = "dd/MM/yyyy"; + if ((type_ & constants_->kDateTime) || (type_ & constants_->kDateOnly)) { + if (GetDateFormatA(LOCALE_USER_DEFAULT, 0, 0, kDateFormatLocal_, dateBuffer_, kDateBuffSize_) != 0) { + SPRINTF(dateBufferOut_, "%s", dateBuffer_); + } + } + if ((type_ & constants_->kDateTime) || (type_ & constants_->kTimeOnly)) { + if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, kTimeFormatLocal_, dateBuffer_, kDateBuffSize_) != 0) { + milliSeconds = static_cast(GetTickCount()) % milliSecondOffset_; + if (type_ & constants_->kDateTime) { + SPRINTF(dateBufferOut_, "%s %s.%03ld", dateBufferOut_, dateBuffer_, milliSeconds); + } else { + SPRINTF(dateBufferOut_, "%s.%03ld", dateBuffer_, milliSeconds); + } + } + } +#endif // _ELPP_OS_UNIX + return std::string(dateBufferOut_); + } + + static std::string formatMilliSeconds(double milliSeconds_) { + double result = milliSeconds_; + std::string unit = "ms"; + std::stringstream stream_; + if (result > 1000.0f) { + result /= 1000; unit = "seconds"; + if (result > 60.0f) { + result /= 60; unit = "minutes"; + if (result > 60.0f) { + result /= 60; unit = "hours"; + if (result > 24.0f) { + result /= 24; unit = "days"; + } + } + } + } + stream_ << result << " " << unit; + return stream_.str(); + } + + static inline double getTimeDifference(const timeval& endTime_, const timeval& startTime_) { + return static_cast((((endTime_.tv_sec - startTime_.tv_sec) * 1000000) + (endTime_.tv_usec - startTime_.tv_usec)) / 1000); + } +}; // class DateUtils +} // namespace utilities + +//! +//! Internal repository base to manage memory on heap. Used internally, you should not use it. +//! +template +class Registry { +public: + Registry(void) { + } + + virtual ~Registry(void) { + unregisterAll(); + } + + Registry(const Registry& other_) { + if (this != &other_) { + unregisterAll(); + for (std::size_t i = 0; i < other_.list_.size(); ++i) { + Class* curr_ = other_.list_.at(i); + if (curr_) { + list_.push_back(new Class(*curr_)); + } + } + } + } + + Registry& operator=(const Registry& other_) { + if (this == &other_) { + return *this; + } + unregisterAll(); + for (std::size_t i = 0; i < other_.list_.size(); ++i) { + Class* curr_ = other_.list_.at(i); + if (curr_) { + list_.push_back(new Class(*curr_)); + } + } + return *this; + } + + inline void registerNew(Class* c_) { + list_.push_back(c_); + } + + bool operator!=(const Registry& other_) { + if (list_.size() != other_.list_.size()) { + return true; + } + for (std::size_t i = 0; i < list_.size(); ++i) { + if (list_.at(i) != other_.list_.at(i)) { + return true; + } + } + return false; + } + + bool operator==(const Registry& other_) { + if (list_.size() != other_.list_.size()) { + return false; + } + for (std::size_t i = 0; i < list_.size(); ++i) { + if (list_.at(i) != other_.list_.at(i)) { + return false; + } + } + return true; + } + + template + Class* get(const T& t_) { + Iterator iter = std::find_if(list_.begin(), list_.end(), Predicate(t_)); + if (iter != list_.end() && *iter != NULL) { + return *iter; + } + return NULL; + } + + template + Class* get(const T& t_, const T2& t2_) { + Iterator iter = std::find_if(list_.begin(), list_.end(), Predicate(t_, t2_)); + if (iter != list_.end() && *iter != NULL) { + return *iter; + } + return NULL; + } + + template + inline bool exist(const T& t_) { + return (get(t_) != NULL); + } + + inline std::size_t count(void) const { + return list_.size(); + } + + inline bool empty(void) const { + return list_.empty(); + } + + Class* at(std::size_t i) const { + return list_.at(i); + } + +protected: + typedef typename std::vector::iterator Iterator; + + inline void unregisterAll(void) { + if (!empty()) { + std::for_each(list_.begin(), list_.end(), std::bind1st(std::mem_fun(&Registry::release), this)); + list_.clear(); + } + } + + inline void unregister(Class*& c_) { + if (c_) { + Iterator iter = list_.begin(); + for (; iter != list_.end(); ++iter) { + if (c_ == *iter) { + break; + } + } + if (iter != list_.end() && *iter != NULL) { + list_.erase(iter); + internal::utilities::safeDelete(c_); + } + } + } + + inline std::vector& list(void) { + return list_; + } +private: + std::vector list_; + + inline void release(Class* c_) { + internal::utilities::safeDelete(c_); + } +}; // class Registry + +//! +//! Scoped pointer used internally. You should not use it. +//! +template +class ScopedPointer { +public: + explicit ScopedPointer(T* ptr_ = 0) : + ptr_(ptr_), referenceCounter_(0) { + referenceCounter_ = new ReferenceCounter(); + referenceCounter_->increment(); + } + + ScopedPointer(const ScopedPointer& scopedPointer_) : + ptr_(scopedPointer_.ptr_), referenceCounter_(scopedPointer_.referenceCounter_) { + referenceCounter_->increment(); + } + + ScopedPointer& operator=(const ScopedPointer& other_) { + if (this != &other_) + { + validate(); + ptr_ = other_.ptr_; + referenceCounter_ = other_.referenceCounter_; + referenceCounter_->increment(); + } + return *this; + } + + virtual ~ScopedPointer(void) { + validate(); + } + + T& operator*(void) { + return *ptr_; + } + + T* operator->(void) { + return ptr_; + } + + T* pointer(void) { + return ptr_; + } + + class ReferenceCounter { + public: + ReferenceCounter(void) : count_(0) { + } + + ReferenceCounter& operator=(const ReferenceCounter& other_) { + if (this != &other_) { + count_ = other_.count_; + } + return *this; + } + + void increment(void) { + ++count_; + } + + int decrement(void) { + return this == NULL ? 0 : --count_; + } + + private: + int count_; + }; +private: + T* ptr_; + ReferenceCounter* referenceCounter_; + + void validate(void) { + if(referenceCounter_->decrement() == 0) { + internal::utilities::safeDelete(ptr_, false); + internal::utilities::safeDelete(referenceCounter_, false); + } + } +}; + +//! +//! Class that represents single configuration. +//! +//! Single configuration has a level (easyloggingpp::Level), type (easyloggingpp::ConfigurationType) +//! and std::string based value. This value is later parsed into more appropriate data type depending on +//! type +//! +class Configuration { +public: + //! + //! Full constructor used to set initial value of configuration + //! \param level_ + //! \param type_ + //! \param value_ + //! + Configuration(unsigned int level_, unsigned int type_, const std::string& value_) : + level_(level_), + type_(type_), + value_(value_) { + } + + //! + //! \return Level of current configuration + //! + unsigned int level(void) const { + return level_; + } + + //! + //! \return Configuration type of current configuration + //! + unsigned int type(void) const { + return type_; + } + + //! + //! \return String based configuration value + //! + std::string value(void) const { + return value_; + } + + //! + //! Set string based configuration value + //! \param value_ Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values + //! use them in quotes. They will be parsed when configuring + //! + void setValue(const std::string& value_) { + this->value_ = value_; + } + + //! + //! Predicate used to find configuration from configuration repository. This is used internally. + //! + class Predicate { + public: + Predicate(unsigned int level_, unsigned int type_) : + level_(level_), + type_(type_) { + } + + bool operator()(const Configuration* conf_) { + return ((conf_ != NULL) && (conf_->level() == level_) && (conf_->type() == type_)); + } + + private: + unsigned int level_; + unsigned int type_; + }; +private: + unsigned int level_; + unsigned int type_; + std::string value_; +}; + +} // namespace internal + +//! +//! Configuration repository that represents configuration for single logger +//! +class Configurations : public internal::Registry { +public: + //! + //! Default constructor + //! + Configurations(void) : + isFromFile_(false) { + } + + //! + //! Constructor used to set configurations via configuration file + //! \param configurationFile_ Full path to configuration file + //! \param base_ Configurations to base new configuration repository off. This value is used when you want to use + //! existing Configurations to base all the values and then set rest of configuration via configuration file. + //! + Configurations(const std::string& configurationFile_, Configurations* base_ = NULL) : + configurationFile_(configurationFile_), + isFromFile_(false) { + parseFromFile(configurationFile_, base_); + } + + //! + //! Set configurations based on other configurations + //! \param base_ Pointer to existing configurations. + //! + inline void setFromBase(Configurations* base_) { + if (base_ == NULL || base_ == this) return; + std::for_each(base_->list().begin(), base_->list().end(), std::bind1st(std::mem_fun(&Configurations::set), this)); + } + + //! + //! Checks to see whether specified configuration type exist in this repository + //! \param configurationType_ Configuration type to check against. Use easyloggingpp::ConfigurationType to prevent confusions + //! \return True if exist, false otherwise + //! + inline bool contains(unsigned int configurationType_) { + ELPP_FOR_EACH_CONFIGURATION(i, ConfigurationType::kMinValid, + if (get(i, configurationType_) != NULL) { + return true; + } + ); + return false; + } + + //! + //! Sets configuration for specified level_ and configurationType_. If configuration already exists for specified + //! level and configuration type, value just gets updated. + //! Remember, it is not recommended to set skip_ELPPALL_Check to false unless you know exactly what you are doing + //! \param level_ Level to set configuration for. Use easyloggingpp::Level to prevent confusion + //! \param configurationType_ Configuration type to set configuration against. Use easyloggingpp::ConfigurationType to prevent confusion + //! \param value_ String based configuration value + //! \param skipLEVEL_ALL Determines whether to skip 'easyloggingpp::Level::All'. This is skipped by default because setting + //! 'All' may override configuration. Be careful with this. + //! + void set(unsigned int level_, unsigned int configurationType_, const std::string& value_, bool skipLEVEL_ALL = false) { + if (value_ == "") return; // ignore empty values + if ((configurationType_ == ConfigurationType::PerformanceTracking && level_ != Level::All) || + (configurationType_ == ConfigurationType::MillisecondsWidth && level_ != Level::All)) { + // configurationType_ not applicable for this level_ + return; + } + internal::Configuration* conf_ = get(level_, configurationType_); + if (conf_ == NULL) { + registerNew(new internal::Configuration(level_, configurationType_, value_)); + } else { + // Configuration already there, just update the value! + conf_->setValue(value_); + } + if (!skipLEVEL_ALL && level_ == Level::All) { + setAll(configurationType_, value_, true); + } + } + + //! + //! Parse configuration from file. + //! \param configurationFile_ + //! \param base_Configurations to base new configuration repository off. This value is used when you want to use + //! existing Configurations to base all the values and then set rest of configuration via configuration file. + //! \return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRST_ELPP_ASSERTION' to make sure you + //! do not proceed without successful parse. + //! + bool parseFromFile(const std::string& configurationFile_, Configurations* base_ = NULL) { + setFromBase(base_); + std::ifstream fileStream_(configurationFile_.c_str(), std::ifstream::in); + __EASYLOGGINGPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile_ << "] for parsing."); + bool parsedSuccessfully_ = false; + std::string line = std::string(); + unsigned int currLevel = 0; + while (fileStream_.good()) { + std::getline(fileStream_, line); + parsedSuccessfully_ = Parser::parseLine(line, currLevel, this); + __EASYLOGGINGPP_ASSERT(parsedSuccessfully_, "Unable to parse configuration line: " << line); + } + isFromFile_ = true; + return parsedSuccessfully_; + } + + //! + //! Parse configurations from configuration string. This configuration string has same syntax as configuration file contents. Make + //! sure all the necessary new line characters are provided. + //! \param configurationsString + //! \return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRST_ELPP_ASSERTION' to make sure you + //! do not proceed without successful parse. + //! + bool parseFromText(const std::string& configurationsString) { + bool parsedSuccessfully_ = false; + std::string line = std::string(); + unsigned int currLevel = 0; + std::vector lines; + internal::utilities::StringUtils::split(configurationsString, '\n', lines); + for (std::size_t i = 0; i < lines.size(); ++i) { + line = lines.at(i); + parsedSuccessfully_ = Parser::parseLine(line, currLevel, this); + __EASYLOGGINGPP_ASSERT(parsedSuccessfully_, "Unable to parse configuration line: " << line); + } + isFromFile_ = false; + return parsedSuccessfully_; + } + + //! + //! Sets configurations to default configurations set by easylogging++. + //! NOTE: This has nothing to do with Loggers::setDefaultConfigurations - thats completely different thing. This is + //! library's own default format. + //! + void setToDefault(void) { + setAll(ConfigurationType::Enabled, "true"); +#if _ELPP_OS_UNIX +# if _ELPP_NDK + setAll(ConfigurationType::Filename, "/data/local/tmp/myeasylog.txt"); +# else + setAll(ConfigurationType::Filename, "/tmp/logs/myeasylog.log"); +# endif // _ELPP_NDK +#elif _ELPP_OS_WINDOWS + setAll(ConfigurationType::Filename, "logs\\myeasylog.log"); +#endif // _ELPP_OS_UNIX + setAll(ConfigurationType::ToFile, "true"); + setAll(ConfigurationType::ToStandardOutput, "true"); + setAll(ConfigurationType::MillisecondsWidth, "3"); + setAll(ConfigurationType::PerformanceTracking, "false"); + setAll(easyloggingpp::ConfigurationType::RollOutSize, "0"); + setAll(ConfigurationType::Format, "%datetime %level [%logger] %log"); + set(Level::Debug, ConfigurationType::Format, "%datetime %level [%logger] [%user@%host] [%func] [%loc] %log"); + // INFO and WARNING are set to default by Level::ALL + set(Level::Error, ConfigurationType::Format, "%datetime %level [%logger] %log"); + set(Level::Fatal, ConfigurationType::Format, "%datetime %level [%logger] %log"); + set(Level::Verbose, ConfigurationType::Format, "%datetime %level-%vlevel [%logger] %log"); + set(Level::QA, ConfigurationType::Format, "%datetime %level [%logger] %log"); + set(Level::Trace, ConfigurationType::Format, "%datetime %level [%logger] [%func] [%loc] %log"); + } + + //! + //! Sets configuration for all levels. + //! Remember, it is not recommended to set skip_ELPPALL_Check to false unless you know exactly what you are doing + //! \param configurationType_ + //! \param value_ + //! \param skipLEVEL_ALL Determines whether to skip 'easyloggingpp::Level::All'. This is skipped by default because setting + //! 'All' may override configuration. Be careful with this. + //! + inline void setAll(unsigned int configurationType_, const std::string& value_, bool skipLEVEL_ALL = false) { + if (!skipLEVEL_ALL) { + set(Level::All, configurationType_, value_); + } + ELPP_FOR_EACH_LEVEL(i, Level::Debug, + set(i, configurationType_, value_); + ); + } + + //! + //! Clears the repository. + //! All the configurations are maintained on heap for faster access so if you are sure you will not use this + //! repository and you have configured all the loggers against this or you have used this configuration for all the + //! purposes you need it for, you may retain memory by using this method. If you do not do this, internal memory management + //! does it itself at the end of application execution. + //! + inline void clear(void) { + unregisterAll(); + } + + //! + //! \return Returns configuration file used in parsing this configurations. If this repository was set manually or by text + //! this returns empty string. + //! + std::string configurationFile(void) const { + return configurationFile_; + } + + //! + //! Parser used internally to parse configurations from file or text. You should not need this unless you are working on + //! some tool for EasyLogging++ + //! + class Parser : private internal::StaticClass { + public: + static void ignoreComments(std::string& line) { + std::size_t foundAt = 0; + std::size_t quotesStart = line.find("\""); + std::size_t quotesEnd = std::string::npos; + if (quotesStart != std::string::npos) { + quotesEnd = line.find("\"", quotesStart + 1); + } + if ((foundAt = line.find("//")) != std::string::npos) { + if (foundAt < quotesEnd) { + foundAt = line.find("//", quotesEnd + 1); + } + line = line.substr(0, foundAt); + } + } + + static inline bool isLevel(const std::string& line) { + return internal::utilities::StringUtils::startsWith(line, "*"); + } + + static inline bool isConfig(const std::string& line) { + std::size_t assignment = line.find('='); + return line != "" && + (line[0] >= 65 || line[0] <= 90 || line[0] >= 97 || line[0] <= 122) && + (assignment != std::string::npos) && + (line.size() > assignment); + } + + static inline bool isComment(const std::string& line) { + return internal::utilities::StringUtils::startsWith(line, "//"); + } + + static bool parseLine(std::string& line, unsigned int& currLevel, Configurations* conf) { + std::string currLevelStr = std::string(); + unsigned int currConfig = 0; + std::string currConfigStr = std::string(); + std::string currValue = std::string(); + line = internal::utilities::StringUtils::trim(line); + if (isComment(line)) return true; + ignoreComments(line); + if (line == "") { + // Comment ignored + return true; + } + if (isLevel(line)) { + currLevelStr = internal::utilities::StringUtils::stripAllWhiteSpaces(line); + if (currLevelStr.size() <= 2) { + return true; + } + currLevelStr = currLevelStr.substr(1, currLevelStr.size() - 2); + internal::utilities::StringUtils::tolower(currLevelStr); + currLevel = Level::convertFromString(currLevelStr); + return true; + } + if (isConfig(line)) { + std::size_t assignment = line.find('='); + currConfigStr = line.substr(0, assignment); + currConfigStr = internal::utilities::StringUtils::stripAllWhiteSpaces(currConfigStr); + internal::utilities::StringUtils::tolower(currConfigStr); + currConfig = ConfigurationType::convertFromString(currConfigStr); + currValue = line.substr(assignment + 1); + currValue = internal::utilities::StringUtils::trim(currValue); + std::size_t quotesStart = currValue.find("\"", 0); + std::size_t quotesEnd = std::string::npos; + if (quotesStart != std::string::npos) { + quotesEnd = currValue.find("\"", quotesStart + 1); + } + if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { + // Quote provided - check and strip if valid + __EASYLOGGINGPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" << currConfigStr << "]"); + __EASYLOGGINGPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]"); + if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { + // Explicit check in case if assertion is disabled + currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); + } + } + } + __EASYLOGGINGPP_ASSERT(currLevel != Level::Unknown, "Unrecognized severity level [" << currLevelStr << "]"); + __EASYLOGGINGPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << currConfigStr << "]"); + if (currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) { + return false; // unrecognizable level or config + } + conf->set(currLevel, currConfig, currValue); + return true; + } + }; // class Parser +private: + std::string configurationFile_; + bool isFromFile_; + internal::threading::Mutex mutex_; + + inline void set(internal::Configuration* conf_) { + if (conf_ == NULL) return; + set(conf_->level(), conf_->type(), conf_->value()); + } +}; // class Configurations + +class Loggers; // fwd declaration + +namespace internal { + +class RegisteredLoggers; // fwd declaration +class Writer; // fwd declaration + +//! +//! Configuration map used internally for faster access of configuration while executing. +//! +template +class ConfigurationMap { +public: + typedef typename std::pair Entry; + + ConfigurationMap(void) { + table = new Entry*[Level::kMaxValid + 1]; + for (unsigned int i = 0; i < (Level::kMaxValid + 1); ++i) { + table[i] = NULL; + } + count = 0; + } + + const T& get(unsigned int level_, bool forceGetLevel = false) { + if (forceGetLevel || table[level_] != NULL) { + if (table[level_] == NULL) { + return default_; + } + return table[level_]->second; + } else if (table[Level::All] != NULL) { + return table[Level::All]->second; + } + return default_; + } + + void set(unsigned int level_, const T& value) { + // Unset any existing value for this level + unset(level_); + table[level_] = new Entry(level_, value); + ++count; + } + + void unset(unsigned int level_) { + if (table[level_] != NULL) { + internal::utilities::safeDelete(table[level_]); + if (count > 0) + --count; + } + } + + inline bool exist(unsigned int level_) const { + return table[level_] != NULL; + } + + inline bool exist(unsigned int level_, const T& value) { + return get(level_, true) == value; + } + + void clear(void) { + for (unsigned int i = 0; i < (Level::kMaxValid + 1); ++i) { + internal::utilities::safeDelete(table[i]); + } + delete[] table; + count = 0; + } + + virtual ~ConfigurationMap(void) { + clear(); + } + + inline void setDefault(const T& default_) { + this->default_ = default_; + } + + inline std::size_t size(void) const { + return count; + } +private: + Entry** table; + std::size_t count; + T default_; +}; + +//! +//! Configurations used internally that defines data type of each configuration from easyloggingpp::ConfigurationType +//! +class TypedConfigurations { +public: + TypedConfigurations(const Configurations& configurations, internal::Constants* constants_) { + this->constants_ = constants_; + this->configurations_ = configurations; + enabledMap_.setDefault(false); + toFileMap_.setDefault(false); + toStandardOutputMap_.setDefault(false); + filenameMap_.setDefault(""); + logFormatMap_.setDefault(""); + dateFormatMap_.setDefault(""); + dateFormatSpecifierMap_.setDefault(""); + millisecondsWidthMap_.setDefault(3); + performanceTrackingMap_.setDefault(false); + fileStreamMap_.setDefault(NULL); + formatFlagMap_.setDefault(0x0); + rollOutSizeMap_.setDefault(0); + parse(configurations); + } + + virtual ~TypedConfigurations(void) { + deleteFileStreams(); + } + + const Configurations& configurations(void) const { + return configurations_; + } +private: + internal::ConfigurationMap enabledMap_; + internal::ConfigurationMap toFileMap_; + internal::ConfigurationMap filenameMap_; + internal::ConfigurationMap toStandardOutputMap_; + internal::ConfigurationMap logFormatMap_; + internal::ConfigurationMap dateFormatMap_; + internal::ConfigurationMap dateFormatSpecifierMap_; + internal::ConfigurationMap millisecondsWidthMap_; + internal::ConfigurationMap performanceTrackingMap_; + internal::ConfigurationMap fileStreamMap_; + internal::ConfigurationMap formatFlagMap_; + internal::ConfigurationMap rollOutSizeMap_; + internal::Constants* constants_; + Configurations configurations_; + + friend class Writer; + friend class easyloggingpp::Loggers; + + inline bool enabled(unsigned int level_) { + return enabledMap_.get(level_); + } + + inline bool toFile(unsigned int level_) { + return toFileMap_.get(level_); + } + + inline const std::string& filename(unsigned int level_) { + return filenameMap_.get(level_); + } + + inline bool toStandardOutput(unsigned int level_) { + return toStandardOutputMap_.get(level_); + } + + inline const std::string& logFormat(unsigned int level_) { + return logFormatMap_.get(level_); + } + + inline const std::string& dateFormat(unsigned int level_) { + return dateFormatMap_.get(level_); + } + + inline const std::string& dateFormatSpecifier(unsigned int level_) { + return dateFormatSpecifierMap_.get(level_); + } + + inline int millisecondsWidth(unsigned int level_ = Level::All) { + return millisecondsWidthMap_.get(level_); + } + + inline bool performanceTracking(unsigned int level_ = Level::All) { + return performanceTrackingMap_.get(level_); + } + + inline std::fstream* fileStream(unsigned int level_) { + return fileStreamMap_.get(level_); + } + + inline std::size_t rollOutSize(unsigned int level_) { + return rollOutSizeMap_.get(level_); + } + + inline int formatFlag(unsigned int level_) { + return formatFlagMap_.get(level_); + } + + void parse(const Configurations& configurations_) { + for (std::size_t i = 0; i < configurations_.count(); ++i) { + Configuration* conf = configurations_.at(i); + switch (conf->type()) { + case ConfigurationType::Enabled: + setValue(conf->level(), getBool(conf->value()), enabledMap_); + break; + case ConfigurationType::ToFile: + setValue(conf->level(), getBool(conf->value()), toFileMap_); + break; + case ConfigurationType::Filename: + insertFilename(conf->level(), conf->value()); + break; + case ConfigurationType::ToStandardOutput: + setValue(conf->level(), getBool(conf->value()), toStandardOutputMap_); + break; + case ConfigurationType::Format: + determineFormats(conf->level(), conf->value()); + break; + case ConfigurationType::MillisecondsWidth: + if (conf->level() == Level::All) { + int origVal = getInt(conf->value()); + int msl_; +#if _ELPP_OS_UNIX + switch (origVal) { + case 3: + msl_ = 1000; + break; + case 4: + msl_ = 100; + break; + case 5: + msl_ = 10; + break; + case 6: + msl_ = 1; + break; + default: + msl_ = constants_->DEFAULT_MILLISECOND_OFFSET; + } +#elif _ELPP_OS_WINDOWS + msl_ = 1000; + __EASYLOGGINGPP_SUPPRESS_UNSED(origVal); +#endif // _ELPP_OS_UNIX + setValue(conf->level(), msl_, millisecondsWidthMap_); + } + break; + case ConfigurationType::PerformanceTracking: + if (conf->level() == Level::All) { + setValue(conf->level(), getBool(conf->value()), performanceTrackingMap_); + } + break; + case ConfigurationType::RollOutSize: + setValue(conf->level(), static_cast(getULong(conf->value())), rollOutSizeMap_); + unsigned int validLevel_ = 0; + std::string rolloutFilename_ = std::string(); + checkRollOuts(conf->level(), validLevel_, rolloutFilename_); + break; + } + } + } + + void determineFormats(unsigned int level_, const std::string& originalFormat) { + unsigned int formatSpec = 0x0; + if (originalFormat.find(constants_->APP_NAME_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kAppName; + } + if (originalFormat.find(constants_->LOGGER_ID_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kLoggerId; + } + if (originalFormat.find(constants_->THREAD_ID_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kThreadId; + } + if (originalFormat.find(constants_->LOCATION_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kLocation; + } + if (originalFormat.find(constants_->FUNCTION_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kFunction; + } + if (originalFormat.find(constants_->USER_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kUser; + } + if (originalFormat.find(constants_->HOST_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kHost; + } + if (originalFormat.find(constants_->LOG_MESSAGE_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kLogMessage; + } + if (originalFormat.find(constants_->VERBOSE_LEVEL_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kVerboseLevel; + } + if (originalFormat.find(constants_->DATE_TIME_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kDateTime; + setValue(level_, constants_->DATE_TIME_FORMAT_SPECIFIER, dateFormatSpecifierMap_); + } else if (originalFormat.find(constants_->DATE_ONLY_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kDateOnly; + setValue(level_, constants_->DATE_ONLY_FORMAT_SPECIFIER, dateFormatSpecifierMap_); + } else if (originalFormat.find(constants_->TIME_ONLY_FORMAT_SPECIFIER) != std::string::npos) { + formatSpec |= constants_->kTimeOnly; + setValue(level_, constants_->TIME_ONLY_FORMAT_SPECIFIER, dateFormatSpecifierMap_); + } +#if _ELPP_OS_UNIX + const std::string kTimeFormatLocal_ = "%H:%M:%S"; + const std::string kDateFormatLocal_ = "%d/%m/%Y"; + std::string dateFormat; + + if (formatSpec & constants_->kDateOnly) { + dateFormat = kDateFormatLocal_; + } else if (formatSpec & constants_->kTimeOnly) { + dateFormat = kTimeFormatLocal_; + } else { + std::stringstream ss; + ss << kDateFormatLocal_ << " " << kTimeFormatLocal_; + dateFormat = ss.str(); + } + setValue(level_, dateFormat, dateFormatMap_); +#endif // _ELPP_OS_UNIX + setValue(level_, formatSpec, formatFlagMap_); + // Update %level + std::string origFormatCopy = originalFormat; + switch (level_) { + case Level::Debug: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_DEBUG_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::Info: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_INFO_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::Warning: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_WARNING_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::Error: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_ERROR_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::Fatal: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_FATAL_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::Verbose: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_VERBOSE_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::QA: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_QA_LEVEL_VALUE, origFormatCopy, constants_); + break; + case Level::Trace: + internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, + constants_->LOG_TRACE_LEVEL_VALUE, origFormatCopy, constants_); + break; + } + setValue(level_, origFormatCopy + "\n", logFormatMap_); + } + + void deleteFileStreams(void) { + ELPP_FOR_EACH_LEVEL(i, Level::kMinValid, + removeFile(i); + ); + } + + // This is different since we need unique values + void insertFilename(unsigned int level_, const std::string& fname_, bool forceNew = false) { + std::string fnameFull = fname_; + if (internal::utilities::StringUtils::endsWith(fnameFull, constants_->PATH_SLASH)) { + fnameFull.append(constants_->DEFAULT_LOG_FILENAME); + } + std::string path_ = internal::utilities::OSUtils::getPathFromFilename(fnameFull, constants_); + if (path_.size() < fnameFull.size()) { + // Contains path - create it if it does not already exist + internal::utilities::OSUtils::createPath(path_); + } + if (filenameMap_.size() == 0) { + filenameMap_.set(Level::All, fnameFull); + std::fstream *fsAll = newFileStream(fnameFull, forceNew); + if (fsAll != NULL) { + fileStreamMap_.set(Level::All, fsAll); + } + return; + } + ELPP_FOR_EACH_LEVEL(i, Level::kMinValid, + if (filenameMap_.exist(i, fnameFull)) { + return; + } + ); + filenameMap_.set(level_, fnameFull); + // Just before we proceed and create new file stream we check for existing one on same level, + // if we have existing one, we first delete it to prevent memory leak. + std::fstream *fs = fileStreamMap_.get(level_, true); + internal::utilities::safeDelete(fs); + fileStreamMap_.unset(level_); + fs = newFileStream(fnameFull, forceNew); + if (fs != NULL) { + fileStreamMap_.set(level_, fs); + } + } + + template + void setValue(unsigned int level_, const T& value_, internal::ConfigurationMap& map_, bool skipLEVEL_ALL = false) { + if (map_.size() == 0 && !skipLEVEL_ALL) { + map_.set(Level::All, value_); + return; + } + if (map_.exist(static_cast(Level::All), value_)) { + return; + } + map_.set(level_, value_); + } + + std::fstream* newFileStream(const std::string& filename, bool forceNew = false) { + std::fstream *fs = NULL; + if (forceNew) { + fs = new std::fstream(filename.c_str(), std::fstream::out); + } else { + fs = new std::fstream(filename.c_str(), std::fstream::out | std::fstream::app); + } + if (fs->is_open()) { + fs->flush(); + } else { + internal::utilities::safeDelete(fs, false); + std::cerr << "Bad file [" << filename << "]" << std::endl; + return NULL; + } + return fs; + } + + void removeFile(unsigned int level_) { + std::fstream* fs = fileStream(level_); + if (!fs) { + return; + } + if (fs->is_open()) { + fs->close(); + } + internal::utilities::safeDelete(fs, false); + fileStreamMap_.unset(level_); + filenameMap_.unset(level_); + } + + unsigned long getULong(const std::string& confValue_) { + bool valid = true; + std::string trimmedVal = internal::utilities::StringUtils::trim(confValue_); + if (trimmedVal.size() == 0) { + valid = false; + __EASYLOGGINGPP_SUPPRESS_UNSED(valid); + __EASYLOGGINGPP_ASSERT(valid, "Configuration value not a valid integer " << trimmedVal); + } + for (std::size_t i = 0; i < trimmedVal.size(); ++i) { + if (trimmedVal[i] < 48 || trimmedVal[i] > 57) { + valid = false; + break; + } + } + __EASYLOGGINGPP_SUPPRESS_UNSED(valid); + __EASYLOGGINGPP_ASSERT(valid, "Configuration value not a valid integer " << trimmedVal); + return atol(confValue_.c_str()); + } + + inline int getInt(const std::string& confValue_) { + return static_cast(getULong(confValue_)); + } + + inline bool getBool(const std::string& confValue_) { + std::string trimmedVal = internal::utilities::StringUtils::trim(confValue_); + return (trimmedVal == "1" || trimmedVal == "true" || trimmedVal == "TRUE"); + } + + std::size_t getSizeOfFile(std::fstream *fs) { + if (!fs) { + return 0; + } + std::streampos currPos = fs->tellg(); + fs->seekg (0, fs->end); + std::size_t size = static_cast(fs->tellg()); + fs->seekg (currPos); + return size; + } + + bool checkRollOuts(unsigned int level_, unsigned int& validLevel_, std::string& fname_) { + std::fstream* fs = fileStream(level_); + std::size_t rollOutSize_ = rollOutSize(level_); + if (rollOutSize_ != 0 && getSizeOfFile(fs) >= rollOutSize_) { + fname_ = filename(level_); +#if defined(_ELPP_INTERNAL_INFO) + std::cout << "Cleaning log file [" << fname_ << "]\n"; +#endif // defined(_ELPP_INTERNAL_INFO) + // Find and reset correct level. By correct level we mean the current + // available level in fileStream because this level_ could actually be using + // configurations from Level::All and you do not want to create a brand new + // stream just because we are rolling log away + validLevel_ = findValidLevel(fileStreamMap_, level_); + forceReinitiateFile(validLevel_, fname_); + return true; + } + return false; + } + + template + inline unsigned int findValidLevel(internal::ConfigurationMap& map_, unsigned int refLevel_) { + return map_.exist(refLevel_) ? refLevel_ : static_cast(Level::All); + } + + inline void forceReinitiateFile(unsigned int level_, const std::string& filename_) { + removeFile(level_); + insertFilename(level_, filename_, true); + } +}; +} // namespace internal + +//! +//! Represents single logger used to write log. +//! +class Logger { +public: + //! + //! Minimal constructor to set logger ID and constants. You should not use this constructor manually, instead use + //! easyloggingpp::Loggers::getLogger + //! \param uniqueIdentifier_ Logger ID that you will require to get logger from logger repository + //! \param constants_ Use easyloggingpp::internal::registeredLoggers->constants() + //! + Logger(const std::string& uniqueIdentifier_, internal::Constants* constants_) : + id_(uniqueIdentifier_), + constants_(constants_), + typedConfigurations_(NULL), + stream_(new std::stringstream()) { + Configurations defaultConfs; + defaultConfs.setToDefault(); + configure(defaultConfs); + userConfigurations_ = defaultConfs; + defaultConfs.clear(); + } + + //! + //! Full constructor to set logger ID, constants and configuration. + //! \param uniqueIdentifier_ Logger ID that you will require to get logger from logger repository + //! \param constants_ Use easyloggingpp::internal::registeredLoggers->constants() + //! \param configurations Configurations to set logger against + //! + Logger(const std::string& uniqueIdentifier_, internal::Constants* constants_, const Configurations& configurations) : + id_(uniqueIdentifier_), + constants_(constants_), + typedConfigurations_(NULL), + stream_(new std::stringstream()) { + configure(configurations); + } + + virtual ~Logger(void) { + internal::utilities::safeDelete(typedConfigurations_); + internal::utilities::safeDelete(stream_); + } + + //! + //! \return Logger ID + //! + inline std::string id(void) const { + return id_; + } + + //! + //! Configures logger against specified configurations + //! \param configurations_ + //! + void configure(const Configurations& configurations_) { +#if _ELPP_ENABLE_MUTEX + internal::threading::ScopedLock slock_(mutex_); + __EASYLOGGINGPP_SUPPRESS_UNSED(slock_); +#endif // _ELPP_ENABLE_MUTEX + // Configuring uses existing configuration as starting point + // and then sets configurations_ as base to prevent losing any + // previous configurations + Configurations base_ = userConfigurations_; + if (userConfigurations_ != configurations_) { + userConfigurations_ = configurations_; + base_.setFromBase(const_cast(&configurations_)); + } + internal::utilities::safeDelete(typedConfigurations_); + typedConfigurations_ = new internal::TypedConfigurations(base_, constants_); + configured_ = true; + } + + //! + //! Reconfigures logger + //! + inline void reconfigure(void) { + configure(this->userConfigurations_); + } + + //! + //! \return Application name for this logger + //! + inline std::string applicationName(void) const { + return applicationName_; + } + + + //! + //! Application name can vary from logger to logger. For example for a library application name may be different. + //! This is whats used later when you use '%app' in log format + //! + inline void setApplicationName(const std::string& applicationName_) { + this->applicationName_ = applicationName_; + } + + //! + //! \return Configurations that this logger is set against + //! + inline Configurations& configurations(void) { + return userConfigurations_; + } + + //! + //! \return Whether or not logger is configured. + //! + inline bool configured(void) const { + return configured_; + } + + //! + //! Predicate used in logger repository to find logger. This is used internally. You should not use it. + //! + class Predicate { + public: + explicit Predicate(const std::string& id_) : + id_(id_) { + } + inline bool operator()(const Logger* logger_) { + return ((logger_ != NULL) && (logger_->id() == id_)); + } + private: + std::string id_; + }; +private: + std::string id_; + internal::Constants* constants_; + Configurations userConfigurations_; + internal::TypedConfigurations* typedConfigurations_; + std::stringstream* stream_; + std::string applicationName_; + bool configured_; + internal::threading::Mutex mutex_; + friend class internal::Writer; + friend class Loggers; + friend class internal::RegisteredLoggers; + + Logger(void); + + std::stringstream* stream(void) { + return stream_; + } + + inline void acquireLock(void) { + mutex_.lock(); + } + + inline void releaseLock(void) { + mutex_.unlock(); + } +}; + +namespace internal { +//! +//! Internal log counter used for interval logging +//! +class LogCounter : private internal::NoCopy { +public: + explicit LogCounter(internal::Constants* constants_) : + file_(""), + line_(0), + position_(1), + constants_(constants_) { + } + + LogCounter(const char* file_, + unsigned long int line_, + internal::Constants* constants_) : + file_(file_), + line_(line_), + position_(1), + constants_(constants_) { + } + + virtual ~LogCounter(void) { + } + + inline void resetLocation(const char* file_, + unsigned long int line_) { + this->file_ = file_; + this->line_ = line_; + } + + inline void reset(std::size_t n_) { + if (position_ >= constants_->MAX_LOG_PER_COUNTER) { + position_ = (n_ >= 1 ? constants_->MAX_LOG_PER_COUNTER % n_ : 0); + } + ++position_; + } + + inline const char* file(void) const { + return file_; + } + + inline unsigned long int line(void) const { + return line_; + } + + inline std::size_t position(void) const { + return position_; + } + + class Predicate { + public: + Predicate(const char* file_, unsigned long int line_) + : file_(file_), + line_(line_) { + } + inline bool operator()(const LogCounter* counter_) { + return ((counter_ != NULL) && + (counter_->file_ == file_) && + (counter_->line_ == line_)); + } + + private: + const char* file_; + unsigned long int line_; + }; +private: + const char* file_; + unsigned long int line_; + std::size_t position_; + internal::Constants* constants_; +}; // class LogCounter + +//! +//! Internal LogCounter repository +//! +class RegisteredCounters : public Registry { +public: + bool validate(const char* file_, unsigned long int line_, std::size_t n_, internal::Constants* constants_) { +#if _ELPP_ENABLE_MUTEX + internal::threading::ScopedLock slock_(mutex_); + __EASYLOGGINGPP_SUPPRESS_UNSED(slock_); +#endif // _ELPP_ENABLE_MUTEX + bool result_ = false; + internal::LogCounter* counter_ = get(file_, line_); + if (counter_ == NULL) { + registerNew(counter_ = new internal::LogCounter(file_, line_, constants_)); + } + if (n_ >= 1 && counter_->position() != 0 && counter_->position() % n_ == 0) { + result_ = true; + } + counter_->reset(n_); + return result_; + } +private: + internal::threading::Mutex mutex_; +}; // class RegisteredCounters + +//! +//! Internal logger repository. You should not access functionalities directly, you should use easyloggingpp::Loggers instead +//! +class RegisteredLoggers : public internal::Registry { +public: + RegisteredLoggers(void) : + constants_(new internal::Constants()), + username_(internal::utilities::OSUtils::currentUser()), + hostname_(internal::utilities::OSUtils::currentHost()), + counters_(new internal::RegisteredCounters()) { + defaultConfigurations_.setToDefault(); + Configurations conf; + conf.setToDefault(); + conf.parseFromText(constants_->DEFAULT_LOGGER_CONFIGURATION); + registerNew(new Logger("trivial", constants_, conf)); + registerNew(new Logger("business", constants_)); + registerNew(new Logger("security", constants_)); + Configurations confPerformance; + confPerformance.setToDefault(); + confPerformance.setAll(ConfigurationType::PerformanceTracking, "true"); + registerNew(new Logger("performance", constants_, confPerformance)); + } + + virtual ~RegisteredLoggers(void) { + internal::utilities::safeDelete(constants_); + internal::utilities::safeDelete(counters_); + } + + inline internal::Constants* constants(void) const { + return constants_; + } + + inline RegisteredCounters* counters(void) { + return counters_; + } + + inline bool validateCounter(const char* file_, unsigned long int line_, std::size_t n_) { + return counters_->validate(file_, line_, n_, constants_); + } +private: + internal::Constants* constants_; + std::string username_; + std::string hostname_; + internal::threading::Mutex mutex_; + internal::RegisteredCounters* counters_; + Configurations defaultConfigurations_; + + friend class Writer; + friend class easyloggingpp::Loggers; + + inline const std::string& username(void) { + return username_; + } + + inline const std::string& hostname(void) { + return hostname_; + } + + inline void setDefaultConfigurations(const Configurations& configurations) { + defaultConfigurations_.setFromBase(const_cast(&configurations)); + } + + Logger* get(const std::string& id_, bool forceCreation_ = true) { +#if _ELPP_ENABLE_MUTEX + internal::threading::ScopedLock slock_(mutex_); + __EASYLOGGINGPP_SUPPRESS_UNSED(slock_); +#endif // _ELPP_ENABLE_MUTEX + Logger* logger_ = internal::Registry::get(id_); + if (logger_ == NULL && forceCreation_) { + logger_ = new Logger(id_, constants_, defaultConfigurations_); + registerNew(logger_); + } + return logger_; + } + + inline void unregister(Logger*& logger_) { +#if _ELPP_ENABLE_MUTEX + internal::threading::ScopedLock slock_(mutex_); +#endif // _ELPP_ENABLE_MUTEX + internal::Registry::unregister(logger_); + } + + inline void acquireLock(void) { + mutex_.lock(); + } + + inline void releaseLock(void) { + mutex_.unlock(); + } + + void setApplicationArguments(int argc, char** argv) { + while (argc-- > 0) { + // Look for --v=X argument + if ((strlen(argv[argc]) >= 5) && (argv[argc][0] == '-') && (argv[argc][1] == '-') && + (argv[argc][2] == 'v') && (argv[argc][3] == '=') && (isdigit(argv[argc][4]))) { + // Current argument is --v=X + // where X is a digit between 0-9 + constants_->CURRENT_VERBOSE_LEVEL = atoi(argv[argc] + 4); + } + // Look for -v argument + else if ((strlen(argv[argc]) == 2) && (argv[argc][0] == '-') && (argv[argc][1] == 'v')) { + constants_->CURRENT_VERBOSE_LEVEL = constants_->MAX_VERBOSE_LEVEL; + } + // Look for --verbose argument + else if ((strlen(argv[argc]) == 9) && (argv[argc][0] == '-') && (argv[argc][1] == '-') && + (argv[argc][2] == 'v') && (argv[argc][3] == 'e') && (argv[argc][4] == 'r') && + (argv[argc][5] == 'b') && (argv[argc][6] == 'o') && (argv[argc][7] == 's') && + (argv[argc][8] == 'e')) { + constants_->CURRENT_VERBOSE_LEVEL = constants_->MAX_VERBOSE_LEVEL; + } + } + } + + inline void setApplicationArguments(int argc, const char** argv) { + setApplicationArguments(argc, const_cast(argv)); + } +}; + +extern internal::ScopedPointer registeredLoggers; +#if defined(_ELPP_STL_LOGGING) +namespace workarounds { +// There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers +// of same type and provide iterator interface and pass it on to writeIterator(). +// Remember, this is passed by value in constructor so that we dont change original containers. +// This operation is as expensive as O(class_.size()) or O(constants->MAX_LOG_PER_COUNTER) which ever is smaller. + +// +// Abstract IterableContainer template that provides interface for iterable classes of type T +// +template +class IterableContainer { +public: + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + IterableContainer(void){} + virtual ~IterableContainer(void) {} + iterator begin(void) { return getContainer().begin(); } + iterator end(void) { return getContainer().end(); } + const_iterator begin(void) const { return getContainer().begin(); } + const_iterator end(void) const { return getContainer().end(); } +private: + virtual Container& getContainer(void) = 0; +}; + +// +// Implements IterableContainer and provides iterable std::priority_queue class +// +template, typename Comparator = std::less > +class IterablePriorityQueue : public IterableContainer, public std::priority_queue { +public: + IterablePriorityQueue(std::priority_queue queue_) { + std::size_t count_ = 0; + while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !queue_.empty()) { + this->push(queue_.top()); + queue_.pop(); + } + } +private: + inline Container& getContainer(void) { + return this->c; + } +}; + +// +// Implements IterableContainer and provides iterable std::queue class +// +template > +class IterableQueue : public IterableContainer, public std::queue { +public: + IterableQueue(std::queue queue_) { + std::size_t count_ = 0; + while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !queue_.empty()) { + this->push(queue_.front()); + queue_.pop(); + } + } +private: + inline Container& getContainer(void) { + return this->c; + } +}; + +// +// Implements IterableContainer and provides iterable std::stack class +// +template > +class IterableStack : public IterableContainer, public std::stack { +public: + IterableStack(std::stack stack_) { + std::size_t count_ = 0; + while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !stack_.empty()) { + this->push(stack_.top()); + stack_.pop(); + } + } +private: + inline Container& getContainer(void) { + return this->c; + } +}; +} // namespace workarounds +#endif //defined(_ELPP_STL_LOGGING) + +#define _ELPP_STREAM(l) (*(l->stream())) + +class NullWriter : private internal::NoCopy { +public: + NullWriter(void) {} + + template + inline NullWriter& operator<<(const T&) { + return *this; + } +}; + +class Writer : private internal::NoCopy { +public: + Writer(const std::string& loggerId_, + unsigned int aspect_, + unsigned int severity_, + const char* func_, + const char* file_, + const unsigned long int line_, + bool condition_ = true, + int verboseLevel_ = 0, + int counter_ = 0) : + aspect_(aspect_), + severity_(severity_), + func_(func_), + file_(file_), + line_(line_), + condition_(condition_), + verboseLevel_(verboseLevel_), + counter_(counter_), + proceed_(true) { + constants_ = registeredLoggers->constants(); + logger_ = registeredLoggers->get(loggerId_, false); + if (logger_ == NULL) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Logger [" << loggerId_ << "] not registered or configured yet!"); + proceed_ = false; + } +#if _ELPP_ENABLE_MUTEX + registeredLoggers->acquireLock(); + mutex_.lock(); +#endif // _ELPP_ENABLE_MUTEX + + if (proceed_) { + proceed_ = logger_->typedConfigurations_->enabled(severity_); + } + if (proceed_) { +#if (defined(_ELPP_STRICT_ROLLOUT)) + checkRollOuts(severity_, logger_); +#endif // (defined(_ELPP_STRICT_ROLLOUT)) + } + if (proceed_ && (severity_ == Level::Verbose)) { + proceed_ = (verboseLevel_ <= constants_->CURRENT_VERBOSE_LEVEL); + } + if (proceed_ && (aspect_ == Aspect::Conditional)) { + proceed_ = condition_; + } + } + + virtual ~Writer(void) { + if (proceed_) { + buildAndWriteLine(); + } +#if _ELPP_ENABLE_MUTEX + registeredLoggers->releaseLock(); + mutex_.unlock(); +#endif // _ELPP_ENABLE_MUTEX + } + + inline Writer& operator<<(const std::string& log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(char log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(bool log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(signed short log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(unsigned short log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(signed int log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(unsigned int log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(signed long log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(unsigned long log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(float log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(double log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(char* log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(const char* log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(const void* log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(long double log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_; + return *this; + } + inline Writer& operator<<(const std::wstring& log_) { + if (!proceed_) { return *this; } + return operator<<(log_.c_str()); + } + inline Writer& operator<<(const wchar_t* log_) { + if (!proceed_) { return *this; } + if (log_ == NULL) { + _ELPP_STREAM(logger_) << constants_->NULL_POINTER; + return *this; + } + std::size_t len_ = wcslen(log_) + 1; + char* buff_ = (char*)malloc(len_ + 1); +# if _ELPP_OS_UNIX || (_ELPP_OS_WINDOWS && !_ELPP_CRT_DBG_WARNINGS) + std::wcstombs(buff_, log_, len_); +# elif _ELPP_OS_WINDOWS + std::size_t convCount_ = 0; + mbstate_t mbState_; + ::memset((void*)&mbState_, 0, sizeof(mbState_)); + wcsrtombs_s(&convCount_, buff_, len_, &log_, len_, &mbState_); +# endif // _ELPP_OS_UNIX + _ELPP_STREAM(logger_) << buff_; + free(buff_); + return *this; + } +#if defined(_ELPP_STL_LOGGING) + template + inline Writer& operator<<(const std::vector& vec_) { + if (!proceed_) { return *this; } + return writeIterator(vec_.begin(), vec_.end(), vec_.size()); + } + template + inline Writer& operator<<(const std::list& list_) { + if (!proceed_) { return *this; } + return writeIterator(list_.begin(), list_.end(), list_.size()); + } + template + inline Writer& operator<<(const std::deque& deque_) { + if (!proceed_) { return *this; } + return writeIterator(deque_.begin(), deque_.end(), deque_.size()); + } + template + inline Writer& operator<<(const std::queue& queue_) { + if (!proceed_) { return *this; } + internal::workarounds::IterableQueue iterableQueue_ = + static_cast >(queue_); + return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); + } + template + inline Writer& operator<<(const std::stack& stack_) { + if (!proceed_) { return *this; } + internal::workarounds::IterableStack iterableStack_ = + static_cast >(stack_); + return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); + } + template + inline Writer& operator<<(const std::priority_queue& priorityQueue_) { + if (!proceed_) { return *this; } + internal::workarounds::IterablePriorityQueue iterablePriorityQueue_ = + static_cast >(priorityQueue_); + return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); + } + template + inline Writer& operator<<(const std::set& set_) { + if (!proceed_) { return *this; } + return writeIterator(set_.begin(), set_.end(), set_.size()); + } + template + inline Writer& operator<<(const std::multiset& set_) { + if (!proceed_) { return *this; } + return writeIterator(set_.begin(), set_.end(), set_.size()); + } + template + inline Writer& operator<<(const std::pair& pair_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << "("; + operator << (static_cast(pair_.first)); + _ELPP_STREAM(logger_) << ", "; + operator << (static_cast(pair_.second)); + _ELPP_STREAM(logger_) << ")"; + return *this; + } + template + inline Writer& operator<<(const std::bitset& bitset_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << "["; + _ELPP_STREAM(logger_) << bitset_.to_string(); + _ELPP_STREAM(logger_) << "]"; + return *this; + } + template + inline Writer& operator<<(const std::map& map_) { + if (!proceed_) { return *this; } + return writeIterator(map_.begin(), map_.end(), map_.size()); + } + template + inline Writer& operator<<(const std::multimap& map_) { + if (!proceed_) { return *this; } + return writeIterator(map_.begin(), map_.end(), map_.size()); + } +#endif // defined(_ELPP_STL_LOGGING) +#if defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) + inline Writer& operator<<(const QString& log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_.toStdString(); + return *this; + } + inline Writer& operator<<(const QStringRef& log_) { + if (!proceed_) { return *this; } + return operator<<(log_.toString()); + } + inline Writer& operator<<(qint64 log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << QString::number(log_).toStdString(); + return *this; + } + inline Writer& operator<<(quint64 log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << QString::number(log_).toStdString(); + return *this; + } + inline Writer& operator<<(QChar log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_.toLatin1(); + return *this; + } +# if (!_ELPP_QT_5) + inline Writer& operator<<(QBool log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << (bool(log_ != 0) ? "true" : "false"); + return *this; + } +# endif // (!_ELPP_QT_5) + inline Writer& operator<<(const QLatin1String& log_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << log_.latin1(); + return *this; + } + template + inline Writer& operator<<(const QList& list_) { + if (!proceed_) { return *this; } + return writeIterator(list_.begin(), list_.end(), list_.size()); + } + template + inline Writer& operator<<(const QVector& vec_) { + if (!proceed_) { return *this; } + return writeIterator(vec_.begin(), vec_.end(), vec_.size()); + } + template + inline Writer& operator<<(const QQueue& queue_) { + if (!proceed_) { return *this; } + return writeIterator(queue_.begin(), queue_.end(), queue_.size()); + } + template + inline Writer& operator<<(const QSet& set_) { + if (!proceed_) { return *this; } + return writeIterator(set_.begin(), set_.end(), set_.size()); + } + template + inline Writer& operator<<(const QPair& pair_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << "("; + operator << (static_cast(pair_.first)); + _ELPP_STREAM(logger_) << ", "; + operator << (static_cast(pair_.second)); + _ELPP_STREAM(logger_) << ")"; + return *this; + } + template + inline Writer& operator<<(const QMap& map_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << "["; + QList keys = map_.keys(); + typename QList::const_iterator begin = keys.begin(); + typename QList::const_iterator end = keys.end(); + int max_ = static_cast(constants_->MAX_LOG_PER_CONTAINER); // to prevent warning + for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { + _ELPP_STREAM(logger_) << "("; + operator << (static_cast(*begin)); + _ELPP_STREAM(logger_) << ", "; + operator << (static_cast(map_.value(*begin))); + _ELPP_STREAM(logger_) << ")"; + _ELPP_STREAM(logger_) << ((index_ < keys.size() -1) ? ", " : ""); + } + if (begin != end) { + _ELPP_STREAM(logger_) << " ..."; + } + _ELPP_STREAM(logger_) << "]"; + return *this; + } + template + inline Writer& operator<<(const QMultiMap& map_) { + if (!proceed_) { return *this; } + operator << (static_cast >(map_)); + return *this; + } + template + inline Writer& operator<<(const QHash& hash_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << "["; + QList keys = hash_.keys(); + typename QList::const_iterator begin = keys.begin(); + typename QList::const_iterator end = keys.end(); + int max_ = static_cast(constants_->MAX_LOG_PER_CONTAINER); // prevent type warning + for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { + _ELPP_STREAM(logger_) << "("; + operator << (static_cast(*begin)); + _ELPP_STREAM(logger_) << ", "; + operator << (static_cast(hash_.value(*begin))); + _ELPP_STREAM(logger_) << ")"; + _ELPP_STREAM(logger_) << ((index_ < keys.size() -1) ? ", " : ""); + } + if (begin != end) { + _ELPP_STREAM(logger_) << " ..."; + } + _ELPP_STREAM(logger_) << "]"; + return *this; + } + template + inline Writer& operator<<(const QMultiHash& multiHash_) { + if (!proceed_) { return *this; } + operator << (static_cast >(multiHash_)); + return *this; + } + template + inline Writer& operator<<(const QLinkedList& linkedList_) { + if (!proceed_) { return *this; } + return writeIterator(linkedList_.begin(), linkedList_.end(), linkedList_.size()); + } + template + inline Writer& operator<<(const QStack& stack_) { + if (!proceed_) { return *this; } + return writeIterator(stack_.begin(), stack_.end(), stack_.size()); + } +#endif // defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) + template + inline Writer& operator<<(const Class& class_) { + if (!proceed_) { return *this; } + _ELPP_STREAM(logger_) << class_; + return *this; + } +private: + unsigned int aspect_; + unsigned int severity_; + const char* func_; + const char* file_; + const unsigned long int line_; + bool condition_; + int verboseLevel_; + int counter_; + Logger* logger_; + std::stringstream tempss_; + std::string currLine_; + bool proceed_; + internal::Constants* constants_; + internal::threading::Mutex mutex_; + + friend class Logger; + + template + inline Writer& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) { + _ELPP_STREAM(logger_) << "["; + for (std::size_t i = 0; begin_ != end_ && i < constants_->MAX_LOG_PER_CONTAINER; ++i, ++begin_) { + operator << (*begin_); + _ELPP_STREAM(logger_) << ((i < size_ - 1) ? ", " : ""); + } + if (begin_ != end_) { + _ELPP_STREAM(logger_) << " ..."; + } + _ELPP_STREAM(logger_) << "]"; + return *this; + } + + void buildAndWriteLine(void) { + internal::RegisteredLoggers* rl_ = registeredLoggers.pointer(); + TypedConfigurations* conf_ = logger_->typedConfigurations_; + unsigned int f_ = conf_->formatFlag(severity_); // format spec + currLine_ = conf_->logFormat(severity_); + std::string dateFormat = conf_->dateFormat(severity_); + std::string fs_; // format specifier + std::string v_; // value + // App name + if (f_ & constants_->kAppName) { + v_ = logger_->applicationName(); + fs_ = constants_->APP_NAME_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); + } + // Logger ID + if (f_ & constants_->kLoggerId) { + v_ = logger_->id(); + fs_ = constants_->LOGGER_ID_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); + } + // Thread ID + if (f_ & constants_->kThreadId) { + std::stringstream ss; + ss << threading::getCurrentThreadId(); + fs_ = constants_->THREAD_ID_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, ss.str(), currLine_, constants_); + } + // Date/Time + if ((f_ & constants_->kDateOnly) || (f_ & constants_->kTimeOnly) || (f_ & constants_->kDateTime)) { + v_ = internal::utilities::DateUtils::getDateTime(dateFormat, + f_, constants_, conf_->millisecondsWidth(Level::All)); + fs_ = conf_->dateFormatSpecifier(severity_); + internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); + } + // Function + if (f_ & constants_->kFunction) { + v_ = std::string(func_); + fs_ = constants_->FUNCTION_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); + } + // Location + if (f_ & constants_->kLocation) { + tempss_ << file_ << ":" << line_; + fs_ = constants_->LOCATION_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, tempss_.str(), currLine_, constants_); + tempss_.str(""); + } + // User + if (f_ & constants_->kUser) { + v_ = rl_->username(); + fs_ = constants_->USER_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); + } + // Host + if (f_ & constants_->kHost) { + v_ = rl_->hostname(); + fs_ = constants_->HOST_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); + } + // Verbose level + if ((severity_ == Level::Verbose) && (f_ & constants_->kVerboseLevel)) { + tempss_ << verboseLevel_; + fs_ = constants_->VERBOSE_LEVEL_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, tempss_.str(), currLine_, constants_); + } + // Log message + if (f_ & constants_->kLogMessage) { + fs_ = constants_->LOG_MESSAGE_FORMAT_SPECIFIER; + internal::utilities::LogManipulator::updateFormatValue(fs_, logger_->stream()->str(), currLine_, constants_); + } + log(); + } + +#if (defined(_ELPP_STRICT_ROLLOUT)) + bool checkRollOuts(unsigned int level_, Logger* baseLogger_) { + unsigned int validLevel_ = 0; + std::string rolledOutFile = std::string(); + if (baseLogger_->typedConfigurations_->checkRollOuts(level_, validLevel_, rolledOutFile)) { + Logger* currLogger_ = NULL; + for (unsigned int i = 0; i < registeredLoggers->count(); ++i) { + currLogger_ = registeredLoggers->list().at(i); + if (currLogger_ == baseLogger_) + continue; + std::string fname = currLogger_->typedConfigurations_->filename(validLevel_); + if (fname == rolledOutFile) { + currLogger_->typedConfigurations_->forceReinitiateFile(validLevel_, fname); + } + } + return true; + } + return false; + } +#endif // (defined(_ELPP_STRICT_ROLLOUT)) + + inline void syncWritePointer(unsigned int level_, Logger* targetLogger_, std::fstream* baseStream_) { + targetLogger_->acquireLock(); + targetLogger_->typedConfigurations_->fileStream(level_)->seekg(baseStream_->tellg()); + targetLogger_->releaseLock(); + } + + void safeWriteToFile(unsigned int level_, Logger* logger_, const std::string& line) { + std::string baseFilename_ = logger_->typedConfigurations_->filename(level_); + std::fstream* fstr = logger_->typedConfigurations_->fileStream(level_); + (*fstr) << line; + fstr->flush(); + Logger* currLogger_ = NULL; + for (std::size_t i = 0; i < registeredLoggers->count(); ++i) { + currLogger_ = registeredLoggers->list().at(i); + if (currLogger_ == logger_) + continue; + std::string fname = currLogger_->typedConfigurations_->filename(level_); + if (fname == baseFilename_) { + syncWritePointer(level_, currLogger_, fstr); + } + } + } + + void log(void) { + if (logger_->stream_) { + if (logger_->typedConfigurations_->toFile(severity_)) { + safeWriteToFile(severity_, logger_, currLine_); + } + if (logger_->typedConfigurations_->toStandardOutput(severity_)) { + std::cout << currLine_; + } + logger_->stream_->str(""); + } + } +}; +} // namespace internal + +class VersionInfo : private internal::StaticClass { +public: + // Minimal formatted displayable information + static inline const std::string formattedInfo(void) { + std::stringstream ss; + ss << "EasyLogging++ v" << version() << " (" << releaseDate() << ")"; + ss << std::endl; + ss << website(); + ss << std::endl; + ss << copyright(); + return ss.str(); + } + + // Current version number + static inline const std::string version(void) { return std::string("8.91"); } + + // Release date of current version + static inline const std::string releaseDate(void) { return std::string("12-07-2013 1243hrs"); } + + // Original author and maintainer + static inline const std::string author(void) { return std::string("Majid Khan "); } + + // Web link + static inline const std::string website(void) { return std::string("http://icplusplus.com/tools/easylogging"); } + + // Link to source code + static inline const std::string sourceCodeLink(void) { return std::string("https://github.com/mkhan3189/EasyLoggingPP"); } + + // Copyright information + static inline const std::string copyright(void) { return std::string("Copyright (c) 2012 - 2013 Majid Khan"); } + + // Full licence + static const std::string licence(void) { + std::stringstream ss; + ss << " This software is provided 'as-is', without any express or implied" << std::endl; + ss << " warranty. In no event will the authors be held liable for any damages" << std::endl; + ss << " arising from the use of this software." << std::endl; + ss << std::endl; + ss << " Permission is granted to anyone to use this software for any purpose," << std::endl; + ss << " including commercial applications, and to alter it and redistribute" << std::endl; + ss << " it freely, subject to the following restrictions:" << std::endl; + ss << std::endl; + ss << " 1. The origin of this software must not be misrepresented; you must" << std::endl; + ss << " not claim that you wrote the original software. If you use this" << std::endl; + ss << " software in a product, an acknowledgment in the product documentation" << std::endl; + ss << " would be appreciated but is not required." << std::endl; + ss << std::endl; + ss << " 2. Altered source versions must be plainly marked as such, and must" << std::endl; + ss << " not be misrepresented as being the original software." << std::endl; + ss << std::endl; + ss << " 3. This notice may not be removed or altered from any source" << std::endl; + ss << " distribution"; + return ss.str(); + } +}; // class VersionInfo + +//! +//! \brief Helper class to manage loggers and configurations +//! +//! A static helper class for users of library. This class contains functions related to register +//! and configure logger/s +//! +class Loggers : private internal::StaticClass { +public: + + //! + //! Get existing logger, if logger does not exist a newly created logger is returned + //! \param identifier_ A unique ID for logger + //! \return Pointer to easyloggingpp::Logger from logger repository + //! + static inline Logger* getLogger(const std::string& identifier_) { + return internal::registeredLoggers->get(identifier_); + } + + //! + //! Reconfigures logger with easyloggingpp::Configurations + //! \param logger_ Pointer to Logger to configure. You get use getLogger() to get pointer from logger repository + //! \param configurations_ easyloggingpp::Configurations to configure logger against + //! \return Updated pointer to Logger + //! + static inline Logger* reconfigureLogger(Logger* logger_, const Configurations& configurations_) { + if (!logger_) return NULL; + logger_->configure(configurations_); + return logger_; + } + + //! + //! Reconfigures logger with easyloggingpp::Configurations + //! \param identifier_ Logger ID + //! \param configurations_ easyloggingpp::Configurations to configure logger against + //! \return Updated pointer to Logger + //! + static inline Logger* reconfigureLogger(const std::string& identifier_, Configurations& configurations_) { + Logger* logger_ = Loggers::getLogger(identifier_); + Loggers::reconfigureLogger(logger_, configurations_); + return logger_; + } + + //! + //! Reconfigures all loggers available in logger repository + //! \param configurations_ easyloggingpp::Configurations to configure logger against + //! + static inline void reconfigureAllLoggers(Configurations& configurations_) { + for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) { + Logger* l = internal::registeredLoggers->at(i); + Loggers::reconfigureLogger(l, configurations_); + } + } + + //! + //! Reconfigures all loggers for single configuration. + //! \param configurationType_ Configuration type to update. Use easyloggingpp::ConfigurationType to prevent confusion + //! \param value_ Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values + //! use them in quotes. They will be parsed when configuring + //! + static inline void reconfigureAllLoggers(unsigned int configurationType_, const std::string& value_) { + for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) { + Logger* l = internal::registeredLoggers->at(i); + l->configurations().setAll(configurationType_, value_); + l->reconfigure(); + } + } + + //! + //! Sets default configurations. This configuration is used for future loggers. + //! \param configurations + //! \param configureExistingLoggers If true, all loggers are updated against provided configuration otherwise only future loggers + //! will be updated and all the existing loggers will use configurations that have been set previously. + //! + static inline void setDefaultConfigurations(Configurations& configurations, bool configureExistingLoggers = false) { + internal::registeredLoggers->setDefaultConfigurations(configurations); + if (configureExistingLoggers) { + Loggers::reconfigureAllLoggers(configurations); + } + } + + //! + //! Sets application arguments and uses them where needed. Example use is when application is run with '--v=X' or '-v', verbose logging + //! turns on + //! \param argc Argument count + //! \param argv Argument value array pointer + //! + static inline void setApplicationArguments(int argc, char** argv) { + internal::registeredLoggers->setApplicationArguments(argc, argv); + } + + //! + //! Sets application arguments and uses them where needed. Example use is when application is run with '--v=X' or '-v', verbose logging + //! turns on + //! \param argc + //! \param argv + //! + static inline void setApplicationArguments(int argc, const char** argv) { + internal::registeredLoggers->setApplicationArguments(argc, argv); + } + + //! + //! Disables all loggers + //! + static inline void disableAll(void) { + reconfigureAllLoggers(ConfigurationType::Enabled, "false"); + } + + //! + //! Enable all loggers + //! + static inline void enableAll(void) { + reconfigureAllLoggers(ConfigurationType::Enabled, "true"); + } + + //! + //! Reconfigure all loggers to write to single log file + //! \param logFilename_ Full path to log file + //! + static inline void setFilename(const std::string& logFilename_) { + reconfigureAllLoggers(ConfigurationType::Filename, logFilename_); + } + + //! + //! Reconfigure specified logger to write to specified log file + //! \param logger_ Pointer to logger. You may use Loggers::get(id) to get pointer + //! \param logFilename_ Full path to log file + //! + static inline void setFilename(Logger* logger_, const std::string& logFilename_) { + if (!logger_) return; + logger_->configurations().setAll(ConfigurationType::Filename, logFilename_); + logger_->reconfigure(); + } + + //! + //! Determines whether or not performance tracking is enabled + //! \return True if enabled, false otherwise + //! + static inline bool performanceTrackingEnabled(void) { + return performanceLogger()->typedConfigurations_->performanceTracking(); + } + + //! + //! Disables performance tracking. + //! Performance tracking is logged using 'performance' logger. + //! + static inline void disablePerformanceTracking(void) { + Logger* l = Loggers::performanceLogger(); + l->configurations().setAll(ConfigurationType::PerformanceTracking, "false"); + l->reconfigure(); + } + + //! + //! Enable performance tracking + //! Performance tracking is logged using 'performance' logger. + //! + static inline void enablePerformanceTracking(void) { + Logger* l = Loggers::performanceLogger(); + l->configurations().setAll(ConfigurationType::PerformanceTracking, "true"); + l->reconfigure(); + } + + //! + //! Iterates through logger repository and puts IDs into listOfIds + //! \param listOfIds (Passed by reference) Vector to fill up + //! + static inline void getAllLogIdentifiers(std::vector& listOfIds) { + listOfIds.clear(); + for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) { + listOfIds.push_back(internal::registeredLoggers->at(i)->id()); + } + } + + //! + //! \return Returns one of default loggers 'trivial' logger + //! + static inline Logger* trivialLogger(void) { + return Loggers::getLogger("trivial"); + } + + //! + //! \return Returns one of default loggers 'business' logger + //! + static inline Logger* businessLogger(void) { + return Loggers::getLogger("business"); + } + + //! + //! \return Returns one of default loggers 'security' logger + //! + static inline Logger* securityLogger(void) { + return Loggers::getLogger("security"); + } + + //! + //! \return Returns one of default loggers 'performance' logger + //! + static inline Logger* performanceLogger(void) { + return Loggers::getLogger("performance"); + } + + //! + //! Static class that contains static helper functions used to read configurations + //! + class ConfigurationsReader : private internal::StaticClass { + public: + static inline bool enabled(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->enabled(level_); + } + + static inline bool enabled(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->enabled(level_); + } + + static inline bool toFile(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->toFile(level_); + } + + static inline bool toFile(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->toFile(level_); + } + + static inline const std::string& filename(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->filename(level_); + } + + static inline const std::string& filename(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->filename(level_); + } + + static inline bool toStandardOutput(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->toStandardOutput(level_); + } + + static inline bool toStandardOutput(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->toStandardOutput(level_); + } + + static inline const std::string& logFormat(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->logFormat(level_); + } + + static inline const std::string& logFormat(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->logFormat(level_); + } + + static inline int millisecondsWidth(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->millisecondsWidth(level_); + } + + static inline int millisecondsWidth(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->millisecondsWidth(level_); + } + + static inline bool performanceTracking(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->performanceTracking(level_); + } + + static inline bool performanceTracking(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->performanceTracking(level_); + } + + static inline std::size_t logRollOutSize(Logger* logger_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); + return constConf(logger_)->rollOutSize(level_); + } + + static inline std::size_t logRollOutSize(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { + __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); + return conf_->rollOutSize(level_); + } + + private: + static inline internal::TypedConfigurations* constConf(Logger* logger_) { + return logger_->typedConfigurations_; + } + }; // class ConfigurationsReader +private: + internal::threading::Mutex mutex_; +}; +// +// Helping Macros +// +// Performance tracking macros +#if ((!defined(_DISABLE_PERFORMANCE_TRACKING)) || (!defined(_DISABLE_INFO_LOGS))) +# if _ELPP_OS_UNIX +# define _ELPP_GET_CURR_TIME(tm) gettimeofday(tm, NULL); +# elif _ELPP_OS_WINDOWS +# define _ELPP_GET_CURR_TIME(tm) easyloggingpp::internal::utilities::DateUtils::gettimeofday(tm); +# endif +# define START_FUNCTION_LOG "Executing [" << __func__ << "]" +# define TIME_OUTPUT "Executed [" << __func__ << "] in [" << \ + easyloggingpp::internal::utilities::DateUtils::formatMilliSeconds( \ + easyloggingpp::internal::utilities::DateUtils::getTimeDifference(functionEndTime, functionStartTime)) << "]" +# define FUNC_SUB_COMMON_START { timeval functionStartTime, functionEndTime; _ELPP_GET_CURR_TIME(&functionStartTime) +# define WRITE_FUNC_PERFORMANCE _ELPP_GET_CURR_TIME(&functionEndTime); \ + if (easyloggingpp::Loggers::performanceTrackingEnabled()) { PINFO << TIME_OUTPUT; } +# define FUNC_SUB_COMMON_END WRITE_FUNC_PERFORMANCE; +# define SUB(FUNCTION_NAME,PARAMS) void FUNCTION_NAME PARAMS FUNC_SUB_COMMON_START +# define END_SUB FUNC_SUB_COMMON_END } +# define FUNC(RETURNING_TYPE,FUNCTION_NAME,PARAMS) RETURNING_TYPE FUNCTION_NAME PARAMS FUNC_SUB_COMMON_START +# define RETURN(return_value) FUNC_SUB_COMMON_END return return_value; +# define END_FUNC(return_value) RETURN(return_value) } +# define MAIN(argc, argv) FUNC(int, main, (argc, argv)) +# define END_MAIN(return_value) FUNC_SUB_COMMON_END; return return_value; } +# define RETURN_MAIN(exit_status) return exit_status; +#else +# define SUB(FUNCTION_NAME,PARAMS) void FUNCTION_NAME PARAMS { +# define END_SUB } +# define FUNC(RETURNING_TYPE,FUNCTION_NAME,PARAMS) RETURNING_TYPE FUNCTION_NAME PARAMS { +# define END_FUNC(x) return x; } +# define RETURN(expr) return expr; +# define MAIN(argc, argv) FUNC(int, main, (argc, argv)) +# define END_MAIN(x) return x; } +# define RETURN_MAIN(exit_status) return exit_status; +#endif // ((!defined(_DISABLE_PERFORMANCE_TRACKING)) || (!defined(_DISABLE_INFO_LOGS))) + +#define _ELPP_LOG_WRITER(_logger, _level) easyloggingpp::internal::Writer(\ + _logger, easyloggingpp::internal::Aspect::Normal, _level, __func__, __FILE__, __LINE__) +#define _ELPP_LOG_WRITER_COND(_c, _logger, _level) if (_c) easyloggingpp::internal::Writer(\ + _logger, easyloggingpp::internal::Aspect::Conditional, _level, __func__, __FILE__, __LINE__, _c) +#define _ELPP_LOG_WRITER_N(_n, _logger, _level) if (easyloggingpp::internal::registeredLoggers->validateCounter(\ + __FILE__, __LINE__, _n)) easyloggingpp::internal::Writer(_logger, easyloggingpp::internal::Aspect::Interval,\ + _level, __func__, __FILE__, __LINE__, true, 0, _n) +#undef VLOG_IS_ON +#define VLOG_IS_ON(verboseLevel) verboseLevel <= easyloggingpp::internal::registeredLoggers->constants()->CURRENT_VERBOSE_LEVEL +// Undef levels to support LOG(LEVEL) +#undef INFO +#undef DEBUG +#undef ERROR +#undef FATAL +#undef QA +#undef TRACE +#undef VERBOSE +// +// Custom loggers - macro names with levels - requires loggerId +// +// Undef existing +#undef CINFO +#undef CWARNING +#undef CDEBUG +#undef CERROR +#undef CFATAL +#undef ERROR +#undef CQA +#undef CTRACE +#undef CVERBOSE +#undef CINFO_IF +#undef CWARNING_IF +#undef CDEBUG_IF +#undef CERROR_IF +#undef CFATAL_IF +#undef ERROR_IF +#undef CQA_IF +#undef CTRACE_IF +#undef CVERBOSE_IF +#undef CINFO_EVERY_N +#undef CWARNING_EVERY_N +#undef CDEBUG_EVERY_N +#undef CERROR_EVERY_N +#undef CFATAL_EVERY_N +#undef ERROR_EVERY_N +#undef CQA_EVERY_N +#undef CTRACE_EVERY_N +#undef CVERBOSE_EVERY_N +// Normal logs +#if _ELPP_INFO_LOG +# define CINFO(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Info) +#else +# define CINFO(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_INFO_LOG +#if _ELPP_WARNING_LOG +# define CWARNING(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Warning) +#else +# define CWARNING(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_WARNING_LOG +#if _ELPP_DEBUG_LOG +# define CDEBUG(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Debug) +#else +# define CDEBUG(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_DEBUG_LOG +#if _ELPP_ERROR_LOG +# define CERROR(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Error) +#else +# define CERROR(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_ERROR_LOG +#if _ELPP_FATAL_LOG +# define CFATAL(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Fatal) +#else +# define CFATAL(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_FATAL_LOG +#if _ELPP_QA_LOG +# define CQA(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::QA) +#else +# define CQA(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_QA_LOG +#if _ELPP_TRACE_LOG +# define CTRACE(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Trace) +#else +# define CTRACE(loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_TRACE_LOG +#if _ELPP_VERBOSE_LOG +# define CVERBOSE(vlevel_, loggerId) easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Normal, \ + easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, true, vlevel_) +#else +# define CVERBOSE(vlevel_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_VERBOSE_LOG +// Conditional logs +#if _ELPP_INFO_LOG +# define CINFO_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Info) +#else +# define CINFO_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_INFO_LOG +#if _ELPP_WARNING_LOG +# define CWARNING_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Warning) +#else +# define CWARNING_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_WARNING_LOG +#if _ELPP_DEBUG_LOG +# define CDEBUG_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Debug) +#else +# define CDEBUG_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_DEBUG_LOG +#if _ELPP_ERROR_LOG +# define CERROR_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Error) +#else +# define CERROR_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_ERROR_LOG +#if _ELPP_FATAL_LOG +# define CFATAL_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Fatal) +#else +# define CFATAL_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_FATAL_LOG +#if _ELPP_QA_LOG +# define CQA_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::QA) +#else +# define CQA_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_QA_LOG +#if _ELPP_TRACE_LOG +# define CTRACE_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Trace) +#else +# define CTRACE_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_TRACE_LOG +#if _ELPP_VERBOSE_LOG +# define CVERBOSE_IF(condition_, vlevel_, loggerId) if (condition_) easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Conditional, \ + easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, condition_, vlevel_) +#else +# define CVERBOSE_IF(condition_, vlevel_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_VERBOSE_LOG +// Interval logs +#if _ELPP_INFO_LOG +# define CINFO_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Info) +#else +# define CINFO_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_INFO_LOG +#if _ELPP_WARNING_LOG +# define CWARNING_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Warning) +#else +# define CWARNING_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_WARNING_LOG +#if _ELPP_DEBUG_LOG +# define CDEBUG_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Debug) +#else +# define CDEBUG_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_DEBUG_LOG +#if _ELPP_ERROR_LOG +# define CERROR_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Error) +#else +# define CERROR_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_ERROR_LOG +#if _ELPP_FATAL_LOG +# define CFATAL_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Fatal) +#else +# define CFATAL_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_FATAL_LOG +#if _ELPP_QA_LOG +# define CQA_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::QA) +#else +# define CQA_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_QA_LOG +#if _ELPP_TRACE_LOG +# define CTRACE_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Trace) +#else +# define CTRACE_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_TRACE_LOG +#if _ELPP_VERBOSE_LOG +# define CVERBOSE_EVERY_N(interval_, vlevel_, loggerId) if (easyloggingpp::internal::registeredLoggers->validateCounter(__FILE__, __LINE__, interval_)) \ + easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Interval, \ + easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, true, vlevel_, interval_) +#else +# define CVERBOSE_EVERY_N(interval_, vlevel_, loggerId) easyloggingpp::internal::NullWriter() +#endif // _ELPP_VERBOSE_LOG +// +// Custom Loggers - Requires (level, loggerId) +// +// undef existing +#undef CLOG +#undef CLOG_VERBOSE +#undef CVLOG +#undef CLOG_IF +#undef CLOG_VERBOSE_IF +#undef CVLOG_IF +#undef CLOG_EVERY_N +#undef CLOG_VERBOSE_EVERY_N +#undef CVLOG_EVERY_N +// Normal logs +#define CLOG(LEVEL, loggerId) C##LEVEL(loggerId) +#define CLOG_VERBOSE(vlevel, loggerId) CVERBOSE(vlevel, loggerId) +#define CVLOG(vlevel, loggerId) CVERBOSE(vlevel, loggerId) +// Conditional logs +#define CLOG_IF(condition, LEVEL, loggerId) C##LEVEL##_IF(condition, loggerId) +#define CLOG_VERBOSE_IF(condition, vlevel, loggerId) CVERBOSE_IF(condition, vlevel, loggerId) +#define CVLOG_IF(condition, vlevel, loggerId) CVERBOSE_IF(condition, vlevel, loggerId) +// Interval logs +#define CLOG_EVERY_N(n, LEVEL, loggerId) C##LEVEL##_EVERY_N(n, loggerId) +#define CLOG_VERBOSE_EVERY_N(n, vlevel, loggerId) CVERBOSE_EVERY_N(n, vlevel, loggerId) +#define CVLOG_EVERY_N(n, vlevel, loggerId) CVERBOSE_EVERY_N(n, vlevel, loggerId) +// +// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros +// +// undef existing +#undef LOG +#undef LOG_VERBOSE +#undef VLOG +#undef LOG_IF +#undef LOG_VERBOSE_IF +#undef VLOG_IF +#undef LOG_EVERY_N +#undef LOG_VERBOSE_EVERY_N +#undef VLOG_EVERY_N +// Normal logs +#define LOG(LEVEL) CLOG(LEVEL, "trivial") +#define LOG_VERBOSE(vlevel) CLOG_VERBOSE(vlevel, "trivial") +#define VLOG(vlevel) CVLOG(vlevel, "trivial") +// Conditional logs +#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, "trivial") +#define LOG_VERBOSE_IF(condition, vlevel) CLOG_VERBOSE_IF(condition, vlevel, "trivial") +#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, "trivial") +// Interval logs +#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, "trivial") +#define LOG_VERBOSE_EVERY_N(n, vlevel) CLOG_VERBOSE_EVERY_N(n, vlevel, "trivial") +#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, "trivial") +// +// Default Loggers macro using C##LEVEL("trivial") +// +// undef existing +#undef LINFO +#undef LWARNING +#undef LDEBUG +#undef LERROR +#undef LFATAL +#undef LQA +#undef LTRACE +#undef LVERBOSE +#undef LINFO_IF +#undef LWARNING_IF +#undef LDEBUG_IF +#undef LERROR_IF +#undef LFATAL_IF +#undef LQA_IF +#undef LTRACE_IF +#undef LVERBOSE_IF +#undef LINFO_EVERY_N +#undef LWARNING_EVERY_N +#undef LDEBUG_EVERY_N +#undef LERROR_EVERY_N +#undef LFATAL_EVERY_N +#undef LQA_EVERY_N +#undef LTRACE_EVERY_N +#undef LVERBOSE_EVERY_N +// Normal logs +#define LINFO CINFO("trivial") +#define LWARNING CWARNING("trivial") +#define LDEBUG CDEBUG("trivial") +#define LERROR CERROR("trivial") +#define LFATAL CFATAL("trivial") +#define LQA CQA("trivial") +#define LTRACE CTRACE("trivial") +#define LVERBOSE(level) CVERBOSE(level, "trivial") +// Conditional logs +#define LINFO_IF(condition) CINFO_IF(condition, "trivial") +#define LWARNING_IF(condition) CWARNING_IF(condition, "trivial") +#define LDEBUG_IF(condition) CDEBUG_IF(condition, "trivial") +#define LERROR_IF(condition) CERROR_IF(condition, "trivial") +#define LFATAL_IF(condition) CFATAL_IF(condition, "trivial") +#define LQA_IF(condition) CQA_IF(condition, "trivial") +#define LTRACE_IF(condition) CTRACE_IF(condition, "trivial") +#define LVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "trivial") +// Interval logs +#define LINFO_EVERY_N(n) CINFO_EVERY_N(n, "trivial") +#define LWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "trivial") +#define LDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "trivial") +#define LERROR_EVERY_N(n) CERROR_EVERY_N(n, "trivial") +#define LFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "trivial") +#define LQA_EVERY_N(n) CQA_EVERY_N(n, "trivial") +#define LTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "trivial") +#define LVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "trivial") +// +// Default Loggers macro using C##LEVEL("business") +// +// undef existing +#undef BINFO +#undef BWARNING +#undef BDEBUG +#undef BERROR +#undef BFATAL +#undef BQA +#undef BTRACE +#undef BVERBOSE +#undef BINFO_IF +#undef BWARNING_IF +#undef BDEBUG_IF +#undef BERROR_IF +#undef BFATAL_IF +#undef BQA_IF +#undef BTRACE_IF +#undef BVERBOSE_IF +#undef BINFO_EVERY_N +#undef BWARNING_EVERY_N +#undef BDEBUG_EVERY_N +#undef BERROR_EVERY_N +#undef BFATAL_EVERY_N +#undef BQA_EVERY_N +#undef BTRACE_EVERY_N +#undef BVERBOSE_EVERY_N +// Normal logs +#define BINFO CINFO("business") +#define BWARNING CWARNING("business") +#define BDEBUG CDEBUG("business") +#define BERROR CERROR("business") +#define BFATAL CFATAL("business") +#define BQA CQA("business") +#define BTRACE CTRACE("business") +#define BVERBOSE(level) CVERBOSE(level, "business") +// Conditional logs +#define BINFO_IF(condition) CINFO_IF(condition, "business") +#define BWARNING_IF(condition) CWARNING_IF(condition, "business") +#define BDEBUG_IF(condition) CDEBUG_IF(condition, "business") +#define BERROR_IF(condition) CERROR_IF(condition, "business") +#define BFATAL_IF(condition) CFATAL_IF(condition, "business") +#define BQA_IF(condition) CQA_IF(condition, "business") +#define BTRACE_IF(condition) CTRACE_IF(condition, "business") +#define BVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "business") +// Interval logs +#define BINFO_EVERY_N(n) CINFO_EVERY_N(n, "business") +#define BWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "business") +#define BDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "business") +#define BERROR_EVERY_N(n) CERROR_EVERY_N(n, "business") +#define BFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "business") +#define BQA_EVERY_N(n) CQA_EVERY_N(n, "business") +#define BTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "business") +#define BVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "business") +// +// Default Loggers macro using C##LEVEL("security") +// +// undef existing +#undef SINFO +#undef SWARNING +#undef SDEBUG +#undef SERROR +#undef SFATAL +#undef SQA +#undef STRACE +#undef SVERBOSE +#undef SINFO_IF +#undef SWARNING_IF +#undef SDEBUG_IF +#undef SERROR_IF +#undef SFATAL_IF +#undef SQA_IF +#undef STRACE_IF +#undef SVERBOSE_IF +#undef SINFO_EVERY_N +#undef SWARNING_EVERY_N +#undef SDEBUG_EVERY_N +#undef SERROR_EVERY_N +#undef SFATAL_EVERY_N +#undef SQA_EVERY_N +#undef STRACE_EVERY_N +#undef SVERBOSE_EVERY_N +// Normal logs +#define SINFO CINFO("security") +#define SWARNING CWARNING("security") +#define SDEBUG CDEBUG("security") +#define SERROR CERROR("security") +#define SFATAL CFATAL("security") +#define SQA CQA("security") +#define STRACE CTRACE("security") +#define SVERBOSE(level) CVERBOSE(level, "security") +// Conditional logs +#define SINFO_IF(condition) CINFO_IF(condition, "security") +#define SWARNING_IF(condition) CWARNING_IF(condition, "security") +#define SDEBUG_IF(condition) CDEBUG_IF(condition, "security") +#define SERROR_IF(condition) CERROR_IF(condition, "security") +#define SFATAL_IF(condition) CFATAL_IF(condition, "security") +#define SQA_IF(condition) CQA_IF(condition, "security") +#define STRACE_IF(condition) CQA_IF(condition, "security") +#define SVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "security") +// Interval logs +#define SINFO_EVERY_N(n) CINFO_EVERY_N(n, "security") +#define SWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "security") +#define SDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "security") +#define SERROR_EVERY_N(n) CERROR_EVERY_N(n, "security") +#define SFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "security") +#define SQA_EVERY_N(n) CQA_EVERY_N(n, "security") +#define STRACE_EVERY_N(n) CTRACE_EVERY_N(n, "security") +#define SVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "security") +// +// Default Loggers macro using C##LEVEL("performance") +// +// undef existing +#undef PINFO +#undef PWARNING +#undef PDEBUG +#undef PERROR +#undef PFATAL +#undef PQA +#undef PTRACE +#undef PVERBOSE +#undef PINFO_IF +#undef PWARNING_IF +#undef PDEBUG_IF +#undef PERROR_IF +#undef PFATAL_IF +#undef PQA_IF +#undef PTRACE_IF +#undef PVERBOSE_IF +#undef PINFO_EVERY_N +#undef PWARNING_EVERY_N +#undef PDEBUG_EVERY_N +#undef PERROR_EVERY_N +#undef PFATAL_EVERY_N +#undef PQA_EVERY_N +#undef PTRACE_EVERY_N +#undef PVERBOSE_EVERY_N +// Normal logs +#define PINFO CINFO("performance") +#define PWARNING CWARNING("performance") +#define PDEBUG CDEBUG("performance") +#define PERROR CERROR("performance") +#define PFATAL CFATAL("performance") +#define PQA CQA("performance") +#define PTRACE CTRACE("performance") +#define PVERBOSE(level) CVERBOSE(level, "performance") +// Conditional logs +#define PINFO_IF(condition) CINFO_IF(condition, "performance") +#define PWARNING_IF(condition) CWARNING_IF(condition, "performance") +#define PDEBUG_IF(condition) CDEBUG_IF(condition, "performance") +#define PERROR_IF(condition) CERROR_IF(condition, "performance") +#define PFATAL_IF(condition) CFATAL_IF(condition, "performance") +#define PQA_IF(condition) CQA_IF(condition, "performance") +#define PTRACE_IF(condition) CQA_IF(condition, "performance") +#define PVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "performance") +// Interval logs +#define PINFO_EVERY_N(n) CINFO_EVERY_N(n, "performance") +#define PWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "performance") +#define PDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "performance") +#define PERROR_EVERY_N(n) CERROR_EVERY_N(n, "performance") +#define PFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "performance") +#define PQA_EVERY_N(n) CQA_EVERY_N(n, "performance") +#define PTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "performance") +#define PVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "performance") +// Undefine macros that are not needed anymore +#undef _ELPP_ASSEMBLY_SUPPORTED +#undef _ELPP_STREAM +#undef _ELPP_MUTEX_LOCK_GNU_ASM +#undef _ELPP_MUTEX_UNLOCK_GNU_ASM +#undef _ELPP_ENABLE_MUTEX +#undef _ENABLE_EASYLOGGING +#undef __EASYLOGGINGPP_SUPPRESS_UNSED +#undef _ELPP_DEBUG_LOG +#undef _ELPP_INFO_LOG +#undef _ELPP_WARNING_LOG +#undef _ELPP_ERROR_LOG +#undef _ELPP_FATAL_LOG +#undef _ELPP_QA_LOG +#undef _ELPP_VERBOSE_LOG +#undef _ELPP_TRACE_LOG +#undef _INITIALIZE_EASYLOGGINGPP +#undef _START_EASYLOGGINGPP +#undef _ELPP_COUNTER +#undef _ELPP_COUNTER_POSITION +#define _INITIALIZE_EASYLOGGINGPP \ + namespace easyloggingpp { \ + namespace internal { \ + ScopedPointer registeredLoggers( \ + new RegisteredLoggers()); \ + } \ + } +#define _START_EASYLOGGINGPP(argc, argv) easyloggingpp::Loggers::setApplicationArguments(argc, argv); +#define _ELPP_COUNTER easyloggingpp::internal::registeredLoggers->counters()->get(__FILE__, __LINE__) +#define _ELPP_COUNTER_POSITION (_ELPP_COUNTER == NULL ? 0 : _ELPP_COUNTER->position()) +} // easyloggingpp +#endif // EASYLOGGINGPP_H diff --git a/WXom062/epm_handler_common.h b/WXom062/epm_handler_common.h new file mode 100644 index 0000000..deb67ab --- /dev/null +++ b/WXom062/epm_handler_common.h @@ -0,0 +1,18 @@ +#ifndef EPM_HANDLER_COMMON +#define EPM_HANDLER_COMMON + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + //user service end +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/WXom062/error_handling.h b/WXom062/error_handling.h new file mode 100644 index 0000000..d38f49d --- /dev/null +++ b/WXom062/error_handling.h @@ -0,0 +1,164 @@ +/*! +* @addtogroup common +* \file error_handling.h +* \brief +* \date 2008/6/10 +* \author Ray Li +*/ + +#ifndef SIMPLE_ERR_H_INCLUDED +#define SIMPLE_ERR_H_INCLUDED + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define BUFSIZE 512 + + +// +#define HANDLER_ARGUMENT_ERROR EMH_USER_error_base + 1 +//#define WORKFLOW_NODE_IS_NOT_VALID EMH_USER_error_base + 2 + +#define ERROR_STATUS_ERROR EMH_USER_error_base + 2 +//#define HANDLER_PLACED_INVALID EMH_USER_error_base + 3 +// +////user errors define +////վļȱ %1$ ã +//#define ERROR_PREFERENCE_NOT_FOUND (EMH_USER_error_base + 100) + + +#define DOFREE(obj) \ +{ \ + if(obj) \ + { \ + MEM_free(obj); \ + obj = NULL; \ + } \ +} + + + +//#define ECHO(X) printf X; +#define SYS_LOG(X) IMAN_write_syslog X; +#define LOG_ECHO(X) printf X; IMAN_write_syslog X; + + + +/*! +* \def CALL(x) +* ӡϢ +*/ +#define CALL(x) { \ + int stat; \ + char *err_string; \ + if( (stat = (x)) != ITK_ok) \ + { \ + EMH_ask_error_text (stat, &err_string); \ + LOG_ECHO( ("ERROR: %d ERROR MSG: %s.\n",stat, err_string) ) \ + LOG_ECHO( ("Function: %s FILE: %s LINE: %d\n", #x, __FILE__, __LINE__ ) ) \ + MEM_free (err_string); \ + return (stat); \ + } \ +} + +/*! +* \def DO(x) +* ӡϢ +*/ +#define DO(x) { \ + int stat; \ + char *err_string; \ + if( (stat = (x)) != POM_ok) \ + { \ + EMH_ask_error_text (stat, &err_string); \ + printf ("ERROR: %d ERROR MSG: %s.\n", stat, err_string); \ + printf ("Function: %s FILE: %s LINE: %d\n",#x, __FILE__, __LINE__); \ + MEM_free (err_string); \ + } \ +} + +/*! +* \def CALLRNULL(x) +* ӡϢ +*/ +#define CALLRNULL(x) { \ + int stat; \ + char *err_string; \ + if( (stat = (x)) != ITK_ok) \ + { \ + EMH_ask_error_text (stat, &err_string); \ + printf ("ERROR: %d ERROR MSG: %s.\n", stat, err_string); \ + printf ("Function: %s FILE: %s LINE: %d\n",#x, __FILE__, __LINE__); \ + MEM_free (err_string); \ + return ((char *)NULL); \ + } \ +} + +/*! +* \def CALL2(x) +* ӡϢ +*/ +#define CALL2(x) { \ + int stat, n_ifails, *serverities, *ifails, err_count; \ + char *err_string, **texts; \ + if( (stat = (x)) != ITK_ok) \ + { \ + printf ("Function: %s FILE: %s LINE: %d\n",#x, __FILE__, __LINE__); \ + EMH_ask_errors( &n_ifails, (const int**)(&serverities), (const int**)(&ifails), (const char***)(&texts) );\ + for( err_count=0; err_count vectorChars(nLength); + _vsnprintf(vectorChars.data(), nLength, pszFmt, args); + str.assign(vectorChars.data()); + } + va_end(args); + return str; +} +//ѯ +int queryResult(string queryName,map fields,vector *result) +{ + tag_t query; + QRY_find2(queryName.c_str(), &query); + if (query == NULL) + { + LINFO << "δҵѯ[" << queryName << "]"; + return 0; + } + int size = fields.size(); + char **entries, **vals; + entries = (char **)MEM_alloc(size * sizeof(char *)); + vals = (char **)MEM_alloc(size* sizeof(char *)); + int index = 0; + for (auto it = fields.begin(); it != fields.end(); it++) + { + string key = it->first.c_str(); + string value = it->second.c_str(); + entries[index] = (char *)MEM_alloc((key.size()+1)*sizeof(char)); + vals[index] = (char *)MEM_alloc((value.size() + 1)*sizeof(char)); + strcpy(entries[index], key.c_str()); + strcpy(vals[index], value.c_str()); + //LINFO << index << "ѯĿ:[" << entries[index] << "];ֵ:[" << vals[index]<<"]"; + index++; + } + //LINFO << "òѯ:"; + tag_t *item_revs; + int count; + SAFECALL(QRY_execute(query, 1, entries, vals, &count, &item_revs)); + for (auto i = 0; i < count; i++) + { + (*result).push_back(item_revs[i]); + } + //LINFO << "ȡ:" << (*result).size(); + DOFREE(item_revs); + DOFREE(entries); + DOFREE(vals); + + //LINFO << "ѯ"; + return 0; +} diff --git a/WXom062/kutil.h b/WXom062/kutil.h new file mode 100644 index 0000000..552419e --- /dev/null +++ b/WXom062/kutil.h @@ -0,0 +1,62 @@ +#include "tc_util.h" +//#include "util.h" + + + +typedef struct +{ + string ebCnCode; + string ebUpperId; + string ebLine; + string ebGoodsCode; + string ebQty; + string ebTeRe; + string ebSign; + string edId; + tag_t rev; + tag_t item; + +}CcemEb_child; + +typedef struct +{ + string ebGoodsCode; + string ebCnCode; + string ebTeRe; + string zt2_MaterialNo; + string ebId; + vector childs; + tag_t rev; + tag_t item; +}CcemEb_parent; + + + + + + + + +/*ϴݿ*/ +typedef struct +{ + //string url = "10.128.10.135:1433:1433@CHINT_DB"; + //string user = "PLMUser"; + //string password = "PLMUser"; +} dbProperties_CC; + + +typedef struct +{ + tag_t factoryNo; //Ŷ + string factoryNo_id; //ID + vector list_FnCnCodes; //淶 + vector boms; //淶ӦBOM + +}CcemFactoryBean; + +bool isEmpty(const char str); +bool isEmpty(string &str); +std::string format(const char *pszFmt, ...); +//ѯ +int queryResult(string queryName, map fields, vector *result); \ No newline at end of file diff --git a/WXom062/rapidjson/allocators.h b/WXom062/rapidjson/allocators.h new file mode 100644 index 0000000..655f4a3 --- /dev/null +++ b/WXom062/rapidjson/allocators.h @@ -0,0 +1,271 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \note implements Allocator concept +*/ +class CrtAllocator { +public: + static const bool kNeedFree = true; + void* Malloc(size_t size) { + if (size) // behavior of malloc(0) is implementation defined. + return std::malloc(size); + else + return NULL; // standardize to returning NULL. + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + (void)originalSize; + if (newSize == 0) { + std::free(originalPtr); + return NULL; + } + return std::realloc(originalPtr, newSize); + } + static void Free(void *ptr) { std::free(ptr); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \note implements Allocator concept +*/ +template +class MemoryPoolAllocator { +public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = reinterpret_cast(buffer); + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() { + Clear(); + RAPIDJSON_DELETE(ownBaseAllocator_); + } + + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() { + while (chunkHead_ && chunkHead_ != userBuffer_) { + ChunkHeader* next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + if (chunkHead_ && chunkHead_ == userBuffer_) + chunkHead_->size = 0; // Clear user buffer + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const { + size_t capacity = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const { + size_t size = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + if (!size) + return NULL; + + size = RAPIDJSON_ALIGN(size); + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) + return NULL; + + void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); + + if (newSize == 0) + return NULL; + + originalSize = RAPIDJSON_ALIGN(originalSize); + newSize = RAPIDJSON_ALIGN(newSize); + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { + size_t increment = static_cast(newSize - originalSize); + if (chunkHead_->size + increment <= chunkHead_->capacity) { + chunkHead_->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + if (void* newBuffer = Malloc(newSize)) { + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + else + return NULL; + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) { (void)ptr; } // Do nothing + +private: + //! Copy constructor is not permitted. + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; + //! Copy assignment operator is not permitted. + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; + + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + \return true if success. + */ + bool AddChunk(size_t capacity) { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + return true; + } + else + return false; + } + + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + void *userBuffer_; //!< User supplied buffer. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/WXom062/rapidjson/cursorstreamwrapper.h b/WXom062/rapidjson/cursorstreamwrapper.h new file mode 100644 index 0000000..52c11a7 --- /dev/null +++ b/WXom062/rapidjson/cursorstreamwrapper.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream& is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() { + Ch ch = this->is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const { return line_; } + //! Get the error column number, if error exists. + size_t GetColumn() const { return col_; } + +private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/WXom062/rapidjson/document.h b/WXom062/rapidjson/document.h new file mode 100644 index 0000000..a6acc24 --- /dev/null +++ b/WXom062/rapidjson/document.h @@ -0,0 +1,2660 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_DOCUMENT_H_ +#define RAPIDJSON_DOCUMENT_H_ + +/*! \file document.h */ + +#include "reader.h" +#include "internal/meta.h" +#include "internal/strfunc.h" +#include "memorystream.h" +#include "encodedstream.h" +#include // placement new +#include + +RAPIDJSON_DIAG_PUSH +#ifdef _MSC_VER +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 6 +RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions +#endif +#endif // __GNUC__ + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include // std::random_access_iterator_tag +#endif + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +// Forward declaration. +template +class GenericValue; + +template +class GenericDocument; + +//! Name-value pair in a JSON object value. +/*! + This class was internal to GenericValue. It used to be a inner struct. + But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. + https://code.google.com/p/rapidjson/issues/detail?id=64 +*/ +template +struct GenericMember { + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericMemberIterator + +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS + +//! (Constant) member iterator for a JSON object value +/*! + \tparam Const Is this a constant iterator? + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. + + This class implements a Random Access Iterator for GenericMember elements + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. + + \note This iterator implementation is mainly intended to avoid implicit + conversions from iterator values to \c NULL, + e.g. from GenericValue::FindMember. + + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + pointer-based implementation, if your platform doesn't provide + the C++ header. + + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator + */ +template +class GenericMemberIterator { + + friend class GenericValue; + template friend class GenericMemberIterator; + + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + +public: + //! Iterator type itself + typedef GenericMemberIterator Iterator; + //! Constant iterator type + typedef GenericMemberIterator ConstIterator; + //! Non-constant iterator type + typedef GenericMemberIterator NonConstIterator; + + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType * pointer; + typedef ValueType & reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} + + //! Pointer to (const) GenericMember + typedef pointer Pointer; + //! Reference to (const) GenericMember + typedef reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef difference_type DifferenceType; + + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} + + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from + + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) + + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} + Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } + + //! @name stepping + //@{ + Iterator& operator++(){ ++ptr_; return *this; } + Iterator& operator--(){ --ptr_; return *this; } + Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } + Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } + //@} + + //! @name increment/decrement + //@{ + Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } + Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } + + Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } + Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } + //@} + + //! @name relations + //@{ + bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } + bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } + bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } + bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } + bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } + bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } + //@} + + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} + + //! Distance + DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } + +private: + //! Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + + Pointer ptr_; //!< raw pointer +}; + +#else // RAPIDJSON_NOMEMBERITERATORCLASS + +// class-based member iterator implementation disabled, use plain pointers + +template +struct GenericMemberIterator; + +//! non-const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain pointer as iterator type + typedef GenericMember* Iterator; +}; +//! const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain const pointer as iterator type + typedef const GenericMember* Iterator; +}; + +#endif // RAPIDJSON_NOMEMBERITERATORCLASS + +/////////////////////////////////////////////////////////////////////////////// +// GenericStringRef + +//! Reference to a constant string (not taking a copy) +/*! + \tparam CharType character type of the string + + This helper class is used to automatically infer constant string + references for string literals, especially from \c const \b (!) + character arrays. + + The main use is for creating JSON string values without copying the + source string via an \ref Allocator. This requires that the referenced + string pointers have a sufficient lifetime, which exceeds the lifetime + of the associated GenericValue. + + \b Example + \code + Value v("foo"); // ok, no need to copy & calculate length + const char foo[] = "foo"; + v.SetString(foo); // ok + + const char* bar = foo; + // Value x(bar); // not ok, can't rely on bar's lifetime + Value x(StringRef(bar)); // lifetime explicitly guaranteed by user + Value y(StringRef(bar, 3)); // ok, explicitly pass length + \endcode + + \see StringRef, GenericValue::SetString +*/ +template +struct GenericStringRef { + typedef CharType Ch; //!< character type of the string + + //! Create string reference from \c const character array +#ifndef __clang__ // -Wdocumentation + /*! + This constructor implicitly creates a constant string reference from + a \c const character array. It has better performance than + \ref StringRef(const CharType*) by inferring the string \ref length + from the array length, and also supports strings containing null + characters. + + \tparam N length of the string, automatically inferred + + \param str Constant character array, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note Constant complexity. + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ +#endif + template + GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT + : s(str), length(N-1) {} + + //! Explicitly create string reference from \c const character pointer +#ifndef __clang__ // -Wdocumentation + /*! + This constructor can be used to \b explicitly create a reference to + a constant string pointer. + + \see StringRef(const CharType*) + + \param str Constant character pointer, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue + + \post \ref s == str + + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ +#endif + explicit GenericStringRef(const CharType* str) + : s(str), length(NotNullStrLen(str)) {} + + //! Create constant string reference from pointer and length +#ifndef __clang__ // -Wdocumentation + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param len length of the string, excluding the trailing NULL terminator + + \post \ref s == str && \ref length == len + \note Constant complexity. + */ +#endif + GenericStringRef(const CharType* str, SizeType len) + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } + + GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} + + //! implicit conversion to plain CharType pointer + operator const Ch *() const { return s; } + + const Ch* const s; //!< plain CharType pointer + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) + +private: + SizeType NotNullStrLen(const CharType* str) { + RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } + + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; + + //! Disallow construction from non-const array + template + GenericStringRef(CharType (&str)[N]) /* = delete */; + //! Copy assignment operator not permitted - immutable type + GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; +}; + +template +const CharType GenericStringRef::emptyString[] = { CharType() }; + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + \tparam CharType Character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + + \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember +*/ +template +inline GenericStringRef StringRef(const CharType* str) { + return GenericStringRef(str); +} + +//! Mark a character pointer as constant string +/*! Mark a plain character pointer as a "string literal". This function + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + This version has better performance with supplied length, and also + supports string containing null characters. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param length The length of source string. + \return GenericStringRef string reference object + \relatesalso GenericStringRef +*/ +template +inline GenericStringRef StringRef(const CharType* str, size_t length) { + return GenericStringRef(str, SizeType(length)); +} + +#if RAPIDJSON_HAS_STDSTRING +//! Mark a string object as constant string +/*! Mark a string object (e.g. \c std::string) as a "string literal". + This function can be used to avoid copying a string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. +*/ +template +inline GenericStringRef StringRef(const std::basic_string& str) { + return GenericStringRef(str.data(), SizeType(str.size())); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue type traits +namespace internal { + +template +struct IsGenericValueImpl : FalseType {}; + +// select candidates according to nested encoding and allocator types +template struct IsGenericValueImpl::Type, typename Void::Type> + : IsBaseOf, T>::Type {}; + +// helper to match arbitrary GenericValue instantiations, including derived classes +template struct IsGenericValue : IsGenericValueImpl::Type {}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// TypeHelper + +namespace internal { + +template +struct TypeHelper {}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsBool(); } + static bool Get(const ValueType& v) { return v.GetBool(); } + static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } + static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static int Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; + +#ifdef _MSC_VER +RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static long Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned long Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; +#endif + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt64(); } + static int64_t Get(const ValueType& v) { return v.GetInt64(); } + static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } + static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint64(); } + static uint64_t Get(const ValueType& v) { return v.GetUint64(); } + static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } + static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsDouble(); } + static double Get(const ValueType& v) { return v.GetDouble(); } + static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } + static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsFloat(); } + static float Get(const ValueType& v) { return v.GetFloat(); } + static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } + static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } +}; + +template +struct TypeHelper { + typedef const typename ValueType::Ch* StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return v.GetString(); } + static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } + static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; + +#if RAPIDJSON_HAS_STDSTRING +template +struct TypeHelper > { + typedef std::basic_string StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } + static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; +#endif + +template +struct TypeHelper { + typedef typename ValueType::Array ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstArray ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(const ValueType& v) { return v.GetArray(); } +}; + +template +struct TypeHelper { + typedef typename ValueType::Object ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstObject ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(const ValueType& v) { return v.GetObject(); } +}; + +} // namespace internal + +// Forward declarations +template class GenericArray; +template class GenericObject; + +/////////////////////////////////////////////////////////////////////////////// +// GenericValue + +//! Represents a JSON value. Use Value for UTF8 encoding and default allocator. +/*! + A JSON value can be one of 7 types. This class is a variant type supporting + these types. + + Use the Value if UTF8 and default allocator + + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. +*/ +template > +class GenericValue { +public: + //! Name-value pair in an object. + typedef GenericMember Member; + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericStringRef StringRefType; //!< Reference to a constant string + typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + typedef GenericValue ValueType; //!< Value type of itself. + typedef GenericArray Array; + typedef GenericArray ConstArray; + typedef GenericObject Object; + typedef GenericObject ConstObject; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor creates a null value. + GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { + rhs.data_.f.flags = kNullFlag; // give up contents + } +#endif + +private: + //! Copy constructor is not permitted. + GenericValue(const GenericValue& rhs); + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Moving from a GenericDocument is not permitted. + template + GenericValue(GenericDocument&& rhs); + + //! Move assignment from a GenericDocument is not permitted. + template + GenericValue& operator=(GenericDocument&& rhs); +#endif + +public: + + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { + static const uint16_t defaultFlags[7] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, + kNumberAnyFlag + }; + RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType); + data_.f.flags = defaultFlags[type]; + + // Use ShortString to store empty string. + if (type == kStringType) + data_.ss.SetLength(0); + } + + //! Explicit copy constructor (with allocator) + /*! Creates a copy of a Value by using the given Allocator + \tparam SourceAllocator allocator of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) + \see CopyFrom() + */ + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: { + SizeType count = rhs.data_.o.size; + Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); + } + data_.f.flags = kObjectFlag; + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } + break; + case kArrayType: { + SizeType count = rhs.data_.a.size; + GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + const GenericValue* re = rhs.GetElementsPointer(); + for (SizeType i = 0; i < count; i++) + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); + data_.f.flags = kArrayFlag; + data_.a.size = data_.a.capacity = count; + SetElementsPointer(le); + } + break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } + else + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } + } + + //! Constructor for boolean value. + /*! \param b Boolean value + \note This constructor is limited to \em real boolean values and rejects + implicitly converted types like arbitrary pointers. Use an explicit cast + to \c bool, if you want to construct a boolean JSON value in such cases. + */ +#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen + template + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 +#else + explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT +#endif + : data_() { + // safe-guard against failing SFINAE + RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + data_.f.flags = b ? kTrueFlag : kFalseFlag; + } + + //! Constructor for int value. + explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i; + data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; + } + + //! Constructor for unsigned value. + explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u; + data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); + } + + //! Constructor for int64_t value. + explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { + data_.n.i64 = i64; + data_.f.flags = kNumberInt64Flag; + if (i64 >= 0) { + data_.f.flags |= kNumberUint64Flag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + + //! Constructor for uint64_t value. + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { + data_.n.u64 = u64; + data_.f.flags = kNumberUint64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + data_.f.flags |= kInt64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + data_.f.flags |= kUintFlag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + data_.f.flags |= kIntFlag; + } + + //! Constructor for double value. + explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + + //! Constructor for float value. + explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } + + //! Constructor for constant string (i.e. do not make a copy of string) + explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor for copy-string from a string object (i.e. do make a copy of string) + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } +#endif + + //! Constructor for Array. + /*! + \param a An array obtained by \c GetArray(). + \note \c Array is always pass-by-value. + \note the source array is moved into this value and the sourec array becomes empty. + */ + GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { + a.value_.data_ = Data(); + a.value_.data_.f.flags = kArrayFlag; + } + + //! Constructor for Object. + /*! + \param o An object obtained by \c GetObject(). + \note \c Object is always pass-by-value. + \note the source object is moved into this value and the sourec object becomes empty. + */ + GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { + o.value_.data_ = Data(); + o.value_.data_.f.flags = kObjectFlag; + } + + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch(data_.f.flags) { + case kArrayFlag: + { + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(e); + } + break; + + case kObjectFlag: + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + Allocator::Free(GetMembersPointer()); + break; + + case kCopyStringFlag: + Allocator::Free(const_cast(GetStringPointer())); + break; + + default: + break; // Do nothing for other types. + } + } + } + + //@} + + //!@name Assignment operators + //@{ + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + RAPIDJSON_ASSERT(this != &rhs); + this->~GenericValue(); + RawAssign(rhs); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { + return *this = rhs.Move(); + } +#endif + + //! Assignment of constant string reference (no copy) + /*! \param str Constant string reference to be assigned + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. + \see GenericStringRef, operator=(T) + */ + GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { + GenericValue s(str); + return *this = s; + } + + //! Assignment with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value The value to be assigned. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref SetString(const Ch*, Allocator&) (for copying) or + \ref StringRef() (to explicitly mark the pointer as constant) instead. + All other pointer types would implicitly convert to \c bool, + use \ref SetBool() instead. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) + operator=(T value) { + GenericValue v(value); + return *this = v; + } + + //! Deep-copy assignment from Value + /*! Assigns a \b copy of the Value to the current Value object + \tparam SourceAllocator Allocator type of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) + */ + template + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); + this->~GenericValue(); + new (this) GenericValue(rhs, allocator, copyConstStrings); + return *this; + } + + //! Exchange the contents of this value with those of other. + /*! + \param other Another value. + \note Constant complexity. + */ + GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { + GenericValue temp; + temp.RawAssign(*this); + RawAssign(other); + other.RawAssign(temp); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Prepare Value for move semantics + /*! \return *this */ + GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } + //@} + + //!@name Equal-to and not-equal-to operators + //@{ + //! Equal-to operator + /*! + \note If an object contains duplicated named member, comparing equality with any object is always \c false. + \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + */ + template + bool operator==(const GenericValue& rhs) const { + typedef GenericValue RhsType; + if (GetType() != rhs.GetType()) + return false; + + switch (GetType()) { + case kObjectType: // Warning: O(n^2) inner-loop + if (data_.o.size != rhs.data_.o.size) + return false; + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { + typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + return false; + } + return true; + + case kArrayType: + if (data_.a.size != rhs.data_.a.size) + return false; + for (SizeType i = 0; i < data_.a.size; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; + + case kStringType: + return StringEqual(rhs); + + case kNumberType: + if (IsDouble() || rhs.IsDouble()) { + double a = GetDouble(); // May convert from integer to double. + double b = rhs.GetDouble(); // Ditto + return a >= b && a <= b; // Prevent -Wfloat-equal + } + else + return data_.n.u64 == rhs.data_.n.u64; + + default: + return true; + } + } + + //! Equal-to operator with const C-string pointer + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } + +#if RAPIDJSON_HAS_STDSTRING + //! Equal-to operator with string object + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } +#endif + + //! Equal-to operator with primitive types + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + + //! Not-equal-to operator + /*! \return !(*this == rhs) + */ + template + bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with const C-string pointer + bool operator!=(const Ch* rhs) const { return !(*this == rhs); } + + //! Not-equal-to operator with arbitrary types + /*! \return !(*this == rhs) + */ + template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } + + //! Equal-to operator with arbitrary types (symmetric version) + /*! \return (rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + + //! Not-Equal-to operator with arbitrary types (symmetric version) + /*! \return !(rhs == lhs) + */ + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } + //@} + + //!@name Type + //@{ + + Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } + bool IsNull() const { return data_.f.flags == kNullFlag; } + bool IsFalse() const { return data_.f.flags == kFalseFlag; } + bool IsTrue() const { return data_.f.flags == kTrueFlag; } + bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } + bool IsObject() const { return data_.f.flags == kObjectFlag; } + bool IsArray() const { return data_.f.flags == kArrayFlag; } + bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } + bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } + bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } + bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } + bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } + bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } + bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } + + // Checks whether a number can be losslessly converted to a double. + bool IsLosslessDouble() const { + if (!IsNumber()) return false; + if (IsUint64()) { + uint64_t u = GetUint64(); + volatile double d = static_cast(u); + return (d >= 0.0) + && (d < static_cast((std::numeric_limits::max)())) + && (u == static_cast(d)); + } + if (IsInt64()) { + int64_t i = GetInt64(); + volatile double d = static_cast(i); + return (d >= static_cast((std::numeric_limits::min)())) + && (d < static_cast((std::numeric_limits::max)())) + && (i == static_cast(d)); + } + return true; // double, int, uint are always lossless + } + + // Checks whether a number is a float (possible lossy). + bool IsFloat() const { + if ((data_.f.flags & kDoubleFlag) == 0) + return false; + double d = GetDouble(); + return d >= -3.4028234e38 && d <= 3.4028234e38; + } + // Checks whether a number can be losslessly converted to a float. + bool IsLosslessFloat() const { + if (!IsNumber()) return false; + double a = GetDouble(); + if (a < static_cast(-(std::numeric_limits::max)()) + || a > static_cast((std::numeric_limits::max)())) + return false; + double b = static_cast(static_cast(a)); + return a >= b && a <= b; // Prevent -Wfloat-equal + } + + //@} + + //!@name Null + //@{ + + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + + //@} + + //!@name Bool + //@{ + + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } + //!< Set boolean value + /*! \post IsBool() == true */ + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + + //@} + + //!@name Object + //@{ + + //! Set this value as an empty object. + /*! \post IsObject() == true */ + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + + //! Get the number of members in the object. + SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + + //! Get the capacity of object. + SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + + //! Check whether the object is empty. + bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. + Since 0.2, if the name is not correct, it will assert. + If user is unsure whether a member exists, user should use HasMember() first. + A better approach is to use FindMember(). + \note Linear time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { + GenericValue n(StringRef(name)); + return (*this)[n]; + } + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } + + //! Get a value from an object associated with the name. + /*! \pre IsObject() == true + \tparam SourceAllocator Allocator of the \c name value + + \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). + And it can also handle strings with embedded null characters. + + \note Linear time complexity. + */ + template + GenericValue& operator[](const GenericValue& name) { + MemberIterator member = FindMember(name); + if (member != MemberEnd()) + return member->value; + else { + RAPIDJSON_ASSERT(false); // see above note + + // This will generate -Wexit-time-destructors in clang + // static GenericValue NullValue; + // return NullValue; + + // Use static buffer and placement-new to prevent destruction + static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); + } + } + template + const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } + +#if RAPIDJSON_HAS_STDSTRING + //! Get a value from an object associated with name (string object). + GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } + const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } +#endif + + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsObject()); + if (newCapacity > data_.o.capacity) { + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + data_.o.capacity = newCapacity; + } + return *this; + } + + //! Check whether a member exists in the object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } + +#if RAPIDJSON_HAS_STDSTRING + //! Check whether a member exists in the object with string object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } +#endif + + //! Check whether a member exists in the object with GenericValue name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + template + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } + + //! Find member by name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const Ch* name) { + GenericValue n(StringRef(name)); + return FindMember(n); + } + + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + + //! Find member by name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + template + MemberIterator FindMember(const GenericValue& name) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } + +#if RAPIDJSON_HAS_STDSTRING + //! Find member by string object name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + */ + MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } +#endif + + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c name and \c value will be transferred to this object on success. + \pre IsObject() && name.IsString() + \post name.IsNull() && value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + + ObjectData& o = data_.o; + if (o.size >= o.capacity) + MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); + Member* members = GetMembersPointer(); + members[o.size].name.RawAssign(name); + members[o.size].value.RawAssign(value); + o.size++; + return *this; + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Add a string object as member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue v(value, allocator); + return AddMember(name, v, allocator); + } +#endif + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A string value as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(GenericValue& name, T value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { + return AddMember(name, value, allocator); + } + GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + + //! Add a member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this object on success. + \pre IsObject() + \post value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A constant string reference as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + AddMember(StringRefType name, T value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Remove all members in the object. + /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void RemoveAllMembers() { + RAPIDJSON_ASSERT(IsObject()); + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) + m->~Member(); + data_.o.size = 0; + } + + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Linear time complexity. + */ + bool RemoveMember(const Ch* name) { + GenericValue n(StringRef(name)); + return RemoveMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } +#endif + + template + bool RemoveMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + RemoveMember(m); + return true; + } + else + return false; + } + + //! Remove a member in object by iterator. + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). + \return the new iterator after removal. + \note This function may reorder the object members. Use \ref + EraseMember(ConstMemberIterator) if you need to preserve the + relative order of the remaining members. + \note Constant time complexity. + */ + MemberIterator RemoveMember(MemberIterator m) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + + MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) + *m = *last; // Move the last one to this place + else + m->~Member(); // Only one left, just destroy + --data_.o.size; + return m; + } + + //! Remove a member from an object by iterator. + /*! \param pos iterator to the member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() + \return Iterator following the removed element. + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. + \note This function preserves the relative order of the remaining object + members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator pos) { + return EraseMember(pos, pos +1); + } + + //! Remove members in the range [first, last) from an object. + /*! \param first iterator to the first member to remove + \param last iterator following the last member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() + \return Iterator following the last removed element. + \note This function preserves the relative order of the remaining object + members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); + RAPIDJSON_ASSERT(first >= MemberBegin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= MemberEnd()); + + MemberIterator pos = MemberBegin() + (first - MemberBegin()); + for (MemberIterator itr = pos; itr != last; ++itr) + itr->~Member(); + std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); + data_.o.size -= static_cast(last - first); + return pos; + } + + //! Erase a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Linear time complexity. + */ + bool EraseMember(const Ch* name) { + GenericValue n(StringRef(name)); + return EraseMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } +#endif + + template + bool EraseMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + EraseMember(m); + return true; + } + else + return false; + } + + Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + + //@} + + //!@name Array + //@{ + + //! Set this value as an empty array. + /*! \post IsArray == true */ + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Get the number of elements in array. + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + + //! Get the capacity of array. + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + + //! Check whether the array is empty. + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void Clear() { + RAPIDJSON_ASSERT(IsArray()); + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + data_.a.size = 0; + } + + //! Get an element from array by index. + /*! \pre IsArray() == true + \param index Zero-based index of element. + \see operator[](T*) + */ + GenericValue& operator[](SizeType index) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(index < data_.a.size); + return GetElementsPointer()[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + + //! Element iterator + /*! \pre IsArray() == true */ + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } + //! \em Past-the-end element iterator + /*! \pre IsArray() == true */ + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } + //! Constant element iterator + /*! \pre IsArray() == true */ + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + //! Constant \em past-the-end element iterator + /*! \pre IsArray() == true */ + ConstValueIterator End() const { return const_cast(*this).End(); } + + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); + data_.a.capacity = newCapacity; + } + return *this; + } + + //! Append a GenericValue at the end of the array. + /*! \param value Value to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \post value.IsNull() == true + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this array on success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); + GetElementsPointer()[data_.a.size++].RawAssign(value); + return *this; + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { + return PushBack(value, allocator); + } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + + //! Append a constant string reference at the end of the array. + /*! \param value Constant string reference to be appended. + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + \see GenericStringRef + */ + GenericValue& PushBack(StringRefType value, Allocator& allocator) { + return (*this).template PushBack(value, allocator); + } + + //! Append a primitive value at the end of the array. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value Value of primitive type T to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref PushBack(GenericValue&, Allocator&) or \ref + PushBack(StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) + PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } + + //! Remove the last element in the array. + /*! + \note Constant time complexity. + */ + GenericValue& PopBack() { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); + GetElementsPointer()[--data_.a.size].~GenericValue(); + return *this; + } + + //! Remove an element of array by iterator. + /*! + \param pos iterator to the element to remove + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator pos) { + return Erase(pos, pos + 1); + } + + //! Remove elements in the range [first, last) of the array. + /*! + \param first iterator to the first element to remove + \param last iterator following the last element to remove + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() + \return Iterator following the last removed element. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(data_.a.size > 0); + RAPIDJSON_ASSERT(GetElementsPointer() != 0); + RAPIDJSON_ASSERT(first >= Begin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= End()); + ValueIterator pos = Begin() + (first - Begin()); + for (ValueIterator itr = pos; itr != last; ++itr) + itr->~GenericValue(); + std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); + data_.a.size -= static_cast(last - first); + return pos; + } + + Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } + ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } + + //@} + + //!@name Number + //@{ + + int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } + uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } + + //! Get the value as double type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. + */ + double GetDouble() const { + RAPIDJSON_ASSERT(IsNumber()); + if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double + if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double + if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) + } + + //! Get the value as float type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. + */ + float GetFloat() const { + return static_cast(GetDouble()); + } + + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } + + //@} + + //!@name String + //@{ + + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } + + //! Get the length of string. + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == length + \see SetString(StringRefType) + */ + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } + + //! Set this value as a string without copying source string. + /*! \param s source string reference + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == s.length + */ + GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } + + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } + +#if RAPIDJSON_HAS_STDSTRING + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } +#endif + + //@} + + //!@name Array + //@{ + + //! Templated version for checking whether this value is type T. + /*! + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string + */ + template + bool Is() const { return internal::TypeHelper::Is(*this); } + + template + T Get() const { return internal::TypeHelper::Get(*this); } + + template + T Get() { return internal::TypeHelper::Get(*this); } + + template + ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } + + template + ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + + //@} + + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + bool Accept(Handler& handler) const { + switch(GetType()) { + case kNullType: return handler.Null(); + case kFalseType: return handler.Bool(false); + case kTrueType: return handler.Bool(true); + + case kObjectType: + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + return false; + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. + if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) + return false; + if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) + return false; + } + return handler.EndObject(data_.o.size); + + case kArrayType: + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + return false; + for (const GenericValue* v = Begin(); v != End(); ++v) + if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) + return false; + return handler.EndArray(data_.a.size); + + case kStringType: + return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); + + default: + RAPIDJSON_ASSERT(GetType() == kNumberType); + if (IsDouble()) return handler.Double(data_.n.d); + else if (IsInt()) return handler.Int(data_.n.i.i); + else if (IsUint()) return handler.Uint(data_.n.u.u); + else if (IsInt64()) return handler.Int64(data_.n.i64); + else return handler.Uint64(data_.n.u64); + } + } + +private: + template friend class GenericValue; + template friend class GenericDocument; + + enum { + kBoolFlag = 0x0008, + kNumberFlag = 0x0010, + kIntFlag = 0x0020, + kUintFlag = 0x0040, + kInt64Flag = 0x0080, + kUint64Flag = 0x0100, + kDoubleFlag = 0x0200, + kStringFlag = 0x0400, + kCopyFlag = 0x0800, + kInlineStrFlag = 0x1000, + + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, + + kTypeMask = 0x07 + }; + + static const SizeType kDefaultArrayCapacity = 16; + static const SizeType kDefaultObjectCapacity = 16; + + struct Flag { +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION + char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer +#elif RAPIDJSON_64BIT + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes +#else + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes +#endif + uint16_t flags; + }; + + struct String { + SizeType length; + SizeType hashcode; //!< reserved + const Ch* str; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars + // (excluding the terminating zero) and store a value to determine the length of the contained + // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string + // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as + // the string terminator as well. For getting the string length back from that value just use + // "MaxSize - str[LenPos]". + // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, + // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). + struct ShortString { + enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; + Ch str[MaxChars]; + + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } + inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } + }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { +#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN + struct I { + int i; + char padding[4]; + }i; + struct U { + unsigned u; + char padding2[4]; + }u; +#else + struct I { + char padding[4]; + int i; + }i; + struct U { + char padding2[4]; + unsigned u; + }u; +#endif + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes + + struct ObjectData { + SizeType size; + SizeType capacity; + Member* members; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + struct ArrayData { + SizeType size; + SizeType capacity; + GenericValue* elements; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + + union Data { + String s; + ShortString ss; + Number n; + ObjectData o; + ArrayData a; + Flag f; + }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION + + RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } + RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } + RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } + RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } + RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } + RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } + + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { + data_.f.flags = kArrayFlag; + if (count) { + GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); + SetElementsPointer(e); +RAPIDJSON_DIAG_PUSH +#if defined(__GNUC__) && __GNUC__ >= 8 +RAPIDJSON_DIAG_OFF(class-memaccess) // ignore complains from gcc that no trivial copy constructor exists. +#endif + std::memcpy(e, values, count * sizeof(GenericValue)); +RAPIDJSON_DIAG_POP + } + else + SetElementsPointer(0); + data_.a.size = data_.a.capacity = count; + } + + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { + data_.f.flags = kObjectFlag; + if (count) { + Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + SetMembersPointer(m); +RAPIDJSON_DIAG_PUSH +#if defined(__GNUC__) && __GNUC__ >= 8 +RAPIDJSON_DIAG_OFF(class-memaccess) // ignore complains from gcc that no trivial copy constructor exists. +#endif + std::memcpy(m, members, count * sizeof(Member)); +RAPIDJSON_DIAG_POP + } + else + SetMembersPointer(0); + data_.o.size = data_.o.capacity = count; + } + + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { + data_.f.flags = kConstStringFlag; + SetStringPointer(s); + data_.s.length = s.length; + } + + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(StringRefType s, Allocator& allocator) { + Ch* str = 0; + if (ShortString::Usable(s.length)) { + data_.f.flags = kShortStringFlag; + data_.ss.SetLength(s.length); + str = data_.ss.str; + } else { + data_.f.flags = kCopyStringFlag; + data_.s.length = s.length; + str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); + SetStringPointer(str); + } + std::memcpy(str, s, s.length * sizeof(Ch)); + str[s.length] = '\0'; + } + + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { + data_ = rhs.data_; + // data_.f.flags = rhs.data_.f.flags; + rhs.data_.f.flags = kNullFlag; + } + + template + bool StringEqual(const GenericValue& rhs) const { + RAPIDJSON_ASSERT(IsString()); + RAPIDJSON_ASSERT(rhs.IsString()); + + const SizeType len1 = GetStringLength(); + const SizeType len2 = rhs.GetStringLength(); + if(len1 != len2) { return false; } + + const Ch* const str1 = GetString(); + const Ch* const str2 = rhs.GetString(); + if(str1 == str2) { return true; } // fast path for constant string + + return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); + } + + Data data_; +}; + +//! GenericValue with UTF8 encoding +typedef GenericValue > Value; + +/////////////////////////////////////////////////////////////////////////////// +// GenericDocument + +//! A document for parsing JSON text as DOM. +/*! + \note implements Handler concept + \tparam Encoding Encoding for both parsing and string storage. + \tparam Allocator Allocator for allocating memory for the DOM + \tparam StackAllocator Allocator for allocating memory for stack during parsing. + \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. +*/ +template , typename StackAllocator = CrtAllocator> +class GenericDocument : public GenericValue { +public: + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + + //! Constructor + /*! Creates an empty document of specified type. + \param type Mandatory type of object to create. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + } + + //! Constructor + /*! Creates an empty document which type is Null. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(std::move(rhs.stack_)), + parseResult_(rhs.parseResult_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + } +#endif + + ~GenericDocument() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move assignment in C++11 + GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT + { + // The cast to ValueType is necessary here, because otherwise it would + // attempt to call GenericValue's templated assignment operator. + ValueType::operator=(std::forward(rhs)); + + // Calling the destructor here would prematurely call stack_'s destructor + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = std::move(rhs.stack_); + parseResult_ = rhs.parseResult_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.parseResult_ = ParseResult(); + + return *this; + } +#endif + + //! Exchange the contents of this document with those of another. + /*! + \param rhs Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); + return *this; + } + + // Allow Swap with ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Populate this document by a generator which produces SAX events. + /*! \tparam Generator A functor with bool f(Handler) prototype. + \param g Generator functor which sends SAX events to the parameter. + \return The document itself for fluent API. + */ + template + GenericDocument& Populate(Generator& g) { + ClearStackOnExit scope(*this); + if (g(*this)) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //!@name Parse from stream + //!@{ + + //! Parse JSON text from an input stream (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Encoding of input stream + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); + ClearStackOnExit scope(*this); + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + + //! Parse JSON text from an input stream + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + //!@} + + //!@name Parse in-place from mutable string + //!@{ + + //! Parse JSON text from a mutable string + /*! \tparam parseFlags Combination of \ref ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) + /*! \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } + //!@} + + //!@name Parse from read-only string + //!@{ + + //! Parse JSON text from a read-only string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \tparam SourceEncoding Transcoding from input Encoding + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } + + //! Parse JSON text from a read-only string + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) + /*! \param str Read-only zero-terminated string to be parsed. + */ + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); + EncodedInputStream is(ms); + ParseStream(is); + return *this; + } + + template + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + template + GenericDocument& Parse(const std::basic_string& str) { + // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) + return Parse(str.c_str()); + } + + template + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str.c_str()); + } + + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str); + } +#endif // RAPIDJSON_HAS_STDSTRING + + //!@} + + //!@name Handling parse errors + //!@{ + + //! Whether a parse error has occurred in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseError() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + + //! Implicit conversion to get the last parse result +#ifndef __clang // -Wdocumentation + /*! \return \ref ParseResult of the last parse operation + + \code + Document doc; + ParseResult ok = doc.Parse(json); + if (!ok) + printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); + \endcode + */ +#endif + operator ParseResult() const { return parseResult_; } + //!@} + + //! Get the allocator of this document. + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } + +private: + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } + private: + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + GenericDocument& d_; + }; + + // callers of the following private Handler functions + // template friend class GenericReader; // for parsing + template friend class GenericValue; // for deep copying + +public: + // Implementation of Handler + bool Null() { new (stack_.template Push()) ValueType(); return true; } + bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } + bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } + bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + + bool RawNumber(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + + bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } + + bool EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); + return true; + } + + bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } + + bool EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; + } + +private: + //! Prohibit copying + GenericDocument(const GenericDocument&); + //! Prohibit assignment + GenericDocument& operator=(const GenericDocument&); + + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + stack_.ShrinkToFit(); + } + + void Destroy() { + RAPIDJSON_DELETE(ownAllocator_); + } + + static const size_t kDefaultStackCapacity = 1024; + Allocator* allocator_; + Allocator* ownAllocator_; + internal::Stack stack_; + ParseResult parseResult_; +}; + +//! GenericDocument with UTF8 encoding +typedef GenericDocument > Document; + +//! Helper class for accessing Value of array type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetArray(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericArray { +public: + typedef GenericArray ConstArray; + typedef GenericArray Array; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef ValueType* ValueIterator; // This may be const or non-const iterator + typedef const ValueT* ConstValueIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + + template + friend class GenericValue; + + GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} + GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } + ~GenericArray() {} + + SizeType Size() const { return value_.Size(); } + SizeType Capacity() const { return value_.Capacity(); } + bool Empty() const { return value_.Empty(); } + void Clear() const { value_.Clear(); } + ValueType& operator[](SizeType index) const { return value_[index]; } + ValueIterator Begin() const { return value_.Begin(); } + ValueIterator End() const { return value_.End(); } + GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + GenericArray PopBack() const { value_.PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + ValueIterator begin() const { return value_.Begin(); } + ValueIterator end() const { return value_.End(); } +#endif + +private: + GenericArray(); + GenericArray(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +//! Helper class for accessing Value of object type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetObject(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericObject { +public: + typedef GenericObject ConstObject; + typedef GenericObject Object; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator + typedef GenericMemberIterator ConstMemberIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename ValueType::Ch Ch; + + template + friend class GenericValue; + + GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} + GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } + ~GenericObject() {} + + SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } + bool ObjectEmpty() const { return value_.ObjectEmpty(); } + template ValueType& operator[](T* name) const { return value_[name]; } + template ValueType& operator[](const GenericValue& name) const { return value_[name]; } +#if RAPIDJSON_HAS_STDSTRING + ValueType& operator[](const std::basic_string& name) const { return value_[name]; } +#endif + MemberIterator MemberBegin() const { return value_.MemberBegin(); } + MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } + bool HasMember(const Ch* name) const { return value_.HasMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } +#endif + template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } + MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } + template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } +#if RAPIDJSON_HAS_STDSTRING + MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } +#endif + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_STDSTRING + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + void RemoveAllMembers() { value_.RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } +#endif + template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } + bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } +#endif + template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + MemberIterator begin() const { return value_.MemberBegin(); } + MemberIterator end() const { return value_.MemberEnd(); } +#endif + +private: + GenericObject(); + GenericObject(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_DOCUMENT_H_ diff --git a/WXom062/rapidjson/encodedstream.h b/WXom062/rapidjson/encodedstream.h new file mode 100644 index 0000000..223601c --- /dev/null +++ b/WXom062/rapidjson/encodedstream.h @@ -0,0 +1,299 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ +#define RAPIDJSON_ENCODEDSTREAM_H_ + +#include "stream.h" +#include "memorystream.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Input byte stream wrapper with a statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. +*/ +template +class EncodedInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedInputStream(InputByteStream& is) : is_(is) { + current_ = Encoding::TakeBOM(is_); + } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); + + InputByteStream& is_; + Ch current_; +}; + +//! Specialized for UTF8 MemoryStream. +template <> +class EncodedInputStream, MemoryStream> { +public: + typedef UTF8<>::Ch Ch; + + EncodedInputStream(MemoryStream& is) : is_(is) { + if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); + } + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) {} + void Flush() {} + Ch* PutBegin() { return 0; } + size_t PutEnd(Ch*) { return 0; } + + MemoryStream& is_; + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); +}; + +//! Output byte stream wrapper with statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. +*/ +template +class EncodedOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef typename Encoding::Ch Ch; + + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { + if (putBOM) + Encoding::PutBOM(os_); + } + + void Put(Ch c) { Encoding::Put(os_, c); } + void Flush() { os_.Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + EncodedOutputStream(const EncodedOutputStream&); + EncodedOutputStream& operator=(const EncodedOutputStream&); + + OutputByteStream& os_; +}; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for reading. + \tparam InputByteStream type of input byte stream to be wrapped. +*/ +template +class AutoUTFInputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param is input stream to be wrapped. + \param type UTF encoding type if it is not detected from the stream. + */ + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + DetectType(); + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; + takeFunc_ = f[type_]; + current_ = takeFunc_(*is_); + } + + UTFType GetType() const { return type_; } + bool HasBOM() const { return hasBOM_; } + + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } + size_t Tell() const { return is_->Tell(); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFInputStream(const AutoUTFInputStream&); + AutoUTFInputStream& operator=(const AutoUTFInputStream&); + + // Detect encoding type with BOM or RFC 4627 + void DetectType() { + // BOM (Byte Order Mark): + // 00 00 FE FF UTF-32BE + // FF FE 00 00 UTF-32LE + // FE FF UTF-16BE + // FF FE UTF-16LE + // EF BB BF UTF-8 + + const unsigned char* c = reinterpret_cast(is_->Peek4()); + if (!c) + return; + + unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); + hasBOM_ = false; + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } + + // RFC 4627: Section 3 + // "Since the first two characters of a JSON text will always be ASCII + // characters [RFC0020], it is possible to determine whether an octet + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + // at the pattern of nulls in the first four octets." + // 00 00 00 xx UTF-32BE + // 00 xx 00 xx UTF-16BE + // xx 00 00 00 UTF-32LE + // xx 00 xx 00 UTF-16LE + // xx xx xx xx UTF-8 + + if (!hasBOM_) { + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + switch (pattern) { + case 0x08: type_ = kUTF32BE; break; + case 0x0A: type_ = kUTF16BE; break; + case 0x01: type_ = kUTF32LE; break; + case 0x05: type_ = kUTF16LE; break; + case 0x0F: type_ = kUTF8; break; + default: break; // Use type defined by user. + } + } + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + } + + typedef Ch (*TakeFunc)(InputByteStream& is); + InputByteStream* is_; + UTFType type_; + Ch current_; + TakeFunc takeFunc_; + bool hasBOM_; +}; + +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for writing. + \tparam OutputByteStream type of output byte stream to be wrapped. +*/ +template +class AutoUTFOutputStream { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); +public: + typedef CharType Ch; + + //! Constructor. + /*! + \param os output stream to be wrapped. + \param type UTF encoding type. + \param putBOM Whether to write BOM at the beginning of the stream. + */ + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; + putFunc_ = f[type_]; + + if (putBOM) + PutBOM(); + } + + UTFType GetType() const { return type_; } + + void Put(Ch c) { putFunc_(*os_, c); } + void Flush() { os_->Flush(); } + + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + AutoUTFOutputStream(const AutoUTFOutputStream&); + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); + + void PutBOM() { + typedef void (*PutBOMFunc)(OutputByteStream&); + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + f[type_](*os_); + } + + typedef void (*PutFunc)(OutputByteStream&, Ch); + + OutputByteStream* os_; + UTFType type_; + PutFunc putFunc_; +}; + +#undef RAPIDJSON_ENCODINGS_FUNC + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/WXom062/rapidjson/encodings.h b/WXom062/rapidjson/encodings.h new file mode 100644 index 0000000..7903e76 --- /dev/null +++ b/WXom062/rapidjson/encodings.h @@ -0,0 +1,716 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODINGS_H_ +#define RAPIDJSON_ENCODINGS_H_ + +#include "rapidjson.h" + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(overflow) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Encoding + +/*! \class rapidjson::Encoding + \brief Concept for encoding of Unicode characters. + +\code +concept Encoding { + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. + + enum { supportUnicode = 1 }; // or 0 if not supporting unicode + + //! \brief Encode a Unicode codepoint to an output stream. + //! \param os Output stream. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + template + static void Encode(OutputStream& os, unsigned codepoint); + + //! \brief Decode a Unicode codepoint from an input stream. + //! \param is Input stream. + //! \param codepoint Output of the unicode codepoint. + //! \return true if a valid codepoint can be decoded from the stream. + template + static bool Decode(InputStream& is, unsigned* codepoint); + + //! \brief Validate one Unicode codepoint from an encoded stream. + //! \param is Input stream to obtain codepoint. + //! \param os Output for copying one codepoint. + //! \return true if it is valid. + //! \note This function just validating and copying the codepoint without actually decode it. + template + static bool Validate(InputStream& is, OutputStream& os); + + // The following functions are deal with byte streams. + + //! Take a character from input byte stream, skip BOM if exist. + template + static CharType TakeBOM(InputByteStream& is); + + //! Take a character from input byte stream. + template + static Ch Take(InputByteStream& is); + + //! Put BOM to output byte stream. + template + static void PutBOM(OutputByteStream& os); + + //! Put a character to output byte stream. + template + static void Put(OutputByteStream& os, Ch c); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// UTF8 + +//! UTF-8 encoding. +/*! http://en.wikipedia.org/wiki/UTF-8 + http://tools.ietf.org/html/rfc3629 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. + \note implements Encoding concept +*/ +template +struct UTF8 { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + os.Put(static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + PutUnsafe(os, static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define TAIL() COPY(); TRANS(0x70) + typename InputStream::Ch c = is.Take(); + if (!(c & 0x80)) { + *codepoint = static_cast(c); + return true; + } + + unsigned char type = GetRange(static_cast(c)); + if (type >= 32) { + *codepoint = 0; + } else { + *codepoint = (0xFFu >> type) & static_cast(c); + } + bool result = true; + switch (type) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } +#undef COPY +#undef TRANS +#undef TAIL + } + + template + static bool Validate(InputStream& is, OutputStream& os) { +#define COPY() os.Put(c = is.Take()) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define TAIL() COPY(); TRANS(0x70) + Ch c; + COPY(); + if (!(c & 0x80)) + return true; + + bool result = true; + switch (GetRange(static_cast(c))) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } +#undef COPY +#undef TRANS +#undef TAIL + } + + static unsigned char GetRange(unsigned char c) { + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. + static const unsigned char type[] = { + 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,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,0,0, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + }; + return type[c]; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + typename InputByteStream::Ch c = Take(is); + if (static_cast(c) != 0xEFu) return c; + c = is.Take(); + if (static_cast(c) != 0xBBu) return c; + c = is.Take(); + if (static_cast(c) != 0xBFu) return c; + c = is.Take(); + return c; + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xEFu)); + os.Put(static_cast(0xBBu)); + os.Put(static_cast(0xBFu)); + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF16 + +//! UTF-16 encoding. +/*! http://en.wikipedia.org/wiki/UTF-16 + http://tools.ietf.org/html/rfc2781 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF16LE and UTF16BE, which handle endianness. +*/ +template +struct UTF16 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + os.Put(static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + os.Put(static_cast((v >> 10) | 0xD800)); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); + } + } + + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + PutUnsafe(os, static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + PutUnsafe(os, static_cast((v >> 10) | 0xD800)); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); + } + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + typename InputStream::Ch c = is.Take(); + if (c < 0xD800 || c > 0xDFFF) { + *codepoint = static_cast(c); + return true; + } + else if (c <= 0xDBFF) { + *codepoint = (static_cast(c) & 0x3FF) << 10; + c = is.Take(); + *codepoint |= (static_cast(c) & 0x3FF); + *codepoint += 0x10000; + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + typename InputStream::Ch c; + os.Put(static_cast(c = is.Take())); + if (c < 0xD800 || c > 0xDFFF) + return true; + else if (c <= 0xDBFF) { + os.Put(c = is.Take()); + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } +}; + +//! UTF-16 little endian encoding. +template +struct UTF16LE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(static_cast(c) & 0xFFu)); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + } +}; + +//! UTF-16 big endian encoding. +template +struct UTF16BE : UTF16 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + os.Put(static_cast(static_cast(c) & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF32 + +//! UTF-32 encoding. +/*! http://en.wikipedia.org/wiki/UTF-32 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF32LE and UTF32BE, which handle endianness. +*/ +template +struct UTF32 { + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(codepoint); + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, codepoint); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c = is.Take(); + *codepoint = c; + return c <= 0x10FFFF; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c; + os.Put(c = is.Take()); + return c <= 0x10FFFF; + } +}; + +//! UTF-32 little endian enocoding. +template +struct UTF32LE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 24; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 24) & 0xFFu)); + } +}; + +//! UTF-32 big endian encoding. +template +struct UTF32BE : UTF32 { + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 24; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((c >> 24) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast(c & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// ASCII + +//! ASCII encoding. +/*! http://en.wikipedia.org/wiki/ASCII + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. + \note implements Encoding concept +*/ +template +struct ASCII { + typedef CharType Ch; + + enum { supportUnicode = 0 }; + + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + os.Put(static_cast(codepoint & 0xFF)); + } + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + PutUnsafe(os, static_cast(codepoint & 0xFF)); + } + + template + static bool Decode(InputStream& is, unsigned* codepoint) { + uint8_t c = static_cast(is.Take()); + *codepoint = c; + return c <= 0X7F; + } + + template + static bool Validate(InputStream& is, OutputStream& os) { + uint8_t c = static_cast(is.Take()); + os.Put(static_cast(c)); + return c <= 0x7F; + } + + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + uint8_t c = static_cast(Take(is)); + return static_cast(c); + } + + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + (void)os; + } + + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// AutoUTF + +//! Runtime-specified UTF encoding type of a stream. +enum UTFType { + kUTF8 = 0, //!< UTF-8. + kUTF16LE = 1, //!< UTF-16 little endian. + kUTF16BE = 2, //!< UTF-16 big endian. + kUTF32LE = 3, //!< UTF-32 little endian. + kUTF32BE = 4 //!< UTF-32 big endian. +}; + +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). +*/ +template +struct AutoUTF { + typedef CharType Ch; + + enum { supportUnicode = 1 }; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + + template + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; + (*f[os.GetType()])(os, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + (*f[os.GetType()])(os, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { + typedef bool (*DecodeFunc)(InputStream&, unsigned*); + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; + return (*f[is.GetType()])(is, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { + typedef bool (*ValidateFunc)(InputStream&, OutputStream&); + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; + return (*f[is.GetType()])(is, os); + } + +#undef RAPIDJSON_ENCODINGS_FUNC +}; + +/////////////////////////////////////////////////////////////////////////////// +// Transcoder + +//! Encoding conversion. +template +struct Transcoder { + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. + template + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::Encode(os, codepoint); + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::EncodeUnsafe(os, codepoint); + return true; + } + + //! Validate one Unicode codepoint from an encoded stream. + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { + return Transcode(is, os); // Since source/target encoding is different, must transcode. + } +}; + +// Forward declaration. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c); + +//! Specialization of Transcoder with same source and target encoding. +template +struct Transcoder { + template + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { + return Encoding::Validate(is, os); // source/target encoding are the same + } +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/WXom062/rapidjson/error/en.h b/WXom062/rapidjson/error/en.h new file mode 100644 index 0000000..2db838b --- /dev/null +++ b/WXom062/rapidjson/error/en.h @@ -0,0 +1,74 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ + +#include "error.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Maps error code of parsing into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { + switch (parseErrorCode) { + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); + + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/WXom062/rapidjson/error/error.h b/WXom062/rapidjson/error/error.h new file mode 100644 index 0000000..9311d2f --- /dev/null +++ b/WXom062/rapidjson/error/error.h @@ -0,0 +1,161 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ + +#include "../rapidjson.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +/*! \file error.h */ + +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_CHARTYPE + +//! Character type of error messages. +/*! \ingroup RAPIDJSON_ERRORS + The default character type is \c char. + On Windows, user can define this macro as \c TCHAR for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_STRING + +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +/*! \ingroup RAPIDJSON_ERRORS + By default this conversion macro does nothing. + On Windows, user can define this macro as \c _T(x) for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode { + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. +}; + +//! Result of parsing (wraps ParseErrorCode) +/*! + \ingroup RAPIDJSON_ERRORS + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ +struct ParseResult { + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; +public: + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + //! Get the error code. + ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const { return offset_; } + + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } + //! Whether the result is an error. + bool IsError() const { return code_ != kParseErrorNone; } + + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + + bool operator!=(const ParseResult& that) const { return !(*this == that); } + bool operator!=(ParseErrorCode code) const { return !(*this == code); } + friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } + + //! Reset error code. + void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + +private: + ParseErrorCode code_; + size_t offset_; +}; + +//! Function pointer type of GetParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/WXom062/rapidjson/filereadstream.h b/WXom062/rapidjson/filereadstream.h new file mode 100644 index 0000000..f1bfb7d --- /dev/null +++ b/WXom062/rapidjson/filereadstream.h @@ -0,0 +1,99 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEREADSTREAM_H_ +#define RAPIDJSON_FILEREADSTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! File byte stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileReadStream { +public: + typedef char Ch; //!< Character type (byte). + + //! Constructor. + /*! + \param fp File pointer opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 <= bufferLast_) ? current_ : 0; + } + +private: + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (readCount_ < bufferSize_) { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } + } + + std::FILE* fp_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/WXom062/rapidjson/filewritestream.h b/WXom062/rapidjson/filewritestream.h new file mode 100644 index 0000000..8b48fee --- /dev/null +++ b/WXom062/rapidjson/filewritestream.h @@ -0,0 +1,104 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of C file stream for output using fwrite(). +/*! + \note implements Stream concept +*/ +class FileWriteStream { +public: + typedef char Ch; //!< Character type. Only support char. + + FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { + RAPIDJSON_ASSERT(fp_ != 0); + } + + void Put(char c) { + if (current_ >= bufferEnd_) + Flush(); + + *current_++ = c; + } + + void PutN(char c, size_t n) { + size_t avail = static_cast(bufferEnd_ - current_); + while (n > avail) { + std::memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = static_cast(bufferEnd_ - current_); + } + + if (n > 0) { + std::memset(current_, c, n); + current_ += n; + } + } + + void Flush() { + if (current_ != buffer_) { + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + if (result < static_cast(current_ - buffer_)) { + // failure deliberately ignored at this time + // added to avoid warn_unused_result build errors + } + current_ = buffer_; + } + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + // Prohibit copy constructor & assignment operator. + FileWriteStream(const FileWriteStream&); + FileWriteStream& operator=(const FileWriteStream&); + + std::FILE* fp_; + char *buffer_; + char *bufferEnd_; + char *current_; +}; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(FileWriteStream& stream, char c, size_t n) { + stream.PutN(c, n); +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/WXom062/rapidjson/fwd.h b/WXom062/rapidjson/fwd.h new file mode 100644 index 0000000..e8104e8 --- /dev/null +++ b/WXom062/rapidjson/fwd.h @@ -0,0 +1,151 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FWD_H_ +#define RAPIDJSON_FWD_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +// encodings.h + +template struct UTF8; +template struct UTF16; +template struct UTF16BE; +template struct UTF16LE; +template struct UTF32; +template struct UTF32BE; +template struct UTF32LE; +template struct ASCII; +template struct AutoUTF; + +template +struct Transcoder; + +// allocators.h + +class CrtAllocator; + +template +class MemoryPoolAllocator; + +// stream.h + +template +struct GenericStringStream; + +typedef GenericStringStream > StringStream; + +template +struct GenericInsituStringStream; + +typedef GenericInsituStringStream > InsituStringStream; + +// stringbuffer.h + +template +class GenericStringBuffer; + +typedef GenericStringBuffer, CrtAllocator> StringBuffer; + +// filereadstream.h + +class FileReadStream; + +// filewritestream.h + +class FileWriteStream; + +// memorybuffer.h + +template +struct GenericMemoryBuffer; + +typedef GenericMemoryBuffer MemoryBuffer; + +// memorystream.h + +struct MemoryStream; + +// reader.h + +template +struct BaseReaderHandler; + +template +class GenericReader; + +typedef GenericReader, UTF8, CrtAllocator> Reader; + +// writer.h + +template +class Writer; + +// prettywriter.h + +template +class PrettyWriter; + +// document.h + +template +struct GenericMember; + +template +class GenericMemberIterator; + +template +struct GenericStringRef; + +template +class GenericValue; + +typedef GenericValue, MemoryPoolAllocator > Value; + +template +class GenericDocument; + +typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; + +// pointer.h + +template +class GenericPointer; + +typedef GenericPointer Pointer; + +// schema.h + +template +class IGenericRemoteSchemaDocumentProvider; + +template +class GenericSchemaDocument; + +typedef GenericSchemaDocument SchemaDocument; +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +template < + typename SchemaDocumentType, + typename OutputHandler, + typename StateAllocator> +class GenericSchemaValidator; + +typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/WXom062/rapidjson/internal/biginteger.h b/WXom062/rapidjson/internal/biginteger.h new file mode 100644 index 0000000..f936a10 --- /dev/null +++ b/WXom062/rapidjson/internal/biginteger.h @@ -0,0 +1,290 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_BIGINTEGER_H_ +#define RAPIDJSON_BIGINTEGER_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64) +#include // for _umul128 +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class BigInteger { +public: + typedef uint64_t Type; + + BigInteger(const BigInteger& rhs) : count_(rhs.count_) { + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + + explicit BigInteger(uint64_t u) : count_(1) { + digits_[0] = u; + } + + BigInteger(const char* decimals, size_t length) : count_(1) { + RAPIDJSON_ASSERT(length > 0); + digits_[0] = 0; + size_t i = 0; + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 + while (length >= kMaxDigitPerIteration) { + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); + length -= kMaxDigitPerIteration; + i += kMaxDigitPerIteration; + } + + if (length > 0) + AppendDecimal64(decimals + i, decimals + i + length); + } + + BigInteger& operator=(const BigInteger &rhs) + { + if (this != &rhs) { + count_ = rhs.count_; + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + return *this; + } + + BigInteger& operator=(uint64_t u) { + digits_[0] = u; + count_ = 1; + return *this; + } + + BigInteger& operator+=(uint64_t u) { + Type backup = digits_[0]; + digits_[0] += u; + for (size_t i = 0; i < count_ - 1; i++) { + if (digits_[i] >= backup) + return *this; // no carry + backup = digits_[i + 1]; + digits_[i + 1] += 1; + } + + // Last carry + if (digits_[count_ - 1] < backup) + PushBack(1); + + return *this; + } + + BigInteger& operator*=(uint64_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + uint64_t hi; + digits_[i] = MulAdd64(digits_[i], u, k, &hi); + k = hi; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator*=(uint32_t u) { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) { + const uint64_t c = digits_[i] >> 32; + const uint64_t d = digits_[i] & 0xFFFFFFFF; + const uint64_t uc = u * c; + const uint64_t ud = u * d; + const uint64_t p0 = ud + k; + const uint64_t p1 = uc + (p0 >> 32); + digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); + k = p1 >> 32; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger& operator<<=(size_t shift) { + if (IsZero() || shift == 0) return *this; + + size_t offset = shift / kTypeBit; + size_t interShift = shift % kTypeBit; + RAPIDJSON_ASSERT(count_ + offset <= kCapacity); + + if (interShift == 0) { + std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); + count_ += offset; + } + else { + digits_[count_] = 0; + for (size_t i = count_; i > 0; i--) + digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); + digits_[offset] = digits_[0] << interShift; + count_ += offset; + if (digits_[count_]) + count_++; + } + + std::memset(digits_, 0, offset * sizeof(Type)); + + return *this; + } + + bool operator==(const BigInteger& rhs) const { + return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; + } + + bool operator==(const Type rhs) const { + return count_ == 1 && digits_[0] == rhs; + } + + BigInteger& MultiplyPow5(unsigned exp) { + static const uint32_t kPow5[12] = { + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + if (exp == 0) return *this; + for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 + for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 + if (exp > 0) *this *= kPow5[exp - 1]; + return *this; + } + + // Compute absolute difference of this and rhs. + // Assume this != rhs + bool Difference(const BigInteger& rhs, BigInteger* out) const { + int cmp = Compare(rhs); + RAPIDJSON_ASSERT(cmp != 0); + const BigInteger *a, *b; // Makes a > b + bool ret; + if (cmp < 0) { a = &rhs; b = this; ret = true; } + else { a = this; b = &rhs; ret = false; } + + Type borrow = 0; + for (size_t i = 0; i < a->count_; i++) { + Type d = a->digits_[i] - borrow; + if (i < b->count_) + d -= b->digits_[i]; + borrow = (d > a->digits_[i]) ? 1 : 0; + out->digits_[i] = d; + if (d != 0) + out->count_ = i + 1; + } + + return ret; + } + + int Compare(const BigInteger& rhs) const { + if (count_ != rhs.count_) + return count_ < rhs.count_ ? -1 : 1; + + for (size_t i = count_; i-- > 0;) + if (digits_[i] != rhs.digits_[i]) + return digits_[i] < rhs.digits_[i] ? -1 : 1; + + return 0; + } + + size_t GetCount() const { return count_; } + Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } + bool IsZero() const { return count_ == 1 && digits_[0] == 0; } + +private: + void AppendDecimal64(const char* begin, const char* end) { + uint64_t u = ParseUint64(begin, end); + if (IsZero()) + *this = u; + else { + unsigned exp = static_cast(end - begin); + (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u + } + } + + void PushBack(Type digit) { + RAPIDJSON_ASSERT(count_ < kCapacity); + digits_[count_++] = digit; + } + + static uint64_t ParseUint64(const char* begin, const char* end) { + uint64_t r = 0; + for (const char* p = begin; p != end; ++p) { + RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); + r = r * 10u + static_cast(*p - '0'); + } + return r; + } + + // Assume a * b + k < 2^128 + static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t low = _umul128(a, b, outHigh) + k; + if (low < k) + (*outHigh)++; + return low; +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(a) * static_cast(b); + p += k; + *outHigh = static_cast(p >> 64); + return static_cast(p); +#else + const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; + uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; + x1 += (x0 >> 32); // can't give carry + x1 += x2; + if (x1 < x2) + x3 += (static_cast(1) << 32); + uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); + uint64_t hi = x3 + (x1 >> 32); + + lo += k; + if (lo < k) + hi++; + *outHigh = hi; + return lo; +#endif + } + + static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 + static const size_t kCapacity = kBitCount / sizeof(Type); + static const size_t kTypeBit = sizeof(Type) * 8; + + Type digits_[kCapacity]; + size_t count_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/WXom062/rapidjson/internal/diyfp.h b/WXom062/rapidjson/internal/diyfp.h new file mode 100644 index 0000000..29abf80 --- /dev/null +++ b/WXom062/rapidjson/internal/diyfp.h @@ -0,0 +1,258 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DIYFP_H_ +#define RAPIDJSON_DIYFP_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) +#include +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +struct DiyFp { + DiyFp() : f(), e() {} + + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} + + explicit DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp& rhs) const { + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp& rhs) const { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = static_cast(p >> 64); + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const { +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#elif defined(__GNUC__) && __GNUC__ >= 4 + int s = __builtin_clzll(f); + return DiyFp(f << s, e - s); +#else + DiyFp res = *this; + while (!(res.f & (static_cast(1) << 63))) { + res.f <<= 1; + res.e--; + } + return res; +#endif + } + + DiyFp NormalizeBoundary() const { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + double ToDouble() const { + union { + double d; + uint64_t u64; + }u; + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + static_cast(e + kDpExponentBias); + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); + return u.d; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMaxExponent = 0x7FF - kDpExponentBias; + static const int kDpMinExponent = -kDpExponentBias; + static const int kDpDenormalExponent = -kDpExponentBias + 1; + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; +}; + +inline DiyFp GetCachedPowerByIndex(size_t index) { + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +inline DiyFp GetCachedPower(int e, int* K) { + + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); +} + +inline DiyFp GetCachedPower10(int exp, int *outExp) { + unsigned index = (static_cast(exp) + 348u) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); + } + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_OFF(padded) +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DIYFP_H_ diff --git a/WXom062/rapidjson/internal/dtoa.h b/WXom062/rapidjson/internal/dtoa.h new file mode 100644 index 0000000..bf2e9b2 --- /dev/null +++ b/WXom062/rapidjson/internal/dtoa.h @@ -0,0 +1,245 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DTOA_ +#define RAPIDJSON_DTOA_ + +#include "itoa.h" // GetDigitsLut() +#include "diyfp.h" +#include "ieee754.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 +#endif + +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} + +inline int CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; +} + +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; + + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default:; + } + if (d || *len) + buffer[(*len)++] = static_cast('0' + static_cast(d)); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); + return; + } + } +} + +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} + +inline char* WriteExponent(int K, char* buffer) { + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = static_cast('0' + static_cast(K / 100)); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast('0' + static_cast(K)); + + return buffer; +} + +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (0 <= k && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); + buffer[kk] = '.'; + if (0 > k + maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; + } + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + if (length - kk > maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + else if (kk < -maxDecimalPlaces) { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + else { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } +} + +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K, maxDecimalPlaces); + } +} + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DTOA_ diff --git a/WXom062/rapidjson/internal/ieee754.h b/WXom062/rapidjson/internal/ieee754.h new file mode 100644 index 0000000..c2684ba --- /dev/null +++ b/WXom062/rapidjson/internal/ieee754.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_IEEE754_ +#define RAPIDJSON_IEEE754_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +class Double { +public: + Double() {} + Double(double d) : d_(d) {} + Double(uint64_t u) : u_(u) {} + + double Value() const { return d_; } + uint64_t Uint64Value() const { return u_; } + + double NextPositiveDouble() const { + RAPIDJSON_ASSERT(!Sign()); + return Double(u_ + 1).Value(); + } + + bool Sign() const { return (u_ & kSignMask) != 0; } + uint64_t Significand() const { return u_ & kSignificandMask; } + int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } + + bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } + bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } + bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } + bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } + bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } + + uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } + int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } + uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } + + static int EffectiveSignificandSize(int order) { + if (order >= -1021) + return 53; + else if (order <= -1074) + return 0; + else + return order + 1074; + } + +private: + static const int kSignificandSize = 52; + static const int kExponentBias = 0x3FF; + static const int kDenormalExponent = 1 - kExponentBias; + static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); + static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + union { + double d_; + uint64_t u_; + }; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_IEEE754_ diff --git a/WXom062/rapidjson/internal/itoa.h b/WXom062/rapidjson/internal/itoa.h new file mode 100644 index 0000000..a39accb --- /dev/null +++ b/WXom062/rapidjson/internal/itoa.h @@ -0,0 +1,309 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline const char* GetDigitsLut() { + static const char cDigitsLut[200] = { + '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', + '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', + '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', + '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', + '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', + '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', + '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', + '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', + '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', + '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' + }; + return cDigitsLut; +} + +inline char* u32toa(uint32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + + const char* cDigitsLut = GetDigitsLut(); + + if (value < 10000) { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else if (value < 100000000) { + // value = bbbbcccc + const uint32_t b = value / 10000; + const uint32_t c = value % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + else { + // value = aabbbbcccc in decimal + + const uint32_t a = value / 100000000; // 1 to 42 + value %= 100000000; + + if (a >= 10) { + const unsigned i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + *buffer++ = static_cast('0' + static_cast(a)); + + const uint32_t b = value / 10000; // 0 to 9999 + const uint32_t c = value % 10000; // 0 to 9999 + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + return buffer; +} + +inline char* i32toa(int32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + uint32_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u32toa(u, buffer); +} + +inline char* u64toa(uint64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + const char* cDigitsLut = GetDigitsLut(); + const uint64_t kTen8 = 100000000; + const uint64_t kTen9 = kTen8 * 10; + const uint64_t kTen10 = kTen8 * 100; + const uint64_t kTen11 = kTen8 * 1000; + const uint64_t kTen12 = kTen8 * 10000; + const uint64_t kTen13 = kTen8 * 100000; + const uint64_t kTen14 = kTen8 * 1000000; + const uint64_t kTen15 = kTen8 * 10000000; + const uint64_t kTen16 = kTen8 * kTen8; + + if (value < kTen8) { + uint32_t v = static_cast(value); + if (v < 10000) { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) + *buffer++ = cDigitsLut[d1]; + if (v >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (v >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else { + // value = bbbbcccc + const uint32_t b = v / 10000; + const uint32_t c = v % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + } + else if (value < kTen16) { + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + if (value >= kTen15) + *buffer++ = cDigitsLut[d1]; + if (value >= kTen14) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= kTen13) + *buffer++ = cDigitsLut[d2]; + if (value >= kTen12) + *buffer++ = cDigitsLut[d2 + 1]; + if (value >= kTen11) + *buffer++ = cDigitsLut[d3]; + if (value >= kTen10) + *buffer++ = cDigitsLut[d3 + 1]; + if (value >= kTen9) + *buffer++ = cDigitsLut[d4]; + if (value >= kTen8) + *buffer++ = cDigitsLut[d4 + 1]; + + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + else { + const uint32_t a = static_cast(value / kTen16); // 1 to 1844 + value %= kTen16; + + if (a < 10) + *buffer++ = static_cast('0' + static_cast(a)); + else if (a < 100) { + const uint32_t i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else if (a < 1000) { + *buffer++ = static_cast('0' + static_cast(a / 100)); + + const uint32_t i = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else { + const uint32_t i = (a / 100) << 1; + const uint32_t j = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + *buffer++ = cDigitsLut[j]; + *buffer++ = cDigitsLut[j + 1]; + } + + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + + return buffer; +} + +inline char* i64toa(int64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + uint64_t u = static_cast(value); + if (value < 0) { + *buffer++ = '-'; + u = ~u + 1; + } + + return u64toa(u, buffer); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ITOA_ diff --git a/WXom062/rapidjson/internal/meta.h b/WXom062/rapidjson/internal/meta.h new file mode 100644 index 0000000..5a9aaa4 --- /dev/null +++ b/WXom062/rapidjson/internal/meta.h @@ -0,0 +1,181 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ + +#include "../rapidjson.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif +#if defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif + +//@cond RAPIDJSON_INTERNAL +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching +template struct Void { typedef void Type; }; + +/////////////////////////////////////////////////////////////////////////////// +// BoolType, TrueType, FalseType +// +template struct BoolType { + static const bool Value = Cond; + typedef BoolType Type; +}; +typedef BoolType TrueType; +typedef BoolType FalseType; + + +/////////////////////////////////////////////////////////////////////////////// +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr +// + +template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; +template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; +template struct SelectIfCond : SelectIfImpl::template Apply {}; +template struct SelectIf : SelectIfCond {}; + +template struct AndExprCond : FalseType {}; +template <> struct AndExprCond : TrueType {}; +template struct OrExprCond : TrueType {}; +template <> struct OrExprCond : FalseType {}; + +template struct BoolExpr : SelectIf::Type {}; +template struct NotExpr : SelectIf::Type {}; +template struct AndExpr : AndExprCond::Type {}; +template struct OrExpr : OrExprCond::Type {}; + + +/////////////////////////////////////////////////////////////////////////////// +// AddConst, MaybeAddConst, RemoveConst +template struct AddConst { typedef const T Type; }; +template struct MaybeAddConst : SelectIfCond {}; +template struct RemoveConst { typedef T Type; }; +template struct RemoveConst { typedef T Type; }; + + +/////////////////////////////////////////////////////////////////////////////// +// IsSame, IsConst, IsMoreConst, IsPointer +// +template struct IsSame : FalseType {}; +template struct IsSame : TrueType {}; + +template struct IsConst : FalseType {}; +template struct IsConst : TrueType {}; + +template +struct IsMoreConst + : AndExpr::Type, typename RemoveConst::Type>, + BoolType::Value >= IsConst::Value> >::Type {}; + +template struct IsPointer : FalseType {}; +template struct IsPointer : TrueType {}; + +/////////////////////////////////////////////////////////////////////////////// +// IsBaseOf +// +#if RAPIDJSON_HAS_CXX11_TYPETRAITS + +template struct IsBaseOf + : BoolType< ::std::is_base_of::value> {}; + +#else // simplified version adopted from Boost + +template struct IsBaseOfImpl { + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + + typedef char (&Yes)[1]; + typedef char (&No) [2]; + + template + static Yes Check(const D*, T); + static No Check(const B*, int); + + struct Host { + operator const B*() const; + operator const D*(); + }; + + enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; +}; + +template struct IsBaseOf + : OrExpr, BoolExpr > >::Type {}; + +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS + + +////////////////////////////////////////////////////////////////////////// +// EnableIf / DisableIf +// +template struct EnableIfCond { typedef T Type; }; +template struct EnableIfCond { /* empty */ }; + +template struct DisableIfCond { typedef T Type; }; +template struct DisableIfCond { /* empty */ }; + +template +struct EnableIf : EnableIfCond {}; + +template +struct DisableIf : DisableIfCond {}; + +// SFINAE helpers +struct SfinaeTag {}; +template struct RemoveSfinaeTag; +template struct RemoveSfinaeTag { typedef T Type; }; + +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type + +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type * = NULL + +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type * = NULL + +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type + +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type + +} // namespace internal +RAPIDJSON_NAMESPACE_END +//@endcond + +#if defined(__GNUC__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/WXom062/rapidjson/internal/pow10.h b/WXom062/rapidjson/internal/pow10.h new file mode 100644 index 0000000..02f475d --- /dev/null +++ b/WXom062/rapidjson/internal/pow10.h @@ -0,0 +1,55 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Computes integer powers of 10 in double (10.0^n). +/*! This function uses lookup table for fast and accurate results. + \param n non-negative exponent. Must <= 308. + \return 10.0^n +*/ +inline double Pow10(int n) { + static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes + 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n >= 0 && n <= 308); + return e[n]; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_POW10_ diff --git a/WXom062/rapidjson/internal/regex.h b/WXom062/rapidjson/internal/regex.h new file mode 100644 index 0000000..e1a2faa --- /dev/null +++ b/WXom062/rapidjson/internal/regex.h @@ -0,0 +1,734 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_REGEX_H_ +#define RAPIDJSON_INTERNAL_REGEX_H_ + +#include "../allocators.h" +#include "../stream.h" +#include "stack.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 7 +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +#ifndef RAPIDJSON_REGEX_VERBOSE +#define RAPIDJSON_REGEX_VERBOSE 0 +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// DecodedStream + +template +class DecodedStream { +public: + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } + unsigned Peek() { return codepoint_; } + unsigned Take() { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + +private: + void Decode() { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream& ss_; + unsigned codepoint_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericRegex + +static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 +static const SizeType kRegexInvalidRange = ~SizeType(0); + +template +class GenericRegexSearch; + +//! Regular expression engine with subset of ECMAscript grammar. +/*! + Supported regular expression syntax: + - \c ab Concatenation + - \c a|b Alternation + - \c a? Zero or one + - \c a* Zero or more + - \c a+ One or more + - \c a{3} Exactly 3 times + - \c a{3,} At least 3 times + - \c a{3,5} 3 to 5 times + - \c (ab) Grouping + - \c ^a At the beginning + - \c a$ At the end + - \c . Any character + - \c [abc] Character classes + - \c [a-c] Character class range + - \c [a-z0-9_] Character class combination + - \c [^abc] Negated character classes + - \c [^a-c] Negated character class range + - \c [\b] Backspace (U+0008) + - \c \\| \\\\ ... Escape characters + - \c \\f Form feed (U+000C) + - \c \\n Line feed (U+000A) + - \c \\r Carriage return (U+000D) + - \c \\t Tab (U+0009) + - \c \\v Vertical tab (U+000B) + + \note This is a Thompson NFA engine, implemented with reference to + Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", + https://swtch.com/~rsc/regexp/regexp1.html +*/ +template +class GenericRegex { +public: + typedef Encoding EncodingType; + typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; + + GenericRegex(const Ch* source, Allocator* allocator = 0) : + states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + anchorBegin_(), anchorEnd_() + { + GenericStringStream ss(source); + DecodedStream, Encoding> ds(ss); + Parse(ds); + } + + ~GenericRegex() {} + + bool IsValid() const { + return root_ != kRegexInvalidState; + } + +private: + enum Operator { + kZeroOrOne, + kZeroOrMore, + kOneOrMore, + kConcatenation, + kAlternation, + kLeftParenthesis + }; + + static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' + static const unsigned kRangeCharacterClass = 0xFFFFFFFE; + static const unsigned kRangeNegationFlag = 0x80000000; + + struct Range { + unsigned start; // + unsigned end; + SizeType next; + }; + + struct State { + SizeType out; //!< Equals to kInvalid for matching state + SizeType out1; //!< Equals to non-kInvalid for split + SizeType rangeStart; + unsigned codepoint; + }; + + struct Frag { + Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} + SizeType start; + SizeType out; //!< link-list of all output states + SizeType minIndex; + }; + + State& GetState(SizeType index) { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + const State& GetState(SizeType index) const { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + Range& GetRange(SizeType index) { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + const Range& GetRange(SizeType index) const { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + template + void Parse(DecodedStream& ds) { + Allocator allocator; + Stack operandStack(&allocator, 256); // Frag + Stack operatorStack(&allocator, 256); // Operator + Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + + *atomCountStack.template Push() = 0; + + unsigned codepoint; + while (ds.Peek() != 0) { + switch (codepoint = ds.Take()) { + case '^': + anchorBegin_ = true; + break; + + case '$': + anchorEnd_ = true; + break; + + case '|': + while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + *operatorStack.template Push() = kAlternation; + *atomCountStack.template Top() = 0; + break; + + case '(': + *operatorStack.template Push() = kLeftParenthesis; + *atomCountStack.template Push() = 0; + break; + + case ')': + while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + if (operatorStack.Empty()) + return; + operatorStack.template Pop(1); + atomCountStack.template Pop(1); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '?': + if (!Eval(operandStack, kZeroOrOne)) + return; + break; + + case '*': + if (!Eval(operandStack, kZeroOrMore)) + return; + break; + + case '+': + if (!Eval(operandStack, kOneOrMore)) + return; + break; + + case '{': + { + unsigned n, m; + if (!ParseUnsigned(ds, &n)) + return; + + if (ds.Peek() == ',') { + ds.Take(); + if (ds.Peek() == '}') + m = kInfinityQuantifier; + else if (!ParseUnsigned(ds, &m) || m < n) + return; + } + else + m = n; + + if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') + return; + ds.Take(); + } + break; + + case '.': + PushOperand(operandStack, kAnyCharacterClass); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '[': + { + SizeType range; + if (!ParseRange(ds, &range)) + return; + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); + GetState(s).rangeStart = range; + *operandStack.template Push() = Frag(s, s, s); + } + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '\\': // Escape character + if (!CharacterEscape(ds, &codepoint)) + return; // Unsupported escape character + // fall through to default + + default: // Pattern character + PushOperand(operandStack, codepoint); + ImplicitConcatenation(atomCountStack, operatorStack); + } + } + + while (!operatorStack.Empty()) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + + // Link the operand to matching state. + if (operandStack.GetSize() == sizeof(Frag)) { + Frag* e = operandStack.template Pop(1); + Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); + root_ = e->start; + +#if RAPIDJSON_REGEX_VERBOSE + printf("root: %d\n", root_); + for (SizeType i = 0; i < stateCount_ ; i++) { + State& s = GetState(i); + printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); + } + printf("\n"); +#endif + } + } + + SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { + State* s = states_.template Push(); + s->out = out; + s->out1 = out1; + s->codepoint = codepoint; + s->rangeStart = kRegexInvalidRange; + return stateCount_++; + } + + void PushOperand(Stack& operandStack, unsigned codepoint) { + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); + *operandStack.template Push() = Frag(s, s, s); + } + + void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { + if (*atomCountStack.template Top()) + *operatorStack.template Push() = kConcatenation; + (*atomCountStack.template Top())++; + } + + SizeType Append(SizeType l1, SizeType l2) { + SizeType old = l1; + while (GetState(l1).out != kRegexInvalidState) + l1 = GetState(l1).out; + GetState(l1).out = l2; + return old; + } + + void Patch(SizeType l, SizeType s) { + for (SizeType next; l != kRegexInvalidState; l = next) { + next = GetState(l).out; + GetState(l).out = s; + } + } + + bool Eval(Stack& operandStack, Operator op) { + switch (op) { + case kConcatenation: + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); + { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + Patch(e1.out, e2.start); + *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); + } + return true; + + case kAlternation: + if (operandStack.GetSize() >= sizeof(Frag) * 2) { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + SizeType s = NewState(e1.start, e2.start, 0); + *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); + return true; + } + return false; + + case kZeroOrOne: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); + return true; + } + return false; + + case kZeroOrMore: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(s, s, e.minIndex); + return true; + } + return false; + + default: + RAPIDJSON_ASSERT(op == kOneOrMore); + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(e.start, s, e.minIndex); + return true; + } + return false; + } + } + + bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { + RAPIDJSON_ASSERT(n <= m); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); + + if (n == 0) { + if (m == 0) // a{0} not support + return false; + else if (m == kInfinityQuantifier) + Eval(operandStack, kZeroOrMore); // a{0,} -> a* + else { + Eval(operandStack, kZeroOrOne); // a{0,5} -> a? + for (unsigned i = 0; i < m - 1; i++) + CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? + for (unsigned i = 0; i < m - 1; i++) + Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? + } + return true; + } + + for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a + CloneTopOperand(operandStack); + + if (m == kInfinityQuantifier) + Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ + else if (m > n) { + CloneTopOperand(operandStack); // a{3,5} -> a a a a + Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? + for (unsigned i = n; i < m - 1; i++) + CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? + for (unsigned i = n; i < m; i++) + Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? + } + + for (unsigned i = 0; i < n - 1; i++) + Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? + + return true; + } + + static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } + + void CloneTopOperand(Stack& operandStack) { + const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation + SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) + State* s = states_.template Push(count); + memcpy(s, &GetState(src.minIndex), count * sizeof(State)); + for (SizeType j = 0; j < count; j++) { + if (s[j].out != kRegexInvalidState) + s[j].out += count; + if (s[j].out1 != kRegexInvalidState) + s[j].out1 += count; + } + *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); + stateCount_ += count; + } + + template + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + unsigned r = 0; + if (ds.Peek() < '0' || ds.Peek() > '9') + return false; + while (ds.Peek() >= '0' && ds.Peek() <= '9') { + if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 + return false; // overflow + r = r * 10 + (ds.Take() - '0'); + } + *u = r; + return true; + } + + template + bool ParseRange(DecodedStream& ds, SizeType* range) { + bool isBegin = true; + bool negate = false; + int step = 0; + SizeType start = kRegexInvalidRange; + SizeType current = kRegexInvalidRange; + unsigned codepoint; + while ((codepoint = ds.Take()) != 0) { + if (isBegin) { + isBegin = false; + if (codepoint == '^') { + negate = true; + continue; + } + } + + switch (codepoint) { + case ']': + if (start == kRegexInvalidRange) + return false; // Error: nothing inside [] + if (step == 2) { // Add trailing '-' + SizeType r = NewRange('-'); + RAPIDJSON_ASSERT(current != kRegexInvalidRange); + GetRange(current).next = r; + } + if (negate) + GetRange(start).start |= kRangeNegationFlag; + *range = start; + return true; + + case '\\': + if (ds.Peek() == 'b') { + ds.Take(); + codepoint = 0x0008; // Escape backspace character + } + else if (!CharacterEscape(ds, &codepoint)) + return false; + // fall through to default + + default: + switch (step) { + case 1: + if (codepoint == '-') { + step++; + break; + } + // fall through to step 0 for other characters + + case 0: + { + SizeType r = NewRange(codepoint); + if (current != kRegexInvalidRange) + GetRange(current).next = r; + if (start == kRegexInvalidRange) + start = r; + current = r; + } + step = 1; + break; + + default: + RAPIDJSON_ASSERT(step == 2); + GetRange(current).end = codepoint; + step = 0; + } + } + } + return false; + } + + SizeType NewRange(unsigned codepoint) { + Range* r = ranges_.template Push(); + r->start = r->end = codepoint; + r->next = kRegexInvalidRange; + return rangeCount_++; + } + + template + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + unsigned codepoint; + switch (codepoint = ds.Take()) { + case '^': + case '$': + case '|': + case '(': + case ')': + case '?': + case '*': + case '+': + case '.': + case '[': + case ']': + case '{': + case '}': + case '\\': + *escapedCodepoint = codepoint; return true; + case 'f': *escapedCodepoint = 0x000C; return true; + case 'n': *escapedCodepoint = 0x000A; return true; + case 'r': *escapedCodepoint = 0x000D; return true; + case 't': *escapedCodepoint = 0x0009; return true; + case 'v': *escapedCodepoint = 0x000B; return true; + default: + return false; // Unsupported escape character + } + } + + Stack states_; + Stack ranges_; + SizeType root_; + SizeType stateCount_; + SizeType rangeCount_; + + static const unsigned kInfinityQuantifier = ~0u; + + // For SearchWithAnchoring() + bool anchorBegin_; + bool anchorEnd_; +}; + +template +class GenericRegexSearch { +public: + typedef typename RegexType::EncodingType Encoding; + typedef typename Encoding::Ch Ch; + + GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : + regex_(regex), allocator_(allocator), ownAllocator_(0), + state0_(allocator, 0), state1_(allocator, 0), stateSet_() + { + RAPIDJSON_ASSERT(regex_.IsValid()); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + state0_.template Reserve(regex_.stateCount_); + state1_.template Reserve(regex_.stateCount_); + } + + ~GenericRegexSearch() { + Allocator::Free(stateSet_); + RAPIDJSON_DELETE(ownAllocator_); + } + + template + bool Match(InputStream& is) { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch* s) { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream& is) { + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); + } + + bool Search(const Ch* s) { + GenericStringStream is(s); + return Search(is); + } + +private: + typedef typename RegexType::State State; + typedef typename RegexType::Range Range; + + template + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { + DecodedStream ds(is); + + state0_.Clear(); + Stack *current = &state0_, *next = &state1_; + const size_t stateSetSize = GetStateSetSize(); + std::memset(stateSet_, 0, stateSetSize); + + bool matched = AddState(*current, regex_.root_); + unsigned codepoint; + while (!current->Empty() && (codepoint = ds.Take()) != 0) { + std::memset(stateSet_, 0, stateSetSize); + next->Clear(); + matched = false; + for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { + const State& sr = regex_.GetState(*s); + if (sr.codepoint == codepoint || + sr.codepoint == RegexType::kAnyCharacterClass || + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + { + matched = AddState(*next, sr.out) || matched; + if (!anchorEnd && matched) + return true; + } + if (!anchorBegin) + AddState(*next, regex_.root_); + } + internal::Swap(current, next); + } + + return matched; + } + + size_t GetStateSetSize() const { + return (regex_.stateCount_ + 31) / 32 * 4; + } + + // Return whether the added states is a match state + bool AddState(Stack& l, SizeType index) { + RAPIDJSON_ASSERT(index != kRegexInvalidState); + + const State& s = regex_.GetState(index); + if (s.out1 != kRegexInvalidState) { // Split + bool matched = AddState(l, s.out); + return AddState(l, s.out1) || matched; + } + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { + stateSet_[index >> 5] |= (1u << (index & 31)); + *l.template PushUnsafe() = index; + } + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. + } + + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; + while (rangeIndex != kRegexInvalidRange) { + const Range& r = regex_.GetRange(rangeIndex); + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) + return yes; + rangeIndex = r.next; + } + return !yes; + } + + const RegexType& regex_; + Allocator* allocator_; + Allocator* ownAllocator_; + Stack state0_; + Stack state1_; + uint32_t* stateSet_; +}; + +typedef GenericRegex > Regex; +typedef GenericRegexSearch RegexSearch; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/WXom062/rapidjson/internal/stack.h b/WXom062/rapidjson/internal/stack.h new file mode 100644 index 0000000..89558d0 --- /dev/null +++ b/WXom062/rapidjson/internal/stack.h @@ -0,0 +1,231 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ + +#include "../allocators.h" +#include "swap.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// Stack + +//! A type-unsafe stack for storing different types of data. +/*! \tparam Allocator Allocator for allocating stack memory. +*/ +template +class Stack { +public: + // Optimization note: Do not allocate memory for stack_ in constructor. + // Do it lazily when first Push() -> Expand() -> Resize(). + Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack(Stack&& rhs) + : allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(rhs.stack_), + stackTop_(rhs.stackTop_), + stackEnd_(rhs.stackEnd_), + initialCapacity_(rhs.initialCapacity_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } +#endif + + ~Stack() { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack& operator=(Stack&& rhs) { + if (&rhs != this) + { + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = rhs.stack_; + stackTop_ = rhs.stackTop_; + stackEnd_ = rhs.stackEnd_; + initialCapacity_ = rhs.initialCapacity_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } + return *this; + } +#endif + + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); + } + + void Clear() { stackTop_ = stack_; } + + void ShrinkToFit() { + if (Empty()) { + // If the stack is empty, completely deallocate the memory. + Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) + stack_ = 0; + stackTop_ = 0; + stackEnd_ = 0; + } + else + Resize(GetSize()); + } + + // Optimization note: try to minimize the size of this function for force inline. + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. + template + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { + // Expand the stack if needed + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + Expand(count); + } + + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + Reserve(count); + return PushUnsafe(count); + } + + template + RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { + RAPIDJSON_ASSERT(stackTop_); + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + T* ret = reinterpret_cast(stackTop_); + stackTop_ += sizeof(T) * count; + return ret; + } + + template + T* Pop(size_t count) { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stackTop_ -= count * sizeof(T); + return reinterpret_cast(stackTop_); + } + + template + T* Top() { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + const T* Top() const { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T* End() { return reinterpret_cast(stackTop_); } + + template + const T* End() const { return reinterpret_cast(stackTop_); } + + template + T* Bottom() { return reinterpret_cast(stack_); } + + template + const T* Bottom() const { return reinterpret_cast(stack_); } + + bool HasAllocator() const { + return allocator_ != 0; + } + + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + bool Empty() const { return stackTop_ == stack_; } + size_t GetSize() const { return static_cast(stackTop_ - stack_); } + size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } + +private: + template + void Expand(size_t count) { + // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. + size_t newCapacity; + if (stack_ == 0) { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + newCapacity = initialCapacity_; + } else { + newCapacity = GetCapacity(); + newCapacity += (newCapacity + 1) / 2; + } + size_t newSize = GetSize() + sizeof(T) * count; + if (newCapacity < newSize) + newCapacity = newSize; + + Resize(newCapacity); + } + + void Resize(size_t newCapacity) { + const size_t size = GetSize(); // Backup the current size + stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); + stackTop_ = stack_ + size; + stackEnd_ = stack_ + newCapacity; + } + + void Destroy() { + Allocator::Free(stack_); + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack + } + + // Prohibit copy constructor & assignment operator. + Stack(const Stack&); + Stack& operator=(const Stack&); + + Allocator* allocator_; + Allocator* ownAllocator_; + char *stack_; + char *stackTop_; + char *stackEnd_; + size_t initialCapacity_; +}; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STACK_H_ diff --git a/WXom062/rapidjson/internal/strfunc.h b/WXom062/rapidjson/internal/strfunc.h new file mode 100644 index 0000000..226439a --- /dev/null +++ b/WXom062/rapidjson/internal/strfunc.h @@ -0,0 +1,69 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +#include "../stream.h" +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom strlen() which works on different character types. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +*/ +template +inline SizeType StrLen(const Ch* s) { + RAPIDJSON_ASSERT(s != 0); + const Ch* p = s; + while (*p) ++p; + return SizeType(p - s); +} + +template <> +inline SizeType StrLen(const char* s) { + return SizeType(std::strlen(s)); +} + +template <> +inline SizeType StrLen(const wchar_t* s) { + return SizeType(std::wcslen(s)); +} + +//! Returns number of code points in a encoded string. +template +bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { + RAPIDJSON_ASSERT(s != 0); + RAPIDJSON_ASSERT(outCount != 0); + GenericStringStream is(s); + const typename Encoding::Ch* end = s + length; + SizeType count = 0; + while (is.src_ < end) { + unsigned codepoint; + if (!Encoding::Decode(is, &codepoint)) + return false; + count++; + } + *outCount = count; + return true; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/WXom062/rapidjson/internal/strtod.h b/WXom062/rapidjson/internal/strtod.h new file mode 100644 index 0000000..adf49e3 --- /dev/null +++ b/WXom062/rapidjson/internal/strtod.h @@ -0,0 +1,269 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "ieee754.h" +#include "biginteger.h" +#include "diyfp.h" +#include "pow10.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +inline double FastPath(double significand, int exp) { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); +} + +inline double StrtodNormalPrecision(double d, int p) { + if (p < -308) { + // Prevent expSum < -308, making Pow10(p) = 0 + d = FastPath(d, -308); + d = FastPath(d, p + 308); + } + else + d = FastPath(d, p); + return d; +} + +template +inline T Min3(T a, T b, T c) { + T m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; +} + +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { + const Double db(b); + const uint64_t bInt = db.IntegerSignificand(); + const int bExp = db.IntegerExponent(); + const int hExp = bExp - 1; + + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; + + // Adjust for decimal exponent + if (dExp >= 0) { + dS_Exp2 += dExp; + dS_Exp5 += dExp; + } + else { + bS_Exp2 -= dExp; + bS_Exp5 -= dExp; + hS_Exp2 -= dExp; + hS_Exp5 -= dExp; + } + + // Adjust for binary exponent + if (bExp >= 0) + bS_Exp2 += bExp; + else { + dS_Exp2 -= bExp; + hS_Exp2 -= bExp; + } + + // Adjust for half ulp exponent + if (hExp >= 0) + hS_Exp2 += hExp; + else { + dS_Exp2 -= hExp; + bS_Exp2 -= hExp; + } + + // Remove common power of two factor from all three scaled values + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); + dS_Exp2 -= common_Exp2; + bS_Exp2 -= common_Exp2; + hS_Exp2 -= common_Exp2; + + BigInteger dS = d; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); + + BigInteger bS(bInt); + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); + + BigInteger hS(1); + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); + + BigInteger delta(0); + dS.Difference(bS, &delta); + + return delta.Compare(hS); +} + +inline bool StrtodFast(double d, int p, double* result) { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (p > 22 && p < 22 + 16) { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 + *result = FastPath(d, p); + return true; + } + else + return false; +} + +// Compute an approximation and see if it is within 1/2 ULP +inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { + uint64_t significand = 0; + size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < length; i++) { + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + break; + significand = significand * 10u + static_cast(decimals[i] - '0'); + } + + if (i < length && decimals[i] >= '5') // Rounding + significand++; + + size_t remaining = length - i; + const int kUlpShift = 3; + const int kUlp = 1 << kUlpShift; + int64_t error = (remaining == 0) ? 0 : kUlp / 2; + + DiyFp v(significand, 0); + v = v.Normalize(); + error <<= -v.e; + + const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; + + int actualExp; + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); + if (actualExp != dExp) { + static const DiyFp kPow10[] = { + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 + }; + int adjustment = dExp - actualExp - 1; + RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); + v = v * kPow10[adjustment]; + if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit + error += kUlp / 2; + } + + v = v * cachedPower; + + error += kUlp + (error == 0 ? 0 : 1); + + const int oldExp = v.e; + v = v.Normalize(); + error <<= oldExp - v.e; + + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; + if (precisionSize + kUlpShift >= 64) { + int scaleExp = (precisionSize + kUlpShift) - 63; + v.f >>= scaleExp; + v.e += scaleExp; + error = (error >> scaleExp) + 1 + kUlp; + precisionSize -= scaleExp; + } + + DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; + if (precisionBits >= halfWay + static_cast(error)) { + rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) + rounded.f >>= 1; + rounded.e++; + } + } + + *result = rounded.ToDouble(); + + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); +} + +inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { + const BigInteger dInt(decimals, length); + const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; + Double a(approx); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); + } + else // adjustment + return a.NextPositiveDouble(); +} + +inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); + + double result; + if (StrtodFast(d, p, &result)) + return result; + + // Trim leading zeros + while (*decimals == '0' && length > 1) { + length--; + decimals++; + decimalPosition--; + } + + // Trim trailing zeros + while (decimals[length - 1] == '0' && length > 1) { + length--; + decimalPosition--; + exp++; + } + + // Trim right-most digits + const int kMaxDecimalDigit = 780; + if (static_cast(length) > kMaxDecimalDigit) { + int delta = (static_cast(length) - kMaxDecimalDigit); + exp += delta; + decimalPosition -= static_cast(delta); + length = kMaxDecimalDigit; + } + + // If too small, underflow to zero + if (int(length) + exp < -324) + return 0.0; + + if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) + return result; + + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison + return StrtodBigInteger(result, decimals, length, decimalPosition, exp); +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRTOD_ diff --git a/WXom062/rapidjson/internal/swap.h b/WXom062/rapidjson/internal/swap.h new file mode 100644 index 0000000..666e49f --- /dev/null +++ b/WXom062/rapidjson/internal/swap.h @@ -0,0 +1,46 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ + +#include "../rapidjson.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom swap() to avoid dependency on C++ header +/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. + \note This has the same semantics as std::swap(). +*/ +template +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { + T tmp = a; + a = b; + b = tmp; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/WXom062/rapidjson/istreamwrapper.h b/WXom062/rapidjson/istreamwrapper.h new file mode 100644 index 0000000..8639c8c --- /dev/null +++ b/WXom062/rapidjson/istreamwrapper.h @@ -0,0 +1,115 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class BasicIStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} + + Ch Peek() const { + typename StreamType::int_type c = stream_.peek(); + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); + } + + Ch Take() { + typename StreamType::int_type c = stream_.get(); + if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { + count_++; + return static_cast(c); + } + else + return '\0'; + } + + // tellg() may return -1 when failed. So we count by ourself. + size_t Tell() const { return count_; } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. + int i; + bool hasError = false; + for (i = 0; i < 4; ++i) { + typename StreamType::int_type c = stream_.get(); + if (c == StreamType::traits_type::eof()) { + hasError = true; + stream_.clear(); + break; + } + peekBuffer_[i] = static_cast(c); + } + for (--i; i >= 0; --i) + stream_.putback(peekBuffer_[i]); + return !hasError ? peekBuffer_ : 0; + } + +private: + BasicIStreamWrapper(const BasicIStreamWrapper&); + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + + StreamType& stream_; + size_t count_; //!< Number of characters read. Note: + mutable Ch peekBuffer_[4]; +}; + +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/WXom062/rapidjson/memorybuffer.h b/WXom062/rapidjson/memorybuffer.h new file mode 100644 index 0000000..39bee1d --- /dev/null +++ b/WXom062/rapidjson/memorybuffer.h @@ -0,0 +1,70 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYBUFFER_H_ +#define RAPIDJSON_MEMORYBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output byte stream. +/*! + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. + + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. + + Differences between MemoryBuffer and StringBuffer: + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. + + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +struct GenericMemoryBuffer { + typedef char Ch; // byte + + GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { stack_.ShrinkToFit(); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetBuffer() const { + return stack_.template Bottom(); + } + + size_t GetSize() const { return stack_.GetSize(); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; +}; + +typedef GenericMemoryBuffer<> MemoryBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { + std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/WXom062/rapidjson/memorystream.h b/WXom062/rapidjson/memorystream.h new file mode 100644 index 0000000..1d71d8a --- /dev/null +++ b/WXom062/rapidjson/memorystream.h @@ -0,0 +1,71 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYSTREAM_H_ +#define RAPIDJSON_MEMORYSTREAM_H_ + +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory input byte stream. +/*! + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. + + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. + + Differences between MemoryStream and StringStream: + 1. StringStream has encoding but MemoryStream is a byte stream. + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). + \note implements Stream concept +*/ +struct MemoryStream { + typedef char Ch; // byte + + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} + + Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } + Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } + size_t Tell() const { return static_cast(src_ - begin_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + return Tell() + 4 <= size_ ? src_ : 0; + } + + const Ch* src_; //!< Current read position. + const Ch* begin_; //!< Original head of the string. + const Ch* end_; //!< End of stream. + size_t size_; //!< Size of the stream. +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/WXom062/rapidjson/msinttypes/inttypes.h b/WXom062/rapidjson/msinttypes/inttypes.h new file mode 100644 index 0000000..1811128 --- /dev/null +++ b/WXom062/rapidjson/msinttypes/inttypes.h @@ -0,0 +1,316 @@ +// ISO C9x compliant inttypes.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. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// miloyip: VC supports inttypes.h since VC2013 +#if _MSC_VER >= 1800 +#include +#else + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + +#endif // _MSC_VER >= 1800 + +#endif // _MSC_INTTYPES_H_ ] diff --git a/WXom062/rapidjson/msinttypes/stdint.h b/WXom062/rapidjson/msinttypes/stdint.h new file mode 100644 index 0000000..3d4477b --- /dev/null +++ b/WXom062/rapidjson/msinttypes/stdint.h @@ -0,0 +1,300 @@ +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#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 + +// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. +#if _MSC_VER >= 1600 // [ +#include + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +#undef INT8_C +#undef INT16_C +#undef INT32_C +#undef INT64_C +#undef UINT8_C +#undef UINT16_C +#undef UINT32_C +#undef UINT64_C + +// 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 . +// 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 ] + +#else // ] _MSC_VER >= 1700 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we have to wrap include with 'extern "C++" {}' +// or compiler would give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if defined(__cplusplus) && !defined(_M_ARM) +extern "C" { +#endif +# include +#if defined(__cplusplus) && !defined(_M_ARM) +} +#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 +#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 . +// 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_ ] diff --git a/WXom062/rapidjson/ostreamwrapper.h b/WXom062/rapidjson/ostreamwrapper.h new file mode 100644 index 0000000..6f4667c --- /dev/null +++ b/WXom062/rapidjson/ostreamwrapper.h @@ -0,0 +1,81 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ +#define RAPIDJSON_OSTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::ostringstream + - \c std::stringstream + - \c std::wpstringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wofstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_ostream. +*/ + +template +class BasicOStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} + + void Put(Ch c) { + stream_.put(c); + } + + void Flush() { + stream_.flush(); + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + BasicOStreamWrapper(const BasicOStreamWrapper&); + BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); + + StreamType& stream_; +}; + +typedef BasicOStreamWrapper OStreamWrapper; +typedef BasicOStreamWrapper WOStreamWrapper; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/WXom062/rapidjson/pointer.h b/WXom062/rapidjson/pointer.h new file mode 100644 index 0000000..8bcb85e --- /dev/null +++ b/WXom062/rapidjson/pointer.h @@ -0,0 +1,1363 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POINTER_H_ +#define RAPIDJSON_POINTER_H_ + +#include "document.h" +#include "internal/itoa.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode { + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericPointer + +//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. +/*! + This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" + (https://tools.ietf.org/html/rfc6901). + + A JSON pointer is for identifying a specific value in a JSON document + (GenericDocument). It can simplify coding of DOM tree manipulation, because it + can access multiple-level depth of DOM tree with single API call. + + After it parses a string representation (e.g. "/foo/0" or URI fragment + representation (e.g. "#/foo/0") into its internal representation (tokens), + it can be used to resolve a specific value in multiple documents, or sub-tree + of documents. + + Contrary to GenericValue, Pointer can be copy constructed and copy assigned. + Apart from assignment, a Pointer cannot be modified after construction. + + Although Pointer is very convenient, please aware that constructing Pointer + involves parsing and dynamic memory allocation. A special constructor with user- + supplied tokens eliminates these. + + GenericPointer depends on GenericDocument and GenericValue. + + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > + \tparam Allocator The allocator type for allocating memory for internal representation. + + \note GenericPointer uses same encoding of ValueType. + However, Allocator of GenericPointer is independent of Allocator of Value. +*/ +template +class GenericPointer { +public: + typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value + typedef typename ValueType::Ch Ch; //!< Character type from Value + + //! A token is the basic units of internal representation. + /*! + A JSON pointer string representation "/foo/123" is parsed to two tokens: + "foo" and 123. 123 will be represented in both numeric form and string form. + They are resolved according to the actual value type (object or array). + + For token that are not numbers, or the numeric value is out of bound + (greater than limits of SizeType), they are only treated as string form + (i.e. the token's index will be equal to kPointerInvalidIndex). + + This struct is public so that user can create a Pointer without parsing and + allocation, using a special constructor. + */ + struct Token { + const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. + SizeType length; //!< Length of the name. + SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. + }; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor. + GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A null-terminated, string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + */ + explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, internal::StrLen(source)); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source.c_str(), source.size()); + } +#endif + + //! Constructor that parses a string or URI fragment representation, with length of the source string. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param length Length of source. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Slightly faster than the overload without length. + */ + GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + Parse(source, length); + } + + //! Constructor with user-supplied tokens. + /*! + This constructor let user supplies const array of tokens. + This prevents the parsing process and eliminates allocation. + This is preferred for memory constrained environments. + + \param tokens An constant array of tokens representing the JSON pointer. + \param tokenCount Number of tokens. + + \b Example + \code + #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } + #define INDEX(i) { #i, sizeof(#i) - 1, i } + + static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; + static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); + // Equivalent to static const Pointer p("/foo/123"); + + #undef NAME + #undef INDEX + \endcode + */ + GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Destructor. + ~GenericPointer() { + if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. + Allocator::Free(tokens_); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator. + GenericPointer& operator=(const GenericPointer& rhs) { + if (this != &rhs) { + // Do not delete ownAllcator + if (nameBuffer_) + Allocator::Free(tokens_); + + tokenCount_ = rhs.tokenCount_; + parseErrorOffset_ = rhs.parseErrorOffset_; + parseErrorCode_ = rhs.parseErrorCode_; + + if (rhs.nameBuffer_) + CopyFromRaw(rhs); // Normally parsed tokens. + else { + tokens_ = rhs.tokens_; // User supplied const tokens. + nameBuffer_ = 0; + } + } + return *this; + } + + //@} + + //!@name Append token + //@{ + + //! Append a token and return a new Pointer + /*! + \param token Token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Token& token, Allocator* allocator = 0) const { + GenericPointer r; + r.allocator_ = allocator; + Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); + std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); + r.tokens_[tokenCount_].name = p; + r.tokens_[tokenCount_].length = token.length; + r.tokens_[tokenCount_].index = token.index; + return r; + } + + //! Append a name token with length, and return a new Pointer + /*! + \param name Name to be appended. + \param length Length of name. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { + Token token = { name, length, kPointerInvalidIndex }; + return Append(token, allocator); + } + + //! Append a name token without length, and return a new Pointer + /*! + \param name Name (const Ch*) to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) + Append(T* name, Allocator* allocator = 0) const { + return Append(name, internal::StrLen(name), allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Append a name token, and return a new Pointer + /*! + \param name Name to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { + return Append(name.c_str(), static_cast(name.size()), allocator); + } +#endif + + //! Append a index token, and return a new Pointer + /*! + \param index Index to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(SizeType index, Allocator* allocator = 0) const { + char buffer[21]; + char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); + SizeType length = static_cast(end - buffer); + buffer[length] = '\0'; + + if (sizeof(Ch) == 1) { + Token token = { reinterpret_cast(buffer), length, index }; + return Append(token, allocator); + } + else { + Ch name[21]; + for (size_t i = 0; i <= length; i++) + name[i] = static_cast(buffer[i]); + Token token = { name, length, index }; + return Append(token, allocator); + } + } + + //! Append a token by value, and return a new Pointer + /*! + \param token token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { + if (token.IsString()) + return Append(token.GetString(), token.GetStringLength(), allocator); + else { + RAPIDJSON_ASSERT(token.IsUint64()); + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); + return Append(static_cast(token.GetUint64()), allocator); + } + } + + //!@name Handling Parse Error + //@{ + + //! Check whether this is a valid pointer. + bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } + + //! Get the parsing error offset in code unit. + size_t GetParseErrorOffset() const { return parseErrorOffset_; } + + //! Get the parsing error code. + PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } + + //@} + + //! Get the allocator of this pointer. + Allocator& GetAllocator() { return *allocator_; } + + //!@name Tokens + //@{ + + //! Get the token array (const version only). + const Token* GetTokens() const { return tokens_; } + + //! Get the number of tokens. + size_t GetTokenCount() const { return tokenCount_; } + + //@} + + //!@name Equality/inequality operators + //@{ + + //! Equality operator. + /*! + \note When any pointers are invalid, always returns false. + */ + bool operator==(const GenericPointer& rhs) const { + if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) + return false; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index || + tokens_[i].length != rhs.tokens_[i].length || + (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) + { + return false; + } + } + + return true; + } + + //! Inequality operator. + /*! + \note When any pointers are invalid, always returns true. + */ + bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } + + //@} + + //!@name Stringify + //@{ + + //! Stringify the pointer into string representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + return Stringify(os); + } + + //! Stringify the pointer into URI fragment representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool StringifyUriFragment(OutputStream& os) const { + return Stringify(os); + } + + //@} + + //!@name Create value + //@{ + + //! Create a value in a subtree. + /*! + If the value is not exist, it creates all parent values and a JSON Null value. + So it always succeed and return the newly created or existing value. + + Remind that it may change types of parents according to tokens, so it + potentially removes previously stored values. For example, if a document + was an array, and "/foo" is used to create a value, then the document + will be changed to an object, and all existing array elements are lost. + + \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created (a JSON Null value), or already exists value. + */ + ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + bool exist = true; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + if (v->IsArray() && t->name[0] == '-' && t->length == 1) { + v->PushBack(ValueType().Move(), allocator); + v = &((*v)[v->Size() - 1]); + exist = false; + } + else { + if (t->index == kPointerInvalidIndex) { // must be object name + if (!v->IsObject()) + v->SetObject(); // Change to Object + } + else { // object name or array index + if (!v->IsArray() && !v->IsObject()) + v->SetArray(); // Change to Array + } + + if (v->IsArray()) { + if (t->index >= v->Size()) { + v->Reserve(t->index + 1, allocator); + while (t->index >= v->Size()) + v->PushBack(ValueType().Move(), allocator); + exist = false; + } + v = &((*v)[t->index]); + } + else { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) { + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); + v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + exist = false; + } + else + v = &m->value; + } + } + } + + if (alreadyExist) + *alreadyExist = exist; + + return *v; + } + + //! Creates a value in a document. + /*! + \param document A document to be resolved. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created, or already exists value. + */ + template + ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { + return Create(document, document.GetAllocator(), alreadyExist); + } + + //@} + + //!@name Query value + //@{ + + //! Query a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \return Pointer to the value if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a value cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. + */ + ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { + RAPIDJSON_ASSERT(IsValid()); + ValueType* v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + break; + v = &m->value; + } + continue; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + break; + v = &((*v)[t->index]); + continue; + default: + break; + } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return 0; + } + return v; + } + + //! Query a const value in a const subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Pointer to the value if it can be resolved. Otherwise null. + */ + const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { + return Get(const_cast(root), unresolvedTokenIndex); + } + + //@} + + //!@name Query a value with default + //@{ + + //! Query a value in a subtree with default value. + /*! + Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. + So that this function always succeed. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param defaultValue Default value to be cloned if the value was not exists. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + ValueType& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); + } + + //! Query a value in a subtree with default null-terminated string. + ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + ValueType& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a subtree with default std::basic_string. + ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { + bool alreadyExist; + ValueType& v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } +#endif + + //! Query a value in a subtree with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { + return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); + } + + //! Query a value in a document with default value. + template + ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //! Query a value in a document with default null-terminated string. + template + ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a document with default std::basic_string. + template + ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } +#endif + + //! Query a value in a document with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + GetWithDefault(GenericDocument& document, T defaultValue) const { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //@} + + //!@name Set a value + //@{ + + //! Set a value in a subtree, with move semantics. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be set. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = value; + } + + //! Set a value in a subtree, with copy semantics. + ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).CopyFrom(value, allocator); + } + + //! Set a null-terminated string in a subtree. + ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Set a std::basic_string in a subtree. + ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } +#endif + + //! Set a primitive value in a subtree. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator) = ValueType(value).Move(); + } + + //! Set a value in a document, with move semantics. + template + ValueType& Set(GenericDocument& document, ValueType& value) const { + return Create(document) = value; + } + + //! Set a value in a document, with copy semantics. + template + ValueType& Set(GenericDocument& document, const ValueType& value) const { + return Create(document).CopyFrom(value, document.GetAllocator()); + } + + //! Set a null-terminated string in a document. + template + ValueType& Set(GenericDocument& document, const Ch* value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Sets a std::basic_string in a document. + template + ValueType& Set(GenericDocument& document, const std::basic_string& value) const { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } +#endif + + //! Set a primitive value in a document. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) + Set(GenericDocument& document, T value) const { + return Create(document) = value; + } + + //@} + + //!@name Swap a value + //@{ + + //! Swap a value with a value in a subtree. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be swapped. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { + return Create(root, allocator).Swap(value); + } + + //! Swap a value with a value in a document. + template + ValueType& Swap(GenericDocument& document, ValueType& value) const { + return Create(document).Swap(value); + } + + //@} + + //! Erase a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Whether the resolved value is found and erased. + + \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. + */ + bool Erase(ValueType& root) const { + RAPIDJSON_ASSERT(IsValid()); + if (tokenCount_ == 0) // Cannot erase the root + return false; + + ValueType* v = &root; + const Token* last = tokens_ + (tokenCount_ - 1); + for (const Token *t = tokens_; t != last; ++t) { + switch (v->GetType()) { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + return false; + v = &m->value; + } + break; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + return false; + v = &((*v)[t->index]); + break; + default: + return false; + } + } + + switch (v->GetType()) { + case kObjectType: + return v->EraseMember(GenericStringRef(last->name, last->length)); + case kArrayType: + if (last->index == kPointerInvalidIndex || last->index >= v->Size()) + return false; + v->Erase(v->Begin() + last->index); + return true; + default: + return false; + } + } + +private: + //! Clone the content from rhs to this. + /*! + \param rhs Source pointer. + \param extraToken Extra tokens to be allocated. + \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. + \return Start of non-occupied name buffer, for storing extra names. + */ + Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { + if (!allocator_) // allocator is independently owned. + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens + for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) + nameBufferSize += t->length; + + tokenCount_ = rhs.tokenCount_ + extraToken; + tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); + nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + if (rhs.tokenCount_ > 0) { + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); + } + if (nameBufferSize > 0) { + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + } + + // Adjust pointers to name buffer + std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; + for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) + t->name += diff; + + return nameBuffer_ + nameBufferSize; + } + + //! Check whether a character should be percent-encoded. + /*! + According to RFC 3986 2.3 Unreserved Characters. + \param c The character (code unit) to be tested. + */ + bool NeedPercentEncode(Ch c) const { + return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); + } + + //! Parse a JSON String or its URI fragment representation into tokens. +#ifndef __clang__ // -Wdocumentation + /*! + \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. + \param length Length of the source string. + \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. + */ +#endif + void Parse(const Ch* source, size_t length) { + RAPIDJSON_ASSERT(source != NULL); + RAPIDJSON_ASSERT(nameBuffer_ == 0); + RAPIDJSON_ASSERT(tokens_ == 0); + + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + // Count number of '/' as tokenCount + tokenCount_ = 0; + for (const Ch* s = source; s != source + length; s++) + if (*s == '/') + tokenCount_++; + + Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); + Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + size_t i = 0; + + // Detect if it is a URI fragment + bool uriFragment = false; + if (source[i] == '#') { + uriFragment = true; + i++; + } + + if (i != length && source[i] != '/') { + parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; + goto error; + } + + while (i < length) { + RAPIDJSON_ASSERT(source[i] == '/'); + i++; // consumes '/' + + token->name = name; + bool isNumber = true; + + while (i < length && source[i] != '/') { + Ch c = source[i]; + if (uriFragment) { + // Decoding percent-encoding for URI fragment + if (c == '%') { + PercentDecodeStream is(&source[i], source + length); + GenericInsituStringStream os(name); + Ch* begin = os.PutBegin(); + if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { + parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; + goto error; + } + size_t len = os.PutEnd(begin); + i += is.Tell() - 1; + if (len == 1) + c = *name; + else { + name += len; + isNumber = false; + i++; + continue; + } + } + else if (NeedPercentEncode(c)) { + parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; + goto error; + } + } + + i++; + + // Escaping "~0" -> '~', "~1" -> '/' + if (c == '~') { + if (i < length) { + c = source[i]; + if (c == '0') c = '~'; + else if (c == '1') c = '/'; + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + i++; + } + else { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + } + + // First check for index: all of characters are digit + if (c < '0' || c > '9') + isNumber = false; + + *name++ = c; + } + token->length = static_cast(name - token->name); + if (token->length == 0) + isNumber = false; + *name++ = '\0'; // Null terminator + + // Second check for index: more than one digit cannot have leading zero + if (isNumber && token->length > 1 && token->name[0] == '0') + isNumber = false; + + // String to SizeType conversion + SizeType n = 0; + if (isNumber) { + for (size_t j = 0; j < token->length; j++) { + SizeType m = n * 10 + static_cast(token->name[j] - '0'); + if (m < n) { // overflow detection + isNumber = false; + break; + } + n = m; + } + } + + token->index = isNumber ? n : kPointerInvalidIndex; + token++; + } + + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer + parseErrorCode_ = kPointerParseErrorNone; + return; + + error: + Allocator::Free(tokens_); + nameBuffer_ = 0; + tokens_ = 0; + tokenCount_ = 0; + parseErrorOffset_ = i; + return; + } + + //! Stringify to string or URI fragment representation. + /*! + \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. + \tparam OutputStream type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream& os) const { + RAPIDJSON_ASSERT(IsValid()); + + if (uriFragment) + os.Put('#'); + + for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { + os.Put('/'); + for (size_t j = 0; j < t->length; j++) { + Ch c = t->name[j]; + if (c == '~') { + os.Put('~'); + os.Put('0'); + } + else if (c == '/') { + os.Put('~'); + os.Put('1'); + } + else if (uriFragment && NeedPercentEncode(c)) { + // Transcode to UTF8 sequence + GenericStringStream source(&t->name[j]); + PercentEncodeStream target(os); + if (!Transcoder >().Validate(source, target)) + return false; + j += source.Tell() - 1; + } + else + os.Put(c); + } + } + return true; + } + + //! A helper stream for decoding a percent-encoded sequence into code unit. + /*! + This stream decodes %XY triplet into code unit (0-255). + If it encounters invalid characters, it sets output code unit as 0 and + mark invalid, and to be checked by IsValid(). + */ + class PercentDecodeStream { + public: + typedef typename ValueType::Ch Ch; + + //! Constructor + /*! + \param source Start of the stream + \param end Past-the-end of the stream. + */ + PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} + + Ch Take() { + if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet + valid_ = false; + return 0; + } + src_++; + Ch c = 0; + for (int j = 0; j < 2; j++) { + c = static_cast(c << 4); + Ch h = *src_; + if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); + else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); + else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); + else { + valid_ = false; + return 0; + } + src_++; + } + return c; + } + + size_t Tell() const { return static_cast(src_ - head_); } + bool IsValid() const { return valid_; } + + private: + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. + const Ch* end_; //!< Past-the-end position. + bool valid_; //!< Whether the parsing is valid. + }; + + //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. + template + class PercentEncodeStream { + public: + PercentEncodeStream(OutputStream& os) : os_(os) {} + void Put(char c) { // UTF-8 must be byte + unsigned char u = static_cast(c); + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + os_.Put('%'); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); + } + private: + OutputStream& os_; + }; + + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator* ownAllocator_; //!< Allocator owned by this Pointer. + Ch* nameBuffer_; //!< A buffer containing all names in tokens. + Token* tokens_; //!< A list of tokens. + size_t tokenCount_; //!< Number of tokens in tokens_. + size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. + PointerParseErrorCode parseErrorCode_; //!< Parsing error code. +}; + +//! GenericPointer for Value (UTF-8, default allocator). +typedef GenericPointer Pointer; + +//!@name Helper functions for GenericPointer +//@{ + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { + return pointer.Create(root, a); +} + +template +typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Create(root, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { + return pointer.Create(document); +} + +template +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Create(document); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); +} + +template +typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { + return pointer.Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) +SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Set(root, value, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { + return pointer.Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { + return pointer.Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { + return GenericPointer(source, N - 1).Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) +SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { + return GenericPointer(source, N - 1).Set(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { + return pointer.Swap(root, value, a); +} + +template +typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { + return GenericPointer(source, N - 1).Swap(root, value, a); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { + return pointer.Swap(document, value); +} + +template +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { + return GenericPointer(source, N - 1).Swap(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +bool EraseValueByPointer(T& root, const GenericPointer& pointer) { + return pointer.Erase(root); +} + +template +bool EraseValueByPointer(T& root, const CharType(&source)[N]) { + return GenericPointer(source, N - 1).Erase(root); +} + +//@} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_POINTER_H_ diff --git a/WXom062/rapidjson/prettywriter.h b/WXom062/rapidjson/prettywriter.h new file mode 100644 index 0000000..95bb6ff --- /dev/null +++ b/WXom062/rapidjson/prettywriter.h @@ -0,0 +1,277 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ + +#include "writer.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Combination of PrettyWriter format flags. +/*! \see PrettyWriter::SetFormatOptions + */ +enum PrettyFormatOptions { + kFormatDefault = 0, //!< Default pretty formatting. + kFormatSingleLineArray = 1 //!< Format arrays on a single line. +}; + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of output os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class PrettyWriter : public Writer { +public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} + + + explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + PrettyWriter(PrettyWriter&& rhs) : + Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} +#endif + + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } + + //! Set pretty writer formatting options. + /*! \param options Formatting options. + */ + PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { + formatOptions_ = options; + return *this; + } + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kNumberType); + return Base::WriteString(str, length); + } + + bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kStringType); + return Base::WriteString(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + return Base::WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::WriteEndObject(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::Flush(); + return true; + } + + bool StartArray() { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + return Base::WriteStartArray(); + } + + bool EndArray(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::WriteEndArray(); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::Flush(); + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + PrettyPrefix(type); + return Base::WriteRawValue(json, length); + } + +protected: + void PrettyPrefix(Type type) { + (void)type; + if (Base::level_stack_.GetSize() != 0) { // this value is not at root + typename Base::Level* level = Base::level_stack_.template Top(); + + if (level->inArray) { + if (level->valueCount > 0) { + Base::os_->Put(','); // add comma if it is not the first element in array + if (formatOptions_ & kFormatSingleLineArray) + Base::os_->Put(' '); + } + + if (!(formatOptions_ & kFormatSingleLineArray)) { + Base::os_->Put('\n'); + WriteIndent(); + } + } + else { // in object + if (level->valueCount > 0) { + if (level->valueCount % 2 == 0) { + Base::os_->Put(','); + Base::os_->Put('\n'); + } + else { + Base::os_->Put(':'); + Base::os_->Put(' '); + } + } + else + Base::os_->Put('\n'); + + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + Base::hasRoot_ = true; + } + } + + void WriteIndent() { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(*Base::os_, static_cast(indentChar_), count); + } + + Ch indentChar_; + unsigned indentCharCount_; + PrettyFormatOptions formatOptions_; + +private: + // Prohibit copy constructor & assignment operator. + PrettyWriter(const PrettyWriter&); + PrettyWriter& operator=(const PrettyWriter&); +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/WXom062/rapidjson/rapidjson.h b/WXom062/rapidjson/rapidjson.h new file mode 100644 index 0000000..98332fa --- /dev/null +++ b/WXom062/rapidjson/rapidjson.h @@ -0,0 +1,628 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ + +/*!\file rapidjson.h + \brief common definitions and configuration + + \see RAPIDJSON_CONFIG + */ + +/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration + \brief Configuration macros for library features + + Some RapidJSON features are configurable to adapt the library to a wide + variety of platforms, environments and usage scenarios. Most of the + features can be configured in terms of overridden or predefined + preprocessor macros at compile-time. + + Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. + + \note These macros should be given on the compiler command-line + (where applicable) to avoid inconsistent values when compiling + different translation units of a single application. + */ + +#include // malloc(), realloc(), free(), size_t +#include // memset(), memcpy(), memmove(), memcmp() + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_VERSION_STRING +// +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. +// + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +// token stringification +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) +#define RAPIDJSON_DO_STRINGIFY(x) #x + +// token concatenation +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y +//!@endcond + +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Major version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Minor version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Patch version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG + \brief Version of RapidJSON in ".." string format. +*/ +#define RAPIDJSON_MAJOR_VERSION 1 +#define RAPIDJSON_MINOR_VERSION 1 +#define RAPIDJSON_PATCH_VERSION 0 +#define RAPIDJSON_VERSION_STRING \ + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NAMESPACE_(BEGIN|END) +/*! \def RAPIDJSON_NAMESPACE + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace + + In order to avoid symbol clashes and/or "One Definition Rule" errors + between multiple inclusions of (different versions of) RapidJSON in + a single binary, users can customize the name of the main RapidJSON + namespace. + + In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE + to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple + levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref + RAPIDJSON_NAMESPACE_END need to be defined as well: + + \code + // in some .cpp file + #define RAPIDJSON_NAMESPACE my::rapidjson + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { + #define RAPIDJSON_NAMESPACE_END } } + #include "rapidjson/..." + \endcode + + \see rapidjson + */ +/*! \def RAPIDJSON_NAMESPACE_BEGIN + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (opening expression) + \see RAPIDJSON_NAMESPACE +*/ +/*! \def RAPIDJSON_NAMESPACE_END + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (closing expression) + \see RAPIDJSON_NAMESPACE +*/ +#ifndef RAPIDJSON_NAMESPACE +#define RAPIDJSON_NAMESPACE rapidjson +#endif +#ifndef RAPIDJSON_NAMESPACE_BEGIN +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { +#endif +#ifndef RAPIDJSON_NAMESPACE_END +#define RAPIDJSON_NAMESPACE_END } +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_INT64DEFINE + +/*! \def RAPIDJSON_NO_INT64DEFINE + \ingroup RAPIDJSON_CONFIG + \brief Use external 64-bit integer types. + + RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types + to be available at global scope. + + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to + prevent RapidJSON from defining its own types. +*/ +#ifndef RAPIDJSON_NO_INT64DEFINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 +#include "msinttypes/stdint.h" +#include "msinttypes/inttypes.h" +#else +// Other compilers should have this. +#include +#include +#endif +//!@endcond +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_INT64DEFINE +#endif +#endif // RAPIDJSON_NO_INT64TYPEDEF + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_FORCEINLINE + +#ifndef RAPIDJSON_FORCEINLINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) +#else +#define RAPIDJSON_FORCEINLINE +#endif +//!@endcond +#endif // RAPIDJSON_FORCEINLINE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine + +//! Endianness of the machine. +/*! + \def RAPIDJSON_ENDIAN + \ingroup RAPIDJSON_CONFIG + + GCC 4.6 provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. + + Default detection implemented with reference to + \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html + \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp +*/ +#ifndef RAPIDJSON_ENDIAN +// Detect with GCC 4.6's macro +# ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __BYTE_ORDER__ +// Detect with GLIBC's endian.h +# elif defined(__GLIBC__) +# include +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __GLIBC__ +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +// Detect with architecture macros +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(RAPIDJSON_DOXYGEN_RUNNING) +# define RAPIDJSON_ENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif +#endif // RAPIDJSON_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_64BIT + +//! Whether using 64-bit architecture +#ifndef RAPIDJSON_64BIT +#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) +#define RAPIDJSON_64BIT 1 +#else +#define RAPIDJSON_64BIT 0 +#endif +#endif // RAPIDJSON_64BIT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ALIGN + +//! Data alignment of the machine. +/*! \ingroup RAPIDJSON_CONFIG + \param x pointer to align + + Some machines require strict data alignment. Currently the default uses 4 bytes + alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. + User can customize by defining the RAPIDJSON_ALIGN function macro. +*/ +#ifndef RAPIDJSON_ALIGN +#if RAPIDJSON_64BIT == 1 +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) +#else +#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_UINT64_C2 + +//! Construct a 64-bit literal by a pair of 32-bit integer. +/*! + 64-bit literal with or without ULL suffix is prone to compiler warnings. + UINT64_C() is C macro which cause compilation problems. + Use this macro to define 64-bit constants by a pair of 32-bit integer. +*/ +#ifndef RAPIDJSON_UINT64_C2 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_48BITPOINTER_OPTIMIZATION + +//! Use only lower 48-bit address for some pointers. +/*! + \ingroup RAPIDJSON_CONFIG + + This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. + The higher 16-bit can be used for storing other data. + \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. +*/ +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 +#else +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#endif +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION + +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 +#if RAPIDJSON_64BIT != 1 +#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 +#endif +#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) +#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) +#else +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) +#define RAPIDJSON_GETPOINTER(type, p) (p) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD + +/*! \def RAPIDJSON_SIMD + \ingroup RAPIDJSON_CONFIG + \brief Enable SSE2/SSE4.2/Neon optimization. + + RapidJSON supports optimized implementations for some parsing operations + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. + + To enable these optimizations, three different symbols can be defined; + \code + // Enable SSE2 optimization. + #define RAPIDJSON_SSE2 + + // Enable SSE4.2 optimization. + #define RAPIDJSON_SSE42 + \endcode + + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. + + If any of these symbols is defined, RapidJSON defines the macro + \c RAPIDJSON_SIMD to indicate the availability of the optimized code. +*/ +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) +#define RAPIDJSON_SIMD +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_SIZETYPEDEFINE + +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE +/*! \def RAPIDJSON_NO_SIZETYPEDEFINE + \ingroup RAPIDJSON_CONFIG + \brief User-provided \c SizeType definition. + + In order to avoid using 32-bit size types for indexing strings and arrays, + define this preprocessor symbol and provide the type rapidjson::SizeType + before including RapidJSON: + \code + #define RAPIDJSON_NO_SIZETYPEDEFINE + namespace rapidjson { typedef ::std::size_t SizeType; } + #include "rapidjson/..." + \endcode + + \see rapidjson::SizeType +*/ +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_SIZETYPEDEFINE +#endif +RAPIDJSON_NAMESPACE_BEGIN +//! Size type (for string lengths, array sizes, etc.) +/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, + instead of using \c size_t. Users may override the SizeType by defining + \ref RAPIDJSON_NO_SIZETYPEDEFINE. +*/ +typedef unsigned SizeType; +RAPIDJSON_NAMESPACE_END +#endif + +// always import std::size_t to rapidjson namespace +RAPIDJSON_NAMESPACE_BEGIN +using std::size_t; +RAPIDJSON_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ASSERT + +//! Assertion. +/*! \ingroup RAPIDJSON_CONFIG + By default, rapidjson uses C \c assert() for internal assertions. + User can override it by defining RAPIDJSON_ASSERT(x) macro. + + \note Parsing errors are handled and can be customized by the + \ref RAPIDJSON_ERRORS APIs. +*/ +#ifndef RAPIDJSON_ASSERT +#include +#define RAPIDJSON_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_STATIC_ASSERT + +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost +#ifndef RAPIDJSON_STATIC_ASSERT +#ifndef __clang__ +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#endif +RAPIDJSON_NAMESPACE_BEGIN +template struct STATIC_ASSERTION_FAILURE; +template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; +template struct StaticAssertTest {}; +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif +#ifndef __clang__ +//!@endcond +#endif + +/*! \def RAPIDJSON_STATIC_ASSERT + \brief (Internal) macro to check for conditions at compile-time + \param x compile-time condition + \hideinitializer + */ +#define RAPIDJSON_STATIC_ASSERT(x) \ + typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ + sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif // RAPIDJSON_STATIC_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY + +//! Compiler branching hint for expression with high probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression likely to be true. +*/ +#ifndef RAPIDJSON_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define RAPIDJSON_LIKELY(x) (x) +#endif +#endif + +//! Compiler branching hint for expression with low probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression unlikely to be true. +*/ +#ifndef RAPIDJSON_UNLIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define RAPIDJSON_UNLIKELY(x) (x) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Helpers + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_END \ +} while((void)0, 0) + +// adopted from Boost +#define RAPIDJSON_VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF + +#if defined(__GNUC__) +#define RAPIDJSON_GNUC \ + RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) +#endif + +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) + +#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) +#define RAPIDJSON_DIAG_OFF(x) \ + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) + +// push/pop support in Clang and GCC>=4.6 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) +#else // GCC >= 4.2, < 4.6 +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ +#endif + +#elif defined(_MSC_VER) + +// pragma (MSVC specific) +#define RAPIDJSON_PRAGMA(x) __pragma(x) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) + +#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) + +#else + +#define RAPIDJSON_DIAG_OFF(x) /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ + +#endif // RAPIDJSON_DIAG_* + +/////////////////////////////////////////////////////////////////////////////// +// C++11 features + +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if defined(__clang__) +#if __has_feature(cxx_rvalue_references) && \ + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) + +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) +// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#else +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 +#endif +#endif +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT noexcept +#else +#define RAPIDJSON_NOEXCEPT /* noexcept */ +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT + +// no automatic detection, yet +#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 +#endif + +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#else +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + +//!@endcond + +/////////////////////////////////////////////////////////////////////////////// +// new/delete + +#ifndef RAPIDJSON_NEW +///! customization point for global \c new +#define RAPIDJSON_NEW(TypeName) new TypeName +#endif +#ifndef RAPIDJSON_DELETE +///! customization point for global \c delete +#define RAPIDJSON_DELETE(x) delete x +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Type + +/*! \namespace rapidjson + \brief main RapidJSON namespace + \see RAPIDJSON_NAMESPACE +*/ +RAPIDJSON_NAMESPACE_BEGIN + +//! Type of JSON value +enum Type { + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/WXom062/rapidjson/reader.h b/WXom062/rapidjson/reader.h new file mode 100644 index 0000000..084efaa --- /dev/null +++ b/WXom062/rapidjson/reader.h @@ -0,0 +1,2222 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_READER_H_ +#define RAPIDJSON_READER_H_ + +/*! \file reader.h */ + +#include "allocators.h" +#include "stream.h" +#include "encodedstream.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strtod.h" +#include + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(old-style-cast) +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define RAPIDJSON_NOTHING /* deliberately empty */ +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END +#endif +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) +//!@endcond + +/*! \def RAPIDJSON_PARSE_ERROR_NORETURN + \ingroup RAPIDJSON_ERRORS + \brief Macro to indicate a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + This macros can be used as a customization point for the internal + error handling mechanism of RapidJSON. + + A common usage model is to throw an exception instead of requiring the + caller to explicitly check the \ref rapidjson::GenericReader::Parse's + return value: + + \code + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ + throw ParseException(parseErrorCode, #parseErrorCode, offset) + + #include // std::runtime_error + #include "rapidjson/error/error.h" // rapidjson::ParseResult + + struct ParseException : std::runtime_error, rapidjson::ParseResult { + ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) + : std::runtime_error(msg), ParseResult(code, offset) {} + }; + + #include "rapidjson/reader.h" + \endcode + + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse + */ +#ifndef RAPIDJSON_PARSE_ERROR_NORETURN +#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ + SetParseError(parseErrorCode, offset); \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +/*! \def RAPIDJSON_PARSE_ERROR + \ingroup RAPIDJSON_ERRORS + \brief (Internal) macro to indicate and handle a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. + + \see RAPIDJSON_PARSE_ERROR_NORETURN + \hideinitializer + */ +#ifndef RAPIDJSON_PARSE_ERROR +#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +#include "error/error.h" // ParseErrorCode, ParseResult + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseFlag + +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kParseDefaultFlags definition. + + User can define this as any \c ParseFlag combinations. +*/ +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags +#endif + +//! Combination of parseFlags +/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream + */ +enum ParseFlag { + kParseNoFlags = 0, //!< No flags are set. + kParseInsituFlag = 1, //!< In-situ(destructive) parsing. + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. + kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. + kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. + kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. + kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. + kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS +}; + +/////////////////////////////////////////////////////////////////////////////// +// Handler + +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. +\code +concept Handler { + typename Ch; + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType length, bool copy); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool Key(const Ch* str, SizeType length, bool copy); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); +}; +\endcode +*/ +/////////////////////////////////////////////////////////////////////////////// +// BaseReaderHandler + +//! Default implementation of Handler. +/*! This can be used as base class of any reader handler. + \note implements Handler concept +*/ +template, typename Derived = void> +struct BaseReaderHandler { + typedef typename Encoding::Ch Ch; + + typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; + + bool Default() { return true; } + bool Null() { return static_cast(*this).Default(); } + bool Bool(bool) { return static_cast(*this).Default(); } + bool Int(int) { return static_cast(*this).Default(); } + bool Uint(unsigned) { return static_cast(*this).Default(); } + bool Int64(int64_t) { return static_cast(*this).Default(); } + bool Uint64(uint64_t) { return static_cast(*this).Default(); } + bool Double(double) { return static_cast(*this).Default(); } + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } + bool StartObject() { return static_cast(*this).Default(); } + bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } + bool EndObject(SizeType) { return static_cast(*this).Default(); } + bool StartArray() { return static_cast(*this).Default(); } + bool EndArray(SizeType) { return static_cast(*this).Default(); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamLocalCopy + +namespace internal { + +template::copyOptimization> +class StreamLocalCopy; + +//! Do copy optimization. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original), original_(original) {} + ~StreamLocalCopy() { original_ = s; } + + Stream s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; + + Stream& original_; +}; + +//! Keep reference. +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s(original) {} + + Stream& s; + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// SkipWhitespace + +//! Skip the JSON white spaces in a stream. +/*! \param is A input stream for skipping white spaces. + \note This function has SSE2/SSE4.2 specialization. +*/ +template +void SkipWhitespace(InputStream& is) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + typename InputStream::Ch c; + while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') + s.Take(); +} + +inline const char* SkipWhitespace(const char* p, const char* end) { + while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + return p; +} + +#ifdef RAPIDJSON_SSE42 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The middle of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_SSE2) + +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz =__builtin_clzll(high);; + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low);; + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON + +#ifdef RAPIDJSON_SIMD +//! Template function specialization for InsituStringStream +template<> inline void SkipWhitespace(InsituStringStream& is) { + is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); +} + +//! Template function specialization for StringStream +template<> inline void SkipWhitespace(StringStream& is) { + is.src_ = SkipWhitespace_SIMD(is.src_); +} + +template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { + is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); +} +#endif // RAPIDJSON_SIMD + +/////////////////////////////////////////////////////////////////////////////// +// GenericReader + +//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. +/*! GenericReader parses JSON text from a stream, and send events synchronously to an + object implementing Handler concept. + + It needs to allocate a stack for storing a single decoded string during + non-destructive parsing. + + For in-situ parsing, the decoded string is directly written to the source + text string, no temporary buffer is required. + + A GenericReader object can be reused for parsing multiple JSON text. + + \tparam SourceEncoding Encoding of the input stream. + \tparam TargetEncoding Encoding of the parse output. + \tparam StackAllocator Allocator type for stack. +*/ +template +class GenericReader { +public: + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type + + //! Constructor. + /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} + + //! Parse JSON text. + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + if (parseFlags & kParseIterativeFlag) + return IterativeParse(is, handler); + + parseResult_.Clear(); + + ClearStackOnExit scope(*this); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + else { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (!(parseFlags & kParseStopWhenDoneFlag)) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + } + } + + return parseResult_; + } + + //! Parse JSON text (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + return Parse(is, handler); + } + + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool IterativeParseNext(InputStream& is, Handler& handler) { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + // If we've finished or hit an error... + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { + // Report errors. + if (d == IterativeParsingErrorState) { + HandleError(state_, is); + return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; + + // If StopWhenDone is not set... + if (!(parseFlags & kParseStopWhenDoneFlag)) { + // ... and extra non-whitespace data is found... + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') { + // ... this is considered an error. + HandleError(state_, is); + return false; + } + } + + // Success! We are done! + return true; + } + + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. + if (!IsIterativeParsingDelimiterState(n)) + return true; + } + + // We reached the end of file. + stack_.Clear(); + + if (state_ != IterativeParsingFinishState) { + HandleError(state_, is); + return false; + } + + return true; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() { + return IsIterativeParsingCompleteState(state_); + } + + //! Whether a parse error has occurred in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } + +protected: + void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } + +private: + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader&); + GenericReader& operator=(const GenericReader&); + + void ClearStack() { stack_.Clear(); } + + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericReader& r) : r_(r) {} + ~ClearStackOnExit() { r_.ClearStack(); } + private: + GenericReader& r_; + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + }; + + template + void SkipWhitespaceAndComments(InputStream& is) { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) { + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { + if (Consume(is, '*')) { + while (true) { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + else if (Consume(is, '*')) { + if (Consume(is, '/')) + break; + } + else + is.Take(); + } + } + else if (RAPIDJSON_LIKELY(Consume(is, '/'))) + while (is.Peek() != '\0' && is.Take() != '\n') {} + else + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + SkipWhitespace(is); + } + } + } + + // Parse object: { string : value, ... } + template + void ParseObject(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '{'); + is.Take(); // Skip '{' + + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, '}')) { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType memberCount = 0;;) { + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + + ParseString(is, handler, true); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++memberCount; + + switch (is.Peek()) { + case ',': + is.Take(); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case '}': + is.Take(); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy + } + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == '}') { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + // Parse array: [ value, ... ] + template + void ParseArray(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '['); + is.Take(); // Skip '[' + + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType elementCount = 0;;) { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++elementCount; + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ',')) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + } + else if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == ']') { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + template + void ParseNull(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'n'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { + if (RAPIDJSON_UNLIKELY(!handler.Null())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseTrue(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 't'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseFalse(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'f'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { + if (RAPIDJSON_LIKELY(is.Peek() == expect)) { + is.Take(); + return true; + } + else + return false; + } + + // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(InputStream& is, size_t escapeOffset) { + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) { + Ch c = is.Peek(); + codepoint <<= 4; + codepoint += static_cast(c); + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + } + is.Take(); + } + return codepoint; + } + + template + class StackStream { + public: + typedef CharType Ch; + + StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} + RAPIDJSON_FORCEINLINE void Put(Ch c) { + *stack_.template Push() = c; + ++length_; + } + + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { + length_ += count; + return stack_.template Push(count); + } + + size_t Length() const { return length_; } + + Ch* Pop() { + return stack_.template Pop(length_); + } + + private: + StackStream(const StackStream&); + StackStream& operator=(const StackStream&); + + internal::Stack& stack_; + SizeType length_; + }; + + // Parse string and generate String event. Different code paths for kParseInsituFlag. + template + void ParseString(InputStream& is, Handler& handler, bool isKey = false) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); + + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + + bool success = false; + if (parseFlags & kParseInsituFlag) { + typename InputStream::Ch *head = s.PutBegin(); + ParseStringToStream(s, s); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + size_t length = s.PutEnd(head) - 1; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); + } + else { + StackStream stackStream(stack_); + ParseStringToStream(s, stackStream); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + SizeType length = static_cast(stackStream.Length()) - 1; + const typename TargetEncoding::Ch* const str = stackStream.Pop(); + success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); + } + if (RAPIDJSON_UNLIKELY(!success)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } + + // Parse string to an output is + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. + template + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + static const char escape[256] = { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; +#undef Z16 +//!@endcond + + for (;;) { + // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. + if (!(parseFlags & kParseValidateEncodingFlag)) + ScanCopyUnescapedString(is, os); + + Ch c = is.Peek(); + if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape + size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset + is.Take(); + Ch e = is.Peek(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { + is.Take(); + os.Put(static_cast(escape[static_cast(e)])); + } + else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode + is.Take(); + unsigned codepoint = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { + // Handle UTF-16 surrogate pair + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + TEncoding::Encode(os, codepoint); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); + } + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote + is.Take(); + os.Put('\0'); // null-terminate the string + return; + } + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); + } + else { + size_t offset = is.Tell(); + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); + } + } + } + + template + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { + // Do nothing for generic version + } + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType length; + #ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; + #else + length = static_cast(__builtin_ffs(r) - 1); + #endif + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16, q += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + for (const char* pend = p + length; p != pend; ) + *q++ = *p++; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + p += length; + break; + } + } + + is.src_ = is.dst_ = p; + } +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high);; + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low);; + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + for (const char* pend = p + length; p != pend; ) { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + p += 8 + (lz >> 3); + break; + } + } else { + int lz = __builtin_clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON + + template + class NumberStream; + + template + class NumberStream { + public: + typedef typename InputStream::Ch Ch; + + NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } + + RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } + RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } + RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } + RAPIDJSON_FORCEINLINE void Push(char) {} + + size_t Tell() { return is.Tell(); } + size_t Length() { return 0; } + const char* Pop() { return 0; } + + protected: + NumberStream& operator=(const NumberStream&); + + InputStream& is; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} + + RAPIDJSON_FORCEINLINE Ch TakePush() { + stackStream.Put(static_cast(Base::is.Peek())); + return Base::is.Take(); + } + + RAPIDJSON_FORCEINLINE void Push(char c) { + stackStream.Put(c); + } + + size_t Length() { return stackStream.Length(); } + + const char* Pop() { + stackStream.Put('\0'); + return stackStream.Pop(); + } + + private: + StackStream stackStream; + }; + + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} + + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } + }; + + template + void ParseNumber(InputStream& is, Handler& handler) { + internal::StreamLocalCopy copy(is); + NumberStream s(*this, copy.s); + + size_t startOffset = s.Tell(); + double d = 0.0; + bool useNanOrInf = false; + + // Parse minus + bool minus = Consume(s, '-'); + + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i = 0; + uint64_t i64 = 0; + bool use64bit = false; + int significandDigit = 0; + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { + i = 0; + s.TakePush(); + } + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { + i = static_cast(s.TakePush() - '0'); + + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + // Parse NaN or Infinity here + else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } + } + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + } + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + + // Parse 64bit int + bool useDouble = false; + if (use64bit) { + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + + // Force double for big integer + if (useDouble) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + d = d * 10 + (s.TakePush() - '0'); + } + } + + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + size_t decimalPosition; + if (Consume(s, '.')) { + decimalPosition = s.Length(); + + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + + if (!useDouble) { +#if RAPIDJSON_64BIT + // Use i64 to store significand in 64-bit architecture + if (!use64bit) + i64 = i; + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path + break; + else { + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + --expFrac; + if (i64 != 0) + significandDigit++; + } + } + + d = static_cast(i64); +#else + // Use double to store significand in 32-bit architecture + d = static_cast(use64bit ? i64 : i); +#endif + useDouble = true; + } + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (significandDigit < 17) { + d = d * 10.0 + (s.TakePush() - '0'); + --expFrac; + if (RAPIDJSON_LIKELY(d > 0.0)) + significandDigit++; + } + else + s.TakePush(); + } + } + else + decimalPosition = s.Length(); // decimal position at the end of integer. + + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (Consume(s, 'e') || Consume(s, 'E')) { + if (!useDouble) { + d = static_cast(use64bit ? i64 : i); + useDouble = true; + } + + bool expMinus = false; + if (Consume(s, '+')) + ; + else if (Consume(s, '-')) + expMinus = true; + + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = static_cast(s.Take() - '0'); + if (expMinus) { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (exp >= 214748364) { // Issue #313: prevent overflow exponent + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent + s.Take(); + } + } + } + else { // positive exp + int maxExp = 308 - expFrac; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + + if (expMinus) + exp = -exp; + } + + // Finish parsing, call event according to the type of number. + bool cont = true; + + if (parseFlags & kParseNumbersAsStringsFlag) { + if (parseFlags & kParseInsituFlag) { + s.Pop(); // Pop stack no matter if it will be used or not. + typename InputStream::Ch* head = is.PutBegin(); + const size_t length = s.Tell() - startOffset; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + // unable to insert the \0 character here, it will erase the comma after this number + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + cont = handler.RawNumber(str, SizeType(length), false); + } + else { + SizeType numCharsToCopy = static_cast(s.Length()); + StringStream srcStream(s.Pop()); + StackStream dstStream(stack_); + while (numCharsToCopy--) { + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + } + dstStream.Put('\0'); + const typename TargetEncoding::Ch* str = dstStream.Pop(); + const SizeType length = static_cast(dstStream.Length()) - 1; + cont = handler.RawNumber(str, SizeType(length), true); + } + } + else { + size_t length = s.Length(); + const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + + if (useDouble) { + int p = exp + expFrac; + if (parseFlags & kParseFullPrecisionFlag) + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); + else + d = internal::StrtodNormalPrecision(d, p); + + cont = handler.Double(minus ? -d : d); + } + else if (useNanOrInf) { + cont = handler.Double(d); + } + else { + if (use64bit) { + if (minus) + cont = handler.Int64(static_cast(~i64 + 1)); + else + cont = handler.Uint64(i64); + } + else { + if (minus) + cont = handler.Int(static_cast(~i + 1)); + else + cont = handler.Uint(i); + } + } + } + if (RAPIDJSON_UNLIKELY(!cont)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); + } + + // Parse any JSON value + template + void ParseValue(InputStream& is, Handler& handler) { + switch (is.Peek()) { + case 'n': ParseNull (is, handler); break; + case 't': ParseTrue (is, handler); break; + case 'f': ParseFalse (is, handler); break; + case '"': ParseString(is, handler); break; + case '{': ParseObject(is, handler); break; + case '[': ParseArray (is, handler); break; + default : + ParseNumber(is, handler); + break; + + } + } + + // Iterative Parsing + + // States + enum IterativeParsingState { + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, + + // Object states + IterativeParsingObjectInitialState, + IterativeParsingMemberKeyState, + IterativeParsingMemberValueState, + IterativeParsingObjectFinishState, + + // Array states + IterativeParsingArrayInitialState, + IterativeParsingElementState, + IterativeParsingArrayFinishState, + + // Single value state + IterativeParsingValueState, + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + + cIterativeParsingStateCount + }; + + // Tokens + enum Token { + LeftBracketToken = 0, + RightBracketToken, + + LeftCurlyBracketToken, + RightCurlyBracketToken, + + CommaToken, + ColonToken, + + StringToken, + FalseToken, + TrueToken, + NullToken, + NumberToken, + + kTokenCount + }; + + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define N NumberToken +#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N + // Maps from ASCII to Token + static const unsigned char tokenMap[256] = { + N16, // 00~0F + N16, // 10~1F + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F + N16, // 40~4F + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF + }; +#undef N +#undef N16 +//!@endcond + + if (sizeof(Ch) == 1 || static_cast(c) < 256) + return static_cast(tokenMap[static_cast(c)]); + else + return NumberToken; + } + + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + // current state x one lookahead token -> new state + static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Start + { + IterativeParsingArrayInitialState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingValueState, // String + IterativeParsingValueState, // False + IterativeParsingValueState, // True + IterativeParsingValueState, // Null + IterativeParsingValueState // Number + }, + // ObjectInitial + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberKey + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingKeyValueDelimiterState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberValue + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingMemberDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ObjectFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ArrayInitial + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // Element + { + IterativeParsingErrorState, // Left bracket + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingElementDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, + }; // End of G + + return static_cast(G[state][token]); + } + + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). + // May return a new state on state pop. + template + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + (void)token; + + switch (dst) { + case IterativeParsingErrorState: + return dst; + + case IterativeParsingObjectInitialState: + case IterativeParsingArrayInitialState: + { + // Push the state(Element or MemeberValue) if we are nested in another array or value of member. + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. + IterativeParsingState n = src; + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) + n = IterativeParsingElementState; + else if (src == IterativeParsingKeyValueDelimiterState) + n = IterativeParsingMemberValueState; + // Push current state. + *stack_.template Push(1) = n; + // Initialize and push the member/element count. + *stack_.template Push(1) = 0; + // Call handler + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return dst; + } + } + + case IterativeParsingMemberKeyState: + ParseString(is, handler, true); + if (HasParseError()) + return IterativeParsingErrorState; + else + return dst; + + case IterativeParsingKeyValueDelimiterState: + RAPIDJSON_ASSERT(token == ColonToken); + is.Take(); + return dst; + + case IterativeParsingMemberValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingElementState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingMemberDelimiterState: + case IterativeParsingElementDelimiterState: + is.Take(); + // Update member/element count. + *stack_.template Top() = *stack_.template Top() + 1; + return dst; + + case IterativeParsingObjectFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); + return IterativeParsingErrorState; + } + // Get member count. + SizeType c = *stack_.template Pop(1); + // If the object is not empty, count the last member. + if (src == IterativeParsingMemberValueState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndObject(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + case IterativeParsingArrayFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); + return IterativeParsingErrorState; + } + // Get element count. + SizeType c = *stack_.template Pop(1); + // If the array is not empty, count the last element. + if (src == IterativeParsingElementState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndArray(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } + + default: + // This branch is for IterativeParsingValueState actually. + // Use `default:` rather than + // `case IterativeParsingValueState:` is for code coverage. + + // The IterativeParsingStartState is not enumerated in this switch-case. + // It is impossible for that case. And it can be caught by following assertion. + + // The IterativeParsingFinishState is not enumerated in this switch-case either. + // It is a "derivative" state which cannot triggered from Predict() directly. + // Therefore it cannot happen here. And it can be caught by following assertion. + RAPIDJSON_ASSERT(dst == IterativeParsingValueState); + + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return IterativeParsingFinishState; + } + } + + template + void HandleError(IterativeParsingState src, InputStream& is) { + if (HasParseError()) { + // Error flag has been set. + return; + } + + switch (src) { + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; + case IterativeParsingObjectInitialState: + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; + case IterativeParsingKeyValueDelimiterState: + case IterativeParsingArrayInitialState: + case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; + default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; + } + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { + return s >= IterativeParsingElementDelimiterState; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { + return s <= IterativeParsingErrorState; + } + + template + ParseResult IterativeParse(InputStream& is, Handler& handler) { + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + while (is.Peek() != '\0') { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); + + if (d == IterativeParsingErrorState) { + HandleError(state, is); + break; + } + + state = d; + + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + + return parseResult_; + } + + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + ParseResult parseResult_; + IterativeParsingState state_; +}; // class GenericReader + +//! Reader with UTF8 encoding and default allocator. +typedef GenericReader, UTF8<> > Reader; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_READER_H_ diff --git a/WXom062/rapidjson/schema.h b/WXom062/rapidjson/schema.h new file mode 100644 index 0000000..35748cc --- /dev/null +++ b/WXom062/rapidjson/schema.h @@ -0,0 +1,2485 @@ +// Tencent is pleased to support the open source community by making RapidJSON available-> +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License-> You may obtain a copy of the License at +// +// http://opensource->org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// specific language governing permissions and limitations under the License-> + +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ + +#include "document.h" +#include "pointer.h" +#include "stringbuffer.h" +#include // abs, floor + +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#endif + +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#include "internal/regex.h" +#elif RAPIDJSON_SCHEMA_USE_STDREGEX +#include +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 +#else +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 +#endif + +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 +#endif + +#if RAPIDJSON_SCHEMA_VERBOSE +#include "stringbuffer.h" +#endif + +RAPIDJSON_DIAG_PUSH + +#if defined(__GNUC__) +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(weak-vtables) +RAPIDJSON_DIAG_OFF(exit-time-destructors) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) +RAPIDJSON_DIAG_OFF(variadic-macros) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Verbose Utilities + +#if RAPIDJSON_SCHEMA_VERBOSE + +namespace internal { + +inline void PrintInvalidKeyword(const char* keyword) { + printf("Fail keyword: %s\n", keyword); +} + +inline void PrintInvalidKeyword(const wchar_t* keyword) { + wprintf(L"Fail keyword: %ls\n", keyword); +} + +inline void PrintInvalidDocument(const char* document) { + printf("Fail document: %s\n\n", document); +} + +inline void PrintInvalidDocument(const wchar_t* document) { + wprintf(L"Fail document: %ls\n\n", document); +} + +inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { + printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); +} + +inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { + wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); +} + +} // namespace internal + +#endif // RAPIDJSON_SCHEMA_VERBOSE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_INVALID_KEYWORD_RETURN + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) +#else +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) +#endif + +#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidKeyword = keyword.GetString();\ + RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ + return false;\ +RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template +class GenericSchemaDocument; + +namespace internal { + +template +class Schema; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaValidator + +class ISchemaValidator { +public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaStateFactory + +template +class ISchemaStateFactory { +public: + virtual ~ISchemaStateFactory() {} + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; + virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; + virtual void* CreateHasher() = 0; + virtual uint64_t GetHashCode(void* hasher) = 0; + virtual void DestroryHasher(void* hasher) = 0; + virtual void* MallocState(size_t size) = 0; + virtual void FreeState(void* p) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// IValidationErrorHandler + +template +class IValidationErrorHandler { +public: + typedef typename SchemaType::Ch Ch; + typedef typename SchemaType::SValue SValue; + + virtual ~IValidationErrorHandler() {} + + virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(double actual, const SValue& expected) = 0; + virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; + + virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; + + virtual void DisallowedItem(SizeType index) = 0; + virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; + + virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void StartMissingProperties() = 0; + virtual void AddMissingProperty(const SValue& name) = 0; + virtual bool EndMissingProperties() = 0; + virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; + + virtual void StartDependencyErrors() = 0; + virtual void StartMissingDependentProperties() = 0; + virtual void AddMissingDependentProperty(const SValue& targetName) = 0; + virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; + virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0; + virtual bool EndDependencyErrors() = 0; + + virtual void DisallowedValue() = 0; + virtual void StartDisallowedType() = 0; + virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; + virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; + virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void Disallowed() = 0; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Hasher + +// For comparison of compound value +template +class Hasher { +public: + typedef typename Encoding::Ch Ch; + + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} + + bool Null() { return WriteType(kNullType); } + bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } + bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Double(double d) { + Number n; + if (d < 0) n.u.i = static_cast(d); + else n.u.u = static_cast(d); + n.d = d; + return WriteNumber(n); + } + + bool RawNumber(const Ch* str, SizeType len, bool) { + WriteBuffer(kNumberType, str, len * sizeof(Ch)); + return true; + } + + bool String(const Ch* str, SizeType len, bool) { + WriteBuffer(kStringType, str, len * sizeof(Ch)); + return true; + } + + bool StartObject() { return true; } + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } + bool EndObject(SizeType memberCount) { + uint64_t h = Hash(0, kObjectType); + uint64_t* kv = stack_.template Pop(memberCount * 2); + for (SizeType i = 0; i < memberCount; i++) + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + *stack_.template Push() = h; + return true; + } + + bool StartArray() { return true; } + bool EndArray(SizeType elementCount) { + uint64_t h = Hash(0, kArrayType); + uint64_t* e = stack_.template Pop(elementCount); + for (SizeType i = 0; i < elementCount; i++) + h = Hash(h, e[i]); // Use hash to achieve element order sensitive + *stack_.template Push() = h; + return true; + } + + bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } + + uint64_t GetHashCode() const { + RAPIDJSON_ASSERT(IsValid()); + return *stack_.template Top(); + } + +private: + static const size_t kDefaultSize = 256; + struct Number { + union U { + uint64_t u; + int64_t i; + }u; + double d; + }; + + bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } + + bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } + + bool WriteBuffer(Type type, const void* data, size_t len) { + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + const unsigned char* d = static_cast(data); + for (size_t i = 0; i < len; i++) + h = Hash(h, d[i]); + *stack_.template Push() = h; + return true; + } + + static uint64_t Hash(uint64_t h, uint64_t d) { + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + h ^= d; + h *= kPrime; + return h; + } + + Stack stack_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidationContext + +template +struct SchemaValidationContext { + typedef Schema SchemaType; + typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; + typedef typename SchemaType::ValueType ValueType; + typedef typename ValueType::Ch Ch; + + enum PatternValidatorType { + kPatternValidatorOnly, + kPatternValidatorWithProperty, + kPatternValidatorWithAdditionalProperty + }; + + SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : + factory(f), + error_handler(eh), + schema(s), + valueSchema(), + invalidKeyword(), + hasher(), + arrayElementHashCodes(), + validators(), + validatorCount(), + patternPropertiesValidators(), + patternPropertiesValidatorCount(), + patternPropertiesSchemas(), + patternPropertiesSchemaCount(), + valuePatternValidatorType(kPatternValidatorOnly), + propertyExist(), + inArray(false), + valueUniqueness(false), + arrayUniqueness(false) + { + } + + ~SchemaValidationContext() { + if (hasher) + factory.DestroryHasher(hasher); + if (validators) { + for (SizeType i = 0; i < validatorCount; i++) + factory.DestroySchemaValidator(validators[i]); + factory.FreeState(validators); + } + if (patternPropertiesValidators) { + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + factory.FreeState(patternPropertiesValidators); + } + if (patternPropertiesSchemas) + factory.FreeState(patternPropertiesSchemas); + if (propertyExist) + factory.FreeState(propertyExist); + } + + SchemaValidatorFactoryType& factory; + ErrorHandlerType& error_handler; + const SchemaType* schema; + const SchemaType* valueSchema; + const Ch* invalidKeyword; + void* hasher; // Only validator access + void* arrayElementHashCodes; // Only validator access this + ISchemaValidator** validators; + SizeType validatorCount; + ISchemaValidator** patternPropertiesValidators; + SizeType patternPropertiesValidatorCount; + const SchemaType** patternPropertiesSchemas; + SizeType patternPropertiesSchemaCount; + PatternValidatorType valuePatternValidatorType; + PatternValidatorType objectPatternValidatorType; + SizeType arrayElementIndex; + bool* propertyExist; + bool inArray; + bool valueUniqueness; + bool arrayUniqueness; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Schema + +template +class Schema { +public: + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + typedef GenericValue SValue; + typedef IValidationErrorHandler ErrorHandler; + friend class GenericSchemaDocument; + + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : + allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), + pointer_(p), + typeless_(schemaDocument->GetTypeless()), + enum_(), + enumCount_(), + not_(), + type_((1 << kTotalSchemaType) - 1), // typeless + validatorCount_(), + notValidatorIndex_(), + properties_(), + additionalPropertiesSchema_(), + patternProperties_(), + patternPropertyCount_(), + propertyCount_(), + minProperties_(), + maxProperties_(SizeType(~0)), + additionalProperties_(true), + hasDependencies_(), + hasRequired_(), + hasSchemaDependencies_(), + additionalItemsSchema_(), + itemsList_(), + itemsTuple_(), + itemsTupleCount_(), + minItems_(), + maxItems_(SizeType(~0)), + additionalItems_(true), + uniqueItems_(false), + pattern_(), + minLength_(0), + maxLength_(~SizeType(0)), + exclusiveMinimum_(false), + exclusiveMaximum_(false) + { + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + + if (!value.IsObject()) + return; + + if (const ValueType* v = GetMember(value, GetTypeString())) { + type_ = 0; + if (v->IsString()) + AddType(*v); + else if (v->IsArray()) + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + AddType(*itr); + } + + if (const ValueType* v = GetMember(value, GetEnumString())) + if (v->IsArray() && v->Size() > 0) { + enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { + typedef Hasher > EnumHasherType; + char buffer[256 + 24]; + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); + itr->Accept(h); + enum_[enumCount_++] = h.GetHashCode(); + } + } + + if (schemaDocument) { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } + + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } + + // Object + + const ValueType* properties = GetMember(value, GetPropertiesString()); + const ValueType* required = GetMember(value, GetRequiredString()); + const ValueType* dependencies = GetMember(value, GetDependenciesString()); + { + // Gather properties from properties/required/dependencies + SValue allProperties(kArrayType); + + if (properties && properties->IsObject()) + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + AddUniqueElement(allProperties, itr->name); + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + AddUniqueElement(allProperties, *itr); + + if (dependencies && dependencies->IsObject()) + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + AddUniqueElement(allProperties, itr->name); + if (itr->value.IsArray()) + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) + if (i->IsString()) + AddUniqueElement(allProperties, *i); + } + + if (allProperties.Size() > 0) { + propertyCount_ = allProperties.Size(); + properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); + for (SizeType i = 0; i < propertyCount_; i++) { + new (&properties_[i]) Property(); + properties_[i].name = allProperties[i]; + properties_[i].schema = typeless_; + } + } + } + + if (properties && properties->IsObject()) { + PointerType q = p.Append(GetPropertiesString(), allocator_); + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { + SizeType index; + if (FindPropertyIndex(itr->name, &index)) + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); + } + } + + if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); + patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); + patternPropertyCount_ = 0; + + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { + new (&patternProperties_[patternPropertyCount_]) PatternProperty(); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); + patternPropertyCount_++; + } + } + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) { + SizeType index; + if (FindPropertyIndex(*itr, &index)) { + properties_[index].required = true; + hasRequired_ = true; + } + } + + if (dependencies && dependencies->IsObject()) { + PointerType q = p.Append(GetDependenciesString(), allocator_); + hasDependencies_ = true; + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + SizeType sourceIndex; + if (FindPropertyIndex(itr->name, &sourceIndex)) { + if (itr->value.IsArray()) { + properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { + SizeType targetIndex; + if (FindPropertyIndex(*targetItr, &targetIndex)) + properties_[sourceIndex].dependencies[targetIndex] = true; + } + } + else if (itr->value.IsObject()) { + hasSchemaDependencies_ = true; + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; + validatorCount_++; + } + } + } + } + + if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { + if (v->IsBool()) + additionalProperties_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + } + + AssignIfExist(minProperties_, value, GetMinPropertiesString()); + AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); + + // Array + if (const ValueType* v = GetMember(value, GetItemsString())) { + PointerType q = p.Append(GetItemsString(), allocator_); + if (v->IsObject()) // List validation + schemaDocument->CreateSchema(&itemsList_, q, *v, document); + else if (v->IsArray()) { // Tuple validation + itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); + SizeType index = 0; + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); + } + } + + AssignIfExist(minItems_, value, GetMinItemsString()); + AssignIfExist(maxItems_, value, GetMaxItemsString()); + + if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { + if (v->IsBool()) + additionalItems_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + } + + AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); + + // String + AssignIfExist(minLength_, value, GetMinLengthString()); + AssignIfExist(maxLength_, value, GetMaxLengthString()); + + if (const ValueType* v = GetMember(value, GetPatternString())) + pattern_ = CreatePattern(*v); + + // Number + if (const ValueType* v = GetMember(value, GetMinimumString())) + if (v->IsNumber()) + minimum_.CopyFrom(*v, *allocator_); + + if (const ValueType* v = GetMember(value, GetMaximumString())) + if (v->IsNumber()) + maximum_.CopyFrom(*v, *allocator_); + + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); + + if (const ValueType* v = GetMember(value, GetMultipleOfString())) + if (v->IsNumber() && v->GetDouble() > 0.0) + multipleOf_.CopyFrom(*v, *allocator_); + } + + ~Schema() { + AllocatorType::Free(enum_); + if (properties_) { + for (SizeType i = 0; i < propertyCount_; i++) + properties_[i].~Property(); + AllocatorType::Free(properties_); + } + if (patternProperties_) { + for (SizeType i = 0; i < patternPropertyCount_; i++) + patternProperties_[i].~PatternProperty(); + AllocatorType::Free(patternProperties_); + } + AllocatorType::Free(itemsTuple_); +#if RAPIDJSON_SCHEMA_HAS_REGEX + if (pattern_) { + pattern_->~RegexType(); + AllocatorType::Free(pattern_); + } +#endif + } + + const SValue& GetURI() const { + return uri_; + } + + const PointerType& GetPointer() const { + return pointer_; + } + + bool BeginValue(Context& context) const { + if (context.inArray) { + if (uniqueItems_) + context.valueUniqueness = true; + + if (itemsList_) + context.valueSchema = itemsList_; + else if (itemsTuple_) { + if (context.arrayElementIndex < itemsTupleCount_) + context.valueSchema = itemsTuple_[context.arrayElementIndex]; + else if (additionalItemsSchema_) + context.valueSchema = additionalItemsSchema_; + else if (additionalItems_) + context.valueSchema = typeless_; + else { + context.error_handler.DisallowedItem(context.arrayElementIndex); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } + } + else + context.valueSchema = typeless_; + + context.arrayElementIndex++; + } + return true; + } + + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + if (context.patternPropertiesValidatorCount > 0) { + bool otherValid = false; + SizeType count = context.patternPropertiesValidatorCount; + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) + otherValid = context.patternPropertiesValidators[--count]->IsValid(); + + bool patternValid = true; + for (SizeType i = 0; i < count; i++) + if (!context.patternPropertiesValidators[i]->IsValid()) { + patternValid = false; + break; + } + + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { + if (!patternValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { + if (!patternValid || !otherValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + + if (enum_) { + const uint64_t h = context.factory.GetHashCode(context.hasher); + for (SizeType i = 0; i < enumCount_; i++) + if (enum_[i] == h) + goto foundEnum; + context.error_handler.DisallowedValue(); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); + foundEnum:; + } + + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) { + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); + } + + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); + foundAny:; + } + + if (oneOf_.schemas) { + bool oneValid = false; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } else + oneValid = true; + } + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + } + + return true; + } + + bool Null(Context& context) const { + if (!(type_ & (1 << kNullSchemaType))) { + DisallowedType(context, GetNullString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + return CreateParallelValidator(context); + } + + bool Bool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(context, GetBooleanString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + return CreateParallelValidator(context); + } + + bool Int(Context& context, int i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint(Context& context, unsigned u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Int64(Context& context, int64_t i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint64(Context& context, uint64_t u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Double(Context& context, double d) const { + if (!(type_ & (1 << kNumberSchemaType))) { + DisallowedType(context, GetNumberString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + return false; + + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + return false; + + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + return false; + + return CreateParallelValidator(context); + } + + bool String(Context& context, const Ch* str, SizeType length, bool) const { + if (!(type_ & (1 << kStringSchemaType))) { + DisallowedType(context, GetStringString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (minLength_ != 0 || maxLength_ != SizeType(~0)) { + SizeType count; + if (internal::CountStringCodePoint(str, length, &count)) { + if (count < minLength_) { + context.error_handler.TooShort(str, length, minLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); + } + if (count > maxLength_) { + context.error_handler.TooLong(str, length, maxLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } + } + } + + if (pattern_ && !IsPatternMatch(pattern_, str, length)) { + context.error_handler.DoesNotMatch(str, length); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + } + + return CreateParallelValidator(context); + } + + bool StartObject(Context& context) const { + if (!(type_ & (1 << kObjectSchemaType))) { + DisallowedType(context, GetObjectString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (hasDependencies_ || hasRequired_) { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); + } + + if (patternProperties_) { // pre-allocate schema array + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType + context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); + context.patternPropertiesSchemaCount = 0; + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); + } + + return CreateParallelValidator(context); + } + + bool Key(Context& context, const Ch* str, SizeType len, bool) const { + if (patternProperties_) { + context.patternPropertiesSchemaCount = 0; + for (SizeType i = 0; i < patternPropertyCount_; i++) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } + } + + SizeType index; + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { + if (context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; + } + else + context.valueSchema = properties_[index].schema; + + if (context.propertyExist) + context.propertyExist[index] = true; + + return true; + } + + if (additionalPropertiesSchema_) { + if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; + } + else + context.valueSchema = additionalPropertiesSchema_; + return true; + } + else if (additionalProperties_) { + context.valueSchema = typeless_; + return true; + } + + if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties + context.error_handler.DisallowedProperty(str, len); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + } + + return true; + } + + bool EndObject(Context& context, SizeType memberCount) const { + if (hasRequired_) { + context.error_handler.StartMissingProperties(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required && !context.propertyExist[index]) + context.error_handler.AddMissingProperty(properties_[index].name); + if (context.error_handler.EndMissingProperties()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + } + + if (memberCount < minProperties_) { + context.error_handler.TooFewProperties(memberCount, minProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + } + + if (memberCount > maxProperties_) { + context.error_handler.TooManyProperties(memberCount, maxProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + } + + if (hasDependencies_) { + context.error_handler.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { + const Property& source = properties_[sourceIndex]; + if (context.propertyExist[sourceIndex]) { + if (source.dependencies) { + context.error_handler.StartMissingDependentProperties(); + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) + context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); + context.error_handler.EndMissingDependentProperties(source.name); + } + else if (source.dependenciesSchema) { + ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; + if (!dependenciesValidator->IsValid()) + context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); + } + } + } + if (context.error_handler.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + + return true; + } + + bool StartArray(Context& context) const { + if (!(type_ & (1 << kArraySchemaType))) { + DisallowedType(context, GetArrayString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + context.arrayElementIndex = 0; + context.inArray = true; + + return CreateParallelValidator(context); + } + + bool EndArray(Context& context, SizeType elementCount) const { + context.inArray = false; + + if (elementCount < minItems_) { + context.error_handler.TooFewItems(elementCount, minItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + } + + if (elementCount > maxItems_) { + context.error_handler.TooManyItems(elementCount, maxItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + } + + return true; + } + + // Generate functions for string literal according to Ch +#define RAPIDJSON_STRING_(name, ...) \ + static const ValueType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ + return v;\ + } + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') + RAPIDJSON_STRING_(Not, 'n', 'o', 't') + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + +#undef RAPIDJSON_STRING_ + +private: + enum SchemaValueType { + kNullSchemaType, + kBooleanSchemaType, + kObjectSchemaType, + kArraySchemaType, + kStringSchemaType, + kNumberSchemaType, + kIntegerSchemaType, + kTotalSchemaType + }; + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + typedef std::basic_regex RegexType; +#else + typedef char RegexType; +#endif + + struct SchemaArray { + SchemaArray() : schemas(), count() {} + ~SchemaArray() { AllocatorType::Free(schemas); } + const SchemaType** schemas; + SizeType begin; // begin index of context.validators + SizeType count; + }; + + template + void AddUniqueElement(V1& a, const V2& v) { + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + if (*itr == v) + return; + V1 c(v, *allocator_); + a.PushBack(c, *allocator_); + } + + static const ValueType* GetMember(const ValueType& value, const ValueType& name) { + typename ValueType::ConstMemberIterator itr = value.FindMember(name); + return itr != value.MemberEnd() ? &(itr->value) : 0; + } + + static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsBool()) + out = v->GetBool(); + } + + static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) + out = static_cast(v->GetUint64()); + } + + void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { + if (const ValueType* v = GetMember(value, name)) { + if (v->IsArray() && v->Size() > 0) { + PointerType q = p.Append(name, allocator_); + out.count = v->Size(); + out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); + memset(out.schemas, 0, sizeof(Schema*)* out.count); + for (SizeType i = 0; i < out.count; i++) + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); + out.begin = validatorCount_; + validatorCount_ += out.count; + } + } + } + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) { + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); + if (!r->IsValid()) { + r->~RegexType(); + AllocatorType::Free(r); + r = 0; + } + return r; + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { + GenericRegexSearch rs(*pattern); + return rs.Search(str); + } +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) + try { + return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + } + catch (const std::regex_error&) { + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { + std::match_results r; + return std::regex_search(str, str + length, r, *pattern); + } +#else + template + RegexType* CreatePattern(const ValueType&) { return 0; } + + static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX + + void AddType(const ValueType& type) { + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); + } + + bool CreateParallelValidator(Context& context) const { + if (enum_ || context.arrayUniqueness) + context.hasher = context.factory.CreateHasher(); + + if (validatorCount_) { + RAPIDJSON_ASSERT(context.validators == 0); + context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + context.validatorCount = validatorCount_; + + if (allOf_.schemas) + CreateSchemaValidators(context, allOf_); + + if (anyOf_.schemas) + CreateSchemaValidators(context, anyOf_); + + if (oneOf_.schemas) + CreateSchemaValidators(context, oneOf_); + + if (not_) + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); + + if (hasSchemaDependencies_) { + for (SizeType i = 0; i < propertyCount_; i++) + if (properties_[i].dependenciesSchema) + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); + } + } + + return true; + } + + void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { + for (SizeType i = 0; i < schemas.count; i++) + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); + } + + // O(n) + bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { + SizeType len = name.GetStringLength(); + const Ch* str = name.GetString(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].name.GetStringLength() == len && + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) + { + *outIndex = index; + return true; + } + return false; + } + + bool CheckInt(Context& context, int64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull()) { + if (minimum_.IsInt64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + } + else if (minimum_.IsUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() + } + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsInt64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + } + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckUint(Context& context, uint64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull()) { + if (minimum_.IsUint64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + } + else if (minimum_.IsInt64()) + /* do nothing */; // i >= 0 > minimum.Getint64() + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsUint64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + } + else if (maximum_.IsInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ + } + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (i % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckDoubleMinimum(Context& context, double d) const { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { + context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + return true; + } + + bool CheckDoubleMaximum(Context& context, double d) const { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + return true; + } + + bool CheckDoubleMultipleOf(Context& context, double d) const { + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); + double q = std::floor(a / b); + double r = a - q * b; + if (r > 0.0) { + context.error_handler.NotMultipleOf(d, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + return true; + } + + void DisallowedType(Context& context, const ValueType& actualType) const { + ErrorHandler& eh = context.error_handler; + eh.StartDisallowedType(); + + if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); + if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); + if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); + if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); + if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); + + if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); + else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); + + eh.EndDisallowedType(actualType); + } + + struct Property { + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} + ~Property() { AllocatorType::Free(dependencies); } + SValue name; + const SchemaType* schema; + const SchemaType* dependenciesSchema; + SizeType dependenciesValidatorIndex; + bool* dependencies; + bool required; + }; + + struct PatternProperty { + PatternProperty() : schema(), pattern() {} + ~PatternProperty() { + if (pattern) { + pattern->~RegexType(); + AllocatorType::Free(pattern); + } + } + const SchemaType* schema; + RegexType* pattern; + }; + + AllocatorType* allocator_; + SValue uri_; + PointerType pointer_; + const SchemaType* typeless_; + uint64_t* enum_; + SizeType enumCount_; + SchemaArray allOf_; + SchemaArray anyOf_; + SchemaArray oneOf_; + const SchemaType* not_; + unsigned type_; // bitmask of kSchemaType + SizeType validatorCount_; + SizeType notValidatorIndex_; + + Property* properties_; + const SchemaType* additionalPropertiesSchema_; + PatternProperty* patternProperties_; + SizeType patternPropertyCount_; + SizeType propertyCount_; + SizeType minProperties_; + SizeType maxProperties_; + bool additionalProperties_; + bool hasDependencies_; + bool hasRequired_; + bool hasSchemaDependencies_; + + const SchemaType* additionalItemsSchema_; + const SchemaType* itemsList_; + const SchemaType** itemsTuple_; + SizeType itemsTupleCount_; + SizeType minItems_; + SizeType maxItems_; + bool additionalItems_; + bool uniqueItems_; + + RegexType* pattern_; + SizeType minLength_; + SizeType maxLength_; + + SValue minimum_; + SValue maximum_; + SValue multipleOf_; + bool exclusiveMinimum_; + bool exclusiveMaximum_; +}; + +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + *documentStack.template Push() = '/'; + char buffer[21]; + size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); + for (size_t i = 0; i < length; i++) + *documentStack.template Push() = static_cast(buffer[i]); + } +}; + +// Partial specialized version for char to prevent buffer copying. +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + if (sizeof(SizeType) == 4) { + char *buffer = documentStack.template Push(1 + 10); // '/' + uint + *buffer++ = '/'; + const char* end = internal::u32toa(index, buffer); + documentStack.template Pop(static_cast(10 - (end - buffer))); + } + else { + char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 + *buffer++ = '/'; + const char* end = internal::u64toa(index, buffer); + documentStack.template Pop(static_cast(20 - (end - buffer))); + } + } +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template +class IGenericRemoteSchemaDocumentProvider { +public: + typedef typename SchemaDocumentType::Ch Ch; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaDocument + +//! JSON schema document. +/*! + A JSON schema document is a compiled version of a JSON schema. + It is basically a tree of internal::Schema. + + \note This is an immutable class (i.e. its instance cannot be modified after construction). + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. + \tparam Allocator Allocator type for allocating memory of this document. +*/ +template +class GenericSchemaDocument { +public: + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + typedef GenericValue URIType; + friend class internal::Schema; + template + friend class GenericSchemaValidator; + + //! Constructor. + /*! + Compile a JSON document into schema document. + + \param document A JSON document as source. + \param uri The base URI of this schema document for purposes of violation reporting. + \param uriLength Length of \c name, in code points. + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. + \param allocator An optional allocator instance for allocating memory. Can be null. + */ + explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + remoteProvider_(remoteProvider), + allocator_(allocator), + ownAllocator_(), + root_(), + typeless_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize) + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); + + // Generate root schema, it will call CreateSchema() to create sub-schemas, + // And call AddRefSchema() if there are $ref. + CreateSchemaRecursive(&root_, PointerType(), document, document); + + // Resolve $ref + while (!schemaRef_.Empty()) { + SchemaRefEntry* refEntry = schemaRef_.template Pop(1); + if (const SchemaType* s = GetSchema(refEntry->target)) { + if (refEntry->schema) + *refEntry->schema = s; + + // Create entry in map if not exist + if (!GetSchema(refEntry->source)) { + new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); + } + } + else if (refEntry->schema) + *refEntry->schema = typeless_; + + refEntry->~SchemaRefEntry(); + } + + RAPIDJSON_ASSERT(root_ != 0); + + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : + remoteProvider_(rhs.remoteProvider_), + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + root_(rhs.root_), + typeless_(rhs.typeless_), + schemaMap_(std::move(rhs.schemaMap_)), + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)) + { + rhs.remoteProvider_ = 0; + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; + } +#endif + + //! Destructor + ~GenericSchemaDocument() { + while (!schemaMap_.Empty()) + schemaMap_.template Pop(1)->~SchemaEntry(); + + if (typeless_) { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + + RAPIDJSON_DELETE(ownAllocator_); + } + + const URIType& GetURI() const { return uri_; } + + //! Get the root schema. + const SchemaType& GetRoot() const { return *root_; } + +private: + //! Prohibit copying + GenericSchemaDocument(const GenericSchemaDocument&); + //! Prohibit assignment + GenericSchemaDocument& operator=(const GenericSchemaDocument&); + + struct SchemaRefEntry { + SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} + PointerType source; + PointerType target; + const SchemaType** schema; + }; + + struct SchemaEntry { + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} + ~SchemaEntry() { + if (owned) { + schema->~SchemaType(); + Allocator::Free(schema); + } + } + PointerType pointer; + SchemaType* schema; + bool owned; + }; + + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + if (schema) + *schema = typeless_; + + if (v.GetType() == kObjectType) { + const SchemaType* s = GetSchema(pointer); + if (!s) + CreateSchema(schema, pointer, v, document); + + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + } + + void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + RAPIDJSON_ASSERT(pointer.IsValid()); + if (v.IsObject()) { + if (!HandleRefSchema(pointer, schema, v, document)) { + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); + new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); + if (schema) + *schema = s; + } + } + } + + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { + static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; + static const ValueType kRefValue(kRefString, 4); + + typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); + if (itr == v.MemberEnd()) + return false; + + if (itr->value.IsString()) { + SizeType len = itr->value.GetStringLength(); + if (len > 0) { + const Ch* s = itr->value.GetString(); + SizeType i = 0; + while (i < len && s[i] != '#') // Find the first # + i++; + + if (i > 0) { // Remote reference, resolve immediately + if (remoteProvider_) { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + new (schemaMap_.template Push()) SchemaEntry(source, const_cast(sc), false, allocator_); + return true; + } + } + } + } + } + else if (s[i] == '#') { // Local reference, defer resolution + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const ValueType* nv = pointer.Get(document)) + if (HandleRefSchema(source, schema, *nv, document)) + return true; + + new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); + return true; + } + } + } + } + return false; + } + + const SchemaType* GetSchema(const PointerType& pointer) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (pointer == target->pointer) + return target->schema; + return 0; + } + + PointerType GetPointer(const SchemaType* schema) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (schema == target->schema) + return target->pointer; + return PointerType(); + } + + const SchemaType* GetTypeless() const { return typeless_; } + + static const size_t kInitialSchemaMapSize = 64; + static const size_t kInitialSchemaRefSize = 64; + + IRemoteSchemaDocumentProviderType* remoteProvider_; + Allocator *allocator_; + Allocator *ownAllocator_; + const SchemaType* root_; //!< Root schema. + SchemaType* typeless_; + internal::Stack schemaMap_; // Stores created Pointer -> Schemas + internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref + URIType uri_; +}; + +//! GenericSchemaDocument using Value type. +typedef GenericSchemaDocument SchemaDocument; +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaValidator + +//! JSON Schema Validator. +/*! + A SAX style JSON schema validator. + It uses a \c GenericSchemaDocument to validate SAX events. + It delegates the incoming SAX events to an output handler. + The default output handler does nothing. + It can be reused multiple times by calling \c Reset(). + + \tparam SchemaDocumentType Type of schema document. + \tparam OutputHandler Type of output handler. Default handler does nothing. + \tparam StateAllocator Allocator for storing the internal validation states. +*/ +template < + typename SchemaDocumentType, + typename OutputHandler = BaseReaderHandler, + typename StateAllocator = CrtAllocator> +class GenericSchemaValidator : + public internal::ISchemaStateFactory, + public internal::ISchemaValidator, + public internal::IValidationErrorHandler +{ +public: + typedef typename SchemaDocumentType::SchemaType SchemaType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename SchemaType::SValue SValue; + typedef typename EncodingType::Ch Ch; + typedef GenericStringRef StringRefType; + typedef GenericValue ValueType; + + //! Constructor without output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Constructor with output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + OutputHandler& outputHandler, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Destructor. + ~GenericSchemaValidator() { + Reset(); + RAPIDJSON_DELETE(ownStateAllocator_); + } + + //! Reset the internal states. + void Reset() { + while (!schemaStack_.Empty()) + PopSchema(); + documentStack_.Clear(); + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); + valid_ = true; + } + + //! Checks whether the current state is valid. + // Implementation of ISchemaValidator + virtual bool IsValid() const { return valid_; } + + //! Gets the error object. + ValueType& GetError() { return error_; } + const ValueType& GetError() const { return error_; } + + //! Gets the JSON pointer pointed to the invalid schema. + PointerType GetInvalidSchemaPointer() const { + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); + } + + //! Gets the keyword of invalid schema. + const Ch* GetInvalidSchemaKeyword() const { + return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; + } + + //! Gets the JSON pointer pointed to the invalid value. + PointerType GetInvalidDocumentPointer() const { + if (documentStack_.Empty()) { + return PointerType(); + } + else { + return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } + } + + void NotMultipleOf(int64_t actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(uint64_t actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(double actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + + void TooLong(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(SchemaType::GetMaxLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void TooShort(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(SchemaType::GetMinLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void DoesNotMatch(const Ch* str, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetPatternString()); + } + + void DisallowedItem(SizeType index) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalItemsString(), true); + } + void TooFewItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMinItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooManyItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMaxItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void DuplicateItems(SizeType index1, SizeType index2) { + ValueType duplicates(kArrayType); + duplicates.PushBack(index1, GetStateAllocator()); + duplicates.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); + AddCurrentError(SchemaType::GetUniqueItemsString(), true); + } + + void TooManyProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMaxPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooFewProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMinPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void StartMissingProperties() { + currentError_.SetArray(); + } + void AddMissingProperty(const SValue& name) { + currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); + } + bool EndMissingProperties() { + if (currentError_.Empty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetRequiredString()); + return true; + } + void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { + for (SizeType i = 0; i < count; ++i) + MergeError(static_cast(subvalidators[i])->GetError()); + } + void DisallowedProperty(const Ch* name, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true); + } + + void StartDependencyErrors() { + currentError_.SetObject(); + } + void StartMissingDependentProperties() { + missingDependents_.SetArray(); + } + void AddMissingDependentProperty(const SValue& targetName) { + missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndMissingDependentProperties(const SValue& sourceName) { + if (!missingDependents_.Empty()) + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + missingDependents_, GetStateAllocator()); + } + void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + static_cast(subvalidator)->GetError(), GetStateAllocator()); + } + bool EndDependencyErrors() { + if (currentError_.ObjectEmpty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetDependenciesString()); + return true; + } + + void DisallowedValue() { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetEnumString()); + } + void StartDisallowedType() { + currentError_.SetArray(); + } + void AddExpectedType(const typename SchemaType::ValueType& expectedType) { + currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndDisallowedType(const typename SchemaType::ValueType& actualType) { + ValueType error(kObjectType); + error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); + error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetTypeString()); + } + void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { + for (SizeType i = 0; i < count; ++i) { + MergeError(static_cast(subvalidators[i])->GetError()); + } + } + void NoneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count); + } + void NotOneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count); + } + void Disallowed() { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetNotString()); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') + RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') + RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') + RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') + RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') + RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') + RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') + +#undef RAPIDJSON_STRING_ + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + internal::PrintInvalidDocument(documentStack_.template Bottom());\ +RAPIDJSON_MULTILINEMACRO_END +#else +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() +#endif + +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ + if (!valid_) return false; \ + if (!BeginValue() || !CurrentSchema().method arg1) {\ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ + return valid_ = false;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ + if (context->hasher)\ + static_cast(context->hasher)->method arg2;\ + if (context->validators)\ + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ + static_cast(context->validators[i_])->method arg2;\ + if (context->patternPropertiesValidators)\ + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ + static_cast(context->patternPropertiesValidators[i_])->method arg2;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) + +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) + + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + bool RawNumber(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + bool String(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + + bool StartObject() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + return valid_ = !outputHandler_ || outputHandler_->StartObject(); + } + + bool Key(const Ch* str, SizeType len, bool copy) { + if (!valid_) return false; + AppendToken(str, len); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + } + + bool EndObject(SizeType memberCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + } + + bool StartArray() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + return valid_ = !outputHandler_ || outputHandler_->StartArray(); + } + + bool EndArray(SizeType elementCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + } + +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ + + // Implementation of ISchemaStateFactory + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), +#if RAPIDJSON_SCHEMA_VERBOSE + depth_ + 1, +#endif + &GetStateAllocator()); + } + + virtual void DestroySchemaValidator(ISchemaValidator* validator) { + GenericSchemaValidator* v = static_cast(validator); + v->~GenericSchemaValidator(); + StateAllocator::Free(v); + } + + virtual void* CreateHasher() { + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); + } + + virtual uint64_t GetHashCode(void* hasher) { + return static_cast(hasher)->GetHashCode(); + } + + virtual void DestroryHasher(void* hasher) { + HasherType* h = static_cast(hasher); + h->~HasherType(); + StateAllocator::Free(h); + } + + virtual void* MallocState(size_t size) { + return GetStateAllocator().Malloc(size); + } + + virtual void FreeState(void* p) { + StateAllocator::Free(p); + } + +private: + typedef typename SchemaType::Context Context; + typedef GenericValue, StateAllocator> HashCodeArray; + typedef internal::Hasher HasherType; + + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + const SchemaType& root, + const char* basePath, size_t basePathSize, +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth, +#endif + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(root), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(depth) +#endif + { + if (basePath && basePathSize) + memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); + } + + StateAllocator& GetStateAllocator() { + if (!stateAllocator_) + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); + return *stateAllocator_; + } + + bool BeginValue() { + if (schemaStack_.Empty()) + PushSchema(root_); + else { + if (CurrentContext().inArray) + internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); + + if (!CurrentSchema().BeginValue(CurrentContext())) + return false; + + SizeType count = CurrentContext().patternPropertiesSchemaCount; + const SchemaType** sa = CurrentContext().patternPropertiesSchemas; + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; + bool valueUniqueness = CurrentContext().valueUniqueness; + RAPIDJSON_ASSERT(CurrentContext().valueSchema); + PushSchema(*CurrentContext().valueSchema); + + if (count > 0) { + CurrentContext().objectPatternValidatorType = patternValidatorType; + ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; + SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; + va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); + for (SizeType i = 0; i < count; i++) + va[validatorCount++] = CreateSchemaValidator(*sa[i]); + } + + CurrentContext().arrayUniqueness = valueUniqueness; + } + return true; + } + + bool EndValue() { + if (!CurrentSchema().EndValue(CurrentContext())) + return false; + +#if RAPIDJSON_SCHEMA_VERBOSE + GenericStringBuffer sb; + schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); + + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); +#endif + + uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; + + PopSchema(); + + if (!schemaStack_.Empty()) { + Context& context = CurrentContext(); + if (context.valueUniqueness) { + HashCodeArray* a = static_cast(context.arrayElementHashCodes); + if (!a) + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) + if (itr->GetUint64() == h) { + DuplicateItems(static_cast(itr - a->Begin()), a->Size()); + RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + } + a->PushBack(h, GetStateAllocator()); + } + } + + // Remove the last token of document pointer + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') + ; + + return true; + } + + void AppendToken(const Ch* str, SizeType len) { + documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters + *documentStack_.template PushUnsafe() = '/'; + for (SizeType i = 0; i < len; i++) { + if (str[i] == '~') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '0'; + } + else if (str[i] == '/') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '1'; + } + else + *documentStack_.template PushUnsafe() = str[i]; + } + } + + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema); } + + RAPIDJSON_FORCEINLINE void PopSchema() { + Context* c = schemaStack_.template Pop(1); + if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { + a->~HashCodeArray(); + StateAllocator::Free(a); + } + c->~Context(); + } + + void AddErrorLocation(ValueType& result, bool parent) { + GenericStringBuffer sb; + PointerType instancePointer = GetInvalidDocumentPointer(); + ((parent && instancePointer.GetTokenCount() > 0) + ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) + : instancePointer).StringifyUriFragment(sb); + ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); + sb.Clear(); + memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()), + CurrentSchema().GetURI().GetString(), + CurrentSchema().GetURI().GetStringLength() * sizeof(Ch)); + GetInvalidSchemaPointer().StringifyUriFragment(sb); + ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); + } + + void AddError(ValueType& keyword, ValueType& error) { + typename ValueType::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, GetStateAllocator()); + else { + if (member->value.IsObject()) { + ValueType errors(kArrayType); + errors.PushBack(member->value, GetStateAllocator()); + member->value = errors; + } + member->value.PushBack(error, GetStateAllocator()); + } + } + + void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) { + AddErrorLocation(currentError_, parent); + AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_); + } + + void MergeError(ValueType& other) { + for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { + AddError(it->name, it->value); + } + } + + void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected, + const typename SchemaType::ValueType& (*exclusive)() = 0) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); + currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); + if (exclusive) + currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); + AddCurrentError(keyword); + } + + void AddErrorArray(const typename SchemaType::ValueType& keyword, + ISchemaValidator** subvalidators, SizeType count) { + ValueType errors(kArrayType); + for (SizeType i = 0; i < count; ++i) + errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); + AddCurrentError(keyword); + } + + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } + Context& CurrentContext() { return *schemaStack_.template Top(); } + const Context& CurrentContext() const { return *schemaStack_.template Top(); } + + static const size_t kDefaultSchemaStackCapacity = 1024; + static const size_t kDefaultDocumentStackCapacity = 256; + const SchemaDocumentType* schemaDocument_; + const SchemaType& root_; + StateAllocator* stateAllocator_; + StateAllocator* ownStateAllocator_; + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + OutputHandler* outputHandler_; + ValueType error_; + ValueType currentError_; + ValueType missingDependents_; + bool valid_; +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth_; +#endif +}; + +typedef GenericSchemaValidator SchemaValidator; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidatingReader + +//! A helper class for parsing with validation. +/*! + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). + + \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam SourceEncoding Encoding of the input stream. + \tparam SchemaDocumentType Type of schema document. + \tparam StackAllocator Allocator type for stack. +*/ +template < + unsigned parseFlags, + typename InputStream, + typename SourceEncoding, + typename SchemaDocumentType = SchemaDocument, + typename StackAllocator = CrtAllocator> +class SchemaValidatingReader { +public: + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename InputStream::Ch Ch; + typedef GenericValue ValueType; + + //! Constructor + /*! + \param is Input stream. + \param sd Schema document. + */ + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {} + + template + bool operator()(Handler& handler) { + GenericReader reader; + GenericSchemaValidator validator(sd_, handler); + parseResult_ = reader.template Parse(is_, validator); + + isValid_ = validator.IsValid(); + if (isValid_) { + invalidSchemaPointer_ = PointerType(); + invalidSchemaKeyword_ = 0; + invalidDocumentPointer_ = PointerType(); + error_.SetObject(); + } + else { + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + error_.CopyFrom(validator.GetError(), allocator_); + } + + return parseResult_; + } + + const ParseResult& GetParseResult() const { return parseResult_; } + bool IsValid() const { return isValid_; } + const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } + const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } + const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + const ValueType& GetError() const { return error_; } + +private: + InputStream& is_; + const SchemaDocumentType& sd_; + + ParseResult parseResult_; + PointerType invalidSchemaPointer_; + const Ch* invalidSchemaKeyword_; + PointerType invalidDocumentPointer_; + StackAllocator allocator_; + ValueType error_; + bool isValid_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/WXom062/rapidjson/stream.h b/WXom062/rapidjson/stream.h new file mode 100644 index 0000000..7f2643e --- /dev/null +++ b/WXom062/rapidjson/stream.h @@ -0,0 +1,223 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "rapidjson.h" + +#ifndef RAPIDJSON_STREAM_H_ +#define RAPIDJSON_STREAM_H_ + +#include "encodings.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + + For write-only stream, only need to implement Put() and Flush(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! Flush the buffer. + void Flush(); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits { + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; +}; + +//! Reserve n characters for writing to a stream. +template +inline void PutReserve(Stream& stream, size_t count) { + (void)stream; + (void)count; +} + +//! Write character to a stream, presuming buffer is reserved. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { + stream.Put(c); +} + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream& stream, Ch c, size_t n) { + PutReserve(stream, n); + for (size_t i = 0; i < n; i++) + PutUnsafe(stream, c); +} + +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. + \note implements Stream concept +*/ + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +template > +class GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + GenericStreamWrapper(InputStream& is): is_(is) {} + + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() { return is_.Tell(); } + Ch* PutBegin() { return is_.PutBegin(); } + void Put(Ch ch) { is_.Put(ch); } + void Flush() { is_.Flush(); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } + + // wrapper for MemoryStream + const Ch* Peek4() const { return is_.Peek4(); } + + // wrapper for AutoUTFInputStream + UTFType GetType() const { return is_.GetType(); } + bool HasBOM() const { return is_.HasBOM(); } + +protected: + InputStream& is_; +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \note implements Stream concept +*/ +template +struct GenericStringStream { + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! String stream with UTF8 encoding. +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \note implements Stream concept +*/ +template +struct GenericInsituStringStream { + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return static_cast(src_ - head_); } + + // Write + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + + Ch* PutBegin() { return dst_ = src_; } + size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} + + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } + + Ch* src_; + Ch* dst_; + Ch* head_; +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! Insitu string stream with UTF8 encoding. +typedef GenericInsituStringStream > InsituStringStream; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STREAM_H_ diff --git a/WXom062/rapidjson/stringbuffer.h b/WXom062/rapidjson/stringbuffer.h new file mode 100644 index 0000000..4e38b82 --- /dev/null +++ b/WXom062/rapidjson/stringbuffer.h @@ -0,0 +1,121 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +#include "internal/stack.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output stream. +/*! + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +class GenericStringBuffer { +public: + typedef typename Encoding::Ch Ch; + + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} + GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { + if (&rhs != this) + stack_ = std::move(rhs.stack_); + return *this; + } +#endif + + void Put(Ch c) { *stack_.template Push() = c; } + void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } + void Flush() {} + + void Clear() { stack_.Clear(); } + void ShrinkToFit() { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.ShrinkToFit(); + stack_.template Pop(1); + } + + void Reserve(size_t count) { stack_.template Reserve(count); } + Ch* Push(size_t count) { return stack_.template Push(count); } + Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } + void Pop(size_t count) { stack_.template Pop(count); } + + const Ch* GetString() const { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); + + return stack_.template Bottom(); + } + + //! Get the size of string in bytes in the string buffer. + size_t GetSize() const { return stack_.GetSize(); } + + //! Get the length of string in Ch in the string buffer. + size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; + +private: + // Prohibit copy constructor & assignment operator. + GenericStringBuffer(const GenericStringBuffer&); + GenericStringBuffer& operator=(const GenericStringBuffer&); +}; + +//! String buffer with UTF8 encoding +typedef GenericStringBuffer > StringBuffer; + +template +inline void PutReserve(GenericStringBuffer& stream, size_t count) { + stream.Reserve(count); +} + +template +inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { + stream.PutUnsafe(c); +} + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { + std::memset(stream.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/WXom062/rapidjson/writer.h b/WXom062/rapidjson/writer.h new file mode 100644 index 0000000..a978891 --- /dev/null +++ b/WXom062/rapidjson/writer.h @@ -0,0 +1,716 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_WRITER_H_ +#define RAPIDJSON_WRITER_H_ + +#include "stream.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strfunc.h" +#include "internal/dtoa.h" +#include "internal/itoa.h" +#include "stringbuffer.h" +#include // placement new + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// WriteFlag + +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kWriteDefaultFlags definition. + + User can define this as any \c WriteFlag combinations. +*/ +#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS +#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags +#endif + +//! Combination of writeFlags +enum WriteFlag { + kWriteNoFlags = 0, //!< No flags are set. + kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. + kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. + kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS +}; + +//! JSON writer +/*! Writer implements the concept Handler. + It generates JSON text by events to an output os. + + User may programmatically calls the functions of a writer to generate JSON text. + + On the other side, a writer can also be passed to objects that generates events, + + for example Reader::Parse() and Document::Accept(). + + \tparam OutputStream Type of output stream. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. + \note implements Handler concept +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class Writer { +public: + typedef typename SourceEncoding::Ch Ch; + + static const int kDefaultMaxDecimalPlaces = 324; + + //! Constructor + /*! \param os Output stream. + \param stackAllocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit + Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + + explicit + Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Writer(Writer&& rhs) : + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { + rhs.os_ = 0; + } +#endif + + //! Reset the writer with a new stream. + /*! + This function reset the writer with a new stream and default settings, + in order to make a Writer object reusable for output multiple JSONs. + + \param os New output stream. + \code + Writer writer(os1); + writer.StartObject(); + // ... + writer.EndObject(); + + writer.Reset(os2); + writer.StartObject(); + // ... + writer.EndObject(); + \endcode + */ + void Reset(OutputStream& os) { + os_ = &os; + hasRoot_ = false; + level_stack_.Clear(); + } + + //! Checks whether the output is a complete JSON. + /*! + A complete JSON has a complete root object or array. + */ + bool IsComplete() const { + return hasRoot_ && level_stack_.Empty(); + } + + int GetMaxDecimalPlaces() const { + return maxDecimalPlaces_; + } + + //! Sets the maximum number of decimal places for double output. + /*! + This setting truncates the output with specified number of decimal places. + + For example, + + \code + writer.SetMaxDecimalPlaces(3); + writer.StartArray(); + writer.Double(0.12345); // "0.123" + writer.Double(0.0001); // "0.0" + writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) + writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) + writer.EndArray(); + \endcode + + The default setting does not truncate any decimal places. You can restore to this setting by calling + \code + writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); + \endcode + */ + void SetMaxDecimalPlaces(int maxDecimalPlaces) { + maxDecimalPlaces_ = maxDecimalPlaces; + } + + /*!@name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } + bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } + bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } + bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } + + //! Writes the given \c double value to the stream + /*! + \param d The value to be written. + \return Whether it is succeed. + */ + bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kNumberType); + return EndValue(WriteString(str, length)); + } + + bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kStringType); + return EndValue(WriteString(str, length)); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string& str) { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + return WriteStartObject(); + } + + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + level_stack_.template Pop(1); + return EndValue(WriteEndObject()); + } + + bool StartArray() { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + return WriteStartArray(); + } + + bool EndArray(SizeType elementCount = 0) { + (void)elementCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + return EndValue(WriteEndArray()); + } + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + */ + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + Prefix(type); + return EndValue(WriteRawValue(json, length)); + } + + //! Flush the output stream. + /*! + Allows the user to flush the output stream immediately. + */ + void Flush() { + os_->Flush(); + } + +protected: + //! Information for each nested level + struct Level { + Level(bool inArray_) : valueCount(0), inArray(inArray_) {} + size_t valueCount; //!< number of values in this level + bool inArray; //!< true if in array, otherwise in object + }; + + static const size_t kDefaultLevelDepth = 32; + + bool WriteNull() { + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; + } + + bool WriteBool(bool b) { + if (b) { + PutReserve(*os_, 4); + PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); + } + else { + PutReserve(*os_, 5); + PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); + } + return true; + } + + bool WriteInt(int i) { + char buffer[11]; + const char* end = internal::i32toa(i, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint(unsigned u) { + char buffer[10]; + const char* end = internal::u32toa(u, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteInt64(int64_t i64) { + char buffer[21]; + const char* end = internal::i64toa(i64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* end = internal::u64toa(u64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + if (!(writeFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + + char buffer[25]; + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + PutReserve(*os_, static_cast(end - buffer)); + for (char* p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteString(const Ch* str, SizeType length) { + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const char escape[256] = { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF +#undef Z16 + }; + + if (TargetEncoding::supportUnicode) + PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + else + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + + PutUnsafe(*os_, '\"'); + GenericStringStream is(str); + while (ScanWriteUnescapedString(is, length)) { + const Ch c = is.Peek(); + if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { + // Unicode escaping + unsigned codepoint; + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) + return false; + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); + } + else { + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(lead ) & 15]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(trail ) & 15]); + } + } + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { + is.Take(); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + if (escape[static_cast(c)] == 'u') { + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); + PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); + } + } + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + PutUnsafe(*os_, '\"'); + return true; + } + + bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { + return RAPIDJSON_LIKELY(is.Tell() < length); + } + + bool WriteStartObject() { os_->Put('{'); return true; } + bool WriteEndObject() { os_->Put('}'); return true; } + bool WriteStartArray() { os_->Put('['); return true; } + bool WriteEndArray() { os_->Put(']'); return true; } + + bool WriteRawValue(const Ch* json, size_t length) { + PutReserve(*os_, length); + GenericStringStream is(json); + while (RAPIDJSON_LIKELY(is.Tell() < length)) { + const Ch c = is.Peek(); + RAPIDJSON_ASSERT(c != '\0'); + if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + return true; + } + + void Prefix(Type type) { + (void)type; + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root + Level* level = level_stack_.template Top(); + if (level->valueCount > 0) { + if (level->inArray) + os_->Put(','); // add comma if it is not the first element in array + else // in object + os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + hasRoot_ = true; + } + } + + // Flush the value if it is the top level one. + bool EndValue(bool ret) { + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text + Flush(); + return ret; + } + + OutputStream* os_; + internal::Stack level_stack_; + int maxDecimalPlaces_; + bool hasRoot_; + +private: + // Prohibit copy constructor & assignment operator. + Writer(const Writer&); + Writer& operator=(const Writer&); +}; + +// Full specialization for StringStream to prevent memory copying + +template<> +inline bool Writer::WriteInt(int i) { + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(static_cast(11 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint(unsigned u) { + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(static_cast(10 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteInt64(int64_t i64) { + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(static_cast(21 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint64(uint64_t u) { + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(static_cast(20 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + + char *buffer = os_->Push(25); + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + os_->Pop(static_cast(25 - (end - buffer))); + return true; +} + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (; p != endAligned; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType len; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + len = offset; +#else + len = static_cast(__builtin_ffs(r) - 1); +#endif + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON + +RAPIDJSON_NAMESPACE_END + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/WXom062/string_utils.cxx b/WXom062/string_utils.cxx new file mode 100644 index 0000000..9f6b79a --- /dev/null +++ b/WXom062/string_utils.cxx @@ -0,0 +1,253 @@ +/*================================================================================================================== + Copyright(c) 2012 ORIGIN. + Unpublished - All rights reserved +==================================================================================================================== +File description: + Filename: string_utils.c + Module : Common module. + + This file includes some operations of the string. + +==================================================================================================================== +Date Name Description of Change +3-Feb-2015 Ray li Initialize creation +$HISTORY$ +===================================================================================================================*/ +#ifndef _cplusplus +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#endif + +#include +#include +#include +#include +#include +#include + +#include "string_utils.h" + +void Split( string strArg, string spliter, vector &ans ) +{ + ans.clear(); + size_t index0; + string one_arg; + if ( strArg.find_first_not_of(' ') == string::npos ) + strArg = ""; + while( strArg.size()>0 ) + { + index0 = strArg.find(spliter); + if( index0 != string::npos ) + { + one_arg = strArg.substr( 0, index0 ); + strArg = strArg.substr( index0 + spliter.size() ); + ans.push_back( one_arg ); + } + else + { + ans.push_back( strArg ); + break; + } + } +} +char* GSTR_clone( char **dst, const char *src ) +{ + char *retVal = NULL; + int srcLen = 0; + + *dst = NULL; + if (src == NULL) + return NULL; + + srcLen = (int)tc_strlen( src ) + 1; + *dst = (char*)MEM_alloc( srcLen * sizeof(char) ); + retVal = tc_strncpy( *dst, src, srcLen ); + (*dst)[srcLen - 1] = '\0'; + + return retVal; +} + +char* GSTR_copy( char *dst, const char *src, int dstSize ) +{ + char *retVal = tc_strncpy( dst, src, dstSize ); + dst[dstSize - 1] = '\0'; + return retVal; +} + +char* GSTR_int_to_string( char **dst, int value ) +{ + char strVal[128 + 1]; + + *dst = NULL; + memset( strVal, 0, sizeof(strVal)/sizeof(char) ); + sprintf( strVal, "%d", value ); + + return GSTR_clone( dst, strVal ); +} + +void GSTR_format_int_to_string( char *dst, int digitNum, int value ) +{ + char sNum[WSO_desc_size_c + 1]; + sprintf( sNum, "%%0%dd", digitNum ); + sprintf( dst, sNum, value ); +} + +void GSTR_format_string( const char *dst, int m, const char *fill_char, char **out ) +{ + char sNum[WSO_name_size_c + 1] = {0}; + char sNew[WSO_name_size_c + 1] = {0}; + sprintf( sNum, "%%%d.%ds", m, m ); + sprintf( sNew, sNum, dst ); + STRNG_replace_str( sNew, " ", fill_char, out ); +} + + +char* GSTR_string_append( const char *s1, const char *s2 ) +{ + char *s = NULL; + if (s1 == NULL || s2 == NULL) + { + GSTR_clone(&s, s1 == NULL ? (s2 == NULL ? "" : s2) : s1 ); + } + else + { + int size = (int)tc_strlen(s1) + (int)tc_strlen(s2) + 1; + s = (char *)MEM_alloc( size ); + tc_strcpy( s, s1 ); + tc_strcat( s, s2 ); + s[size - 1] = '\0'; + } + return s; +} + +logical GSTR_is_float(const char *str) +{ + logical isfloat = true; + char *pStr = (char *)str; + logical hasPositive = false; + logical hasMinus = false; + logical hasDot = false; + + if (str == NULL) + return false; + + while (*pStr != '\0' && isfloat == true) + { + if ( (*pStr >= '0' && *pStr <= '9')) + { + //continue; + } + else if ( *pStr == '+' ) + { + isfloat = (hasPositive ? false : (hasPositive = true)); + } + else if ( *pStr == '-' ) + { + isfloat = (hasMinus ? false : (hasMinus = true)); + } + else if ( *pStr == '.' ) + { + isfloat = (hasDot ? false : (hasDot = true)); + } + else + isfloat = false; + + pStr ++; + } + return isfloat; +} + +logical GSTR_is_number(const char *str) +{ + logical is_number = true; + char *pStr = (char *)str; + if (str == NULL) + return false; + + while (*pStr != '\0') + { + if ( !( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' ) ) + { + is_number = false; + break; + } + pStr ++; + } + return is_number; +} + +logical GSTR_is_ascii(char ch) +{ + return ((unsigned int)ch) < 128; +} + +int GSTR_trim_l( char *str, char s ) +{ + int count = 0; + char *pointer = str, *poffset = NULL; + if (str == NULL || str[0] == '\0') + return 0; + + while ( *pointer != '\0' ) + { + if ( *pointer != s ) + { + break; + } + count++; + pointer++; + } + if (count == 0) + return 0; + + poffset = str + count; + pointer = str; + while ( *poffset != '\0' ) + { + *pointer = *poffset; + pointer ++; + poffset ++; + } + *pointer = '\0'; + + return count; +} + +int GSTR_trim_r( char *str, char s ) +{ + int count = 0; + char *pointer = NULL; + if (str == NULL || str[0] == '\0') + return 0; + + pointer = str + ((int) strlen(str) - 1); + + while ( pointer != str ) + { + if ( *pointer != s ) + { + break; + } + + *pointer = '\0'; + + count++; + pointer--; + } + + return count; +} + +void GSTR_trim_float( char *floatValue ) +{ + if ( !IS_EMPTY(floatValue) && tc_strstr(floatValue, ".") != NULL ) + { + int len = 0; + GSTR_trim_r(floatValue, '0'); + len = (int)tc_strlen(floatValue); + if (floatValue[ len - 1 ] == '.') + floatValue[ len - 1 ] = '\0'; + } +} + diff --git a/WXom062/string_utils.h b/WXom062/string_utils.h new file mode 100644 index 0000000..4b379cc --- /dev/null +++ b/WXom062/string_utils.h @@ -0,0 +1,125 @@ +/*===================================================================================================================== + Copyright(c) 2005 ORIGIN PLM Software Corp. All rights reserved. + Unpublished - All rights reserved +======================================================================================================================= +File description: + Filename: string_utils.h + Module : Common module. + + This file includes some operations of the string. + +======================================================================================================================= +Date Name Description of Change +14-Jul-2009 Ray Li Initialize creation +$HISTORY$ +=====================================================================================================================*/ +#ifndef STRING_UTILS_H +#define STRING_UTILS_H +#include +#include +#include +using namespace std; +#ifdef __cplusplus + extern "C" + { +#endif + +// @{{ String assister +#define IS_NULL(S) ((S)==NULL) +#define IS_EMPTY(S) (((S)==NULL) || !(*(S))) +// @}} + void Split( string strArg, string spliter, vector &ans ); + /** + * Clones the string. + * @param dst - the output string. + * @param src - the string to be cloned. + * @return - the destinatin string pointer. + */ + extern char* GSTR_clone( char **dst, const char *src ); + + /** + * Copy safely the string with null end. + * @param dst - the output string. + * @param src - the string to be cloned. + * @param dstSize - the size of output string. + * @return - the destinatin string pointer. + */ + extern char *GSTR_copy( char *dst, const char *src, int dstSize ); + + /** + * Converts int to string. + * @param dst - the output string. + * @param value - the int to be cloned. + * @return - the destinatin string pointer. + */ + extern char* GSTR_int_to_string( char **dst, int value ); + + /** + * Formats the int/string value as string. + * @param dst - the destination string. + * @param digitNum - the digit number of the value. + * @param value - the value to be converted. + * @return - N/A. + */ + extern void GSTR_format_int_to_string( char *dst, int digitNum, int value ); + extern void GSTR_format_string( const char *dst, int m, const char *fill_char, char **out ); + + /** + * Appends the strings( never null returned ) + * @param s1 - string 1 + * @param s2 - string 2 + * @return - new string + */ + extern char* GSTR_string_append( const char *s1, const char *s2 ); + + /** + * Whether the string is float type + * @param str - The string + * + * NOTE: it's only check whether each word is in "+-.0123456789", not care the float with "E" or the float rule, + * like "00-1.+01", it will return true. + * @return - return true if it is one. + */ + extern logical GSTR_is_float(const char *str); + + /** + * Whether all char of the string are number + * @param str - The string + * + * NOTE: it's only check whether each word is in "0123456789" + * @return - return true if it is one. + */ + extern logical GSTR_is_number(const char *str); + + /** + * Is ascii char + * @param ch - ascii char + * @return - return true if it is. + */ + extern logical GSTR_is_ascii(char ch); + + /** + * Trims the string's prefix. + * @param str - The string + * @param s - The char + * + * @return - count. + */ + extern int GSTR_trim_l( char *str, char s ); + extern int GSTR_trim_r( char *str, char s ); + + /** + * Remove the zero. + * For Example: + * floatValue="50.00" -> = "50" + * floatValue="50.0100" -> = "50.01" + * @return - count. + */ + extern void GSTR_trim_float( char *floatValue ); + +#ifdef __cplusplus + } +#endif + + +#endif //STRING_UTILS_H diff --git a/WXom062/tc_log.cxx b/WXom062/tc_log.cxx new file mode 100644 index 0000000..8643318 --- /dev/null +++ b/WXom062/tc_log.cxx @@ -0,0 +1,111 @@ +/** +* @file common_itk_util.cpp +* @brief itk warpper utility function +* @author James +* @history +* =================================================================================== +* Date Name Description of Change +* 18-July-2008 Ray +*/ +#include +#include +#include + +#include +#include +#include +#include +// +#ifdef WIN32 +#include +#include +#else +#include +#endif +// +#include "tc_log.h" + +#define ARGS_LENGTH 200 +#define MAX_PRINTLINE_LENGTH 2000 +#define MAX_PATH_LENGTH 2000 +#define MAX_ARGUMENT_LENGTH 400 +#define MAX_PARAMNAME_LENGTH 50 +#define MAX_FILE_EXT_LENGTH 10 +#define TRUE_FLAG 1 +#define FALSE_FLAG 0 +#define DETAILLOG 1 + +#define DOFREE(obj) \ +{ \ + if(obj) \ + { \ + MEM_free(obj); \ + obj = NULL; \ + } \ +} + + +FILE* logFile = NULL; + +void CreateLogFile(char* logFileName) +{ + int i=0; + + logFile = NULL; + + + //get logFileName + sprintf(logFileName, "%s", logFileName); + printf("log file name: %s\n", logFileName); + + + //create log file + if((logFile = fopen(logFileName, "w"))==NULL) + { + printf("log file create failed\n"); + } + +} + +void WriteLog(const char* format, ...) +{ + va_list arg; + char tmp[MAX_PRINTLINE_LENGTH]; + struct tm *p; + time_t now; + time(&now); + p = localtime(&now); + char now_time[128]="\0"; + + sprintf_s(now_time, "[ %d-%d-%d %d:%02d ]", 1900+p->tm_year,p->tm_mon+1 ,p->tm_mday,p->tm_hour,p->tm_min ); + + if(logFile) + { + //get the message + memset(tmp, 0, sizeof(tmp)); + va_start(arg, format); + vsprintf(tmp, format, arg); + va_end(arg); + + //----------print to command window for trace--------// + printf("%s\n", tmp); + + //print message to log file + fprintf(logFile, "%s %s\n", now_time,tmp); + fflush(logFile); + } + else + { + printf("*!Error!*: Log File Not Exist\n"); + } +} + +void CloseLog(void) +{ + if(logFile) + { + fclose(logFile); + logFile = NULL; + } +} +//--------------------------------------------------- diff --git a/WXom062/tc_log.h b/WXom062/tc_log.h new file mode 100644 index 0000000..2ac59c4 --- /dev/null +++ b/WXom062/tc_log.h @@ -0,0 +1,26 @@ +/** +* @file common_itk_util.h +* @brief itk warpper utility function +* @author Ray +* @history +* =================================================================================== +* Date Name Description of Change +* 09-July-2008 Ray +*/ +#ifndef TC_LOG_H +#define TC_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +void CreateLogFile(char* logFileName); +void WriteLog(const char* format, ...); +void CloseLog(void); + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/WXom062/tc_util.cpp b/WXom062/tc_util.cpp new file mode 100644 index 0000000..4085171 --- /dev/null +++ b/WXom062/tc_util.cpp @@ -0,0 +1,280 @@ +#include "tc_util.h" +#include "util.h" + + +void split(std::string s, const char* delim, std::vector* ret) +{ + size_t last = 0; + size_t index = s.find(delim, last); + int size = strlen(delim); + while (index != std::string::npos) { + ret->push_back(s.substr(last, index - last)); + last = index + size; + index = s.find(delim, last); + } + if (index - last > 0) { + ret->push_back(s.substr(last, index - last)); + } +} + + +void current_time( date_t * date_tag ) +{ + time_t ltime; + struct tm *today ; + + time( <ime ); + + today = localtime( <ime ); + date_tag->year = today->tm_year + 1900 ; + date_tag->month = today->tm_mon ; + date_tag->day = today->tm_mday ; + date_tag->hour = today->tm_hour ; + date_tag->minute = today->tm_min ; + date_tag->second = today->tm_sec ; +} + +void ECHO(char *format, ...) +{ + char msg[2048]; + va_list args; + + va_start( args, format ); + vsprintf_s( msg, format, args ); + va_end( args ); + + printf( msg ); + TC_write_syslog( msg ); +} + +/** +*жijǷ +*objtag ҪжϵĶ +*type_name ͵ +*/ +int checkIsTypeOrSubtype1(tag_t objtag,char * type_name){ + //printf("жǷ%s\n",type_name); + tag_t type = NULLTAG; + ITKCALL(TCTYPE_ask_object_type(objtag,&type));// + tag_t item_type = NULLTAG; + ITKCALL(TCTYPE_find_type(type_name,"",&item_type));//Ϊtype_nameĶ + int is_type = 0; + if(item_type != NULLTAG){ + //printf("ҵ%s\n",type_name); + //printf(" find Folder type ok !!!! \n"); + logical isok = FALSE; + ITKCALL(TCTYPE_is_type_of(type,item_type,&isok));//жtypeǷΪitem_typeͬ + if(isok){ + //printf("%s༰\n",type_name); + is_type= 1; + }else{ + //printf("%s༰\n",type_name); + is_type= 0; + } + }else{ + //printf("ûҵ%s\n",type_name); + } + return is_type; +} + +/** +* ȡѡ +*/ +int getPrefStrings1( const char *preference, TC_preference_search_scope_t scope, vector &pref_vec ) +{ + int ifail = ITK_ok , i = 0, j = 0, k =0, num = 0; + char **values; + TC_preference_search_scope_t old_scope; + ITKCALL( ifail = PREF_ask_search_scope( &old_scope) ); + ITKCALL( ifail = PREF_set_search_scope( scope ) ); + ITKCALL( ifail = PREF_ask_char_values( preference, &num, &values ) ); + //WriteLog("num=%d",num); + for(i = 0; i < num; i++) + { + pref_vec.push_back(values[i]); + } + DOFREE(values); + ITKCALL( ifail = PREF_set_search_scope( old_scope ) ); + return ifail; +} +//attr1:A001 map +int getResult(string str, map *map) +{ + int index = -1; + index = str.find('('); + if (index != -1) + { + int index2 = str.find(')'); + if (index2 == -1 || index2 == str.size() - 1) + return 0; + if (index == 0) + { + + if (str[index2 + 1] == '&') + { + return getResult(str.substr(index + 1, index2 - 1), map)*getResult(str.substr(index2 + 2), map); + } + else if (str[index2 + 1] == '|') + { + return getResult(str.substr(index + 1, index2 - 1), map) + getResult(str.substr(index2 + 2), map); + } + return 0; + } + else + { + if (str[index - 1] == '&') + { + if (str[index2 + 1] == '&') + { + return getResult(str.substr(0, index - 1), map)*getResult(str.substr(index + 1, index2 - index - 1), map)*getResult(str.substr(index2 + 2), map); + } + else if (str[index2 + 1] == '|') + { + return getResult(str.substr(0, index - 1), map)*getResult(str.substr(index + 1, index2 - index - 1), map) + getResult(str.substr(index2 + 2), map); + } + return 0; + } + else if (str[index - 1] == '|') + { + if (str[index2 + 1] == '&') + { + return getResult(str.substr(0, index - 1), map) + getResult(str.substr(index + 1, index2 - index - 1), map)*getResult(str.substr(index2 + 2), map); + } + else if (str[index2 + 1] == '|') + { + return getResult(str.substr(0, index - 1), map) + getResult(str.substr(index + 1, index2 - index - 1), map) + getResult(str.substr(index2 + 2), map); + } + return 0; + } + else if (str[index - 1] == '!') + { + if (index == 1) + { + if (str[index2 + 1] == '&') + { + return !getResult(str.substr(index + 1, index2 - index - 1), map)*getResult(str.substr(index2 + 2), map); + } + else if (str[index2 + 1] == '|') + { + return !getResult(str.substr(index + 1, index2 - index - 1), map) + getResult(str.substr(index2 + 2), map); + } + return 0; + } + else if (str[index - 2] == '&') + { + if (str[index2 + 1] == '&') + { + return getResult(str.substr(0, index - 2), map) + !getResult(str.substr(index + 1, index2 - index - 1), map)*getResult(str.substr(index2 + 2), map); + } + else if (str[index2 + 1] == '|') + { + return getResult(str.substr(0, index - 2), map) + !getResult(str.substr(index + 1, index2 - index - 1), map) + getResult(str.substr(index2 + 2), map); + } + return 0; + } + else if (str[index - 2] == '|') + { + if (str[index2 + 1] == '&') + { + return getResult(str.substr(0, index - 2), map) + !getResult(str.substr(index + 1, index2 - index - 1), map)*getResult(str.substr(index2 + 2), map); + } + else if (str[index2 + 1] == '|') + { + return getResult(str.substr(0, index - 2), map) + !getResult(str.substr(index + 1, index2 - index - 1), map) + getResult(str.substr(index2 + 2), map); + } + return 0; + } + } + return 0; + } + } + index = str.find('|'); + if (index != -1) + { + return getResult(str.substr(0, index), map) + getResult(str.substr(index + 1), map); + } + index = str.find('&'); + if (index != -1) + { + return getResult(str.substr(0, index), map)*getResult(str.substr(index + 1), map); + } + index = str.find('!'); + if (index != -1) + { + if (index != 0) + return 0; + index = str.find(':'); + if (index == -1) + return 0; + vector temp_vec; + split((*map)[str.substr(1, index - 1)], ", ", &temp_vec); + if (str.substr(index + 1) == "null") + { + for (auto i = 0; i temp_vec; + split((*map)[str.substr(0, index)], ", ", &temp_vec); + if (str.substr(index + 1) == "null") + { + for (auto i = 0; i *vec_tag) +{ + int m = 0, + c_line_count = 0, + view_count = 0; + tag_t bom_window_tag = NULLTAG, + top_line_tag = NULLTAG, + *c_line_tags = NULL, + *view_tags = NULL; + SAFECALL(AOM_ask_value_tags(tagt, "structure_revisions", &view_count, &view_tags)); + if (view_count>0){ + SAFECALL(BOM_create_window(&bom_window_tag)); + SAFECALL(BOM_set_window_top_line_bvr(bom_window_tag, view_tags[0], &top_line_tag)); + SAFECALL(BOM_line_ask_all_child_lines(top_line_tag, &c_line_count, &c_line_tags)); + BOM_line_pack(top_line_tag); + if (c_line_count == 0){ + printf("no bom\n"); + } + else{ + + for (int m = 0; m < c_line_count; m++) + { + tag_t rev_tag = NULLTAG; + SAFECALL(AOM_ask_value_tag(c_line_tags[m], "bl_line_object", &rev_tag)); + (*vec_tag).push_back(rev_tag); + + } + + } + SAFECALL(BOM_close_window(bom_window_tag)); + } + return 0; +}; diff --git a/WXom062/tc_util.h b/WXom062/tc_util.h new file mode 100644 index 0000000..50277d4 --- /dev/null +++ b/WXom062/tc_util.h @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include
+#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "metaframework/BusinessObjectRef.hxx" +#include "tccore/ItemRevision.hxx" +#include "tccore/Item.hxx" +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +//ݿ +#include "SQLAPI.h" + +#include "rapidjson/document.h" // rapidjson's DOM-style API +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/prettywriter.h" +using namespace std; +using namespace rapidjson; + +#define DOFREE(obj) \ +{ \ + if(obj) \ + { \ + MEM_free(obj); \ + obj = NULL; \ + } \ +} + +void current_time( date_t * date_tag ); + +void ECHO(char *format, ...); + +extern "C" int POM_AM__set_application_bypass(logical bypass); + +int checkIsTypeOrSubtype1(tag_t objtag,char * type_name); +int getPrefStrings1( const char *preference, TC_preference_search_scope_t scope, vector &pref_vec ); + +bool isTypeOf(tag_t objtag, const char * type_name); +std::string UTF8ToGBK(const char* strUTF8); +string GBKToUTF8(const std::string& strGBK); +void pushDistJob(string sendStr, string importID, string formID); +int ITEM_list_all_revs_alpha(tag_t item_tag, int *rev_cnt, tag_t **revs); +bool isNeedNotice(tag_t tag); +void split(std::string s, const char* delim, std::vector* ret); +int getVectagFromBom(tag_t tagt, vector *vec_tag); +int getResult(string str, map *map); + +/*ݼ*/ +int create_dataset(char *type_name, const char *name, tag_t excelTag); +/*ȡ16λGUID*/ +string GenerateGuid(); +/*ȡǰʱ*/ +void get_current_time(char *date_time); + +wstring StringToWString(const string s); +//ļݣ"" ""β +void WritePushLog(const char* formID, string message); +//ȥַǰհ׷ +string trim(string &str); +string getTime3(); +string getTime(); + +#define SAFECALL( argument ) \ +{ \ + int retcode = argument; \ + if ( retcode != ITK_ok ) { \ + const char* *err; \ + const int *e1,*e2; \ + int e; \ + EMH_ask_errors(&e,&e1,&e2,&err); \ + stringstream err_ss;\ + for(auto e_i=0;e_i +#include +#include "HTTPRequest.hpp" + +#include "tc_util.h" +//#include "util.h" +#include +#include +#include +#include +#include +#include +#include +#include "metaframework/BusinessObjectRef.hxx" +#include "tccore/ItemRevision.hxx" +#include "ps/ps.h" +#include "tccore/Item.hxx" +using namespace Teamcenter; + +//utfתGBK +std::string UTF8ToGBK(const char* strUTF8) +{ + int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, NULL, 0); + wchar_t* wszGBK = new wchar_t[len + 1]; + memset(wszGBK, 0, len * 2 + 2); + MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, wszGBK, len); + len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); + char* szGBK = new char[len + 1]; + memset(szGBK, 0, len + 1); + WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); + std::string strTemp(szGBK); + if (wszGBK) delete[] wszGBK; + if (szGBK) delete[] szGBK; + return strTemp; +} + +string GBKToUTF8(const std::string& strGBK) +{ + string strOutUTF8 = ""; + WCHAR * str1; + int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0); + str1 = new WCHAR[n]; + MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n); + n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL); + char * str2 = new char[n]; + WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL); + strOutUTF8 = str2; + delete[]str1; + str1 = NULL; + delete[]str2; + str2 = NULL; + return strOutUTF8; +} + +void pushDistJob(string sendStr, string importID, string formID) +{ + WSADATA wsaData; + WSAStartup(0x202, &wsaData); + + //http::Request request("http://10.128.20.202:8080/mes-intfe/mes/wkpcs/mapChange"); + http::Request request("http://10.128.20.250:8090/mes-intfe/mes/map/mapChange"); + + vector head; + http::Response response; + stringstream ss; + map para; + string jobs = GBKToUTF8(sendStr); + + para["ccod"] = jobs; + try { + response = request.send("POST", para, { "Content-Type:application/x-www-form-urlencoded" }); // + } + catch (system_error e) { + printf("get system error;%s\n", e.what()); + return; + } + catch (runtime_error r) { + printf("error:5s\r\n", r.what()); + return; + } + catch (exception e) { + printf("get error\r\n"); + return; + } + vector vec = response.body; + for (int i = 0; i < vec.size(); i++) + { + ss << vec[i]; + } + string resp = UTF8ToGBK(ss.str().c_str()); + //stringstream mess; + //mess.str(""); + //mess << "ͼֽ[" << importID << "]--ϱ[" << sendStr << "],ؽ:" << resp; + //LINFO << mess.str().c_str(); + printf("ssss====:%s\r\n", resp.c_str()); + +} + + +bool isTypeOf(tag_t objtag, const char * type_name) { + tag_t type = NULLTAG; + TCTYPE_ask_object_type(objtag, &type); + tag_t item_type = NULLTAG; + TCTYPE_find_type(type_name, "", &item_type); + bool is_type = false; + if (item_type != NULLTAG) { + logical isok = FALSE; + TCTYPE_is_type_of(type, item_type, &isok); + if (isok) { + is_type = true; + } + } + return is_type; +} + +//ͼֽ󲻴->ZT2_Design3DRevision;DZ汾->V01ϰ汾 +bool isNeedNotice(tag_t tag) +{ + bool flag = false; + if (!isTypeOf(tag, "ZT2_Design3DRevision")) + return true; + char *item_revision_id; + AOM_ask_value_string(tag,"item_revision_id",&item_revision_id); + if (strcmp(item_revision_id, "V01") == 0) + { + flag = true; + } + /* + tag_t item; + ITEM_ask_item_of_rev(tag, &item); + tag_t *revs; + int cnt; + ITEM_list_all_revs_alpha(item, &cnt, &revs); + for (auto i = 0; i < cnt; i++) + { + int rel_cnt; + tag_t *rels; + (AOM_ask_value_tags(revs[i], "release_status_list", &rel_cnt, &rels)); + MEM_free(rels); + if (rel_cnt) + { + printf("ѷͼֽ汾"); + flag = true; + break; + } + } + */ + return flag; +} + + +struct rev_sort +{ + tag_t rev; + string id; +}; + +bool sort_by_rev(const rev_sort &a, const rev_sort &b) +{ + + return a.id(item_tag); + vector tag_vec; + vector int_vec; + vector rev_vec; + item->getTagArray("revision_list", tag_vec, int_vec); + for (auto i = 0; i> result; + return result; +} +string getTime() +{ + stringstream ss; + time_t t = time(0); + tm* local = localtime(&t); + ss << local->tm_year + 1900 << '-'; + if (local->tm_mon < 9) + ss << "0"; + ss << local->tm_mon + 1 << '-'; + if (local->tm_mday < 10) + ss << "0"; + ss << local->tm_mday << ' '; + if (local->tm_hour < 10) + ss << "0"; + ss << local->tm_hour << ':'; + if (local->tm_min < 10) + ss << "0"; + ss << local->tm_min << ':'; + if (local->tm_sec<10) + ss << "0"; + ss << local->tm_sec; + return ss.str(); +} \ No newline at end of file diff --git a/WXom062/util.h b/WXom062/util.h new file mode 100644 index 0000000..c1ceca1 --- /dev/null +++ b/WXom062/util.h @@ -0,0 +1,2 @@ +#include "easylogging++.h" +_INITIALIZE_EASYLOGGINGPP \ No newline at end of file diff --git a/WXom062/wx_main.cpp b/WXom062/wx_main.cpp new file mode 100644 index 0000000..e673ceb --- /dev/null +++ b/WXom062/wx_main.cpp @@ -0,0 +1,31 @@ +#include "wx_main.h" +#include "wx_registry.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + + /** + * @fn extern "C" DLLAPI int liborigin_register_callbacks + * @return usually return ITK_ok + * @brief liborigin customization entry + */ + DLLAPI int WXom062_register_callbacks() + { + int ifail = ITK_ok; + ITKCALL(ifail = CUSTOM_register_exit( + "WXom062", + "USER_gs_shell_init_module", + (CUSTOM_EXIT_ftn_t)WX_Handler)); + //עUserserviceMethod + ITKCALL(ifail = CUSTOM_register_exit( + "WXom062", + "USERSERVICE_register_methods", + (CUSTOM_EXIT_ftn_t)WX_Method)); + return ifail; + } +#ifdef __cplusplus +} +#endif diff --git a/WXom062/wx_main.h b/WXom062/wx_main.h new file mode 100644 index 0000000..97e6520 --- /dev/null +++ b/WXom062/wx_main.h @@ -0,0 +1,3 @@ +#include +#include +#include diff --git a/WXom062/x64/Release/CHINT_BOMEC2SAP.obj b/WXom062/x64/Release/CHINT_BOMEC2SAP.obj new file mode 100644 index 0000000..00320e1 Binary files /dev/null and b/WXom062/x64/Release/CHINT_BOMEC2SAP.obj differ diff --git a/WXom062/x64/Release/CHINT_TC2CC.obj b/WXom062/x64/Release/CHINT_TC2CC.obj new file mode 100644 index 0000000..d66e756 Binary files /dev/null and b/WXom062/x64/Release/CHINT_TC2CC.obj differ diff --git a/WXom062/x64/Release/ChintSendMessage.obj b/WXom062/x64/Release/ChintSendMessage.obj new file mode 100644 index 0000000..b695028 Binary files /dev/null and b/WXom062/x64/Release/ChintSendMessage.obj differ diff --git a/WXom062/x64/Release/DYCreateElectricalBOM.obj b/WXom062/x64/Release/DYCreateElectricalBOM.obj new file mode 100644 index 0000000..d0a5910 Binary files /dev/null and b/WXom062/x64/Release/DYCreateElectricalBOM.obj differ diff --git a/WXom062/x64/Release/WXom062.Build.CppClean.log b/WXom062/x64/Release/WXom062.Build.CppClean.log new file mode 100644 index 0000000..0a2520f --- /dev/null +++ b/WXom062/x64/Release/WXom062.Build.CppClean.log @@ -0,0 +1,16 @@ +F:\VS\WXOM062\WXOM062\X64\RELEASE\WX_REGISTRY.OBJ +F:\VS\WXOM062\WXOM062\X64\RELEASE\WX_METHOD.OBJ +F:\VS\WXOM062\WXOM062\X64\RELEASE\WX_MAIN.OBJ +F:\VS\WXOM062\WXOM062\X64\RELEASE\TC_UTIL.OBJ +F:\VS\WXOM062\WXOM062\X64\RELEASE\TC_LOG.OBJ +F:\VS\WXOM062\WXOM062\X64\RELEASE\STRING_UTILS.OBJ +F:\VS\WXom062\WXom062\x64\Release\string_utils.obj +F:\VS\WXom062\WXom062\x64\Release\tc_log.obj +F:\VS\WXom062\WXom062\x64\Release\tc_util.obj +F:\VS\WXom062\WXom062\x64\Release\wx_main.obj +F:\VS\WXom062\WXom062\x64\Release\wx_method.obj +F:\VS\WXom062\WXom062\x64\Release\wx_registry.obj +F:\VS\WXom062\WXom062\x64\Release\cl.command.1.tlog +F:\VS\WXom062\WXom062\x64\Release\CL.read.1.tlog +F:\VS\WXom062\WXom062\x64\Release\CL.write.1.tlog +F:\VS\WXom062\WXom062\x64\Release\vc110.pdb diff --git a/WXom062/x64/Release/WXom062.lastbuildstate b/WXom062/x64/Release/WXom062.lastbuildstate new file mode 100644 index 0000000..e78de3f --- /dev/null +++ b/WXom062/x64/Release/WXom062.lastbuildstate @@ -0,0 +1,2 @@ +#v4.0:v110:false +Release|x64|F:\VS\WXom062\| diff --git a/WXom062/x64/Release/WXom062.log b/WXom062/x64/Release/WXom062.log new file mode 100644 index 0000000..79e97cf --- /dev/null +++ b/WXom062/x64/Release/WXom062.log @@ -0,0 +1,108 @@ +生成启动时间为 2024/7/22 14:50:09。 + 1>项目“Z:\TC_install\ZhengTai\c\WXom062\WXom062\WXom062.vcxproj”在节点 2 上(Build 个目标)。 + 1>ClCompile: + D:\VS2015\VC\bin\x86_amd64\CL.exe /c /IZ:\TC_install\YSR\c\TC11.6\include /IZ:\TC_install\YSR\c\TC11.6\include_cpp /I"D:\Siemens\HTTPRequest-master\include" /IZ:\TC_install\ZhengTai\c\libxl\include /Zi /nologo /W3 /WX- /O2 /Oi /GL /D WIN32 /D NDEBUG /D _WINDOWS /D _USRDLL /D WXOM062_EXPORTS /D IPLIB=none /D _CRT_SECURE_NO_WARNINGS /D _WINDLL /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /Fo"x64\Release\\" /Fd"x64\Release\vc140.pdb" /Gd /TP /errorReport:prompt test.cpp + test.cpp + 1>z:\tc_install\zhengtai\c\wxom062\wxom062\HTTPRequest.hpp(822): error C2143: 语法错误: 缺少“;”(在“}”的前面) + 1>z:\tc_install\zhengtai\c\wxom062\wxom062\HTTPRequest.hpp(825): error C2143: 语法错误: 缺少“;”(在“}”的前面) + 1>Z:\TC_install\YSR\c\TC11.6\include\pom/pom/pom.h(805): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>Z:\TC_install\YSR\c\TC11.6\include\pom/pom/pom.h(5414): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>Z:\TC_install\YSR\c\TC11.6\include\qry/qry.h(591): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>Z:\TC_install\YSR\c\TC11.6\include\qry/qry.h(591): warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\base_utils/IFail.hxx(114): warning C4251: “IFail::m_message”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“IFail”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/FeatureKeyCheck.hxx(55): warning C4251: “Teamcenter::FeatureKeyCheck::featureKey”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::FeatureKeyCheck”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/FeatureKeyCheck.hxx(74): warning C4251: “Teamcenter::FeatureKeyCheckAND::featureKeyChecks”: class“std::vector>”需要有 dll 接口由 class“Teamcenter::FeatureKeyCheckAND”的客户端使用 + with + [ + _Ty=Teamcenter::FeatureKeyCheck * + ] + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/FeatureKeyCheck.hxx(94): warning C4251: “Teamcenter::FeatureKeyCheckOR::featureKeyChecks”: class“std::vector>”需要有 dll 接口由 class“Teamcenter::FeatureKeyCheckOR”的客户端使用 + with + [ + _Ty=Teamcenter::FeatureKeyCheck * + ] + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/RootObject.hxx(90): warning C4251: “Teamcenter::RootObject::m_typeName”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::RootObject”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/RootObject.hxx(95): warning C4251: “Teamcenter::RootObject::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::RootObject”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/OperationInput.hxx(381): warning C4251: “Teamcenter::OperationInput::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::OperationInput”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/CreateInput.hxx(134): warning C4251: “Teamcenter::CreateInput::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::CreateInput”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/SaveAsInput.hxx(92): warning C4251: “Teamcenter::SaveAsInput::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::SaveAsInput”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/ReviseInput.hxx(92): warning C4251: “Teamcenter::ReviseInput::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::ReviseInput”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/BulkInput.hxx(116): warning C4251: “Teamcenter::BulkInput::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::BulkInput”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/BulkData.hxx(119): warning C4251: “Teamcenter::BulkData::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::BulkData”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/DeepCopyData.hxx(92): warning C4251: “Teamcenter::DeepCopyData::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::DeepCopyData”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/BusinessObject.hxx(605): warning C4251: “Teamcenter::BusinessObject::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::BusinessObject”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\metaframework/RuntimeBusinessObject.hxx(92): warning C4251: “Teamcenter::RuntimeBusinessObject::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::RuntimeBusinessObject”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tc/Fnd0BaseProvider.hxx(101): warning C4251: “Teamcenter::Fnd0BaseProvider::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::Fnd0BaseProvider”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/POM_object.hxx(236): warning C4251: “Teamcenter::POM_object::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::POM_object”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/POM_application_object.hxx(142): warning C4251: “Teamcenter::POM_application_object::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::POM_application_object”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/WorkspaceObject.hxx(506): warning C4251: “Teamcenter::WorkspaceObject::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::WorkspaceObject”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/ItemRevision.hxx(471): warning C4251: “Teamcenter::ItemRevision::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::ItemRevision”的客户端使用 + 1>Z:\TC_install\YSR\c\TC11.6\include_cpp\tccore/Item.hxx(318): warning C4251: “Teamcenter::Item::name”: class“std::basic_string,std::allocator>”需要有 dll 接口由 class“Teamcenter::Item”的客户端使用 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(112): warning C4005: “PRId64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(210): note: 参见“PRId64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(123): warning C4005: “PRIdPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(218): note: 参见“PRIdPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(131): warning C4005: “PRIi64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(211): note: 参见“PRIi64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(142): warning C4005: “PRIiPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(219): note: 参见“PRIiPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(150): warning C4005: “PRIo64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(213): note: 参见“PRIo64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(161): warning C4005: “PRIoPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(221): note: 参见“PRIoPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(169): warning C4005: “PRIu64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(212): note: 参见“PRIu64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(180): warning C4005: “PRIuPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(220): note: 参见“PRIuPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(188): warning C4005: “PRIx64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(214): note: 参见“PRIx64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(199): warning C4005: “PRIxPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(222): note: 参见“PRIxPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(207): warning C4005: “PRIX64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(215): note: 参见“PRIX64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(218): warning C4005: “PRIXPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(223): note: 参见“PRIXPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(233): warning C4005: “SCNd64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(233): note: 参见“SCNd64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(244): warning C4005: “SCNdPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(240): note: 参见“SCNdPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(252): warning C4005: “SCNi64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(234): note: 参见“SCNi64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(263): warning C4005: “SCNiPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(241): note: 参见“SCNiPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(271): warning C4005: “SCNo64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(236): note: 参见“SCNo64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(282): warning C4005: “SCNoPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(243): note: 参见“SCNoPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(290): warning C4005: “SCNu64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(235): note: 参见“SCNu64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(301): warning C4005: “SCNuPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(242): note: 参见“SCNuPTR”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(309): warning C4005: “SCNx64”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(237): note: 参见“SCNx64”的前一个定义 + 1>C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt\inttypes.h(320): warning C4005: “SCNxPTR”: 宏重定义 + Z:\TC_install\YSR\c\TC11.6\include_cpp\mach_datatypes.h(244): note: 参见“SCNxPTR”的前一个定义 + 1>test.cpp(72): error C2664: “http::Response http::Request::send(const std::string &,const std::vector> &,const http::HeaderFields &,const std::chrono::milliseconds)”: 无法将参数 2 从“std::map,std::allocator>>”转换为“const std::string &” + with + [ + _Ty=uint8_t + ] + and + [ + _Kty=std::string, + _Ty=std::string + ] + test.cpp(72): note: 原因如下: 无法从“std::map,std::allocator>>”转换为“const std::string” + with + [ + _Kty=std::string, + _Ty=std::string + ] + test.cpp(72): note: 没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符 + 1>test.cpp(183): warning C4267: “=”: 从“size_t”转换到“int”,可能丢失数据 + 1>test.cpp(184): warning C4267: “参数”: 从“size_t”转换到“int”,可能丢失数据 + 1>已完成生成项目“Z:\TC_install\ZhengTai\c\WXom062\WXom062\WXom062.vcxproj”(Build 个目标)的操作 - 失败。 + +生成失败。 + +已用时间 00:00:04.38 diff --git a/WXom062/x64/Release/chint.Build.CppClean.log b/WXom062/x64/Release/chint.Build.CppClean.log new file mode 100644 index 0000000..a4faedd --- /dev/null +++ b/WXom062/x64/Release/chint.Build.CppClean.log @@ -0,0 +1,32 @@ +d:\项目\正泰\wxom062 - 副本 (2)\x64\release\chint.lib +d:\项目\正泰\wxom062 - 副本 (2)\x64\release\chint.exp +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\vc120.pdb +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\test.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_registry.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_method.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_main.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_handler.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\tc_util.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\tc_log.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\string_utils.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\kutil.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\dycreateelectricalbom.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_tc2cc.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_standard.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_set_prop.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_materialtcmcheck.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_design_task.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint_bomec2sap.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chintsignchange.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chintsendmessage.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chintproperty.obj +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\common_itk_util.obj +d:\项目\正泰\wxom062 - 副本 (2)\x64\release\chint.dll +d:\项目\正泰\wxom062 - 副本 (2)\x64\release\chint.pdb +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\chint.write.1u.tlog +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\cl.command.1.tlog +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\cl.read.1.tlog +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\cl.write.1.tlog +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\link.command.1.tlog +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\link.read.1.tlog +d:\项目\正泰\wxom062 - 副本 (2)\wxom062\x64\release\chint.tlog\link.write.1.tlog diff --git a/WXom062/x64/Release/chint.lastbuildstate b/WXom062/x64/Release/chint.lastbuildstate new file mode 100644 index 0000000..155ea5a --- /dev/null +++ b/WXom062/x64/Release/chint.lastbuildstate @@ -0,0 +1,2 @@ +#v4.0:v110:false +Release|x64|D:\项目\正泰\WXom062 - 副本 (2)\| diff --git a/WXom062/x64/Release/chint.tlog/CL.read.1.tlog b/WXom062/x64/Release/chint.tlog/CL.read.1.tlog new file mode 100644 index 0000000..9ce3041 Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/CL.read.1.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/CL.write.1.tlog b/WXom062/x64/Release/chint.tlog/CL.write.1.tlog new file mode 100644 index 0000000..5b0718e Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/CL.write.1.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/chint.lastbuildstate b/WXom062/x64/Release/chint.tlog/chint.lastbuildstate new file mode 100644 index 0000000..9529d0d --- /dev/null +++ b/WXom062/x64/Release/chint.tlog/chint.lastbuildstate @@ -0,0 +1,2 @@ +#TargetFrameworkVersion=v4.0:PlatformToolSet=v140:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit +Release|x64|Z:\TC_install\ZhengTai\c\WXom062\| diff --git a/WXom062/x64/Release/chint.tlog/chint.write.1u.tlog b/WXom062/x64/Release/chint.tlog/chint.write.1u.tlog new file mode 100644 index 0000000..ad291f3 Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/chint.write.1u.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/cl.command.1.tlog b/WXom062/x64/Release/chint.tlog/cl.command.1.tlog new file mode 100644 index 0000000..8108272 Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/cl.command.1.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/link.command.1.tlog b/WXom062/x64/Release/chint.tlog/link.command.1.tlog new file mode 100644 index 0000000..cf0afa6 Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/link.command.1.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/link.read.1.tlog b/WXom062/x64/Release/chint.tlog/link.read.1.tlog new file mode 100644 index 0000000..c2259dc Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/link.read.1.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/link.write.1.tlog b/WXom062/x64/Release/chint.tlog/link.write.1.tlog new file mode 100644 index 0000000..12c7c66 Binary files /dev/null and b/WXom062/x64/Release/chint.tlog/link.write.1.tlog differ diff --git a/WXom062/x64/Release/chint.tlog/unsuccessfulbuild b/WXom062/x64/Release/chint.tlog/unsuccessfulbuild new file mode 100644 index 0000000..e69de29 diff --git a/WXom062/x64/Release/chint.unsuccessfulbuild b/WXom062/x64/Release/chint.unsuccessfulbuild new file mode 100644 index 0000000..e69de29 diff --git a/WXom062/x64/Release/chintProperty.obj b/WXom062/x64/Release/chintProperty.obj new file mode 100644 index 0000000..38de7aa Binary files /dev/null and b/WXom062/x64/Release/chintProperty.obj differ diff --git a/WXom062/x64/Release/chintSignChange.obj b/WXom062/x64/Release/chintSignChange.obj new file mode 100644 index 0000000..aff812a Binary files /dev/null and b/WXom062/x64/Release/chintSignChange.obj differ diff --git a/WXom062/x64/Release/chint_Design_Task.obj b/WXom062/x64/Release/chint_Design_Task.obj new file mode 100644 index 0000000..349c2da Binary files /dev/null and b/WXom062/x64/Release/chint_Design_Task.obj differ diff --git a/WXom062/x64/Release/chint_Handler.obj b/WXom062/x64/Release/chint_Handler.obj new file mode 100644 index 0000000..f260f75 Binary files /dev/null and b/WXom062/x64/Release/chint_Handler.obj differ diff --git a/WXom062/x64/Release/chint_MaterialTCMCheck.obj b/WXom062/x64/Release/chint_MaterialTCMCheck.obj new file mode 100644 index 0000000..4960f53 Binary files /dev/null and b/WXom062/x64/Release/chint_MaterialTCMCheck.obj differ diff --git a/WXom062/x64/Release/chint_main.obj b/WXom062/x64/Release/chint_main.obj new file mode 100644 index 0000000..9844b95 Binary files /dev/null and b/WXom062/x64/Release/chint_main.obj differ diff --git a/WXom062/x64/Release/chint_method.obj b/WXom062/x64/Release/chint_method.obj new file mode 100644 index 0000000..84822b2 Binary files /dev/null and b/WXom062/x64/Release/chint_method.obj differ diff --git a/WXom062/x64/Release/chint_registry.obj b/WXom062/x64/Release/chint_registry.obj new file mode 100644 index 0000000..ab79118 Binary files /dev/null and b/WXom062/x64/Release/chint_registry.obj differ diff --git a/WXom062/x64/Release/chint_set_prop.obj b/WXom062/x64/Release/chint_set_prop.obj new file mode 100644 index 0000000..5d8b576 Binary files /dev/null and b/WXom062/x64/Release/chint_set_prop.obj differ diff --git a/WXom062/x64/Release/chint_standard.obj b/WXom062/x64/Release/chint_standard.obj new file mode 100644 index 0000000..51b2672 Binary files /dev/null and b/WXom062/x64/Release/chint_standard.obj differ diff --git a/WXom062/x64/Release/kutil.obj b/WXom062/x64/Release/kutil.obj new file mode 100644 index 0000000..228b606 Binary files /dev/null and b/WXom062/x64/Release/kutil.obj differ diff --git a/WXom062/x64/Release/string_utils.obj b/WXom062/x64/Release/string_utils.obj new file mode 100644 index 0000000..32984dd Binary files /dev/null and b/WXom062/x64/Release/string_utils.obj differ diff --git a/WXom062/x64/Release/tc_log.obj b/WXom062/x64/Release/tc_log.obj new file mode 100644 index 0000000..31660ad Binary files /dev/null and b/WXom062/x64/Release/tc_log.obj differ diff --git a/WXom062/x64/Release/tc_util.obj b/WXom062/x64/Release/tc_util.obj new file mode 100644 index 0000000..c388283 Binary files /dev/null and b/WXom062/x64/Release/tc_util.obj differ diff --git a/WXom062/x64/Release/vc140.pdb b/WXom062/x64/Release/vc140.pdb new file mode 100644 index 0000000..165213f Binary files /dev/null and b/WXom062/x64/Release/vc140.pdb differ diff --git a/x64/Release/CUST_ITK.dll b/x64/Release/CUST_ITK.dll new file mode 100644 index 0000000..eb2a178 Binary files /dev/null and b/x64/Release/CUST_ITK.dll differ diff --git a/x64/Release/CUST_ITK.exp b/x64/Release/CUST_ITK.exp new file mode 100644 index 0000000..13e4b6a Binary files /dev/null and b/x64/Release/CUST_ITK.exp differ diff --git a/x64/Release/CUST_ITK.lib b/x64/Release/CUST_ITK.lib new file mode 100644 index 0000000..861afaa Binary files /dev/null and b/x64/Release/CUST_ITK.lib differ diff --git a/x64/Release/CUST_ITK.pdb b/x64/Release/CUST_ITK.pdb new file mode 100644 index 0000000..b93046d Binary files /dev/null and b/x64/Release/CUST_ITK.pdb differ diff --git a/x64/Release/TEST_ITK.exp b/x64/Release/TEST_ITK.exp new file mode 100644 index 0000000..f0c1bfa Binary files /dev/null and b/x64/Release/TEST_ITK.exp differ diff --git a/x64/Release/TEST_ITK.lib b/x64/Release/TEST_ITK.lib new file mode 100644 index 0000000..9c99621 Binary files /dev/null and b/x64/Release/TEST_ITK.lib differ diff --git a/x64/Release/TEST_ITK.pdb b/x64/Release/TEST_ITK.pdb new file mode 100644 index 0000000..e1c569a Binary files /dev/null and b/x64/Release/TEST_ITK.pdb differ diff --git a/x64/Release/WXom062.dll b/x64/Release/WXom062.dll new file mode 100644 index 0000000..8ef4642 Binary files /dev/null and b/x64/Release/WXom062.dll differ diff --git a/x64/Release/WXom062.exp b/x64/Release/WXom062.exp new file mode 100644 index 0000000..e8d22cc Binary files /dev/null and b/x64/Release/WXom062.exp differ diff --git a/x64/Release/WXom062.lib b/x64/Release/WXom062.lib new file mode 100644 index 0000000..5ca15fc Binary files /dev/null and b/x64/Release/WXom062.lib differ diff --git a/x64/Release/WXom062.pdb b/x64/Release/WXom062.pdb new file mode 100644 index 0000000..2f1b506 Binary files /dev/null and b/x64/Release/WXom062.pdb differ diff --git a/x64/Release/lp.dll b/x64/Release/lp.dll new file mode 100644 index 0000000..6eb44c6 Binary files /dev/null and b/x64/Release/lp.dll differ