Commit 22754379968bd554fe2dcd0e7cae91b0a44b096f

Authored by DarkGod
1 parent cec3556f

plop

Too many changes to show.

To preserve performance only 31 of 31+ files are displayed.

... ... @@ -66,6 +66,11 @@ newoption {
66 66 }
67 67
68 68 newoption {
  69 + trigger = "discord",
  70 + description = "Discord integration"
  71 +}
  72 +
  73 +newoption {
69 74 trigger = "web-awesomium",
70 75 description = "Use awesomium embedded browser as the webcore"
71 76 }
... ...
... ... @@ -38,6 +38,7 @@ project "TEngine"
38 38 files { "../steamworks/luasteam.c", }
39 39 end
40 40 links { "physfs", "lua".._OPTIONS.lua, "fov", "luasocket", "luaprofiler", "lpeg", "tcodimport", "lxp", "expatstatic", "luamd5", "luazlib", "luabitop", "te4-bzip" }
  41 + if _OPTIONS.discord then links { "te4-discord" } defines { "DISCORD_TE4" } end
41 42 defines { "_DEFAULT_VIDEOMODE_FLAGS_='SDL_HWSURFACE|SDL_DOUBLEBUF'" }
42 43 defines { [[TENGINE_HOME_PATH='".t-engine"']], "TE4CORE_VERSION="..TE4CORE_VERSION }
43 44 buildoptions { "-O3" }
... ... @@ -597,3 +598,24 @@ end
597 598 if _OPTIONS.steam then
598 599 dofile("../steamworks/build/steam-code.lua")
599 600 end
  601 +
  602 +if _OPTIONS.discord then
  603 +project "te4-discord"
  604 + kind "SharedLib"
  605 + language "C++"
  606 + targetname "te4-discord"
  607 +
  608 + includedirs { "../src/discord-rpc/include/", "../src/discord-rpc/rapidjson/", }
  609 +
  610 + files { "../src/discord-rpc/te4-discord.cpp", "../src/discord-rpc/src/discord-rpc.cpp", "../src/discord-rpc/src/rpc_connection.cpp", "../src/discord-rpc/src/serialization.cpp", }
  611 + -- defines { "DISCORD_DISABLE_IO_THREAD" }
  612 +
  613 + -- configuration "macosx"
  614 + -- files {}
  615 +
  616 + configuration "linux"
  617 + files { "../src/discord-rpc/src/connection_unix.cpp", "../src/discord-rpc/src/discord_register_linux.cpp", }
  618 +
  619 + configuration "windows"
  620 + files { "../src/discord-rpc/src/connection_win.cpp", "../src/discord-rpc/src/discord_register_win.cpp", }
  621 +end
... ...
... ... @@ -1019,6 +1019,7 @@ function _M:instanciate(mod, name, new_game, no_reboot, extra_module_info)
1019 1019 profile:incrLoadProfile(mod)
1020 1020 profile:currentCharacter(mod.full_version_string, "game did not tell us")
1021 1021
  1022 +
1022 1023 UIBase:clearCache()
1023 1024
1024 1025 -- Some requires cleanup, to correctly let modules apply settings
... ...
... ... @@ -169,4 +169,8 @@ savefile_pipe = engine.SavefilePipe.new()
169 169 -- Setup FPS
170 170 core.game.setFPS(config.settings.display_fps)
171 171
  172 +if config.settings.disable_discord then core.discord = nil end
  173 +if core.discord then core.discord.init() end
  174 +
172 175 util.showMainMenu(true)
  176 +
... ...
... ... @@ -91,6 +91,7 @@ function _M:init()
91 91
92 92 self:loaded()
93 93 profile:currentCharacter("Main Menu", "Main Menu")
  94 + if core.discord then core.discord.updatePresence{state="Main Menu", details="Thinking about which character to die with!", large_image="default", large_image_text="Pondering..."} end
94 95 end
95 96
96 97 function _M:loaded()
... ...
... ... @@ -710,6 +710,28 @@ function _M:updateCurrentChar()
710 710 if not self.party then return end
711 711 local player = self.party:findMember{main=true}
712 712 profile:currentCharacter(self.__mod_info.full_version_string, ("%s the level %d %s %s"):format(player.name, player.level, player.descriptor.subrace, player.descriptor.subclass), player.__te4_uuid)
  713 + if core.discord and self.zone then
  714 + local info = {}
  715 + info.zone = self:getZoneName()
  716 + info.char = ("Lvl %d %s %s"):format(player.level, player.descriptor.subrace, player.descriptor.subclass)
  717 + info.splash = "default"
  718 + info.splash_text = ("%s playing on %s %s; died %d time%s!"):format(player.name, player.descriptor.permadeath, player.descriptor.difficulty, player.died_times and #player.died_times or 0, (player.died_times and #player.died_times == 1) and "" or "s")
  719 + -- info.icon = "archmage"
  720 + -- info.icon_text = "lol"
  721 +
  722 + -- Determine which dlc it originates from
  723 + local _, _, addon = self.zone.short_name:find("^([^+]+)%+(.*)$")
  724 + if addon then
  725 + local addon_data = self.__mod_info.addons[addon]
  726 + if addon_data and addon_data.id_dlc then
  727 + info.splash = addon
  728 + end
  729 + end
  730 + -- Let the DLC override it in a more smart way
  731 + self:triggerHook{"Discord:check", info=info}
  732 +
  733 + core.discord.updatePresence{state=info.zone, details=info.char, large_image=info.splash, large_image_text=info.splash_text, small_image=info.icon, small_image_text=info.icon_text}
  734 + end
713 735 end
714 736
715 737 function _M:getSaveDescription()
... ... @@ -1386,10 +1408,7 @@ function _M:chronoRestore(name, remove)
1386 1408 return true
1387 1409 end
1388 1410
1389   ---- Update the zone name, if needed
1390   -function _M:updateZoneName()
1391   - if not self.zone_font then return end
1392   - local name
  1411 +function _M:getZoneName()
1393 1412 if self.zone.display_name then
1394 1413 name = self.zone.display_name()
1395 1414 else
... ... @@ -1401,6 +1420,13 @@ function _M:updateZoneName()
1401 1420 name = ("%s (%d)"):format(self.zone.name, lev)
1402 1421 end
1403 1422 end
  1423 + return name
  1424 +end
  1425 +
  1426 +--- Update the zone name, if needed
  1427 +function _M:updateZoneName()
  1428 + if not self.zone_font then return end
  1429 + local name = self:getZoneName()
1404 1430 if self.zone_name_s and self.old_zone_name == name then return end
1405 1431
1406 1432 local s = core.display.drawStringBlendedNewSurface(self.zone_font, name, unpack(colors.simple(colors.GOLD)))
... ...
... ... @@ -205,6 +205,8 @@ function _M:onEnterLevel(zone, level)
205 205 end
206 206
207 207 self:fireTalentCheck("callbackOnChangeLevel", "enter", zone, level)
  208 +
  209 + game:updateCurrentChar()
208 210 end
209 211
210 212 function _M:onEnterLevelEnd(zone, level)
... ...
... ... @@ -588,6 +588,15 @@ function _M:generateListOnline()
588 588 self.c_list:drawItem(item)
589 589 end,}
590 590
  591 + local zone = Textzone.new{width=self.c_desc.w, height=self.c_desc.h, text=string.toTString"Enable Discord's Rich Presence integration to show your current character on your currently playing profile on Discord (restart the game to apply).\n#ANTIQUE_WHITE#If you do not use Discord this option doesn't do anything in either state."}
  592 + list[#list+1] = { zone=zone, name=string.toTString"#GOLD##{bold}#Discord's Rich Presence#WHITE##{normal}#", status=function(item)
  593 + return tostring(not config.settings.disable_discord and "enabled" or "disabled")
  594 + end, fct=function(item)
  595 + config.settings.disable_discord = not config.settings.disable_discord
  596 + game:saveSettings("disable_discord", ("disable_discord = %s\n"):format(tostring(config.settings.disable_discord)))
  597 + self.c_list:drawItem(item)
  598 + end,}
  599 +
591 600 self.list = list
592 601 end
593 602
... ...
  1 +Copyright 2017 Discord, Inc.
  2 +
  3 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  4 +this software and associated documentation files (the "Software"), to deal in
  5 +the Software without restriction, including without limitation the rights to
  6 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  7 +of the Software, and to permit persons to whom the Software is furnished to do
  8 +so, subject to the following conditions:
  9 +
  10 +The above copyright notice and this permission notice shall be included in all
  11 +copies or substantial portions of the Software.
  12 +
  13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19 +SOFTWARE.
... ...
  1 +#pragma once
  2 +#include <stdint.h>
  3 +
  4 +// clang-format off
  5 +
  6 +#if defined(DISCORD_DYNAMIC_LIB)
  7 +# if defined(_WIN32)
  8 +# if defined(DISCORD_BUILDING_SDK)
  9 +# define DISCORD_EXPORT __declspec(dllexport)
  10 +# else
  11 +# define DISCORD_EXPORT __declspec(dllimport)
  12 +# endif
  13 +# else
  14 +# define DISCORD_EXPORT __attribute__((visibility("default")))
  15 +# endif
  16 +#else
  17 +# define DISCORD_EXPORT
  18 +#endif
  19 +
  20 +// clang-format on
  21 +
  22 +#ifdef __cplusplus
  23 +extern "C" {
  24 +#endif
  25 +
  26 +typedef struct DiscordRichPresence {
  27 + const char* state; /* max 128 bytes */
  28 + const char* details; /* max 128 bytes */
  29 + int64_t startTimestamp;
  30 + int64_t endTimestamp;
  31 + const char* largeImageKey; /* max 32 bytes */
  32 + const char* largeImageText; /* max 128 bytes */
  33 + const char* smallImageKey; /* max 32 bytes */
  34 + const char* smallImageText; /* max 128 bytes */
  35 + const char* partyId; /* max 128 bytes */
  36 + int partySize;
  37 + int partyMax;
  38 + const char* matchSecret; /* max 128 bytes */
  39 + const char* joinSecret; /* max 128 bytes */
  40 + const char* spectateSecret; /* max 128 bytes */
  41 + int8_t instance;
  42 +} DiscordRichPresence;
  43 +
  44 +typedef struct DiscordJoinRequest {
  45 + const char* userId;
  46 + const char* username;
  47 + const char* avatar;
  48 +} DiscordJoinRequest;
  49 +
  50 +typedef struct DiscordEventHandlers {
  51 + void (*ready)();
  52 + void (*disconnected)(int errorCode, const char* message);
  53 + void (*errored)(int errorCode, const char* message);
  54 + void (*joinGame)(const char* joinSecret);
  55 + void (*spectateGame)(const char* spectateSecret);
  56 + void (*joinRequest)(const DiscordJoinRequest* request);
  57 +} DiscordEventHandlers;
  58 +
  59 +#define DISCORD_REPLY_NO 0
  60 +#define DISCORD_REPLY_YES 1
  61 +#define DISCORD_REPLY_IGNORE 2
  62 +
  63 +DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
  64 + DiscordEventHandlers* handlers,
  65 + int autoRegister,
  66 + const char* optionalSteamId);
  67 +DISCORD_EXPORT void Discord_Shutdown(void);
  68 +
  69 +/* checks for incoming messages, dispatches callbacks */
  70 +DISCORD_EXPORT void Discord_RunCallbacks(void);
  71 +
  72 +/* If you disable the lib starting its own io thread, you'll need to call this from your own */
  73 +#ifdef DISCORD_DISABLE_IO_THREAD
  74 +DISCORD_EXPORT void Discord_UpdateConnection(void);
  75 +#endif
  76 +
  77 +DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
  78 +
  79 +DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
  80 +
  81 +#ifdef __cplusplus
  82 +} /* extern "C" */
  83 +#endif
... ...
  1 +// Tencent is pleased to support the open source community by making RapidJSON available.
  2 +//
  3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
  4 +//
  5 +// Licensed under the MIT License (the "License"); you may not use this file except
  6 +// in compliance with the License. You may obtain a copy of the License at
  7 +//
  8 +// http://opensource.org/licenses/MIT
  9 +//
  10 +// Unless required by applicable law or agreed to in writing, software distributed
  11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13 +// specific language governing permissions and limitations under the License.
  14 +
  15 +#ifndef RAPIDJSON_ALLOCATORS_H_
  16 +#define RAPIDJSON_ALLOCATORS_H_
  17 +
  18 +#include "rapidjson.h"
  19 +
  20 +RAPIDJSON_NAMESPACE_BEGIN
  21 +
  22 +///////////////////////////////////////////////////////////////////////////////
  23 +// Allocator
  24 +
  25 +/*! \class rapidjson::Allocator
  26 + \brief Concept for allocating, resizing and freeing memory block.
  27 +
  28 + Note that Malloc() and Realloc() are non-static but Free() is static.
  29 +
  30 + So if an allocator need to support Free(), it needs to put its pointer in
  31 + the header of memory block.
  32 +
  33 +\code
  34 +concept Allocator {
  35 + static const bool kNeedFree; //!< Whether this allocator needs to call Free().
  36 +
  37 + // Allocate a memory block.
  38 + // \param size of the memory block in bytes.
  39 + // \returns pointer to the memory block.
  40 + void* Malloc(size_t size);
  41 +
  42 + // Resize a memory block.
  43 + // \param originalPtr The pointer to current memory block. Null pointer is permitted.
  44 + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
  45 + // \param newSize the new size in bytes.
  46 + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
  47 +
  48 + // Free a memory block.
  49 + // \param pointer to the memory block. Null pointer is permitted.
  50 + static void Free(void *ptr);
  51 +};
  52 +\endcode
  53 +*/
  54 +
  55 +///////////////////////////////////////////////////////////////////////////////
  56 +// CrtAllocator
  57 +
  58 +//! C-runtime library allocator.
  59 +/*! This class is just wrapper for standard C library memory routines.
  60 + \note implements Allocator concept
  61 +*/
  62 +class CrtAllocator {
  63 +public:
  64 + static const bool kNeedFree = true;
  65 + void* Malloc(size_t size) {
  66 + if (size) // behavior of malloc(0) is implementation defined.
  67 + return std::malloc(size);
  68 + else
  69 + return NULL; // standardize to returning NULL.
  70 + }
  71 + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
  72 + (void)originalSize;
  73 + if (newSize == 0) {
  74 + std::free(originalPtr);
  75 + return NULL;
  76 + }
  77 + return std::realloc(originalPtr, newSize);
  78 + }
  79 + static void Free(void *ptr) { std::free(ptr); }
  80 +};
  81 +
  82 +///////////////////////////////////////////////////////////////////////////////
  83 +// MemoryPoolAllocator
  84 +
  85 +//! Default memory allocator used by the parser and DOM.
  86 +/*! This allocator allocate memory blocks from pre-allocated memory chunks.
  87 +
  88 + It does not free memory blocks. And Realloc() only allocate new memory.
  89 +
  90 + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
  91 +
  92 + User may also supply a buffer as the first chunk.
  93 +
  94 + If the user-buffer is full then additional chunks are allocated by BaseAllocator.
  95 +
  96 + The user-buffer is not deallocated by this allocator.
  97 +
  98 + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
  99 + \note implements Allocator concept
  100 +*/
  101 +template <typename BaseAllocator = CrtAllocator>
  102 +class MemoryPoolAllocator {
  103 +public:
  104 + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
  105 +
  106 + //! Constructor with chunkSize.
  107 + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
  108 + \param baseAllocator The allocator for allocating memory chunks.
  109 + */
  110 + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
  111 + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
  112 + {
  113 + }
  114 +
  115 + //! Constructor with user-supplied buffer.
  116 + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
  117 +
  118 + The user buffer will not be deallocated when this allocator is destructed.
  119 +
  120 + \param buffer User supplied buffer.
  121 + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
  122 + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
  123 + \param baseAllocator The allocator for allocating memory chunks.
  124 + */
  125 + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
  126 + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
  127 + {
  128 + RAPIDJSON_ASSERT(buffer != 0);
  129 + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
  130 + chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
  131 + chunkHead_->capacity = size - sizeof(ChunkHeader);
  132 + chunkHead_->size = 0;
  133 + chunkHead_->next = 0;
  134 + }
  135 +
  136 + //! Destructor.
  137 + /*! This deallocates all memory chunks, excluding the user-supplied buffer.
  138 + */
  139 + ~MemoryPoolAllocator() {
  140 + Clear();
  141 + RAPIDJSON_DELETE(ownBaseAllocator_);
  142 + }
  143 +
  144 + //! Deallocates all memory chunks, excluding the user-supplied buffer.
  145 + void Clear() {
  146 + while (chunkHead_ && chunkHead_ != userBuffer_) {
  147 + ChunkHeader* next = chunkHead_->next;
  148 + baseAllocator_->Free(chunkHead_);
  149 + chunkHead_ = next;
  150 + }
  151 + if (chunkHead_ && chunkHead_ == userBuffer_)
  152 + chunkHead_->size = 0; // Clear user buffer
  153 + }
  154 +
  155 + //! Computes the total capacity of allocated memory chunks.
  156 + /*! \return total capacity in bytes.
  157 + */
  158 + size_t Capacity() const {
  159 + size_t capacity = 0;
  160 + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
  161 + capacity += c->capacity;
  162 + return capacity;
  163 + }
  164 +
  165 + //! Computes the memory blocks allocated.
  166 + /*! \return total used bytes.
  167 + */
  168 + size_t Size() const {
  169 + size_t size = 0;
  170 + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
  171 + size += c->size;
  172 + return size;
  173 + }
  174 +
  175 + //! Allocates a memory block. (concept Allocator)
  176 + void* Malloc(size_t size) {
  177 + if (!size)
  178 + return NULL;
  179 +
  180 + size = RAPIDJSON_ALIGN(size);
  181 + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
  182 + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
  183 + return NULL;
  184 +
  185 + void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
  186 + chunkHead_->size += size;
  187 + return buffer;
  188 + }
  189 +
  190 + //! Resizes a memory block (concept Allocator)
  191 + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
  192 + if (originalPtr == 0)
  193 + return Malloc(newSize);
  194 +
  195 + if (newSize == 0)
  196 + return NULL;
  197 +
  198 + originalSize = RAPIDJSON_ALIGN(originalSize);
  199 + newSize = RAPIDJSON_ALIGN(newSize);
  200 +
  201 + // Do not shrink if new size is smaller than original
  202 + if (originalSize >= newSize)
  203 + return originalPtr;
  204 +
  205 + // Simply expand it if it is the last allocation and there is sufficient space
  206 + if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
  207 + size_t increment = static_cast<size_t>(newSize - originalSize);
  208 + if (chunkHead_->size + increment <= chunkHead_->capacity) {
  209 + chunkHead_->size += increment;
  210 + return originalPtr;
  211 + }
  212 + }
  213 +
  214 + // Realloc process: allocate and copy memory, do not free original buffer.
  215 + if (void* newBuffer = Malloc(newSize)) {
  216 + if (originalSize)
  217 + std::memcpy(newBuffer, originalPtr, originalSize);
  218 + return newBuffer;
  219 + }
  220 + else
  221 + return NULL;
  222 + }
  223 +
  224 + //! Frees a memory block (concept Allocator)
  225 + static void Free(void *ptr) { (void)ptr; } // Do nothing
  226 +
  227 +private:
  228 + //! Copy constructor is not permitted.
  229 + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
  230 + //! Copy assignment operator is not permitted.
  231 + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
  232 +
  233 + //! Creates a new chunk.
  234 + /*! \param capacity Capacity of the chunk in bytes.
  235 + \return true if success.
  236 + */
  237 + bool AddChunk(size_t capacity) {
  238 + if (!baseAllocator_)
  239 + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
  240 + if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
  241 + chunk->capacity = capacity;
  242 + chunk->size = 0;
  243 + chunk->next = chunkHead_;
  244 + chunkHead_ = chunk;
  245 + return true;
  246 + }
  247 + else
  248 + return false;
  249 + }
  250 +
  251 + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
  252 +
  253 + //! Chunk header for perpending to each chunk.
  254 + /*! Chunks are stored as a singly linked list.
  255 + */
  256 + struct ChunkHeader {
  257 + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
  258 + size_t size; //!< Current size of allocated memory in bytes.
  259 + ChunkHeader *next; //!< Next chunk in the linked list.
  260 + };
  261 +
  262 + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
  263 + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
  264 + void *userBuffer_; //!< User supplied buffer.
  265 + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
  266 + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
  267 +};
  268 +
  269 +RAPIDJSON_NAMESPACE_END
  270 +
  271 +#endif // RAPIDJSON_ENCODINGS_H_
... ...
This diff could not be displayed because it is too large.
  1 +// Tencent is pleased to support the open source community by making RapidJSON available.
  2 +//
  3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
  4 +//
  5 +// Licensed under the MIT License (the "License"); you may not use this file except
  6 +// in compliance with the License. You may obtain a copy of the License at
  7 +//
  8 +// http://opensource.org/licenses/MIT
  9 +//
  10 +// Unless required by applicable law or agreed to in writing, software distributed
  11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13 +// specific language governing permissions and limitations under the License.
  14 +
  15 +#ifndef RAPIDJSON_ENCODEDSTREAM_H_
  16 +#define RAPIDJSON_ENCODEDSTREAM_H_
  17 +
  18 +#include "stream.h"
  19 +#include "memorystream.h"
  20 +
  21 +#ifdef __GNUC__
  22 +RAPIDJSON_DIAG_PUSH
  23 +RAPIDJSON_DIAG_OFF(effc++)
  24 +#endif
  25 +
  26 +#ifdef __clang__
  27 +RAPIDJSON_DIAG_PUSH
  28 +RAPIDJSON_DIAG_OFF(padded)
  29 +#endif
  30 +
  31 +RAPIDJSON_NAMESPACE_BEGIN
  32 +
  33 +//! Input byte stream wrapper with a statically bound encoding.
  34 +/*!
  35 + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
  36 + \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
  37 +*/
  38 +template <typename Encoding, typename InputByteStream>
  39 +class EncodedInputStream {
  40 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  41 +public:
  42 + typedef typename Encoding::Ch Ch;
  43 +
  44 + EncodedInputStream(InputByteStream& is) : is_(is) {
  45 + current_ = Encoding::TakeBOM(is_);
  46 + }
  47 +
  48 + Ch Peek() const { return current_; }
  49 + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
  50 + size_t Tell() const { return is_.Tell(); }
  51 +
  52 + // Not implemented
  53 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
  54 + void Flush() { RAPIDJSON_ASSERT(false); }
  55 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
  56 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
  57 +
  58 +private:
  59 + EncodedInputStream(const EncodedInputStream&);
  60 + EncodedInputStream& operator=(const EncodedInputStream&);
  61 +
  62 + InputByteStream& is_;
  63 + Ch current_;
  64 +};
  65 +
  66 +//! Specialized for UTF8 MemoryStream.
  67 +template <>
  68 +class EncodedInputStream<UTF8<>, MemoryStream> {
  69 +public:
  70 + typedef UTF8<>::Ch Ch;
  71 +
  72 + EncodedInputStream(MemoryStream& is) : is_(is) {
  73 + if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
  74 + if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
  75 + if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
  76 + }
  77 + Ch Peek() const { return is_.Peek(); }
  78 + Ch Take() { return is_.Take(); }
  79 + size_t Tell() const { return is_.Tell(); }
  80 +
  81 + // Not implemented
  82 + void Put(Ch) {}
  83 + void Flush() {}
  84 + Ch* PutBegin() { return 0; }
  85 + size_t PutEnd(Ch*) { return 0; }
  86 +
  87 + MemoryStream& is_;
  88 +
  89 +private:
  90 + EncodedInputStream(const EncodedInputStream&);
  91 + EncodedInputStream& operator=(const EncodedInputStream&);
  92 +};
  93 +
  94 +//! Output byte stream wrapper with statically bound encoding.
  95 +/*!
  96 + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
  97 + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
  98 +*/
  99 +template <typename Encoding, typename OutputByteStream>
  100 +class EncodedOutputStream {
  101 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  102 +public:
  103 + typedef typename Encoding::Ch Ch;
  104 +
  105 + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
  106 + if (putBOM)
  107 + Encoding::PutBOM(os_);
  108 + }
  109 +
  110 + void Put(Ch c) { Encoding::Put(os_, c); }
  111 + void Flush() { os_.Flush(); }
  112 +
  113 + // Not implemented
  114 + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
  115 + Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
  116 + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
  117 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
  118 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
  119 +
  120 +private:
  121 + EncodedOutputStream(const EncodedOutputStream&);
  122 + EncodedOutputStream& operator=(const EncodedOutputStream&);
  123 +
  124 + OutputByteStream& os_;
  125 +};
  126 +
  127 +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
  128 +
  129 +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
  130 +/*!
  131 + \tparam CharType Type of character for reading.
  132 + \tparam InputByteStream type of input byte stream to be wrapped.
  133 +*/
  134 +template <typename CharType, typename InputByteStream>
  135 +class AutoUTFInputStream {
  136 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  137 +public:
  138 + typedef CharType Ch;
  139 +
  140 + //! Constructor.
  141 + /*!
  142 + \param is input stream to be wrapped.
  143 + \param type UTF encoding type if it is not detected from the stream.
  144 + */
  145 + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
  146 + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
  147 + DetectType();
  148 + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
  149 + takeFunc_ = f[type_];
  150 + current_ = takeFunc_(*is_);
  151 + }
  152 +
  153 + UTFType GetType() const { return type_; }
  154 + bool HasBOM() const { return hasBOM_; }
  155 +
  156 + Ch Peek() const { return current_; }
  157 + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
  158 + size_t Tell() const { return is_->Tell(); }
  159 +
  160 + // Not implemented
  161 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
  162 + void Flush() { RAPIDJSON_ASSERT(false); }
  163 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
  164 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
  165 +
  166 +private:
  167 + AutoUTFInputStream(const AutoUTFInputStream&);
  168 + AutoUTFInputStream& operator=(const AutoUTFInputStream&);
  169 +
  170 + // Detect encoding type with BOM or RFC 4627
  171 + void DetectType() {
  172 + // BOM (Byte Order Mark):
  173 + // 00 00 FE FF UTF-32BE
  174 + // FF FE 00 00 UTF-32LE
  175 + // FE FF UTF-16BE
  176 + // FF FE UTF-16LE
  177 + // EF BB BF UTF-8
  178 +
  179 + const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
  180 + if (!c)
  181 + return;
  182 +
  183 + unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
  184 + hasBOM_ = false;
  185 + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
  186 + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
  187 + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
  188 + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
  189 + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
  190 +
  191 + // RFC 4627: Section 3
  192 + // "Since the first two characters of a JSON text will always be ASCII
  193 + // characters [RFC0020], it is possible to determine whether an octet
  194 + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
  195 + // at the pattern of nulls in the first four octets."
  196 + // 00 00 00 xx UTF-32BE
  197 + // 00 xx 00 xx UTF-16BE
  198 + // xx 00 00 00 UTF-32LE
  199 + // xx 00 xx 00 UTF-16LE
  200 + // xx xx xx xx UTF-8
  201 +
  202 + if (!hasBOM_) {
  203 + unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
  204 + switch (pattern) {
  205 + case 0x08: type_ = kUTF32BE; break;
  206 + case 0x0A: type_ = kUTF16BE; break;
  207 + case 0x01: type_ = kUTF32LE; break;
  208 + case 0x05: type_ = kUTF16LE; break;
  209 + case 0x0F: type_ = kUTF8; break;
  210 + default: break; // Use type defined by user.
  211 + }
  212 + }
  213 +
  214 + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
  215 + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
  216 + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
  217 + }
  218 +
  219 + typedef Ch (*TakeFunc)(InputByteStream& is);
  220 + InputByteStream* is_;
  221 + UTFType type_;
  222 + Ch current_;
  223 + TakeFunc takeFunc_;
  224 + bool hasBOM_;
  225 +};
  226 +
  227 +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
  228 +/*!
  229 + \tparam CharType Type of character for writing.
  230 + \tparam OutputByteStream type of output byte stream to be wrapped.
  231 +*/
  232 +template <typename CharType, typename OutputByteStream>
  233 +class AutoUTFOutputStream {
  234 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  235 +public:
  236 + typedef CharType Ch;
  237 +
  238 + //! Constructor.
  239 + /*!
  240 + \param os output stream to be wrapped.
  241 + \param type UTF encoding type.
  242 + \param putBOM Whether to write BOM at the beginning of the stream.
  243 + */
  244 + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
  245 + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
  246 +
  247 + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
  248 + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
  249 + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
  250 +
  251 + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
  252 + putFunc_ = f[type_];
  253 +
  254 + if (putBOM)
  255 + PutBOM();
  256 + }
  257 +
  258 + UTFType GetType() const { return type_; }
  259 +
  260 + void Put(Ch c) { putFunc_(*os_, c); }
  261 + void Flush() { os_->Flush(); }
  262 +
  263 + // Not implemented
  264 + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
  265 + Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
  266 + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
  267 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
  268 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
  269 +
  270 +private:
  271 + AutoUTFOutputStream(const AutoUTFOutputStream&);
  272 + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
  273 +
  274 + void PutBOM() {
  275 + typedef void (*PutBOMFunc)(OutputByteStream&);
  276 + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
  277 + f[type_](*os_);
  278 + }
  279 +
  280 + typedef void (*PutFunc)(OutputByteStream&, Ch);
  281 +
  282 + OutputByteStream* os_;
  283 + UTFType type_;
  284 + PutFunc putFunc_;
  285 +};
  286 +
  287 +#undef RAPIDJSON_ENCODINGS_FUNC
  288 +
  289 +RAPIDJSON_NAMESPACE_END
  290 +
  291 +#ifdef __clang__
  292 +RAPIDJSON_DIAG_POP
  293 +#endif
  294 +
  295 +#ifdef __GNUC__
  296 +RAPIDJSON_DIAG_POP
  297 +#endif
  298 +
  299 +#endif // RAPIDJSON_FILESTREAM_H_
... ...
  1 +// Tencent is pleased to support the open source community by making RapidJSON available.
  2 +//
  3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
  4 +//
  5 +// Licensed under the MIT License (the "License"); you may not use this file except
  6 +// in compliance with the License. You may obtain a copy of the License at
  7 +//
  8 +// http://opensource.org/licenses/MIT
  9 +//
  10 +// Unless required by applicable law or agreed to in writing, software distributed
  11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13 +// specific language governing permissions and limitations under the License.
  14 +
  15 +#ifndef RAPIDJSON_ENCODINGS_H_
  16 +#define RAPIDJSON_ENCODINGS_H_
  17 +
  18 +#include "rapidjson.h"
  19 +
  20 +#ifdef _MSC_VER
  21 +RAPIDJSON_DIAG_PUSH
  22 +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
  23 +RAPIDJSON_DIAG_OFF(4702) // unreachable code
  24 +#elif defined(__GNUC__)
  25 +RAPIDJSON_DIAG_PUSH
  26 +RAPIDJSON_DIAG_OFF(effc++)
  27 +RAPIDJSON_DIAG_OFF(overflow)
  28 +#endif
  29 +
  30 +RAPIDJSON_NAMESPACE_BEGIN
  31 +
  32 +///////////////////////////////////////////////////////////////////////////////
  33 +// Encoding
  34 +
  35 +/*! \class rapidjson::Encoding
  36 + \brief Concept for encoding of Unicode characters.
  37 +
  38 +\code
  39 +concept Encoding {
  40 + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
  41 +
  42 + enum { supportUnicode = 1 }; // or 0 if not supporting unicode
  43 +
  44 + //! \brief Encode a Unicode codepoint to an output stream.
  45 + //! \param os Output stream.
  46 + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
  47 + template<typename OutputStream>
  48 + static void Encode(OutputStream& os, unsigned codepoint);
  49 +
  50 + //! \brief Decode a Unicode codepoint from an input stream.
  51 + //! \param is Input stream.
  52 + //! \param codepoint Output of the unicode codepoint.
  53 + //! \return true if a valid codepoint can be decoded from the stream.
  54 + template <typename InputStream>
  55 + static bool Decode(InputStream& is, unsigned* codepoint);
  56 +
  57 + //! \brief Validate one Unicode codepoint from an encoded stream.
  58 + //! \param is Input stream to obtain codepoint.
  59 + //! \param os Output for copying one codepoint.
  60 + //! \return true if it is valid.
  61 + //! \note This function just validating and copying the codepoint without actually decode it.
  62 + template <typename InputStream, typename OutputStream>
  63 + static bool Validate(InputStream& is, OutputStream& os);
  64 +
  65 + // The following functions are deal with byte streams.
  66 +
  67 + //! Take a character from input byte stream, skip BOM if exist.
  68 + template <typename InputByteStream>
  69 + static CharType TakeBOM(InputByteStream& is);
  70 +
  71 + //! Take a character from input byte stream.
  72 + template <typename InputByteStream>
  73 + static Ch Take(InputByteStream& is);
  74 +
  75 + //! Put BOM to output byte stream.
  76 + template <typename OutputByteStream>
  77 + static void PutBOM(OutputByteStream& os);
  78 +
  79 + //! Put a character to output byte stream.
  80 + template <typename OutputByteStream>
  81 + static void Put(OutputByteStream& os, Ch c);
  82 +};
  83 +\endcode
  84 +*/
  85 +
  86 +///////////////////////////////////////////////////////////////////////////////
  87 +// UTF8
  88 +
  89 +//! UTF-8 encoding.
  90 +/*! http://en.wikipedia.org/wiki/UTF-8
  91 + http://tools.ietf.org/html/rfc3629
  92 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
  93 + \note implements Encoding concept
  94 +*/
  95 +template<typename CharType = char>
  96 +struct UTF8 {
  97 + typedef CharType Ch;
  98 +
  99 + enum { supportUnicode = 1 };
  100 +
  101 + template<typename OutputStream>
  102 + static void Encode(OutputStream& os, unsigned codepoint) {
  103 + if (codepoint <= 0x7F)
  104 + os.Put(static_cast<Ch>(codepoint & 0xFF));
  105 + else if (codepoint <= 0x7FF) {
  106 + os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
  107 + os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
  108 + }
  109 + else if (codepoint <= 0xFFFF) {
  110 + os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
  111 + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
  112 + os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
  113 + }
  114 + else {
  115 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
  116 + os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
  117 + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
  118 + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
  119 + os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
  120 + }
  121 + }
  122 +
  123 + template<typename OutputStream>
  124 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
  125 + if (codepoint <= 0x7F)
  126 + PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
  127 + else if (codepoint <= 0x7FF) {
  128 + PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
  129 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
  130 + }
  131 + else if (codepoint <= 0xFFFF) {
  132 + PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
  133 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
  134 + PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
  135 + }
  136 + else {
  137 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
  138 + PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
  139 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
  140 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
  141 + PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
  142 + }
  143 + }
  144 +
  145 + template <typename InputStream>
  146 + static bool Decode(InputStream& is, unsigned* codepoint) {
  147 +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
  148 +#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
  149 +#define TAIL() COPY(); TRANS(0x70)
  150 + typename InputStream::Ch c = is.Take();
  151 + if (!(c & 0x80)) {
  152 + *codepoint = static_cast<unsigned char>(c);
  153 + return true;
  154 + }
  155 +
  156 + unsigned char type = GetRange(static_cast<unsigned char>(c));
  157 + if (type >= 32) {
  158 + *codepoint = 0;
  159 + } else {
  160 + *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
  161 + }
  162 + bool result = true;
  163 + switch (type) {
  164 + case 2: TAIL(); return result;
  165 + case 3: TAIL(); TAIL(); return result;
  166 + case 4: COPY(); TRANS(0x50); TAIL(); return result;
  167 + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
  168 + case 6: TAIL(); TAIL(); TAIL(); return result;
  169 + case 10: COPY(); TRANS(0x20); TAIL(); return result;
  170 + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
  171 + default: return false;
  172 + }
  173 +#undef COPY
  174 +#undef TRANS
  175 +#undef TAIL
  176 + }
  177 +
  178 + template <typename InputStream, typename OutputStream>
  179 + static bool Validate(InputStream& is, OutputStream& os) {
  180 +#define COPY() os.Put(c = is.Take())
  181 +#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
  182 +#define TAIL() COPY(); TRANS(0x70)
  183 + Ch c;
  184 + COPY();
  185 + if (!(c & 0x80))
  186 + return true;
  187 +
  188 + bool result = true;
  189 + switch (GetRange(static_cast<unsigned char>(c))) {
  190 + case 2: TAIL(); return result;
  191 + case 3: TAIL(); TAIL(); return result;
  192 + case 4: COPY(); TRANS(0x50); TAIL(); return result;
  193 + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
  194 + case 6: TAIL(); TAIL(); TAIL(); return result;
  195 + case 10: COPY(); TRANS(0x20); TAIL(); return result;
  196 + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
  197 + default: return false;
  198 + }
  199 +#undef COPY
  200 +#undef TRANS
  201 +#undef TAIL
  202 + }
  203 +
  204 + static unsigned char GetRange(unsigned char c) {
  205 + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
  206 + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
  207 + static const unsigned char type[] = {
  208 + 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,
  209 + 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,
  210 + 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,
  211 + 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,
  212 + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
  213 + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
  214 + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  215 + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  216 + 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,
  217 + 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,
  218 + };
  219 + return type[c];
  220 + }
  221 +
  222 + template <typename InputByteStream>
  223 + static CharType TakeBOM(InputByteStream& is) {
  224 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  225 + typename InputByteStream::Ch c = Take(is);
  226 + if (static_cast<unsigned char>(c) != 0xEFu) return c;
  227 + c = is.Take();
  228 + if (static_cast<unsigned char>(c) != 0xBBu) return c;
  229 + c = is.Take();
  230 + if (static_cast<unsigned char>(c) != 0xBFu) return c;
  231 + c = is.Take();
  232 + return c;
  233 + }
  234 +
  235 + template <typename InputByteStream>
  236 + static Ch Take(InputByteStream& is) {
  237 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  238 + return static_cast<Ch>(is.Take());
  239 + }
  240 +
  241 + template <typename OutputByteStream>
  242 + static void PutBOM(OutputByteStream& os) {
  243 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  244 + os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
  245 + os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
  246 + os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
  247 + }
  248 +
  249 + template <typename OutputByteStream>
  250 + static void Put(OutputByteStream& os, Ch c) {
  251 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  252 + os.Put(static_cast<typename OutputByteStream::Ch>(c));
  253 + }
  254 +};
  255 +
  256 +///////////////////////////////////////////////////////////////////////////////
  257 +// UTF16
  258 +
  259 +//! UTF-16 encoding.
  260 +/*! http://en.wikipedia.org/wiki/UTF-16
  261 + http://tools.ietf.org/html/rfc2781
  262 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
  263 + \note implements Encoding concept
  264 +
  265 + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
  266 + For streaming, use UTF16LE and UTF16BE, which handle endianness.
  267 +*/
  268 +template<typename CharType = wchar_t>
  269 +struct UTF16 {
  270 + typedef CharType Ch;
  271 + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
  272 +
  273 + enum { supportUnicode = 1 };
  274 +
  275 + template<typename OutputStream>
  276 + static void Encode(OutputStream& os, unsigned codepoint) {
  277 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
  278 + if (codepoint <= 0xFFFF) {
  279 + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
  280 + os.Put(static_cast<typename OutputStream::Ch>(codepoint));
  281 + }
  282 + else {
  283 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
  284 + unsigned v = codepoint - 0x10000;
  285 + os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
  286 + os.Put((v & 0x3FF) | 0xDC00);
  287 + }
  288 + }
  289 +
  290 +
  291 + template<typename OutputStream>
  292 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
  293 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
  294 + if (codepoint <= 0xFFFF) {
  295 + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
  296 + PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
  297 + }
  298 + else {
  299 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
  300 + unsigned v = codepoint - 0x10000;
  301 + PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
  302 + PutUnsafe(os, (v & 0x3FF) | 0xDC00);
  303 + }
  304 + }
  305 +
  306 + template <typename InputStream>
  307 + static bool Decode(InputStream& is, unsigned* codepoint) {
  308 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
  309 + typename InputStream::Ch c = is.Take();
  310 + if (c < 0xD800 || c > 0xDFFF) {
  311 + *codepoint = static_cast<unsigned>(c);
  312 + return true;
  313 + }
  314 + else if (c <= 0xDBFF) {
  315 + *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
  316 + c = is.Take();
  317 + *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
  318 + *codepoint += 0x10000;
  319 + return c >= 0xDC00 && c <= 0xDFFF;
  320 + }
  321 + return false;
  322 + }
  323 +
  324 + template <typename InputStream, typename OutputStream>
  325 + static bool Validate(InputStream& is, OutputStream& os) {
  326 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
  327 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
  328 + typename InputStream::Ch c;
  329 + os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
  330 + if (c < 0xD800 || c > 0xDFFF)
  331 + return true;
  332 + else if (c <= 0xDBFF) {
  333 + os.Put(c = is.Take());
  334 + return c >= 0xDC00 && c <= 0xDFFF;
  335 + }
  336 + return false;
  337 + }
  338 +};
  339 +
  340 +//! UTF-16 little endian encoding.
  341 +template<typename CharType = wchar_t>
  342 +struct UTF16LE : UTF16<CharType> {
  343 + template <typename InputByteStream>
  344 + static CharType TakeBOM(InputByteStream& is) {
  345 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  346 + CharType c = Take(is);
  347 + return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
  348 + }
  349 +
  350 + template <typename InputByteStream>
  351 + static CharType Take(InputByteStream& is) {
  352 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  353 + unsigned c = static_cast<uint8_t>(is.Take());
  354 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
  355 + return static_cast<CharType>(c);
  356 + }
  357 +
  358 + template <typename OutputByteStream>
  359 + static void PutBOM(OutputByteStream& os) {
  360 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  361 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
  362 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
  363 + }
  364 +
  365 + template <typename OutputByteStream>
  366 + static void Put(OutputByteStream& os, CharType c) {
  367 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  368 + os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
  369 + os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
  370 + }
  371 +};
  372 +
  373 +//! UTF-16 big endian encoding.
  374 +template<typename CharType = wchar_t>
  375 +struct UTF16BE : UTF16<CharType> {
  376 + template <typename InputByteStream>
  377 + static CharType TakeBOM(InputByteStream& is) {
  378 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  379 + CharType c = Take(is);
  380 + return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
  381 + }
  382 +
  383 + template <typename InputByteStream>
  384 + static CharType Take(InputByteStream& is) {
  385 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
  386 + unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
  387 + c |= static_cast<uint8_t>(is.Take());
  388 + return static_cast<CharType>(c);
  389 + }
  390 +
  391 + template <typename OutputByteStream>
  392 + static void PutBOM(OutputByteStream& os) {
  393 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  394 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
  395 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
  396 + }
  397 +
  398 + template <typename OutputByteStream>
  399 + static void Put(OutputByteStream& os, CharType c) {
  400 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
  401 + os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
  402 + os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
  403 + }
  404 +};
  405 +
  406 +///////////////////////////////////////////////////////////////////////////////
  407 +// UTF32
  408 +
  409 +//! UTF-32 encoding.
  410 +/*! http://en.wikipedia.org/wiki/UTF-32
  411 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
  412 + \note implements Encoding concept
  413 +
  414 + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
  415 + For streaming, use UTF32LE and UTF32BE, which handle endianness.
  416 +*/
  417 +template<typename CharType = unsigned>
  418 +struct UTF32 {
  419 + typedef CharType Ch;
  420 + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
  421 +
  422 + enum { supportUnicode = 1 };
  423 +
  424 + template<typename OutputStream>
  425 + static void Encode(OutputStream& os, unsigned codepoint) {
  426 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
  427 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
  428 + os.Put(codepoint);
  429 + }
  430 +
  431 + template<typename OutputStream>
  432 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
  433 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
  434 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
  435 + PutUnsafe(os, codepoint);
  436 + }
  437 +
  438 + template <typename InputStream>
  439 + static bool Decode(InputStream& is, unsigned* codepoint) {
  440 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
  441 + Ch c = is.Take();
  442 + *codepoint = c;
  443 + return c <= 0x10FFFF;
  444 + }
  445 +
  446 + template <typename InputStream, typename OutputStream>
  447 + static bool Validate(InputStream& is, OutputStream& os) {
  448 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
  449 + Ch c;
  450 + os.Put(c = is.Take());
  451 + return c <= 0x10FFFF;
  452 + }
  453 +};
  454 +
  455 +//! UTF-32 little endian enocoding.
  456 +template<typename CharType = unsigned>
  457 +struct UTF32LE : UTF32<CharType> {
  458 + template <typename InputByteStream>
  459 + static CharType TakeBOM(InputByteStream& is) {
  460 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);