From 964d89e34bb0b8dd3231dd9805d6b6b87bfe6b0d Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 10 Feb 2016 11:31:29 +0800 Subject: [PATCH] Add encoding validation option for Writer/PrettyWriter --- include/rapidjson/fwd.h | 7 ++++++- include/rapidjson/prettywriter.h | 10 +++++++--- include/rapidjson/writer.h | 29 +++++++++++++++++++++++++---- test/unittest/fwdtest.cpp | 12 +++++++++++- test/unittest/writertest.cpp | 25 +++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 9 deletions(-) diff --git a/include/rapidjson/fwd.h b/include/rapidjson/fwd.h index 9c0466c3..e8104e84 100644 --- a/include/rapidjson/fwd.h +++ b/include/rapidjson/fwd.h @@ -91,9 +91,14 @@ typedef GenericReader, UTF8, CrtAllocator> Reader; // writer.h -template +template class Writer; +// prettywriter.h + +template +class PrettyWriter; + // document.h template diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index adfff4fd..dd0e516d 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -31,8 +31,8 @@ RAPIDJSON_NAMESPACE_BEGIN \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. */ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> -class PrettyWriter : public Writer { +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class PrettyWriter : public Writer { public: typedef Writer Base; typedef typename Base::Ch Ch; @@ -42,9 +42,13 @@ public: \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ - PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + + explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + //! 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. diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 4f42b9e0..6e6f2fd4 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -35,6 +35,26 @@ RAPIDJSON_DIAG_OFF(padded) 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. + 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. @@ -51,7 +71,7 @@ RAPIDJSON_NAMESPACE_BEGIN \tparam StackAllocator Type of allocator for allocating memory of stack. \note implements Handler concept */ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class Writer { public: typedef typename SourceEncoding::Ch Ch; @@ -318,9 +338,10 @@ protected: PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); } } - else - if (RAPIDJSON_UNLIKELY(!(Transcoder::TranscodeUnsafe(is, *os_)))) - return false; + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; } PutUnsafe(*os_, '\"'); return true; diff --git a/test/unittest/fwdtest.cpp b/test/unittest/fwdtest.cpp index 4420dd18..bf746dfe 100644 --- a/test/unittest/fwdtest.cpp +++ b/test/unittest/fwdtest.cpp @@ -69,7 +69,10 @@ struct Foo { Reader* reader; // writer.h - Writer, UTF8, CrtAllocator>* writer; + Writer, UTF8, CrtAllocator, 0>* writer; + + // prettywriter.h + PrettyWriter, UTF8, CrtAllocator, 0>* prettywriter; // document.h Value* value; @@ -94,6 +97,7 @@ struct Foo { #include "rapidjson/memorystream.h" #include "rapidjson/document.h" // -> reader.h #include "rapidjson/writer.h" +#include "rapidjson/prettywriter.h" #include "rapidjson/schema.h" // -> pointer.h Foo::Foo() : @@ -139,6 +143,9 @@ Foo::Foo() : // writer.h writer(RAPIDJSON_NEW((Writer))), + // prettywriter.h + prettywriter(RAPIDJSON_NEW((PrettyWriter))), + // document.h value(RAPIDJSON_NEW(Value)), document(RAPIDJSON_NEW(Document)), @@ -196,6 +203,9 @@ Foo::~Foo() { // writer.h RAPIDJSON_DELETE(writer); + // prettywriter.h + RAPIDJSON_DELETE(prettywriter); + // document.h RAPIDJSON_DELETE(value); RAPIDJSON_DELETE(document); diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 197411ca..3b1dfe87 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -347,6 +347,31 @@ TEST(Writer, InvalidEncoding) { } } +TEST(Writer, ValidateEncoding) { + { + StringBuffer buffer; + Writer, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer); + writer.StartArray(); + EXPECT_TRUE(writer.String("\x24")); // Dollar sign U+0024 + EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2 + EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC + EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E + writer.EndArray(); + EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString()); + } + + // Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + { + StringBuffer buffer; + Writer, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer); + writer.StartArray(); + EXPECT_FALSE(writer.String("\xfe")); + EXPECT_FALSE(writer.String("\xff")); + EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff")); + writer.EndArray(); + } +} + TEST(Writer, InvalidEventSequence) { // {] {