mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-23 09:02:29 +00:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 86fddc4d3b | |||
| 570234a6ee | |||
| 8e4bb3b0fe | |||
| 385f3d0394 | |||
| 6186ec8e12 | |||
| aa749f27dc | |||
| 598a4a6878 | |||
| 6064ca95f9 | |||
| 3448dd1a9e | |||
| dd6d1d5511 | |||
| b8dd81de66 | |||
| 31158ed03d | |||
| fa5dedec11 | |||
| 774e9becbd | |||
| 5cbd741358 | |||
| b0274e34e2 | |||
| adc740da5a | |||
| 240b066f34 | |||
| fffe59c52e | |||
| 7ad2ead1be | |||
| f2114c7611 | |||
| cb009aba7c | |||
| 9df7e9e1f3 | |||
| 7f6997baf4 | |||
| 6edb4c2b37 | |||
| 910ee66fce | |||
| f662141f86 | |||
| c5498c66fa | |||
| 3df5b6da57 | |||
| e47ad72b1c | |||
| f3af295f34 | |||
| 9eb41c7b0d | |||
| ee8b950df1 | |||
| 29b4498534 | |||
| 91ecf759e3 | |||
| 5a7a2b0aef | |||
| 45b83feb99 | |||
| f4621bd5c0 | |||
| 06f7f6b483 | |||
| 509babc2d1 | |||
| ca86763c2b | |||
| a602640188 | |||
| b9e6a1f5eb | |||
| 119e0bb0ac | |||
| 34913c2046 | |||
| c6d8b7e337 | |||
| 2ed960d733 | |||
| dd88d0096b | |||
| 7c3cfd43de | |||
| 4e1fcfb7e5 | |||
| 379ecc655c | |||
| ae30d8b257 | |||
| 40b555a55b | |||
| 002f5e3bcc | |||
| 780789fbad | |||
| 927580b983 | |||
| 7359eb01d4 | |||
| da6d7538b0 | |||
| 69e90aac0a | |||
| 2dff51a4db | |||
| e442d682cd | |||
| 0e0638f11d | |||
| 5ad7b84415 | |||
| e0bc0e2e5c | |||
| 4109b0b88d | |||
| 80892f1d4d | |||
| 9e3e8dbfa6 | |||
| 74f07f8e19 | |||
| f866fd59d9 | |||
| d6da569fc6 | |||
| 7ec0994433 |
+7
-12
@@ -257,7 +257,7 @@ OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF)
|
||||
OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF)
|
||||
OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON)
|
||||
OPTION(EQEMU_BUILD_LUA "Build Lua parser." ON)
|
||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON)
|
||||
OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Inport/Export Data Programs." ON)
|
||||
|
||||
#C++11 stuff
|
||||
IF(NOT MSVC)
|
||||
@@ -265,6 +265,8 @@ IF(NOT MSVC)
|
||||
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reserved-user-defined-literal")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-D__STDC_CONSTANT_MACROS)
|
||||
ENDIF(NOT MSVC)
|
||||
|
||||
#Various definitions
|
||||
@@ -323,8 +325,7 @@ IF(EQEMU_BUILD_LUA)
|
||||
SET(BOOST_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/boost")
|
||||
|
||||
FIND_PACKAGE(Boost REQUIRED)
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/luabind")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${LUA_INCLUDE_DIR}" "${Boost_INCLUDE_DIRS}" "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luabind")
|
||||
|
||||
OPTION(EQEMU_SANITIZE_LUA_LIBS "Sanitize Lua Libraries (Remove OS and IO standard libraries from being able to run)." ON)
|
||||
IF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
@@ -332,18 +333,10 @@ IF(EQEMU_BUILD_LUA)
|
||||
ENDIF(EQEMU_SANITIZE_LUA_LIBS)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/src")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format")
|
||||
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm" "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libwebsockets" "${CMAKE_CURRENT_SOURCE_DIR}/common/rapidjson")
|
||||
|
||||
IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
ADD_SUBDIRECTORY(libs)
|
||||
ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS)
|
||||
IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(shared_memory)
|
||||
@@ -352,6 +345,8 @@ IF(EQEMU_BUILD_SERVER)
|
||||
ADD_SUBDIRECTORY(ucs)
|
||||
ADD_SUBDIRECTORY(queryserv)
|
||||
ADD_SUBDIRECTORY(eqlaunch)
|
||||
ADD_SUBDIRECTORY(dependencies)
|
||||
ADD_SUBDIRECTORY(web_interface)
|
||||
ENDIF(EQEMU_BUILD_SERVER)
|
||||
IF(EQEMU_BUILD_LOGIN)
|
||||
ADD_SUBDIRECTORY(loginserver)
|
||||
|
||||
@@ -1,59 +1,54 @@
|
||||
# EQEmulator Core Server
|
||||
|Travis CI (Linux)|Appveyor (Windows) |
|
||||
|:---:|:---:|
|
||||
|[](https://travis-ci.org/EQEmu/Server) |[](https://ci.appveyor.com/project/KimLS/server/branch/master) |
|
||||
EQEmu
|
||||
===
|
||||
|
||||
***
|
||||
[](https://travis-ci.org/EQEmu/Server)
|
||||
[](https://ci.appveyor.com/project/KimLS/server/branch/master)
|
||||
|
||||
**EQEmulator is a custom completely from-scratch open source server implementation for EverQuest built mostly on C++**
|
||||
* MySQL/MariaDB is used as the database engine (over 200+ tables)
|
||||
* Perl and LUA are both supported scripting languages for NPC/Player/Quest oriented events
|
||||
* Open source database (Project EQ) has content up to expansion GoD (included in server installs)
|
||||
* Game server environments and databases can be heavily customized to create all new experiences
|
||||
* Hundreds of Quests/events created and maintained by Project EQ
|
||||
Overview
|
||||
---
|
||||
|
||||
## Server Installs
|
||||
||Windows|Linux|
|
||||
|:---:|:---:|:---:|
|
||||
|**Install Count**|||
|
||||
### > Windows
|
||||
* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
|
||||
* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
|
||||
EQEmu is a custom server implementation for EverQuest
|
||||
|
||||
### > Debian/Ubuntu
|
||||
Dependencies
|
||||
---
|
||||
|
||||
> wget --no-check-certificate https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh -O install.sh && chmod 755 install.sh && ./install.sh
|
||||
For Windows: http://eqemu.github.io
|
||||
|
||||
### > CentOS/Fedora
|
||||
Login Server dependencies for Windows/Linux/OSX: http://eqemu.github.io
|
||||
|
||||
> curl -O https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/linux_installer/install.sh install.sh && chmod 755 install.sh && ./install.sh
|
||||
For Debian based distros (adjust to your local flavor):
|
||||
|
||||
## Supported Clients
|
||||
- libmysqlclient-dev
|
||||
- libperl-dev
|
||||
- liblua5.1-0-dev (5.2 should work as well)
|
||||
- libboost-dev
|
||||
|
||||
|Titanium Edition|Secrets of Faydwer|Seeds of Destruction|Underfoot|Rain of Fear|
|
||||
|:---:|:---:|:---:|:---:|:---:|
|
||||
|<img src="http://i.imgur.com/hrwDxoM.jpg" height="150">|<img src="http://i.imgur.com/cRDW5tn.png" height="150">|<img src="http://i.imgur.com/V48kuVn.jpg" height="150">|<img src="http://i.imgur.com/IJQ0XMa.jpg" height="150">|<img src="http://i.imgur.com/OMpHkKa.png" height="100">|
|
||||
Further instructions on building the source can be found on the
|
||||
[wiki](http://wiki.eqemulator.org/i?M=Wiki).
|
||||
|
||||
## Bug Reports <img src="http://i.imgur.com/daf1Vjw.png" height="20">
|
||||
* Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
|
||||
Bug reports
|
||||
---
|
||||
|
||||
Please use the [issue tracker](https://github.com/EQEmu/Server/issues) provided by GitHub to send us bug
|
||||
reports or feature requests.
|
||||
* The [EQEmu Forums](http://www.eqemulator.org/forums/) are also a place to submit and get help with bugs.
|
||||
|
||||
## Contributions <img src="http://image.flaticon.com/icons/png/512/25/25231.png" width="20">
|
||||
The [EQEmu Forums](http://www.eqemulator.org/forums/) also have forums to submit
|
||||
bugs/get help with bugs.
|
||||
|
||||
* The preferred way to contribute is to fork the repo and submit a pull request on
|
||||
Contributions
|
||||
---
|
||||
|
||||
The preferred way to contribute is to fork the repo and submit a pull request on
|
||||
GitHub. If you need help with your changes, you can always post on the forums or
|
||||
try Discord. You can also post unified diffs (`git diff` should do the trick) on the
|
||||
try IRC. You can also post unified diffs (`git diff` should do the trick) on the
|
||||
[Server Code Submissions](http://www.eqemulator.org/forums/forumdisplay.php?f=669)
|
||||
forum, although pull requests will be much quicker and easier on all parties.
|
||||
|
||||
## Contact <img src="http://gamerescape.com/wp-content/uploads/2015/06/discord.png" height="20">
|
||||
|
||||
- Discord Channel: https://discord.gg/QHsm7CD
|
||||
- **User Discord Channel**: `#general`
|
||||
- **Developer Discord Channel**: `#eqemucoders`
|
||||
|
||||
Resources
|
||||
Contact
|
||||
---
|
||||
- **User IRC Channel**: `#eqemu` on `irc.eqemulator.net`
|
||||
- **Developer IRC Channel**: `#eqemucoders` on `irc.eqemulator.net`
|
||||
|
||||
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
||||
- [EQEmulator Wiki](http://wiki.eqemulator.org/i?M=Wiki)
|
||||
|
||||
|
||||
@@ -1,22 +1,5 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 09/03/2016 ==
|
||||
Uleat: Changed 'Bind Wound' behavior to match the best references that I could find for post-2004 era.
|
||||
Note: If you wish to retain the old method, source in the optional '2016_09_03_old_bind_wound_rule.sql' script file.
|
||||
|
||||
== 08/27/2016 ==
|
||||
Kinglykrab: Added optional IP-based account exemptions.
|
||||
- To use this system simply set World:EnableIPExemptions to true and create an entry in the ip_exemptions table.
|
||||
- Example: exemption_ip of IP 192.168.1.4 in ip_exemptions with exemption_amount of 1 will allow only 1 account to login from IP 192.168.1.4.
|
||||
- Note: If there is no exemption, the amount of accounts logged in from a singular IP will default to World:MaxClientsPerIP
|
||||
|
||||
== 08/23/2016 ==
|
||||
noudess: Force mobs on a depop @ end pathgrid to still do this on idle zones.
|
||||
This makes them be more random after a zone is idle, rather than always showing
|
||||
up at start point when 1st person logs into an idle zone. Much more like live.
|
||||
I dion't think this will be much of a performance problem. Once they path and
|
||||
depop, no mkore cpu usage.
|
||||
|
||||
== 08/14/2016 ==
|
||||
mackal: Implement Linked Spell Reuse Timers
|
||||
- For whatever reason this is a bit unfriendly, but that's how it is on live.
|
||||
|
||||
@@ -9,7 +9,7 @@ SET(export_headers
|
||||
|
||||
ADD_EXECUTABLE(export_client_files ${export_sources} ${export_headers})
|
||||
|
||||
INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
INSTALL(TARGETS export_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
TARGET_LINK_LIBRARIES(export_client_files common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
@@ -30,6 +30,7 @@ IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(export_client_files "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(export_client_files "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
@@ -9,7 +9,7 @@ SET(import_headers
|
||||
|
||||
ADD_EXECUTABLE(import_client_files ${import_sources} ${import_headers})
|
||||
|
||||
INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
INSTALL(TARGETS import_client_files RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
TARGET_LINK_LIBRARIES(import_client_files common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY})
|
||||
|
||||
@@ -30,6 +30,7 @@ IF(UNIX)
|
||||
TARGET_LINK_LIBRARIES(import_client_files "rt")
|
||||
ENDIF(NOT DARWIN)
|
||||
TARGET_LINK_LIBRARIES(import_client_files "pthread")
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
ENDIF(UNIX)
|
||||
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
+5
-56
@@ -72,17 +72,11 @@ SET(common_sources
|
||||
timeoutmgr.cpp
|
||||
timer.cpp
|
||||
unix.cpp
|
||||
uuid.cpp
|
||||
worldconn.cpp
|
||||
web_interface_utils.cpp
|
||||
xml_parser.cpp
|
||||
platform.cpp
|
||||
net/crc32.cpp
|
||||
net/daybreak_connection.cpp
|
||||
net/eqstream.cpp
|
||||
net/packet.cpp
|
||||
patch/chat.cpp
|
||||
patch/login_sod.cpp
|
||||
patch/login_titanium.cpp
|
||||
patch/patch.cpp
|
||||
patches/patches.cpp
|
||||
patches/sod.cpp
|
||||
patches/sod_limits.cpp
|
||||
@@ -213,24 +207,13 @@ SET(common_headers
|
||||
timer.h
|
||||
types.h
|
||||
unix.h
|
||||
uuid.h
|
||||
useperl.h
|
||||
version.h
|
||||
worldconn.h
|
||||
web_interface_utils.h
|
||||
xml_parser.h
|
||||
zone_numbers.h
|
||||
event/background_task.h
|
||||
event/event_loop.h
|
||||
event/timer.h
|
||||
net/crc32.h
|
||||
net/daybreak_connection.h
|
||||
net/daybreak_structs.h
|
||||
net/endian.h
|
||||
net/eqstream.h
|
||||
net/packet.h
|
||||
patch/chat.h
|
||||
patch/login_sod.h
|
||||
patch/login_titanium.h
|
||||
patch/patch.h
|
||||
patches/patches.h
|
||||
patches/sod.h
|
||||
# patches/sod_itemfields.h
|
||||
@@ -282,37 +265,6 @@ SET(common_headers
|
||||
StackWalker/StackWalker.h
|
||||
tinyxml/tinystr.h
|
||||
tinyxml/tinyxml.h
|
||||
util/memory_stream.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Event FILES
|
||||
event/background_task.h
|
||||
event/event_loop.h
|
||||
event/timer.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Net FILES
|
||||
net/crc32.cpp
|
||||
net/crc32.h
|
||||
net/daybreak_connection.cpp
|
||||
net/daybreak_connection.h
|
||||
net/daybreak_structs.h
|
||||
net/endian.h
|
||||
net/eqstream.h
|
||||
net/eqstream.cpp
|
||||
net/packet.cpp
|
||||
net/packet.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Patch FILES
|
||||
patch/chat.cpp
|
||||
patch/chat.h
|
||||
patch/login_sod.cpp
|
||||
patch/login_sod.h
|
||||
patch/login_titanium.cpp
|
||||
patch/login_titanium.h
|
||||
patch/patch.cpp
|
||||
patch/patch.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Patches FILES
|
||||
@@ -407,15 +359,12 @@ SOURCE_GROUP(TinyXML FILES
|
||||
tinyxml/tinyxmlparser.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Util FILES
|
||||
util/memory_stream.h
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(Patches SocketLib StackWalker TinyXML)
|
||||
|
||||
ADD_LIBRARY(common ${common_sources} ${common_headers})
|
||||
|
||||
IF(UNIX)
|
||||
ADD_DEFINITIONS(-fPIC)
|
||||
SET_SOURCE_FILES_PROPERTIES("SocketLib/Mime.cpp" PROPERTY COMPILE_FLAGS -Wno-unused-result)
|
||||
SET_SOURCE_FILES_PROPERTIES("patches/sod.cpp" "patches/sof.cpp" "patches/rof.cpp" "patches/rof2.cpp" "patches/uf.cpp" PROPERTIES COMPILE_FLAGS -O0)
|
||||
ENDIF(UNIX)
|
||||
|
||||
@@ -2136,15 +2136,3 @@ bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year
|
||||
return results.Success();
|
||||
|
||||
}
|
||||
|
||||
int Database::GetIPExemption(std::string account_ip) {
|
||||
std::string query = StringFormat("SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '%s'", account_ip.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
return RuleI(World, MaxClientsPerIP);
|
||||
}
|
||||
+11
-2
@@ -79,6 +79,17 @@ struct VarCache_Struct {
|
||||
|
||||
class PTimerList;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#if _MSC_VER > 1700 // greater than 2012 (2013+)
|
||||
# define _ISNAN_(a) std::isnan(a)
|
||||
#else
|
||||
# include <float.h>
|
||||
# define _ISNAN_(a) _isnan(a)
|
||||
#endif
|
||||
#else
|
||||
# define _ISNAN_(a) std::isnan(a)
|
||||
#endif
|
||||
|
||||
class Database : public DBcore {
|
||||
public:
|
||||
Database();
|
||||
@@ -175,8 +186,6 @@ public:
|
||||
|
||||
void GetAccountFromID(uint32 id, char* oAccountName, int16* oStatus);
|
||||
void SetAgreementFlag(uint32 acctid);
|
||||
|
||||
int GetIPExemption(std::string account_ip);
|
||||
|
||||
|
||||
/* Groups */
|
||||
|
||||
@@ -472,18 +472,31 @@ bool Database::CheckDatabaseConversions() {
|
||||
CheckDatabaseConvertPPDeblob();
|
||||
CheckDatabaseConvertCorpseDeblob();
|
||||
|
||||
/* Fetch EQEmu Server script */
|
||||
if (!std::ifstream("eqemu_server.pl")){
|
||||
/* Fetch Automatic Upgrade Script */
|
||||
if (!std::ifstream("eqemu_update.pl")){
|
||||
std::cout << "Pulling down automatic database upgrade script..." << std::endl;
|
||||
#ifdef _WIN32
|
||||
system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl'); if ($response->is_success){ open(FILE, '> eqemu_server.pl'); print FILE $response->decoded_content; close(FILE); }\"");
|
||||
system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl'); if ($response->is_success){ open(FILE, '> eqemu_update.pl'); print FILE $response->decoded_content; close(FILE); }\"");
|
||||
#else
|
||||
system("wget --no-check-certificate -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl");
|
||||
system("wget --no-check-certificate -O eqemu_update.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Run EQEmu Server script (Checks for database updates) */
|
||||
system("perl eqemu_server.pl ran_from_world");
|
||||
/*
|
||||
Automatic (Database) Upgrade Script
|
||||
Script: eqemu_update.pl V 1 - the number that world passes to the script will
|
||||
force the script to check for a newer version to update itself with
|
||||
eqemu_update.pl ran_from_world - won't bring up a menu if your database versions match
|
||||
eqemu_update.pl - ran standalone will bring up a menu prompt
|
||||
*/
|
||||
|
||||
/* Check for a new version of this script, the arg passed
|
||||
would have to be higher than the copy they have downloaded
|
||||
locally and they will re fetch */
|
||||
system("perl eqemu_update.pl V 14");
|
||||
|
||||
/* Run Automatic Database Upgrade Script */
|
||||
system("perl eqemu_update.pl ran_from_world");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1327,7 +1340,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
if (rquery != ""){ results = QueryDatabase(rquery); }
|
||||
|
||||
/* Run Bind Home Convert */
|
||||
if (pp->binds[4].zoneId < 999 && !std::isnan(pp->binds[4].x) && !std::isnan(pp->binds[4].y) && !std::isnan(pp->binds[4].z) && !std::isnan(pp->binds[4].heading)) {
|
||||
if (pp->binds[4].zoneId < 999 && !_ISNAN_(pp->binds[4].x) && !_ISNAN_(pp->binds[4].y) && !_ISNAN_(pp->binds[4].z) && !_ISNAN_(pp->binds[4].heading)) {
|
||||
rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, 1)",
|
||||
character_id, pp->binds[4].zoneId, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading);
|
||||
@@ -1335,7 +1348,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){
|
||||
}
|
||||
|
||||
/* Run Bind Convert */
|
||||
if (pp->binds[0].zoneId < 999 && !std::isnan(pp->binds[0].x) && !std::isnan(pp->binds[0].y) && !std::isnan(pp->binds[0].z) && !std::isnan(pp->binds[0].heading)) {
|
||||
if (pp->binds[0].zoneId < 999 && !_ISNAN_(pp->binds[0].x) && !_ISNAN_(pp->binds[0].y) && !_ISNAN_(pp->binds[0].z) && !_ISNAN_(pp->binds[0].heading)) {
|
||||
rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, 0)",
|
||||
character_id, pp->binds[0].zoneId, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading);
|
||||
|
||||
@@ -363,6 +363,22 @@ bool EmuTCPConnection::LineOutQueuePush(char* line) {
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
if (strcmp(line, "**PACKETMODEWI**") == 0) {
|
||||
MSendQueue.lock();
|
||||
safe_delete_array(sendbuf);
|
||||
if (TCPMode == modeConsole)
|
||||
Send((const uchar*) "\0**PACKETMODEWI**\r", 18);
|
||||
TCPMode = modePacket;
|
||||
PacketMode = packetModeWebInterface;
|
||||
EmuTCPNetPacket_Struct* tnps = 0;
|
||||
while ((tnps = InModeQueue.pop())) {
|
||||
SendPacket(tnps);
|
||||
safe_delete_array(tnps);
|
||||
}
|
||||
MSendQueue.unlock();
|
||||
safe_delete_array(line);
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(TCPConnection::LineOutQueuePush(line));
|
||||
@@ -416,6 +432,13 @@ bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) {
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size);
|
||||
}
|
||||
else if (PacketMode == packetModeWebInterface) {
|
||||
safe_delete_array(sendbuf);
|
||||
sendbuf_size = 18;
|
||||
sendbuf_used = sendbuf_size;
|
||||
sendbuf = new uchar[sendbuf_size];
|
||||
memcpy(sendbuf, "\0**PACKETMODEWI**\r", sendbuf_size);
|
||||
}
|
||||
else {
|
||||
//default: packetModeZone
|
||||
safe_delete_array(sendbuf);
|
||||
|
||||
@@ -31,7 +31,7 @@ class ServerPacket;
|
||||
class EmuTCPConnection : public TCPConnection {
|
||||
public:
|
||||
enum eTCPMode { modeConsole, modeTransition, modePacket };
|
||||
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ };
|
||||
enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ, packetModeWebInterface };
|
||||
|
||||
EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false);
|
||||
EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
|
||||
|
||||
+13
-14
@@ -1934,7 +1934,8 @@ struct Merchant_Sell_Struct {
|
||||
/*004*/ uint32 playerid; // Player's entity id
|
||||
/*008*/ uint32 itemslot;
|
||||
uint32 unknown12;
|
||||
/*016*/ uint32 quantity;
|
||||
/*016*/ uint8 quantity; // Already sold
|
||||
/*017*/ uint8 Unknown016[3];
|
||||
/*020*/ uint32 price;
|
||||
};
|
||||
struct Merchant_Purchase_Struct {
|
||||
@@ -2508,25 +2509,23 @@ struct BookRequest_Struct {
|
||||
*/
|
||||
struct Object_Struct {
|
||||
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
|
||||
/*08*/ float size; //
|
||||
/*08*/ uint16 size; //
|
||||
/*10*/ uint16 solidtype; //
|
||||
/*12*/ uint32 drop_id; // Unique object id for zone
|
||||
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
|
||||
/*18*/ uint16 zone_instance; //
|
||||
/*20*/ uint32 unknown020; //
|
||||
/*24*/ uint32 unknown024; //
|
||||
/*28*/ float tilt_x;
|
||||
/*32*/ float tilt_y;
|
||||
/*36*/ float heading; // heading
|
||||
/*40*/ float z; // z coord
|
||||
/*44*/ float x; // x coord
|
||||
/*76*/ float y; // y coord
|
||||
/*80*/ char object_name[32]; // Name of object, usually something like IT63_ACTORDEF
|
||||
/*84*/ uint32 unknown076; //
|
||||
/*88*/ uint32 object_type; // Type of object, not directly translated to OP_OpenObject
|
||||
/*92*/ uint32 unknown084; //set to 0xFF
|
||||
uint32 spawn_id; // Spawn Id of client interacting with object
|
||||
|
||||
/*28*/ float heading; // heading
|
||||
/*32*/ float z; // z coord
|
||||
/*36*/ float x; // x coord
|
||||
/*40*/ float y; // y coord
|
||||
/*44*/ char object_name[32]; // Name of object, usually something like IT63_ACTORDEF
|
||||
/*76*/ uint32 unknown076; //
|
||||
/*80*/ uint32 object_type; // Type of object, not directly translated to OP_OpenObject
|
||||
/*84*/ uint32 unknown084; //set to 0xFF
|
||||
/*88*/ uint32 spawn_id; // Spawn Id of client interacting with object
|
||||
/*92*/
|
||||
};
|
||||
// 01 = generic drop, 02 = armor, 19 = weapon
|
||||
//[13:40] and 0xff seems to be indicative of the tradeskill/openable items that end up returning the old style item type in the OP_OpenObject
|
||||
|
||||
+30
-2
@@ -29,7 +29,7 @@ EQEmuConfig *EQEmuConfig::_config = nullptr;
|
||||
void EQEmuConfig::do_world(TiXmlElement *ele)
|
||||
{
|
||||
const char *text;
|
||||
TiXmlElement * sub_ele;;
|
||||
TiXmlElement * sub_ele;
|
||||
text = ParseTextBlock(ele, "shortname");
|
||||
if (text) {
|
||||
ShortName = text;
|
||||
@@ -220,6 +220,29 @@ void EQEmuConfig::do_qsdatabase(TiXmlElement *ele)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EQEmuConfig::do_web_interface(TiXmlElement *ele) {
|
||||
const char *text;
|
||||
|
||||
text = ParseTextBlock(ele, "port", true);
|
||||
if (text)
|
||||
WebInterfacePort = atoi(text);
|
||||
|
||||
text = ParseTextBlock(ele, "cert", true);
|
||||
if (text)
|
||||
WebInterfaceCert = text;
|
||||
|
||||
text = ParseTextBlock(ele, "priv_key", true);
|
||||
if (text)
|
||||
WebInterfacePrivKey = text;
|
||||
|
||||
TiXmlElement *sub_ele = ele->FirstChildElement("ssl");
|
||||
if (sub_ele != nullptr) {
|
||||
WebInterfaceUseSSL = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EQEmuConfig::do_zones(TiXmlElement *ele)
|
||||
{
|
||||
const char *text;
|
||||
@@ -486,6 +509,8 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const
|
||||
return ("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EQEmuConfig::Dump() const
|
||||
{
|
||||
std::cout << "ShortName = " << ShortName << std::endl;
|
||||
@@ -516,6 +541,10 @@ void EQEmuConfig::Dump() const
|
||||
std::cout << "QSDatabasePassword = " << QSDatabasePassword << std::endl;
|
||||
std::cout << "QSDatabaseDB = " << QSDatabaseDB << std::endl;
|
||||
std::cout << "QSDatabasePort = " << QSDatabasePort << std::endl;
|
||||
std::cout << "WebInterfacePort = " << WebInterfacePort << std::endl;
|
||||
std::cout << "WebInterfaceUseSSL = " << WebInterfaceUseSSL << std::endl;
|
||||
std::cout << "WebInterfaceCert = " << WebInterfaceCert << std::endl;
|
||||
std::cout << "WebInterfacePrivKey = " << WebInterfacePrivKey << std::endl;
|
||||
std::cout << "SpellsFile = " << SpellsFile << std::endl;
|
||||
std::cout << "OpCodesFile = " << OpCodesFile << std::endl;
|
||||
std::cout << "PluginPlFile = " << PluginPlFile << std::endl;
|
||||
@@ -529,6 +558,5 @@ void EQEmuConfig::Dump() const
|
||||
std::cout << "ZonePortLow = " << ZonePortLow << std::endl;
|
||||
std::cout << "ZonePortHigh = " << ZonePortHigh << std::endl;
|
||||
std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl;
|
||||
// std::cout << "DynamicCount = " << DynamicCount << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,12 @@ class EQEmuConfig : public XMLParser
|
||||
std::string QSDatabaseDB;
|
||||
uint16 QSDatabasePort;
|
||||
|
||||
// from <web_interface>
|
||||
uint16 WebInterfacePort;
|
||||
bool WebInterfaceUseSSL;
|
||||
std::string WebInterfaceCert;
|
||||
std::string WebInterfacePrivKey;
|
||||
|
||||
// From <files/>
|
||||
std::string SpellsFile;
|
||||
std::string OpCodesFile;
|
||||
@@ -220,7 +226,7 @@ class EQEmuConfig : public XMLParser
|
||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(), "server");
|
||||
}
|
||||
|
||||
void Dump() const;
|
||||
void Dump() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,6 +4,7 @@ ELEMENT(mailserver)
|
||||
ELEMENT(zones)
|
||||
ELEMENT(database)
|
||||
ELEMENT(qsdatabase)
|
||||
ELEMENT(web_interface)
|
||||
ELEMENT(files)
|
||||
ELEMENT(directories)
|
||||
ELEMENT(launcher)
|
||||
|
||||
+2
-11
@@ -19,11 +19,11 @@
|
||||
#ifndef EQEMU_LOGSYS_H
|
||||
#define EQEMU_LOGSYS_H
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Logs {
|
||||
@@ -83,7 +83,6 @@ namespace Logs {
|
||||
Server_Client_Packet_With_Dump,
|
||||
Client_Server_Packet_With_Dump,
|
||||
Login_Server,
|
||||
Client_Login,
|
||||
MaxCategoryID /* Don't Remove this*/
|
||||
};
|
||||
|
||||
@@ -132,8 +131,7 @@ namespace Logs {
|
||||
"Packet :: Client -> Server Unhandled",
|
||||
"Packet :: Server -> Client (Dump)",
|
||||
"Packet :: Client -> Server (Dump)",
|
||||
"Login Server",
|
||||
"Client Login"
|
||||
"Login Server"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -158,13 +156,6 @@ public:
|
||||
void SetCurrentTimeStamp(char* time_stamp); /* Used in file logs to prepend a timestamp entry for logs */
|
||||
void StartFileLogs(const std::string &log_name = ""); /* Used to declare the processes file log and to keep it open for later use */
|
||||
|
||||
template <typename... Args>
|
||||
void OutF(Logs::DebugLevel debug_level, uint16 log_category, const char *fmt, const Args&... args)
|
||||
{
|
||||
std::string log_str = fmt::format(fmt, args...);
|
||||
Out(debug_level, log_category, log_str);
|
||||
}
|
||||
|
||||
/*
|
||||
LogSettings Struct
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "event_loop.h"
|
||||
|
||||
namespace EQ {
|
||||
class BackgroundTask
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void)> BackgroundTaskFunction;
|
||||
struct BackgroundTaskBaton
|
||||
{
|
||||
BackgroundTaskFunction fn;
|
||||
BackgroundTaskFunction on_finish;
|
||||
};
|
||||
|
||||
BackgroundTask(BackgroundTaskFunction fn, BackgroundTaskFunction on_finish) {
|
||||
uv_work_t *m_work = new uv_work_t;
|
||||
memset(m_work, 0, sizeof(uv_work_t));
|
||||
BackgroundTaskBaton *baton = new BackgroundTaskBaton();
|
||||
baton->fn = fn;
|
||||
baton->on_finish = on_finish;
|
||||
|
||||
m_work->data = baton;
|
||||
uv_queue_work(EventLoop::Get().Handle(), m_work, [](uv_work_t* req) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->fn();
|
||||
}, [](uv_work_t* req, int status) {
|
||||
BackgroundTaskBaton *baton = (BackgroundTaskBaton*)req->data;
|
||||
baton->on_finish();
|
||||
delete baton;
|
||||
delete req;
|
||||
});
|
||||
}
|
||||
|
||||
~BackgroundTask() {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <uv.h>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
class EventLoop
|
||||
{
|
||||
public:
|
||||
static EventLoop &Get() {
|
||||
static EventLoop inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
~EventLoop() {
|
||||
uv_loop_close(&m_loop);
|
||||
}
|
||||
|
||||
void Process() {
|
||||
uv_run(&m_loop, UV_RUN_NOWAIT);
|
||||
}
|
||||
|
||||
uv_loop_t* Handle() { return &m_loop; }
|
||||
|
||||
private:
|
||||
EventLoop() {
|
||||
memset(&m_loop, 0, sizeof(uv_loop_t));
|
||||
uv_loop_init(&m_loop);
|
||||
}
|
||||
|
||||
EventLoop(const EventLoop&);
|
||||
EventLoop& operator=(const EventLoop&);
|
||||
|
||||
uv_loop_t m_loop;
|
||||
};
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include "event_loop.h"
|
||||
|
||||
namespace EQ {
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(uint64_t duration_ms, bool repeats, std::function<void(void)> cb)
|
||||
{
|
||||
memset(&m_timer, 0, sizeof(uv_timer_t));
|
||||
m_cb = cb;
|
||||
m_duration_ms = duration_ms;
|
||||
m_repeats = repeats;
|
||||
m_attached = nullptr;
|
||||
Attach(EventLoop::Get().Handle());
|
||||
}
|
||||
|
||||
~Timer()
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
private:
|
||||
void Execute() {
|
||||
m_cb();
|
||||
}
|
||||
|
||||
virtual void Attach(uv_loop_t *loop) {
|
||||
if (!m_attached) {
|
||||
uv_timer_init(loop, &m_timer);
|
||||
m_timer.data = this;
|
||||
|
||||
if (m_repeats) {
|
||||
uv_timer_start(&m_timer, [](uv_timer_t *handle) {
|
||||
Timer *t = (Timer*)handle->data;
|
||||
t->Execute();
|
||||
}, m_duration_ms, m_duration_ms);
|
||||
}
|
||||
else {
|
||||
uv_timer_start(&m_timer, [](uv_timer_t *handle) {
|
||||
Timer *t = (Timer*)handle->data;
|
||||
t->Execute();
|
||||
}, m_duration_ms, 0);
|
||||
}
|
||||
|
||||
m_attached = loop;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Detach() {
|
||||
if (m_attached) {
|
||||
uv_timer_stop(&m_timer);
|
||||
m_attached = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uv_timer_t m_timer;
|
||||
std::function<void(void)> m_cb;
|
||||
uint64_t m_duration_ms;
|
||||
bool m_repeats;
|
||||
uv_loop_t *m_attached;
|
||||
};
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#include "crc32.h"
|
||||
#include <memory.h>
|
||||
|
||||
unsigned int CRC32EncodeTable[256] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
||||
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
||||
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
||||
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
||||
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
||||
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
||||
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
||||
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
||||
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
||||
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
||||
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
||||
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
||||
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
||||
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
||||
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
||||
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
||||
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
||||
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
||||
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
||||
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
||||
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
int EQ::Crc32(const void * data, int size)
|
||||
{
|
||||
int crc = 0xffffffff;
|
||||
auto buffer = (const uint8_t *)data;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
crc = ((crc >> 8) & 0x00FFFFFFL) ^ CRC32EncodeTable[(crc ^ *&buffer[i]) & 0x000000FFL];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
int EQ::Crc32(const void * data, int size, int key)
|
||||
{
|
||||
int crc = 0xffffffff;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
crc = ((crc >> 8) & 0x00FFFFFFL) ^ CRC32EncodeTable[(crc ^ ((key >> (i * 8)) & 0xff)) & 0x000000FFL];
|
||||
}
|
||||
|
||||
auto buffer = (const uint8_t *)data;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
crc = ((crc >> 8) & 0x00FFFFFFL) ^ CRC32EncodeTable[(crc ^ *&buffer[i]) & 0x000000FFL];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
int Crc32(const void *data, int size);
|
||||
int Crc32(const void *data, int size, int key);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,271 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../random.h"
|
||||
#include "packet.h"
|
||||
#include "daybreak_structs.h"
|
||||
#include <uv.h>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
enum DaybreakProtocolOpcode
|
||||
{
|
||||
OP_Padding = 0x00,
|
||||
OP_SessionRequest = 0x01,
|
||||
OP_SessionResponse = 0x02,
|
||||
OP_Combined = 0x03,
|
||||
OP_SessionDisconnect = 0x05,
|
||||
OP_KeepAlive = 0x06,
|
||||
OP_SessionStatRequest = 0x07,
|
||||
OP_SessionStatResponse = 0x08,
|
||||
OP_Packet = 0x09,
|
||||
OP_Packet2 = 0x0a,
|
||||
OP_Packet3 = 0x0b,
|
||||
OP_Packet4 = 0x0c,
|
||||
OP_Fragment = 0x0d,
|
||||
OP_Fragment2 = 0x0e,
|
||||
OP_Fragment3 = 0x0f,
|
||||
OP_Fragment4 = 0x10,
|
||||
OP_OutOfOrderAck = 0x11,
|
||||
OP_OutOfOrderAck2 = 0x12,
|
||||
OP_OutOfOrderAck3 = 0x13,
|
||||
OP_OutOfOrderAck4 = 0x14,
|
||||
OP_Ack = 0x15,
|
||||
OP_Ack2 = 0x16,
|
||||
OP_Ack3 = 0x17,
|
||||
OP_Ack4 = 0x18,
|
||||
OP_AppCombined = 0x19,
|
||||
OP_OutboundPing = 0x1c,
|
||||
OP_OutOfSession = 0x1d
|
||||
};
|
||||
|
||||
enum DbProtocolStatus
|
||||
{
|
||||
StatusConnecting,
|
||||
StatusConnected,
|
||||
StatusDisconnecting,
|
||||
StatusDisconnected
|
||||
};
|
||||
|
||||
enum DaybreakEncodeType
|
||||
{
|
||||
EncodeNone = 0,
|
||||
EncodeCompression = 1,
|
||||
EncodeXOR = 4,
|
||||
};
|
||||
|
||||
enum SequenceOrder
|
||||
{
|
||||
SequenceCurrent,
|
||||
SequenceFuture,
|
||||
SequencePast
|
||||
};
|
||||
|
||||
typedef std::chrono::system_clock::time_point Timestamp;
|
||||
typedef std::chrono::system_clock Clock;
|
||||
|
||||
struct DaybreakConnectionStats
|
||||
{
|
||||
DaybreakConnectionStats() {
|
||||
recv_bytes = 0;
|
||||
sent_bytes = 0;
|
||||
recv_packets = 0;
|
||||
sent_packets = 0;
|
||||
total_ping = 0;
|
||||
total_acks = 0;
|
||||
min_ping = 0xFFFFFFFFFFFFFFFFUL;
|
||||
max_ping = 0;
|
||||
created = Clock::now();
|
||||
}
|
||||
|
||||
uint64_t recv_bytes;
|
||||
uint64_t sent_bytes;
|
||||
uint64_t recv_packets;
|
||||
uint64_t sent_packets;
|
||||
uint64_t total_ping;
|
||||
uint64_t total_acks;
|
||||
uint64_t min_ping;
|
||||
uint64_t max_ping;
|
||||
Timestamp created;
|
||||
};
|
||||
|
||||
class DaybreakConnectionManager;
|
||||
class DaybreakConnection;
|
||||
class DaybreakConnection
|
||||
{
|
||||
public:
|
||||
DaybreakConnection(DaybreakConnectionManager *owner, const DaybreakConnect &connect, const std::string &endpoint, int port);
|
||||
DaybreakConnection(DaybreakConnectionManager *owner, const std::string &endpoint, int port);
|
||||
~DaybreakConnection();
|
||||
|
||||
const std::string& RemoteEndpoint() const { return m_endpoint; }
|
||||
int RemotePort() const { return m_port; }
|
||||
|
||||
void QueuePacket(Packet &p);
|
||||
void QueuePacket(Packet &p, int stream);
|
||||
void QueuePacket(Packet &p, int stream, bool reliable);
|
||||
const DaybreakConnectionStats& GetStats() const { return m_stats; }
|
||||
void ResetStats();
|
||||
size_t GetRollingPing() const { return m_rolling_ping; }
|
||||
private:
|
||||
DaybreakConnectionManager *m_owner;
|
||||
std::string m_endpoint;
|
||||
int m_port;
|
||||
uint32_t m_connect_code;
|
||||
uint32_t m_encode_key;
|
||||
uint32_t m_max_packet_size;
|
||||
uint32_t m_crc_bytes;
|
||||
DaybreakEncodeType m_encode_passes[2];
|
||||
|
||||
Timestamp m_last_send;
|
||||
Timestamp m_last_recv;
|
||||
DbProtocolStatus m_status;
|
||||
Timestamp m_hold_time;
|
||||
std::list<WritablePacket> m_buffered_packets;
|
||||
size_t m_buffered_packets_length;
|
||||
Timestamp m_last_stats;
|
||||
DaybreakConnectionStats m_stats;
|
||||
Timestamp m_last_session_stats;
|
||||
uint64_t m_last_session_stats_ping;
|
||||
size_t m_resend_delay;
|
||||
size_t m_rolling_ping;
|
||||
|
||||
struct DaybreakSentPacket
|
||||
{
|
||||
WritablePacket packet;
|
||||
Timestamp last_sent;
|
||||
Timestamp first_sent;
|
||||
size_t times_resent;
|
||||
};
|
||||
|
||||
struct DaybreakStream
|
||||
{
|
||||
DaybreakStream() {
|
||||
sequence_in = 0;
|
||||
sequence_out = 0;
|
||||
fragment_current_bytes = 0;
|
||||
fragment_total_bytes = 0;
|
||||
}
|
||||
|
||||
uint16_t sequence_in;
|
||||
uint16_t sequence_out;
|
||||
std::map<uint16_t, Packet*> packet_queue;
|
||||
|
||||
WritablePacket fragment_packet;
|
||||
uint32_t fragment_current_bytes;
|
||||
uint32_t fragment_total_bytes;
|
||||
|
||||
std::map<uint16_t, DaybreakSentPacket> sent_packets;
|
||||
};
|
||||
|
||||
DaybreakStream m_streams[4];
|
||||
std::weak_ptr<DaybreakConnection> m_self;
|
||||
|
||||
void Process();
|
||||
void ProcessPacket(Packet &p);
|
||||
void ProcessQueue();
|
||||
void RemoveFromQueue(int stream, uint16_t seq);
|
||||
void AddToQueue(int stream, uint16_t seq, const Packet &p);
|
||||
void ProcessDecodedPacket(const Packet &p);
|
||||
void ChangeStatus(DbProtocolStatus new_status);
|
||||
bool ValidateCRC(Packet &p);
|
||||
void AppendCRC(Packet &p);
|
||||
bool PacketCanBeEncoded(Packet &p) const;
|
||||
void Decode(Packet &p, size_t offset, size_t length);
|
||||
void Encode(Packet &p, size_t offset, size_t length);
|
||||
void Decompress(Packet &p, size_t offset, size_t length);
|
||||
void Compress(Packet &p, size_t offset, size_t length);
|
||||
void ProcessResend();
|
||||
void ProcessResend(int stream);
|
||||
void Ack(int stream, uint16_t seq);
|
||||
void OutOfOrderAck(int stream, uint16_t seq);
|
||||
|
||||
void SendConnect();
|
||||
void SendKeepAlive();
|
||||
void SendAck(int stream, uint16_t seq);
|
||||
void SendOutOfOrderAck(int stream, uint16_t seq);
|
||||
void SendStatSync();
|
||||
void InternalBufferedSend(Packet &p);
|
||||
void InternalSend(Packet &p);
|
||||
void InternalQueuePacket(Packet &p, int stream_id, bool reliable);
|
||||
void FlushBuffer();
|
||||
SequenceOrder CompareSequence(uint16_t expected, uint16_t actual) const;
|
||||
|
||||
friend class DaybreakConnectionManager;
|
||||
};
|
||||
|
||||
struct DaybreakConnectionManagerOptions
|
||||
{
|
||||
DaybreakConnectionManagerOptions() {
|
||||
max_connection_count = 0;
|
||||
keepalive_delay_ms = 0;
|
||||
resend_delay_ms = 1000;
|
||||
stats_delay_ms = 10000;
|
||||
connect_delay_ms = 1000;
|
||||
stale_connection_ms = 60000;
|
||||
crc_length = 2;
|
||||
max_packet_size = 512;
|
||||
encode_passes[0] = DaybreakEncodeType::EncodeNone;
|
||||
encode_passes[1] = DaybreakEncodeType::EncodeNone;
|
||||
port = 0;
|
||||
hold_size = 384;
|
||||
hold_length_ms = 50;
|
||||
}
|
||||
|
||||
size_t max_packet_size;
|
||||
size_t max_connection_count;
|
||||
size_t keepalive_delay_ms;
|
||||
size_t resend_delay_ms;
|
||||
size_t stats_delay_ms;
|
||||
size_t connect_delay_ms;
|
||||
size_t stale_connection_ms;
|
||||
size_t crc_length;
|
||||
size_t hold_size;
|
||||
size_t hold_length_ms;
|
||||
DaybreakEncodeType encode_passes[2];
|
||||
int port;
|
||||
};
|
||||
|
||||
class DaybreakConnectionManager
|
||||
{
|
||||
public:
|
||||
DaybreakConnectionManager();
|
||||
DaybreakConnectionManager(const DaybreakConnectionManagerOptions &opts);
|
||||
~DaybreakConnectionManager();
|
||||
|
||||
void Connect(const std::string &addr, int port);
|
||||
void Process();
|
||||
void ProcessResend();
|
||||
void OnNewConnection(std::function<void(std::shared_ptr<DaybreakConnection>)> func) { m_on_new_connection = func; }
|
||||
void OnConnectionStateChange(std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
|
||||
void OnPacketRecv(std::function<void(std::shared_ptr<DaybreakConnection>, const Packet &)> func) { m_on_packet_recv = func; }
|
||||
private:
|
||||
void Attach(uv_loop_t *loop);
|
||||
void Detach();
|
||||
|
||||
EQEmu::Random m_rand;
|
||||
uv_timer_t m_timer;
|
||||
uv_timer_t m_resend_timer;
|
||||
uv_udp_t m_socket;
|
||||
uv_loop_t *m_attached;
|
||||
DaybreakConnectionManagerOptions m_options;
|
||||
std::function<void(std::shared_ptr<DaybreakConnection>)> m_on_new_connection;
|
||||
std::function<void(std::shared_ptr<DaybreakConnection>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change;
|
||||
std::function<void(std::shared_ptr<DaybreakConnection>, const Packet&)> m_on_packet_recv;
|
||||
std::map<std::pair<std::string, int>, std::shared_ptr<DaybreakConnection>> m_connections;
|
||||
|
||||
void ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size);
|
||||
std::shared_ptr<DaybreakConnection> FindConnectionByEndpoint(std::string addr, int port);
|
||||
void SendSessionLost(const std::string &addr, int port);
|
||||
|
||||
friend class DaybreakConnection;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cstdint>
|
||||
#include "endian.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
struct DaybreakHeader
|
||||
{
|
||||
static size_t size() { return 2; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakConnect
|
||||
{
|
||||
static size_t size() { return 14; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint32_t protocol_version;
|
||||
uint32_t connect_code;
|
||||
uint32_t max_packet_size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(protocol_version),
|
||||
CEREAL_NVP(connect_code),
|
||||
CEREAL_NVP(max_packet_size));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakConnectReply
|
||||
{
|
||||
static size_t size() { return 17; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint32_t connect_code;
|
||||
uint32_t encode_key;
|
||||
uint8_t crc_bytes;
|
||||
uint8_t encode_pass1;
|
||||
uint8_t encode_pass2;
|
||||
uint32_t max_packet_size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(connect_code),
|
||||
CEREAL_NVP(encode_key),
|
||||
CEREAL_NVP(crc_bytes),
|
||||
CEREAL_NVP(encode_pass1),
|
||||
CEREAL_NVP(encode_pass2),
|
||||
CEREAL_NVP(max_packet_size));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakDisconnect
|
||||
{
|
||||
static size_t size() { return 8; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint32_t connect_code;
|
||||
uint16_t disconnect_code;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(connect_code),
|
||||
CEREAL_NVP(disconnect_code));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakReliableHeader
|
||||
{
|
||||
static size_t size() { return 4; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint16_t sequence;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(sequence));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakReliableFragmentHeader
|
||||
{
|
||||
static size_t size() { return 4 + DaybreakReliableHeader::size(); }
|
||||
DaybreakReliableHeader reliable;
|
||||
uint32_t total_size;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(reliable),
|
||||
CEREAL_NVP(total_size));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakSessionStatRequestHeader
|
||||
{
|
||||
static size_t size() { return 40; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint16_t timestamp;
|
||||
uint32_t stat_ping;
|
||||
uint32_t avg_ping;
|
||||
uint32_t min_ping;
|
||||
uint32_t max_ping;
|
||||
uint32_t last_ping;
|
||||
uint64_t packets_sent;
|
||||
uint64_t packets_recv;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(timestamp),
|
||||
CEREAL_NVP(stat_ping),
|
||||
CEREAL_NVP(avg_ping),
|
||||
CEREAL_NVP(min_ping),
|
||||
CEREAL_NVP(max_ping),
|
||||
CEREAL_NVP(last_ping),
|
||||
CEREAL_NVP(packets_sent),
|
||||
CEREAL_NVP(packets_recv));
|
||||
}
|
||||
};
|
||||
|
||||
struct DaybreakSessionStatResponseHeader
|
||||
{
|
||||
static size_t size() { return 40; }
|
||||
uint8_t zero;
|
||||
uint8_t opcode;
|
||||
uint16_t timestamp;
|
||||
uint32_t our_timestamp;
|
||||
uint64_t client_sent;
|
||||
uint64_t client_recv;
|
||||
uint64_t server_sent;
|
||||
uint64_t server_recv;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive & archive)
|
||||
{
|
||||
archive(CEREAL_NVP(zero),
|
||||
CEREAL_NVP(opcode),
|
||||
CEREAL_NVP(timestamp),
|
||||
CEREAL_NVP(our_timestamp),
|
||||
CEREAL_NVP(client_sent),
|
||||
CEREAL_NVP(client_recv),
|
||||
CEREAL_NVP(server_sent),
|
||||
CEREAL_NVP(server_recv));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
inline bool IsLittleEndian() {
|
||||
static int32_t v = 1;
|
||||
return 1 == *(int8_t*)&v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ByteSwap(T in) {
|
||||
static_assert(std::is_integral<T>::value, "Byte swap only works on integer types.");
|
||||
T ret;
|
||||
|
||||
char *first = (char*)∈
|
||||
char *last = (char*)&in + sizeof(in);
|
||||
char *d_first = (char*)&ret;
|
||||
while (first != last) {
|
||||
*(d_first++) = *(--last);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T HostToNetwork(T in) {
|
||||
if (IsLittleEndian()) {
|
||||
return ByteSwap(in);
|
||||
}
|
||||
else {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T NetworkToHost(T in) {
|
||||
if (IsLittleEndian()) {
|
||||
return ByteSwap(in);
|
||||
}
|
||||
else {
|
||||
return in;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
#include "eqstream.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
EQ::Net::EQStreamManager::EQStreamManager(EQStreamManagerOptions &options) : m_daybreak(options.daybreak_options)
|
||||
{
|
||||
m_options = options;
|
||||
|
||||
m_daybreak.OnNewConnection(std::bind(&EQStreamManager::DaybreakNewConnection, this, std::placeholders::_1));
|
||||
m_daybreak.OnConnectionStateChange(std::bind(&EQStreamManager::DaybreakConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
m_daybreak.OnPacketRecv(std::bind(&EQStreamManager::DaybreakPacketRecv, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
EQ::Net::EQStreamManager::~EQStreamManager()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection)
|
||||
{
|
||||
std::shared_ptr<EQStream> stream(new EQStream(this, connection));
|
||||
m_streams.insert(std::make_pair(connection, stream));
|
||||
if (m_on_new_connection) {
|
||||
m_on_new_connection(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStreamManager::DaybreakConnectionStateChange(std::shared_ptr<DaybreakConnection> connection, DbProtocolStatus from, DbProtocolStatus to)
|
||||
{
|
||||
auto iter = m_streams.find(connection);
|
||||
if (iter != m_streams.end()) {
|
||||
if (m_on_connection_state_change) {
|
||||
m_on_connection_state_change(iter->second, from, to);
|
||||
}
|
||||
|
||||
if (to == EQ::Net::StatusDisconnected) {
|
||||
m_streams.erase(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStreamManager::DaybreakPacketRecv(std::shared_ptr<DaybreakConnection> connection, const Packet &p)
|
||||
{
|
||||
auto iter = m_streams.find(connection);
|
||||
if (iter != m_streams.end()) {
|
||||
auto patch = iter->second->GetRegisteredPatch();
|
||||
if (patch == nullptr && m_possible_patches.size() > 0) {
|
||||
for (auto &pt : m_possible_patches) {
|
||||
auto match = pt->TryIdentityMatch(p);
|
||||
if (match == EQ::Patches::IdentityMatchSuccess) {
|
||||
iter->second->RegisterPatch(pt.get());
|
||||
patch = pt.get();
|
||||
Log.OutF(Logs::General, Logs::Debug, "Identified patch with name {0}", pt->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (patch) {
|
||||
EmuOpcode opcode;
|
||||
EQ::Net::WritablePacket out;
|
||||
patch->Decode(&p, opcode, out);
|
||||
|
||||
if (opcode == OP_Unknown) {
|
||||
Log.OutF(Logs::General, Logs::Netcode, "Incoming packet was not handled because the opcode was not found.\n{0}", p.ToString());
|
||||
}
|
||||
else {
|
||||
if (m_on_packet_recv) {
|
||||
m_on_packet_recv(iter->second, opcode, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.OutF(Logs::General, Logs::Netcode, "Incoming packet was not handled because we don't have a patch set.\n{0}", p.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EQ::Net::EQStream::EQStream(EQStreamManager *owner, std::shared_ptr<DaybreakConnection> connection)
|
||||
{
|
||||
m_owner = owner;
|
||||
m_connection = connection;
|
||||
m_patch = nullptr;
|
||||
}
|
||||
|
||||
EQ::Net::EQStream::~EQStream()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::QueuePacket(EmuOpcode type, const Packet &p)
|
||||
{
|
||||
if (m_patch) {
|
||||
EQ::Net::WritablePacket trans;
|
||||
m_patch->Encode(m_connection, type, &p);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::ResetStats()
|
||||
{
|
||||
m_connection->ResetStats();
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::Close()
|
||||
{
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::QueuePacket(const EQApplicationPacket *p)
|
||||
{
|
||||
EQ::Net::ReadOnlyPacket out(p->pBuffer, p->size);
|
||||
QueuePacket(p->GetOpcode(), out);
|
||||
|
||||
}
|
||||
|
||||
void EQ::Net::EQStream::FastQueuePacket(const EQApplicationPacket **p)
|
||||
{
|
||||
QueuePacket(*p);
|
||||
delete *p;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../patch/patch.h"
|
||||
#include "../eq_packet.h"
|
||||
#include "daybreak_connection.h"
|
||||
#include <vector>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Net
|
||||
{
|
||||
struct EQStreamManagerOptions
|
||||
{
|
||||
EQStreamManagerOptions() {
|
||||
|
||||
}
|
||||
|
||||
EQStreamManagerOptions(bool encoded, bool compressed) {
|
||||
if (encoded) {
|
||||
daybreak_options.encode_passes[0] = EncodeXOR;
|
||||
|
||||
if (compressed) {
|
||||
daybreak_options.encode_passes[1] = EncodeCompression;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (compressed) {
|
||||
daybreak_options.encode_passes[0] = EncodeCompression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DaybreakConnectionManagerOptions daybreak_options;
|
||||
};
|
||||
|
||||
class EQStream;
|
||||
class EQStreamManager
|
||||
{
|
||||
public:
|
||||
EQStreamManager(EQStreamManagerOptions &options);
|
||||
~EQStreamManager();
|
||||
|
||||
void OnNewConnection(std::function<void(std::shared_ptr<EQStream>)> func) { m_on_new_connection = func; }
|
||||
void OnConnectionStateChange(std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; }
|
||||
void OnPacketRecv(std::function<void(std::shared_ptr<EQStream>, EmuOpcode, const Packet &)> func) { m_on_packet_recv = func; }
|
||||
|
||||
void RegisterPotentialPatch(EQ::Patches::BasePatch *patch) { m_possible_patches.push_back(std::unique_ptr<EQ::Patches::BasePatch>(patch)); }
|
||||
private:
|
||||
EQStreamManagerOptions m_options;
|
||||
DaybreakConnectionManager m_daybreak;
|
||||
std::function<void(std::shared_ptr<EQStream>)> m_on_new_connection;
|
||||
std::function<void(std::shared_ptr<EQStream>, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change;
|
||||
std::function<void(std::shared_ptr<EQStream>, EmuOpcode, const Packet &)> m_on_packet_recv;
|
||||
std::map<std::shared_ptr<DaybreakConnection>, std::shared_ptr<EQStream>> m_streams;
|
||||
std::vector<std::unique_ptr<EQ::Patches::BasePatch>> m_possible_patches;
|
||||
|
||||
void DaybreakNewConnection(std::shared_ptr<DaybreakConnection> connection);
|
||||
void DaybreakConnectionStateChange(std::shared_ptr<DaybreakConnection> connection, DbProtocolStatus from, DbProtocolStatus to);
|
||||
void DaybreakPacketRecv(std::shared_ptr<DaybreakConnection> connection, const Packet &p);
|
||||
friend class EQStream;
|
||||
};
|
||||
|
||||
class EQStream
|
||||
{
|
||||
public:
|
||||
EQStream(EQStreamManager *parent, std::shared_ptr<DaybreakConnection> connection);
|
||||
~EQStream();
|
||||
|
||||
const std::string& RemoteEndpoint() const { return m_connection->RemoteEndpoint(); }
|
||||
int RemotePort() const { return m_connection->RemotePort(); }
|
||||
|
||||
void QueuePacket(EmuOpcode type, const Packet &p);
|
||||
const DaybreakConnectionStats& GetStats() const { return m_connection->GetStats(); }
|
||||
void ResetStats();
|
||||
size_t GetRollingPing() const { return m_connection->GetRollingPing(); }
|
||||
void Close();
|
||||
void QueuePacket(const EQApplicationPacket *p);
|
||||
void FastQueuePacket(const EQApplicationPacket **p);
|
||||
|
||||
void RegisterPatch(EQ::Patches::BasePatch *p) { m_patch = p; }
|
||||
EQ::Patches::BasePatch *GetRegisteredPatch() { return m_patch; }
|
||||
private:
|
||||
EQStreamManager *m_owner;
|
||||
std::shared_ptr<DaybreakConnection> m_connection;
|
||||
EQ::Patches::BasePatch *m_patch;
|
||||
friend class EQStreamManager;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,332 +0,0 @@
|
||||
#include "packet.h"
|
||||
#include "endian.h"
|
||||
#include <fmt/format.h>
|
||||
#include <cctype>
|
||||
|
||||
void EQ::Net::Packet::PutInt8(size_t offset, int8_t value)
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
if (!Resize(offset + 1)) {
|
||||
throw std::out_of_range("Packet::PutInt8(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int8_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutInt16(size_t offset, int16_t value)
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
if (!Resize(offset + 2)) {
|
||||
throw std::out_of_range("Packet::PutInt16(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int16_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutInt32(size_t offset, int32_t value)
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
if (!Resize(offset + 4)) {
|
||||
throw std::out_of_range("Packet::PutInt32(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int32_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutInt64(size_t offset, int64_t value)
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
if (!Resize(offset + 8)) {
|
||||
throw std::out_of_range("Packet::PutInt64(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(int64_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt8(size_t offset, uint8_t value)
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
if (!Resize(offset + 1)) {
|
||||
throw std::out_of_range("Packet::PutUInt8(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint8_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt16(size_t offset, uint16_t value)
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
if (!Resize(offset + 2)) {
|
||||
throw std::out_of_range("Packet::PutUInt16(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint16_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt32(size_t offset, uint32_t value)
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
if (!Resize(offset + 4)) {
|
||||
throw std::out_of_range("Packet::PutUInt32(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint32_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutUInt64(size_t offset, uint64_t value)
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
if (!Resize(offset + 8)) {
|
||||
throw std::out_of_range("Packet::PutUInt64(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(uint64_t*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutFloat(size_t offset, float value)
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
if (!Resize(offset + 4)) {
|
||||
throw std::out_of_range("Packet::PutFloat(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(float*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutDouble(size_t offset, double value)
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
if (!Resize(offset + 8)) {
|
||||
throw std::out_of_range("Packet::PutDouble(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
*(double*)((char*)Data() + offset) = value;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutString(size_t offset, const std::string &str)
|
||||
{
|
||||
if (Length() < offset + str.length()) {
|
||||
if (!Resize(offset + str.length())) {
|
||||
throw std::out_of_range("Packet::PutString(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutCString(size_t offset, const char *str)
|
||||
{
|
||||
size_t sz = strlen(str);
|
||||
if (Length() < offset + sz + 1) {
|
||||
if (!Resize(offset + sz + 1)) {
|
||||
throw std::out_of_range("Packet::PutCString(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), str, sz);
|
||||
*((char*)Data() + offset + sz) = 0;
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutPacket(size_t offset, const Packet &p)
|
||||
{
|
||||
if (Length() < offset + p.Length()) {
|
||||
if (!Resize(offset + p.Length())) {
|
||||
throw std::out_of_range("Packet::PutPacket(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), p.Data(), p.Length());
|
||||
}
|
||||
|
||||
void EQ::Net::Packet::PutData(size_t offset, void *data, size_t length)
|
||||
{
|
||||
if (Length() < offset + length) {
|
||||
if (!Resize(offset + length)) {
|
||||
throw std::out_of_range("Packet::PutData(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(((char*)Data() + offset), data, length);
|
||||
}
|
||||
|
||||
int8_t EQ::Net::Packet::GetInt8(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int8_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
int16_t EQ::Net::Packet::GetInt16(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int16_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
int32_t EQ::Net::Packet::GetInt32(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int32_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
int64_t EQ::Net::Packet::GetInt64(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(int64_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint8_t EQ::Net::Packet::GetUInt8(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint8_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint16_t EQ::Net::Packet::GetUInt16(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 2) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint16_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint32_t EQ::Net::Packet::GetUInt32(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint32_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
uint64_t EQ::Net::Packet::GetUInt64(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(uint64_t*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
float EQ::Net::Packet::GetFloat(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 4) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(float*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
double EQ::Net::Packet::GetDouble(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 8) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return *(double*)((char*)Data() + offset);
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::GetString(size_t offset, size_t length) const
|
||||
{
|
||||
if (Length() < offset + length) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
return std::string((char*)Data(), (char*)Data() + length);
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::GetCString(size_t offset) const
|
||||
{
|
||||
if (Length() < offset + 1) {
|
||||
throw std::out_of_range("Packet read out of range.");
|
||||
}
|
||||
|
||||
char *str = ((char*)Data() + offset);
|
||||
return std::string(str);
|
||||
}
|
||||
|
||||
char ToSafePrint(unsigned char in) {
|
||||
if (std::isprint(in)) {
|
||||
return in;
|
||||
}
|
||||
|
||||
return '.';
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::ToString() const
|
||||
{
|
||||
return ToString(16);
|
||||
}
|
||||
|
||||
std::string EQ::Net::Packet::ToString(size_t line_length) const
|
||||
{
|
||||
std::string ret;
|
||||
size_t lines = Length() / line_length;
|
||||
size_t i;
|
||||
|
||||
char *data = (char*)Data();
|
||||
|
||||
for (i = 0; i < lines; ++i) {
|
||||
ret += fmt::format("{:0>5x} |", i * line_length);
|
||||
std::string hex;
|
||||
std::string ascii;
|
||||
for (size_t j = 0; j < line_length; ++j) {
|
||||
hex += fmt::format(" {:0>2x}", (uint8_t)data[(i * line_length) + j]);
|
||||
ascii += fmt::format("{}", ToSafePrint(data[(i * line_length) + j]));
|
||||
}
|
||||
|
||||
ret += hex;
|
||||
ret += " | ";
|
||||
ret += ascii;
|
||||
ret += "\n";
|
||||
}
|
||||
|
||||
if (Length() % line_length > 0) {
|
||||
ret += fmt::format("{:0>5x} |", i * line_length);
|
||||
|
||||
size_t non_blank_count = Length() % line_length;
|
||||
size_t blank_count = line_length - non_blank_count;
|
||||
std::string hex;
|
||||
std::string ascii;
|
||||
|
||||
for (size_t j = 0; j < non_blank_count; ++j) {
|
||||
hex += fmt::format(" {:0>2x}", (uint8_t)data[(i * line_length) + j]);
|
||||
ascii += fmt::format("{}", ToSafePrint(data[(i * line_length) + j]));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < blank_count; ++j) {
|
||||
hex += " ";
|
||||
ascii += " ";
|
||||
}
|
||||
|
||||
ret += hex;
|
||||
ret += " | ";
|
||||
ret += ascii;
|
||||
ret += "\n";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include "../util/memory_stream.h"
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
namespace EQ {
|
||||
namespace Net {
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
Packet() { }
|
||||
virtual ~Packet() { }
|
||||
|
||||
virtual const void *Data() const = 0;
|
||||
virtual void *Data() = 0;
|
||||
virtual size_t Length() const = 0;
|
||||
virtual size_t Length() = 0;
|
||||
virtual bool Clear() = 0;
|
||||
virtual bool Resize(size_t new_size) = 0;
|
||||
virtual void Reserve(size_t new_size) = 0;
|
||||
|
||||
template<typename T>
|
||||
T GetSerialize(size_t offset) const
|
||||
{
|
||||
if (T::size() > (Length() - offset)) {
|
||||
throw std::out_of_range("Packet::GetSerialize(), packet not large enough to cast to type.");
|
||||
}
|
||||
|
||||
T ret;
|
||||
Util::MemoryStreamReader reader(((char*)Data() + offset), Length());
|
||||
cereal::BinaryInputArchive input(reader);
|
||||
input(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PutSerialize(size_t offset, const T &value) {
|
||||
std::stringstream buffer(std::ios::in | std::ios::out | std::ios::binary);
|
||||
cereal::BinaryOutputArchive output(buffer);
|
||||
output(value);
|
||||
|
||||
auto str = buffer.str();
|
||||
if (Length() < offset + str.length()) {
|
||||
if (!Resize(offset + str.length())) {
|
||||
throw std::out_of_range("Packet::PutSerialize(), could not resize packet and would of written past the end.");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy((char*)Data() + offset, &str[0], str.length());
|
||||
}
|
||||
|
||||
void PutInt8(size_t offset, int8_t value);
|
||||
void PutInt16(size_t offset, int16_t value);
|
||||
void PutInt32(size_t offset, int32_t value);
|
||||
void PutInt64(size_t offset, int64_t value);
|
||||
void PutUInt8(size_t offset, uint8_t value);
|
||||
void PutUInt16(size_t offset, uint16_t value);
|
||||
void PutUInt32(size_t offset, uint32_t value);
|
||||
void PutUInt64(size_t offset, uint64_t value);
|
||||
void PutFloat(size_t offset, float value);
|
||||
void PutDouble(size_t offset, double value);
|
||||
void PutString(size_t offset, const std::string &str);
|
||||
void PutCString(size_t offset, const char *str);
|
||||
void PutPacket(size_t offset, const Packet &p);
|
||||
void PutData(size_t offset, void *data, size_t length);
|
||||
|
||||
int8_t GetInt8(size_t offset) const;
|
||||
int16_t GetInt16(size_t offset) const;
|
||||
int32_t GetInt32(size_t offset) const;
|
||||
int64_t GetInt64(size_t offset) const;
|
||||
uint8_t GetUInt8(size_t offset) const;
|
||||
uint16_t GetUInt16(size_t offset) const;
|
||||
uint32_t GetUInt32(size_t offset) const;
|
||||
uint64_t GetUInt64(size_t offset) const;
|
||||
float GetFloat(size_t offset) const;
|
||||
double GetDouble(size_t offset) const;
|
||||
std::string GetString(size_t offset, size_t length) const;
|
||||
std::string GetCString(size_t offset) const;
|
||||
|
||||
std::string ToString() const;
|
||||
std::string ToString(size_t line_length) const;
|
||||
};
|
||||
|
||||
class ReadOnlyPacket : public Packet
|
||||
{
|
||||
public:
|
||||
ReadOnlyPacket(void *data, size_t size) { m_data = data; m_data_length = size; }
|
||||
virtual ~ReadOnlyPacket() { }
|
||||
ReadOnlyPacket(const ReadOnlyPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
ReadOnlyPacket& operator=(const ReadOnlyPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; }
|
||||
ReadOnlyPacket(ReadOnlyPacket &&o) { m_data = o.m_data; m_data_length = o.m_data_length; }
|
||||
|
||||
virtual const void *Data() const { return m_data; }
|
||||
virtual void *Data() { return m_data; }
|
||||
virtual size_t Length() const { return m_data_length; }
|
||||
virtual size_t Length() { return m_data_length; }
|
||||
virtual bool Clear() { return false; }
|
||||
virtual bool Resize(size_t new_size) { return false; }
|
||||
virtual void Reserve(size_t new_size) { }
|
||||
|
||||
protected:
|
||||
void *m_data;
|
||||
size_t m_data_length;
|
||||
};
|
||||
|
||||
class WritablePacket : public Packet
|
||||
{
|
||||
public:
|
||||
WritablePacket() { }
|
||||
virtual ~WritablePacket() { }
|
||||
WritablePacket(WritablePacket &&o) { m_data = std::move(o.m_data); }
|
||||
WritablePacket(const WritablePacket &o) { m_data = o.m_data; }
|
||||
WritablePacket& operator=(const WritablePacket &o) { m_data = o.m_data; return *this; }
|
||||
|
||||
virtual const void *Data() const { return &m_data[0]; }
|
||||
virtual void *Data() { return &m_data[0]; }
|
||||
virtual size_t Length() const { return m_data.size(); }
|
||||
virtual size_t Length() { return m_data.size(); }
|
||||
virtual bool Clear() { m_data.clear(); return true; }
|
||||
virtual bool Resize(size_t new_size) { m_data.resize(new_size); return true; }
|
||||
virtual void Reserve(size_t new_size) { m_data.reserve(new_size); }
|
||||
protected:
|
||||
std::vector<char> m_data;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "chat.h"
|
||||
|
||||
EQ::Patches::ChatPatch::ChatPatch()
|
||||
{
|
||||
m_opcode_manager.reset(new RegularOpcodeManager());
|
||||
if (!m_opcode_manager->LoadOpcodes("mail_opcodes.conf")) {
|
||||
m_opcode_manager.release();
|
||||
}
|
||||
|
||||
m_signature.match_message_opcode = 0x0;
|
||||
m_signature.match_message_size = 0;
|
||||
m_message_size = 1;
|
||||
}
|
||||
|
||||
EQ::Patches::ChatPatch::~ChatPatch()
|
||||
{
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#include "../patch/patch.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Patches
|
||||
{
|
||||
class ChatPatch : public BasePatch
|
||||
{
|
||||
public:
|
||||
ChatPatch();
|
||||
virtual ~ChatPatch();
|
||||
virtual std::string GetName() const { return "Chat"; }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "login_sod.h"
|
||||
|
||||
EQ::Patches::LoginSoDPatch::LoginSoDPatch()
|
||||
{
|
||||
m_opcode_manager.reset(new RegularOpcodeManager());
|
||||
if (!m_opcode_manager->LoadOpcodes("login_opcodes_sod.conf")) {
|
||||
m_opcode_manager.release();
|
||||
}
|
||||
|
||||
m_signature.match_message_opcode = 0x01;
|
||||
m_signature.match_message_size = 0;
|
||||
m_message_size = 2;
|
||||
}
|
||||
|
||||
EQ::Patches::LoginSoDPatch::~LoginSoDPatch()
|
||||
{
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#include "../patch/patch.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Patches
|
||||
{
|
||||
class LoginSoDPatch : public BasePatch
|
||||
{
|
||||
public:
|
||||
LoginSoDPatch();
|
||||
virtual ~LoginSoDPatch();
|
||||
virtual std::string GetName() const { return "Login SoD+"; }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "login_titanium.h"
|
||||
|
||||
EQ::Patches::LoginTitaniumPatch::LoginTitaniumPatch()
|
||||
{
|
||||
m_opcode_manager.reset(new RegularOpcodeManager());
|
||||
if (!m_opcode_manager->LoadOpcodes("login_opcodes.conf")) {
|
||||
m_opcode_manager.release();
|
||||
}
|
||||
|
||||
m_signature.match_message_opcode = 0x01;
|
||||
m_signature.match_message_size = 0;
|
||||
m_message_size = 2;
|
||||
}
|
||||
|
||||
EQ::Patches::LoginTitaniumPatch::~LoginTitaniumPatch()
|
||||
{
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#include "../patch/patch.h"
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Patches
|
||||
{
|
||||
class LoginTitaniumPatch : public BasePatch
|
||||
{
|
||||
public:
|
||||
LoginTitaniumPatch();
|
||||
virtual ~LoginTitaniumPatch();
|
||||
virtual std::string GetName() const { return "Login Titanium"; }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
#include "patch.h"
|
||||
#include "../eqemu_logsys.h"
|
||||
|
||||
EQ::Patches::IdentityMatchStatus EQ::Patches::BasePatch::TryIdentityMatch(const EQ::Net::Packet &p) const
|
||||
{
|
||||
if (p.Length() < m_message_size) {
|
||||
return IdentityMatchFailure;
|
||||
}
|
||||
|
||||
int raw_opcode = 0;
|
||||
switch (m_message_size) {
|
||||
case 1:
|
||||
raw_opcode = *(uint8_t*)p.Data();
|
||||
break;
|
||||
case 2:
|
||||
raw_opcode = *(uint16_t*)p.Data();
|
||||
break;
|
||||
default:
|
||||
return IdentityMatchFailure;
|
||||
}
|
||||
|
||||
if (m_signature.match_message_opcode != 0 && m_signature.match_message_opcode != raw_opcode) {
|
||||
return IdentityMatchFailure;
|
||||
}
|
||||
|
||||
if (m_signature.match_message_size > 0 && m_signature.match_message_size != p.Length() - m_message_size) {
|
||||
return IdentityMatchFailure;
|
||||
}
|
||||
|
||||
return IdentityMatchSuccess;
|
||||
}
|
||||
|
||||
void EQ::Patches::BasePatch::Decode(const EQ::Net::Packet *in, EmuOpcode &opcode, EQ::Net::WritablePacket &out)
|
||||
{
|
||||
int raw_opcode = 0;
|
||||
switch (m_message_size) {
|
||||
case 1:
|
||||
raw_opcode = *(uint8_t*)in->Data();
|
||||
break;
|
||||
case 2:
|
||||
raw_opcode = *(uint16_t*)in->Data();
|
||||
break;
|
||||
default:
|
||||
opcode = OP_Unknown;
|
||||
return;
|
||||
}
|
||||
|
||||
opcode = m_opcode_manager->EQToEmu(raw_opcode);
|
||||
if (opcode == OP_Unknown) {
|
||||
out.PutData(0, (uint8_t*)in->Data() + m_message_size, in->Length() - m_message_size);
|
||||
return;
|
||||
}
|
||||
|
||||
auto decode_iter = m_decode.find(opcode);
|
||||
if (decode_iter != m_decode.end()) {
|
||||
EQ::Net::ReadOnlyPacket p((uint8_t*)in->Data() + m_message_size, in->Length() - m_message_size);
|
||||
decode_iter->second(&p, opcode, out);
|
||||
}
|
||||
else {
|
||||
out.PutData(0, (uint8_t*)in->Data() + m_message_size, in->Length() - m_message_size);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Patches::BasePatch::Encode(std::shared_ptr<EQ::Net::DaybreakConnection> connection, EmuOpcode opcode, const EQ::Net::Packet *in)
|
||||
{
|
||||
auto encode_iter = m_encode.find(opcode);
|
||||
if (encode_iter != m_encode.end()) {
|
||||
encode_iter->second(connection, opcode, in);
|
||||
}
|
||||
else {
|
||||
SendPacket(connection, opcode, in);
|
||||
}
|
||||
}
|
||||
|
||||
void EQ::Patches::BasePatch::RegisterDecode(int protocol_number, DecodeStructFunction f)
|
||||
{
|
||||
m_decode.insert(std::make_pair(protocol_number, f));
|
||||
}
|
||||
|
||||
void EQ::Patches::BasePatch::RegisterEncode(EmuOpcode opcode, EncodeStructFunction f)
|
||||
{
|
||||
m_encode.insert(std::make_pair(opcode, f));
|
||||
}
|
||||
|
||||
void EQ::Patches::BasePatch::SendPacket(std::shared_ptr<EQ::Net::DaybreakConnection> connection, EmuOpcode opcode, const EQ::Net::Packet *p)
|
||||
{
|
||||
if (!m_opcode_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto raw_opcode = m_opcode_manager->EmuToEQ(opcode);
|
||||
EQ::Net::WritablePacket out;
|
||||
switch (m_message_size) {
|
||||
case 1:
|
||||
out.PutUInt8(0, (uint8_t)raw_opcode);
|
||||
out.PutPacket(1, *p);
|
||||
break;
|
||||
case 2:
|
||||
out.PutUInt16(0, raw_opcode);
|
||||
out.PutPacket(2, *p);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
connection->QueuePacket(out);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../opcodemgr.h"
|
||||
#include "../net/packet.h"
|
||||
#include "../net/daybreak_connection.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Patches
|
||||
{
|
||||
enum IdentityMatchStatus
|
||||
{
|
||||
IdentityMatchFailure,
|
||||
IdentityMatchSuccess
|
||||
};
|
||||
|
||||
struct Signature
|
||||
{
|
||||
int match_message_opcode;
|
||||
size_t match_message_size;
|
||||
};
|
||||
|
||||
class BasePatch
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(const EQ::Net::Packet*, EmuOpcode, EQ::Net::WritablePacket&)> DecodeStructFunction;
|
||||
typedef std::function<void(std::shared_ptr<EQ::Net::DaybreakConnection>, EmuOpcode, const EQ::Net::Packet*)> EncodeStructFunction;
|
||||
|
||||
BasePatch() { }
|
||||
virtual ~BasePatch() { }
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
IdentityMatchStatus TryIdentityMatch(const EQ::Net::Packet &p) const;
|
||||
|
||||
void Decode(const EQ::Net::Packet *in, EmuOpcode& opcode, EQ::Net::WritablePacket& out);
|
||||
void Encode(std::shared_ptr<EQ::Net::DaybreakConnection> connection, EmuOpcode opcode, const EQ::Net::Packet *in);
|
||||
|
||||
void RegisterDecode(int protocol_number, DecodeStructFunction f);
|
||||
void RegisterEncode(EmuOpcode opcode, EncodeStructFunction f);
|
||||
protected:
|
||||
void SendPacket(std::shared_ptr<EQ::Net::DaybreakConnection> connection, EmuOpcode opcode, const EQ::Net::Packet *p);
|
||||
|
||||
std::unique_ptr<OpcodeManager> m_opcode_manager;
|
||||
std::map<int, DecodeStructFunction> m_decode;
|
||||
std::map<EmuOpcode, EncodeStructFunction> m_encode;
|
||||
Signature m_signature;
|
||||
int m_message_size;
|
||||
};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -477,11 +477,10 @@ namespace RoF
|
||||
for (uint16 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
uint16 buffslot = emu->entries[i].buff_slot;
|
||||
if (emu->type == 0) { // only correct for self packets
|
||||
if (emu->entries[i].buff_slot >= 25)
|
||||
buffslot += 17;
|
||||
if (buffslot == 54)
|
||||
buffslot = 62;
|
||||
// Not sure if this is needs amending for RoF yet.
|
||||
if (emu->entries[i].buff_slot >= 25)
|
||||
{
|
||||
buffslot += 17;
|
||||
}
|
||||
|
||||
__packet->WriteUInt32(buffslot);
|
||||
@@ -987,8 +986,8 @@ namespace RoF
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading);
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_x); // X tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_y); // Y tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // X tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Y tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
|
||||
|
||||
+11
-10
@@ -549,15 +549,16 @@ namespace RoF2
|
||||
for (uint16 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
uint16 buffslot = emu->entries[i].buff_slot;
|
||||
if (emu->type == 0) { // only correct for self packets
|
||||
if (emu->entries[i].buff_slot >= 25)
|
||||
buffslot += 17;
|
||||
// TODO: We should really just deal with these "server side"
|
||||
// so we can have clients not limited to other clients.
|
||||
// This fixes discs, songs were changed to 20
|
||||
if (buffslot == 54)
|
||||
buffslot = 62;
|
||||
// Not sure if this is needs amending for RoF2 yet.
|
||||
if (emu->entries[i].buff_slot >= 25)
|
||||
{
|
||||
buffslot += 17;
|
||||
}
|
||||
// TODO: We should really just deal with these "server side"
|
||||
// so we can have clients not limited to other clients.
|
||||
// This fixes discs, songs were changed to 20
|
||||
if (buffslot == 54)
|
||||
buffslot = 62;
|
||||
|
||||
__packet->WriteUInt32(buffslot);
|
||||
__packet->WriteUInt32(emu->entries[i].spell_id);
|
||||
@@ -1062,8 +1063,8 @@ namespace RoF2
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading);
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_x); // X tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_y); // Y tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // X tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Y tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
|
||||
|
||||
@@ -3246,10 +3246,8 @@ namespace SoD
|
||||
DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct);
|
||||
SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct);
|
||||
|
||||
for (int i = 0; i < structs::MAX_PP_MEMSPELL; ++i)
|
||||
for (uint32 i = 0; i < MAX_PP_MEMSPELL; ++i)
|
||||
emu->spell[i] = eq->spell[i];
|
||||
for (int i = structs::MAX_PP_MEMSPELL; i < MAX_PP_MEMSPELL; ++i)
|
||||
emu->spell[i] = 0xFFFFFFFF;
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
@@ -1880,7 +1880,8 @@ struct Merchant_Sell_Struct {
|
||||
/*004*/ uint32 playerid; // Player's entity id
|
||||
/*008*/ uint32 itemslot;
|
||||
/*012*/ uint32 unknown12;
|
||||
/*016*/ uint32 quantity;
|
||||
/*016*/ uint8 quantity; // Already sold
|
||||
/*017*/ uint8 Unknown017[3];
|
||||
/*020*/ uint32 Unknown020;
|
||||
/*024*/ uint32 price;
|
||||
/*028*/ uint32 pricehighorderbits; // It appears the price is 64 bits in SoD+
|
||||
|
||||
@@ -2623,21 +2623,6 @@ namespace SoF
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_LoadSpellSet)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct);
|
||||
SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct);
|
||||
|
||||
for (int i = 0; i < structs::MAX_PP_MEMSPELL; ++i)
|
||||
IN(spell[i]);
|
||||
for (int i = structs::MAX_PP_MEMSPELL; i < MAX_PP_MEMSPELL; ++i)
|
||||
emu->spell[i] = 0xFFFFFFFF;
|
||||
|
||||
IN(unknown);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_LootItem)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
|
||||
@@ -111,7 +111,6 @@ D(OP_GroupFollow2)
|
||||
D(OP_InspectRequest)
|
||||
D(OP_ItemLinkClick)
|
||||
D(OP_ItemVerifyRequest)
|
||||
D(OP_LoadSpellSet)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_PetCommands)
|
||||
|
||||
@@ -1859,7 +1859,8 @@ struct Merchant_Sell_Struct {
|
||||
/*004*/ uint32 playerid; // Player's entity id
|
||||
/*008*/ uint32 itemslot;
|
||||
uint32 unknown12;
|
||||
/*016*/ uint32 quantity;
|
||||
/*016*/ uint8 quantity; // Already sold
|
||||
/*017*/ uint8 Unknown016[3];
|
||||
/*020*/ uint32 price;
|
||||
};
|
||||
struct Merchant_Purchase_Struct {
|
||||
@@ -3728,11 +3729,6 @@ struct AnnoyingZoneUnknown_Struct {
|
||||
uint32 value; //always 4
|
||||
};
|
||||
|
||||
struct LoadSpellSet_Struct {
|
||||
uint32 spell[MAX_PP_MEMSPELL];
|
||||
uint32 unknown;
|
||||
};
|
||||
|
||||
struct BlockedBuffs_Struct {
|
||||
/*000*/ uint8 unknown000[80];
|
||||
/*080*/ uint8 unknown081;
|
||||
|
||||
@@ -595,46 +595,6 @@ namespace Titanium
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_GroundSpawn)
|
||||
{
|
||||
// We are not encoding the spawn_id field here, but it doesn't appear to matter.
|
||||
//
|
||||
EQApplicationPacket *in = *p;
|
||||
*p = nullptr;
|
||||
|
||||
//store away the emu struct
|
||||
unsigned char *__emu_buffer = in->pBuffer;
|
||||
Object_Struct *emu = (Object_Struct *)__emu_buffer;
|
||||
|
||||
in->size = strlen(emu->object_name) + sizeof(structs::Object_Struct) - 1;
|
||||
in->pBuffer = new unsigned char[in->size];
|
||||
|
||||
structs::Object_Struct *eq = (structs::Object_Struct *) in->pBuffer;
|
||||
|
||||
eq->drop_id = emu->drop_id;
|
||||
eq->heading = emu->heading;
|
||||
eq->linked_list_addr[0] = 0;
|
||||
eq->linked_list_addr[1] = 0;
|
||||
strcpy(eq->object_name, emu->object_name);
|
||||
eq->object_type = emu->object_type;
|
||||
eq->spawn_id = 0;
|
||||
eq->unknown008[0] = 0;
|
||||
eq->unknown008[1] = 0;
|
||||
eq->unknown020 = 0;
|
||||
eq->unknown024 = 0;
|
||||
eq->unknown076 = 0;
|
||||
eq->unknown084 = 0xffffffff;
|
||||
eq->z = emu->z;
|
||||
eq->x = emu->x;
|
||||
eq->y = emu->y;
|
||||
eq->zone_id = emu->zone_id;
|
||||
eq->zone_instance = emu->zone_instance;
|
||||
|
||||
|
||||
delete[] __emu_buffer;
|
||||
dest->FastQueuePacket(&in, ack_req);
|
||||
}
|
||||
|
||||
ENCODE(OP_GuildMemberList)
|
||||
{
|
||||
//consume the packet
|
||||
@@ -1978,21 +1938,6 @@ namespace Titanium
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_LoadSpellSet)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::LoadSpellSet_Struct);
|
||||
SETUP_DIRECT_DECODE(LoadSpellSet_Struct, structs::LoadSpellSet_Struct);
|
||||
|
||||
for (int i = 0; i < structs::MAX_PP_MEMSPELL; ++i)
|
||||
IN(spell[i]);
|
||||
for (int i = structs::MAX_PP_MEMSPELL; i < MAX_PP_MEMSPELL; ++i)
|
||||
emu->spell[i] = 0xFFFFFFFF;
|
||||
|
||||
IN(unknown);
|
||||
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
DECODE(OP_LootItem)
|
||||
{
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
|
||||
@@ -40,7 +40,6 @@ E(OP_DzLeaderStatus)
|
||||
E(OP_DzMemberList)
|
||||
E(OP_Emote)
|
||||
E(OP_FormattedMessage)
|
||||
E(OP_GroundSpawn)
|
||||
E(OP_GuildMemberLevelUpdate)
|
||||
E(OP_GuildMemberList)
|
||||
E(OP_Illusion)
|
||||
@@ -89,7 +88,6 @@ D(OP_InspectAnswer)
|
||||
D(OP_InspectRequest)
|
||||
D(OP_ItemLinkClick)
|
||||
D(OP_LFGuild)
|
||||
D(OP_LoadSpellSet)
|
||||
D(OP_LootItem)
|
||||
D(OP_MoveItem)
|
||||
D(OP_PetCommands)
|
||||
|
||||
@@ -1657,7 +1657,8 @@ struct Merchant_Sell_Struct {
|
||||
/*004*/ uint32 playerid; // Player's entity id
|
||||
/*008*/ uint32 itemslot;
|
||||
uint32 unknown12;
|
||||
/*016*/ uint32 quantity;
|
||||
/*016*/ uint8 quantity; // Already sold
|
||||
/*017*/ uint8 Unknown016[3];
|
||||
/*020*/ uint32 price;
|
||||
};
|
||||
struct Merchant_Purchase_Struct {
|
||||
@@ -3228,11 +3229,6 @@ struct AnnoyingZoneUnknown_Struct {
|
||||
uint32 value; //always 4
|
||||
};
|
||||
|
||||
struct LoadSpellSet_Struct {
|
||||
uint32 spell[MAX_PP_MEMSPELL];
|
||||
uint32 unknown;
|
||||
};
|
||||
|
||||
struct ApplyPoison_Struct {
|
||||
uint32 inventorySlot;
|
||||
uint32 success;
|
||||
|
||||
@@ -410,11 +410,13 @@ namespace UF
|
||||
for (uint16 i = 0; i < emu->count; ++i)
|
||||
{
|
||||
uint16 buffslot = emu->entries[i].buff_slot;
|
||||
if (emu->type == 0) { // only correct for self packets
|
||||
if (emu->entries[i].buff_slot >= 25 && emu->entries[i].buff_slot < 37)
|
||||
buffslot += 5;
|
||||
else if (emu->entries[i].buff_slot >= 37)
|
||||
buffslot += 14;
|
||||
if (emu->entries[i].buff_slot >= 25 && emu->entries[i].buff_slot < 37)
|
||||
{
|
||||
buffslot += 5;
|
||||
}
|
||||
else if (emu->entries[i].buff_slot >= 37)
|
||||
{
|
||||
buffslot += 14;
|
||||
}
|
||||
|
||||
__packet->WriteUInt32(buffslot);
|
||||
@@ -875,8 +877,8 @@ namespace UF
|
||||
// This next field is actually a float. There is a groundspawn in freeportwest (sack of money sitting on some barrels) which requires this
|
||||
// field to be set to (float)255.0 to appear at all, and also the size field below to be 5, to be the correct size. I think SoD has the same
|
||||
// issue.
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_x); //X tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->tilt_y); //Y tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); //X tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); //Y tilt
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt.
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y);
|
||||
VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x);
|
||||
|
||||
@@ -847,7 +847,7 @@ struct BindStruct {
|
||||
*/
|
||||
static const uint32 MAX_PP_LANGUAGE = 25; //
|
||||
static const uint32 MAX_PP_SPELLBOOK = 720; // Confirmed 60 pages on Underfoot now
|
||||
static const uint32 MAX_PP_MEMSPELL = 12; //was 9 now 10 on Underfoot
|
||||
static const uint32 MAX_PP_MEMSPELL = 10; //was 9 now 10 on Underfoot
|
||||
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size
|
||||
static const uint32 MAX_PP_AA_ARRAY = 300; //was 299
|
||||
static const uint32 MAX_GROUP_MEMBERS = 6;
|
||||
@@ -917,7 +917,7 @@ struct PlayerProfile_Struct
|
||||
/*00160*/ uint32 deity; // deity
|
||||
/*00164*/ uint32 intoxication; // Alcohol level (in ticks till sober?)
|
||||
/*00168*/ uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; // Refresh time (millis) - 4 Octets Each
|
||||
/*00208*/ uint8 unknown00208[6]; // Seen 00 00 00 00 00 00 00 00 00 00 00 00 02 01
|
||||
/*00208*/ uint8 unknown00208[14]; // Seen 00 00 00 00 00 00 00 00 00 00 00 00 02 01
|
||||
/*00222*/ uint32 abilitySlotRefresh;
|
||||
/*00226*/ uint8 haircolor; // Player hair color
|
||||
/*00227*/ uint8 beardcolor; // Player beard color
|
||||
@@ -945,7 +945,7 @@ struct PlayerProfile_Struct
|
||||
/*04217*/ uint8 unknown04217[147]; // was [175]
|
||||
/*04364*/ uint32 spell_book[MAX_PP_SPELLBOOK]; // List of the Spells in spellbook 720 = 90 pages [2880] was [1920]
|
||||
/*07244*/ uint32 mem_spells[MAX_PP_MEMSPELL]; // List of spells memorized
|
||||
/*07284*/ uint8 unknown07284[20]; //#### uint8 unknown04396[32]; in Titanium ####[28]
|
||||
/*07284*/ uint8 unknown07284[28]; //#### uint8 unknown04396[32]; in Titanium ####[28]
|
||||
/*07312*/ uint32 platinum; // Platinum Pieces on player
|
||||
/*07316*/ uint32 gold; // Gold Pieces on player
|
||||
/*07320*/ uint32 silver; // Silver Pieces on player
|
||||
@@ -1921,7 +1921,8 @@ struct Merchant_Sell_Struct {
|
||||
/*004*/ uint32 playerid; // Player's entity id
|
||||
/*008*/ uint32 itemslot;
|
||||
/*012*/ uint32 unknown12;
|
||||
/*016*/ uint32 quantity;
|
||||
/*016*/ uint8 quantity; // Already sold
|
||||
/*017*/ uint8 Unknown017[3];
|
||||
/*020*/ uint32 Unknown020;
|
||||
/*024*/ uint32 price;
|
||||
/*028*/ uint32 pricehighorderbits; // It appears the price is 64 bits in Underfoot+
|
||||
@@ -3928,6 +3929,7 @@ struct AnnoyingZoneUnknown_Struct {
|
||||
|
||||
struct LoadSpellSet_Struct {
|
||||
uint8 spell[MAX_PP_MEMSPELL]; // 0 if no action
|
||||
uint16 unknown2; // is this two more spell gems?
|
||||
uint32 unknown; // there seems to be an extra field in this packet...
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ enum EQEmuExePlatform
|
||||
ExePlatformWorld,
|
||||
ExePlatformLogin,
|
||||
ExePlatformQueryServ,
|
||||
ExePlatformSocket_Server,
|
||||
ExePlatformWebInterface,
|
||||
ExePlatformUCS,
|
||||
ExePlatformLaunch,
|
||||
ExePlatformSharedMemory,
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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) { return malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
|
||||
static void Free(void *ptr) { 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 <typename BaseAllocator = CrtAllocator>
|
||||
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)
|
||||
{
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
|
||||
AddChunk(chunk_capacity_);
|
||||
}
|
||||
|
||||
//! 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<ChunkHeader*>(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();
|
||||
delete ownBaseAllocator_;
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
//! 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) {
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + 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);
|
||||
|
||||
// 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 == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
increment = RAPIDJSON_ALIGN(increment);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
void* newBuffer = Malloc(newSize);
|
||||
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||
return memcpy(newBuffer, originalPtr, originalSize);
|
||||
}
|
||||
|
||||
//! 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.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
|
||||
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.
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,270 @@
|
||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! 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 <typename Encoding, typename InputByteStream>
|
||||
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_;
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with 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, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
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); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
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<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::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 <typename CharType, typename InputByteStream>
|
||||
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) {
|
||||
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 = (const unsigned char *)is_->Peek4();
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = 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_) {
|
||||
unsigned 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.
|
||||
switch (type_) {
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid type
|
||||
}
|
||||
}
|
||||
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
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 InputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
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) {
|
||||
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid UTFType
|
||||
}
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
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); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
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
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
@@ -0,0 +1,610 @@
|
||||
#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++)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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<typename OutputStream>
|
||||
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 <typename InputStream>
|
||||
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 <typename InputStream, typename OutputStream>
|
||||
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 <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is);
|
||||
|
||||
//! Take a character from input byte stream.
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is);
|
||||
|
||||
//! Put BOM to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os);
|
||||
|
||||
//! Put a character to output byte stream.
|
||||
template <typename OutputByteStream>
|
||||
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<typename CharType = char>
|
||||
struct UTF8 {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
if (codepoint <= 0x7F)
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
else if (codepoint <= 0x7FF) {
|
||||
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) {
|
||||
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
|
||||
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c = is.Take();
|
||||
if (!(c & 0x80)) {
|
||||
*codepoint = (unsigned char)c;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char type = GetRange((unsigned char)c);
|
||||
*codepoint = (0xFF >> type) & (unsigned char)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 <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
#define COPY() os.Put(c = is.Take())
|
||||
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||
#define TAIL() COPY(); TRANS(0x70)
|
||||
Ch c;
|
||||
COPY();
|
||||
if (!(c & 0x80))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
switch (GetRange((unsigned char)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 <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
Ch c = Take(is);
|
||||
if ((unsigned char)c != 0xEFu) return c;
|
||||
c = is.Take();
|
||||
if ((unsigned char)c != 0xBBu) return c;
|
||||
c = is.Take();
|
||||
if ((unsigned char)c != 0xBFu) return c;
|
||||
c = is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return is.Take();
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(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<typename CharType = wchar_t>
|
||||
struct UTF16 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
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<typename OutputStream::Ch>(codepoint));
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
unsigned v = codepoint - 0x10000;
|
||||
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||
os.Put((v & 0x3FF) | 0xDC00);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
Ch c = is.Take();
|
||||
if (c < 0xD800 || c > 0xDFFF) {
|
||||
*codepoint = c;
|
||||
return true;
|
||||
}
|
||||
else if (c <= 0xDBFF) {
|
||||
*codepoint = (c & 0x3FF) << 10;
|
||||
c = is.Take();
|
||||
*codepoint |= (c & 0x3FF);
|
||||
*codepoint += 0x10000;
|
||||
return c >= 0xDC00 && c <= 0xDFFF;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||
Ch c;
|
||||
os.Put(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<typename CharType = wchar_t>
|
||||
struct UTF16LE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take();
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFFu); os.Put(0xFEu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-16 big endian encoding.
|
||||
template<typename CharType = wchar_t>
|
||||
struct UTF16BE : UTF16<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFEu); os.Put(0xFFu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(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<typename CharType = unsigned>
|
||||
struct UTF32 {
|
||||
typedef CharType Ch;
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||
os.Put(codepoint);
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
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 <typename InputStream, typename OutputStream>
|
||||
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<typename CharType = unsigned>
|
||||
struct UTF32LE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take();
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take() << 16;
|
||||
c |= (unsigned char)is.Take() << 24;
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(c & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put((c >> 16) & 0xFFu);
|
||||
os.Put((c >> 24) & 0xFFu);
|
||||
}
|
||||
};
|
||||
|
||||
//! UTF-32 big endian encoding.
|
||||
template<typename CharType = unsigned>
|
||||
struct UTF32BE : UTF32<CharType> {
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = Take(is);
|
||||
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
CharType c = (unsigned char)is.Take() << 24;
|
||||
c |= (unsigned char)is.Take() << 16;
|
||||
c |= (unsigned char)is.Take() << 8;
|
||||
c |= (unsigned char)is.Take();
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, CharType c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put((c >> 24) & 0xFFu);
|
||||
os.Put((c >> 16) & 0xFFu);
|
||||
os.Put((c >> 8) & 0xFFu);
|
||||
os.Put(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<typename CharType = char>
|
||||
struct ASCII {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 0 };
|
||||
|
||||
template<typename OutputStream>
|
||||
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||
}
|
||||
|
||||
template <typename InputStream>
|
||||
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||
unsigned char c = static_cast<unsigned char>(is.Take());
|
||||
*codepoint = c;
|
||||
return c <= 0X7F;
|
||||
}
|
||||
|
||||
template <typename InputStream, typename OutputStream>
|
||||
static bool Validate(InputStream& is, OutputStream& os) {
|
||||
unsigned char c = is.Take();
|
||||
os.Put(c);
|
||||
return c <= 0x7F;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static CharType TakeBOM(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
Ch c = Take(is);
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename InputByteStream>
|
||||
static Ch Take(InputByteStream& is) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
return is.Take();
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void PutBOM(OutputByteStream& os) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
(void)os;
|
||||
}
|
||||
|
||||
template <typename OutputByteStream>
|
||||
static void Put(OutputByteStream& os, Ch c) {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
os.Put(static_cast<typename OutputByteStream::Ch>(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<typename CharType>
|
||||
struct AutoUTF {
|
||||
typedef CharType Ch;
|
||||
|
||||
enum { supportUnicode = 1 };
|
||||
|
||||
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||
|
||||
template<typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static 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 <typename InputStream>
|
||||
RAPIDJSON_FORCEINLINE static 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 <typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static 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<typename SourceEncoding, typename TargetEncoding>
|
||||
struct Transcoder {
|
||||
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
TargetEncoding::Encode(os, codepoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Validate one Unicode codepoint from an encoded stream.
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||
}
|
||||
};
|
||||
|
||||
//! Specialization of Transcoder with same source and target encoding.
|
||||
template<typename Encoding>
|
||||
struct Transcoder<Encoding, Encoding> {
|
||||
template<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static 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<typename InputStream, typename OutputStream>
|
||||
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSV_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef RAPIDJSON_ERROR_EN_H__
|
||||
#define RAPIDJSON_ERROR_EN_H__
|
||||
|
||||
#include "error.h"
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
/*!
|
||||
\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 kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array.");
|
||||
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow 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.");
|
||||
case kParseErrorStackSizeLimitExceeded: return RAPIDJSON_ERROR_STRING("Parsing stack size limit is exceeded.");
|
||||
|
||||
default:
|
||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_ERROR_EN_H__
|
||||
@@ -0,0 +1,124 @@
|
||||
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
||||
#define RAPIDJSON_ERROR_ERROR_H__
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ERROR_CHARTYPE
|
||||
|
||||
//! Character type of error messages.
|
||||
/*! The default charater type is char.
|
||||
On Windows, user can define this macro as 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 RAPIDJSON_ERROR_CHARTYPE[].
|
||||
/*! By default this conversion macro does nothing.
|
||||
On Windows, user can define this macro as _T(x) for supporting both
|
||||
unicode/non-unicode settings.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ERROR_STRING
|
||||
#define RAPIDJSON_ERROR_STRING(x) x
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ParseErrorCode
|
||||
|
||||
//! Error code of parsing.
|
||||
/*! \see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||
*/
|
||||
enum ParseErrorCode {
|
||||
kParseErrorNone = 0, //!< No error.
|
||||
|
||||
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||
kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array.
|
||||
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.
|
||||
kParseErrorStackSizeLimitExceeded //!< Parsing stack size limit is exceeded.
|
||||
};
|
||||
|
||||
//! Result of parsing (wraps ParseErrorCode)
|
||||
/*!
|
||||
\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 {
|
||||
|
||||
//! 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_; }
|
||||
|
||||
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||
operator bool() const { return !IsError(); }
|
||||
//! 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_; }
|
||||
|
||||
//! 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().
|
||||
/*! This is the prototype for GetParseError_X(), where 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);
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_ERROR_ERROR_H__
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! 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(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<size_t>(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_ = fread(buffer_, 1, bufferSize_, fp_);
|
||||
bufferLast_ = buffer_ + readCount_ - 1;
|
||||
current_ = buffer_;
|
||||
|
||||
if (readCount_ < bufferSize_) {
|
||||
buffer_[readCount_] = '\0';
|
||||
++bufferLast_;
|
||||
eof_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef RAPIDJSON_FILESTREAM_H_
|
||||
#define RAPIDJSON_FILESTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! (Depreciated) Wrapper of C file stream for input or output.
|
||||
/*!
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\note implements Stream concept
|
||||
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
|
||||
*/
|
||||
class FileStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
void Flush() { fflush(fp_); }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileStream(const FileStream&);
|
||||
FileStream& operator=(const FileStream&);
|
||||
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else if (current_ != '\0')
|
||||
current_ = '\0';
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
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<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
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&);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
//@cond RAPIDJSON_INTERNAL
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
template <int N> struct IntegralC { enum { Value = N }; };
|
||||
template <bool Cond> struct BoolType : IntegralC<Cond> {};
|
||||
struct TrueType : BoolType<true> {};
|
||||
struct FalseType : BoolType<false> {};
|
||||
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
template <bool Condition, typename T1, typename T2> struct SelectIfCond;
|
||||
template <typename T1, typename T2> struct SelectIfCond<true,T1,T2> { typedef T1 Type; };
|
||||
template <typename T1, typename T2> struct SelectIfCond<false,T1,T2> { typedef T2 Type; };
|
||||
|
||||
template <typename Condition, typename T1, typename T2>
|
||||
struct SelectIf : SelectIfCond<Condition::Value,T1,T2> {};
|
||||
|
||||
template <bool Constify, typename T>
|
||||
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T,T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst {
|
||||
enum { Value =
|
||||
( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
|
||||
&& ( IsConst<CT>::Value >= IsConst<T>::Value ) )
|
||||
};
|
||||
};
|
||||
|
||||
template <bool Condition, typename T = void> struct EnableIfCond;
|
||||
template <typename T> struct EnableIfCond<true, T> { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void>
|
||||
struct DisableIfCond : EnableIfCond<!Condition, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeResultTag {};
|
||||
template <typename T> struct RemoveSfinaeFptr {};
|
||||
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::rapidjson::internal::RemoveSfinaeFptr \
|
||||
< ::rapidjson::internal::SfinaeResultTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::rapidjson::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
|
||||
|
||||
} // namespace internal
|
||||
} // namespace rapidjson
|
||||
//@endcond
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||
+9
-4
@@ -42,7 +42,7 @@ public:
|
||||
stack_top_ = stack_ + size;
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
T* ret = (T*)stack_top_;
|
||||
T* ret = reinterpret_cast<T*>(stack_top_);
|
||||
stack_top_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
@@ -51,23 +51,28 @@ public:
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stack_top_ -= count * sizeof(T);
|
||||
return (T*)stack_top_;
|
||||
return reinterpret_cast<T*>(stack_top_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return (T*)(stack_top_ - sizeof(T));
|
||||
return reinterpret_cast<T*>(stack_top_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
|
||||
Allocator& GetAllocator() { return *allocator_; }
|
||||
size_t GetSize() const { return stack_top_ - stack_; }
|
||||
bool Empty() const { return stack_top_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stack_top_ - stack_); }
|
||||
size_t GetCapacity() const { return stack_capacity_; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
+1
-2
@@ -13,8 +13,7 @@ namespace internal {
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p != '\0')
|
||||
++p;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
// 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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"
|
||||
|
||||
// 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_INTTYPES_H_ ]
|
||||
+18
-5
@@ -1,7 +1,7 @@
|
||||
// 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-2008 Alexander Chemeris
|
||||
// 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:
|
||||
@@ -13,8 +13,9 @@
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. The name of the author may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
// 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
|
||||
@@ -40,6 +41,11 @@
|
||||
#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 >= 1700 // [
|
||||
#include <stdint.h>
|
||||
#else // ] _MSC_VER >= 1700 [
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
@@ -238,10 +244,17 @@ typedef uint64_t uintmax_t;
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#endif // _MSC_VER >= 1600 ]
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
@@ -0,0 +1,195 @@
|
||||
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||
#define RAPIDJSON_PRETTYWRITER_H_
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! Writer with indentation and spacing.
|
||||
/*!
|
||||
\tparam OutputStream Type of ouptut os.
|
||||
\tparam SourceEncoding Encoding of source string.
|
||||
\tparam TargetEncoding Encoding of output stream.
|
||||
\tparam Allocator Type of allocator for allocating memory of stack.
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> {
|
||||
public:
|
||||
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> 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.
|
||||
*/
|
||||
PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
//! Overridden for fluent API, see \ref Writer::SetDoublePrecision()
|
||||
PrettyWriter& SetDoublePrecision(int p) { Base::SetDoublePrecision(p); return *this; }
|
||||
|
||||
//! 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;
|
||||
}
|
||||
|
||||
/*! @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 String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::WriteString(str, length);
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
if (!Base::WriteEndObject())
|
||||
return false;
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
PrettyPrefix(kArrayType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) 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<typename Base::Level>()->inArray);
|
||||
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
if (!Base::WriteEndArray())
|
||||
return false;
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
//! Overridden for fluent API, see \ref Writer::Double()
|
||||
bool Double(double d, int precision) {
|
||||
int oldPrecision = Base::GetDoublePrecision();
|
||||
SetDoublePrecision(precision);
|
||||
bool ret = Double(d);
|
||||
SetDoublePrecision(oldPrecision);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//@}
|
||||
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<typename Base::Level>();
|
||||
|
||||
if (level->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else
|
||||
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(type == kObjectType || type == kArrayType);
|
||||
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_, indentChar_, count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
@@ -0,0 +1,397 @@
|
||||
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||
#define RAPIDJSON_RAPIDJSON_H_
|
||||
|
||||
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
||||
// Version 0.1
|
||||
|
||||
/*!\file rapidjson.h
|
||||
\brief common definitions and configuration
|
||||
|
||||
\todo Complete Doxygen documentation for configure macros.
|
||||
*/
|
||||
|
||||
#include <cstdlib> // malloc(), realloc(), free()
|
||||
#include <cstring> // memcpy()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_INT64DEFINE
|
||||
|
||||
// Here defines int64_t and uint64_t types in global namespace as well as the
|
||||
// (U)INT64_C constant macros.
|
||||
// If user have their own definition, can define RAPIDJSON_NO_INT64DEFINE to disable this.
|
||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#include "msinttypes/stdint.h"
|
||||
#include "msinttypes/inttypes.h"
|
||||
#else
|
||||
// Other compilers should have this.
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
//!@endcond
|
||||
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_FORCEINLINE
|
||||
|
||||
#ifndef RAPIDJSON_FORCEINLINE
|
||||
#ifdef _MSC_VER
|
||||
#define RAPIDJSON_FORCEINLINE __forceinline
|
||||
#else
|
||||
#define RAPIDJSON_FORCEINLINE
|
||||
#endif
|
||||
#endif // RAPIDJSON_FORCEINLINE
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ENDIAN
|
||||
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||
|
||||
//! Endianness of the machine.
|
||||
/*! 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.
|
||||
|
||||
Implemented with reference to
|
||||
https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
|
||||
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 endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif // __BYTE_ORDER__
|
||||
// Detect with GLIBC's endian.h
|
||||
# elif defined(__GLIBC__)
|
||||
# include <endian.h>
|
||||
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||
# else
|
||||
# error Unknown machine endianess 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
|
||||
# else
|
||||
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||
# endif
|
||||
#endif // RAPIDJSON_ENDIAN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ALIGNSIZE
|
||||
|
||||
//! Data alignment of the machine.
|
||||
/*!
|
||||
Some machine requires strict data alignment.
|
||||
Currently the default uses 4 bytes alignment. User can customize this.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ALIGN
|
||||
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||
|
||||
// Enable SSE2 optimization.
|
||||
//#define RAPIDJSON_SSE2
|
||||
|
||||
// Enable SSE4.2 optimization.
|
||||
//#define RAPIDJSON_SSE42
|
||||
|
||||
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||
#define RAPIDJSON_SIMD
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
|
||||
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||
namespace rapidjson {
|
||||
//! Use 32-bit array/string indices even for 64-bit platform, instead of using size_t.
|
||||
/*! User may override the SizeType by defining RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||
*/
|
||||
typedef unsigned SizeType;
|
||||
} // namespace rapidjson
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_ASSERT
|
||||
|
||||
//! Assertion.
|
||||
/*! By default, rapidjson uses C assert() for assertion.
|
||||
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||
*/
|
||||
#ifndef RAPIDJSON_ASSERT
|
||||
#include <cassert>
|
||||
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||
#endif // RAPIDJSON_ASSERT
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_STATIC_ASSERT
|
||||
|
||||
// Adopt from boost
|
||||
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||
namespace rapidjson {
|
||||
|
||||
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||
template<int x> struct StaticAssertTest {};
|
||||
} // namespace rapidjson
|
||||
|
||||
#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
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
||||
#else
|
||||
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#endif
|
||||
//!@endcond
|
||||
|
||||
/*! \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::StaticAssertTest<\
|
||||
sizeof(::rapidjson::STATIC_ASSERTION_FAILURE<bool(x) >)>\
|
||||
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||
#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))
|
||||
|
||||
// token stringification
|
||||
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
|
||||
#define RAPIDJSON_DO_STRINGIFY(x) #x
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||
|
||||
#if defined(__clang__) || (defined(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= 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(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= 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_*
|
||||
|
||||
//!@endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Allocators and Encodings
|
||||
|
||||
#include "allocators.h"
|
||||
#include "encodings.h"
|
||||
|
||||
//! main RapidJSON namespace
|
||||
namespace rapidjson {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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<typename Stream>
|
||||
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<StringStream>.
|
||||
*/
|
||||
enum { copyOptimization = 0 };
|
||||
};
|
||||
|
||||
//! Put N copies of a character to a stream.
|
||||
template<typename Stream, typename Ch>
|
||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
stream.Put(c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// StringStream
|
||||
|
||||
//! Read-only string stream.
|
||||
/*! \note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
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<size_t>(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 <typename Encoding>
|
||||
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! String stream with UTF8 encoding.
|
||||
typedef GenericStringStream<UTF8<> > StringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InsituStringStream
|
||||
|
||||
//! A read-write string stream.
|
||||
/*! This string stream is particularly designed for in-situ parsing.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding>
|
||||
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<size_t>(src_ - head_); }
|
||||
|
||||
// Write
|
||||
Ch* PutBegin() { return dst_ = src_; }
|
||||
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||
void Flush() {}
|
||||
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
|
||||
|
||||
Ch* src_;
|
||||
Ch* dst_;
|
||||
Ch* head_;
|
||||
};
|
||||
|
||||
template <typename Encoding>
|
||||
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||
enum { copyOptimization = 1 };
|
||||
};
|
||||
|
||||
//! Insitu string stream with UTF8 encoding.
|
||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Type
|
||||
|
||||
//! 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
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
File diff suppressed because it is too large
Load Diff
+5
-3
@@ -10,7 +10,7 @@ namespace rapidjson {
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\implements Stream
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
struct GenericStringBuffer {
|
||||
@@ -19,10 +19,11 @@ struct GenericStringBuffer {
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
|
||||
const char* GetString() const {
|
||||
const Ch* GetString() const {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.template Pop<Ch>(1);
|
||||
@@ -30,12 +31,13 @@ struct GenericStringBuffer {
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t Size() const { return stack_.GetSize(); }
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
@@ -0,0 +1,387 @@
|
||||
#ifndef RAPIDJSON_WRITER_H_
|
||||
#define RAPIDJSON_WRITER_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strfunc.h"
|
||||
#include <cstdio> // snprintf() or _sprintf_s()
|
||||
#include <new> // placement new
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
//! 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 Allocator Type of allocator for allocating memory of stack.
|
||||
\note implements Handler concept
|
||||
*/
|
||||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
|
||||
class Writer {
|
||||
public:
|
||||
typedef typename SourceEncoding::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.
|
||||
*/
|
||||
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)),
|
||||
doublePrecision_(kDefaultDoublePrecision), hasRoot_(false) {}
|
||||
|
||||
//! 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<OutputStream> writer(os1);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
|
||||
writer.Reset(os2);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
\endcode
|
||||
*/
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
doublePrecision_ = kDefaultDoublePrecision;
|
||||
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();
|
||||
}
|
||||
|
||||
//! Set the number of significant digits for \c double values
|
||||
/*! When writing a \c double value to the \c OutputStream, the number
|
||||
of significant digits is limited to 6 by default.
|
||||
\param p maximum number of significant digits (default: 6)
|
||||
\return The Writer itself for fluent API.
|
||||
*/
|
||||
Writer& SetDoublePrecision(int p = kDefaultDoublePrecision) {
|
||||
if (p < 0) p = kDefaultDoublePrecision; // negative precision is ignored
|
||||
doublePrecision_ = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \see SetDoublePrecision()
|
||||
int GetDoublePrecision() const { return doublePrecision_; }
|
||||
|
||||
/*!@name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { Prefix(kNullType); return WriteNull(); }
|
||||
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
|
||||
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
|
||||
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
|
||||
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
|
||||
|
||||
//! Writes the given \c double value to the stream
|
||||
/*!
|
||||
The number of significant digits (the precision) to be written
|
||||
can be set by \ref SetDoublePrecision() for the Writer:
|
||||
\code
|
||||
Writer<...> writer(...);
|
||||
writer.SetDoublePrecision(12).Double(M_PI);
|
||||
\endcode
|
||||
\param d The value to be written.
|
||||
\return Whether it is succeed.
|
||||
*/
|
||||
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
return WriteString(str, length);
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
return WriteStartObject();
|
||||
}
|
||||
|
||||
bool EndObject(SizeType memberCount = 0) {
|
||||
(void)memberCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
bool ret = WriteEndObject();
|
||||
if (level_stack_.Empty()) // end of json text
|
||||
os_->Flush();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
Prefix(kArrayType);
|
||||
new (level_stack_.template Push<Level>()) Level(true);
|
||||
return WriteStartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType elementCount = 0) {
|
||||
(void)elementCount;
|
||||
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||
level_stack_.template Pop<Level>(1);
|
||||
bool ret = WriteEndArray();
|
||||
if (level_stack_.Empty()) // end of json text
|
||||
os_->Flush();
|
||||
return ret;
|
||||
}
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Writes the given \c double value to the stream (explicit precision)
|
||||
/*!
|
||||
The currently set double precision is ignored in favor of the explicitly
|
||||
given precision for this value.
|
||||
\see Double(), SetDoublePrecision(), GetDoublePrecision()
|
||||
\param d The value to be written
|
||||
\param precision The number of significant digits for this value
|
||||
\return Whether it is succeeded.
|
||||
*/
|
||||
bool Double(double d, int precision) {
|
||||
int oldPrecision = GetDoublePrecision();
|
||||
SetDoublePrecision(precision);
|
||||
bool ret = Double(d);
|
||||
SetDoublePrecision(oldPrecision);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
|
||||
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() {
|
||||
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
|
||||
}
|
||||
|
||||
bool WriteBool(bool b) {
|
||||
if (b) {
|
||||
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
|
||||
}
|
||||
else {
|
||||
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
os_->Put('-');
|
||||
i = -i;
|
||||
}
|
||||
return WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
os_->Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u64 % 10) + '0';
|
||||
u64 /= 10;
|
||||
} while (u64 > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define RAPIDJSON_SNPRINTF sprintf_s
|
||||
#else
|
||||
#define RAPIDJSON_SNPRINTF snprintf
|
||||
#endif
|
||||
|
||||
//! \todo Optimization with custom double-to-string converter.
|
||||
bool WriteDouble(double d) {
|
||||
char buffer[100];
|
||||
int ret = RAPIDJSON_SNPRINTF(buffer, sizeof(buffer), "%.*g", doublePrecision_, d);
|
||||
RAPIDJSON_ASSERT(ret >= 1);
|
||||
for (int i = 0; i < ret; i++)
|
||||
os_->Put(buffer[i]);
|
||||
return true;
|
||||
}
|
||||
#undef RAPIDJSON_SNPRINTF
|
||||
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const 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
|
||||
};
|
||||
|
||||
os_->Put('\"');
|
||||
GenericStringStream<SourceEncoding> is(str);
|
||||
while (is.Tell() < length) {
|
||||
const Ch c = is.Peek();
|
||||
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
|
||||
// Unicode escaping
|
||||
unsigned codepoint;
|
||||
if (!SourceEncoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
os_->Put('\\');
|
||||
os_->Put('u');
|
||||
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
||||
os_->Put(hexDigits[(codepoint >> 12) & 15]);
|
||||
os_->Put(hexDigits[(codepoint >> 8) & 15]);
|
||||
os_->Put(hexDigits[(codepoint >> 4) & 15]);
|
||||
os_->Put(hexDigits[(codepoint ) & 15]);
|
||||
}
|
||||
else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) {
|
||||
// Surrogate pair
|
||||
unsigned s = codepoint - 0x010000;
|
||||
unsigned lead = (s >> 10) + 0xD800;
|
||||
unsigned trail = (s & 0x3FF) + 0xDC00;
|
||||
os_->Put(hexDigits[(lead >> 12) & 15]);
|
||||
os_->Put(hexDigits[(lead >> 8) & 15]);
|
||||
os_->Put(hexDigits[(lead >> 4) & 15]);
|
||||
os_->Put(hexDigits[(lead ) & 15]);
|
||||
os_->Put('\\');
|
||||
os_->Put('u');
|
||||
os_->Put(hexDigits[(trail >> 12) & 15]);
|
||||
os_->Put(hexDigits[(trail >> 8) & 15]);
|
||||
os_->Put(hexDigits[(trail >> 4) & 15]);
|
||||
os_->Put(hexDigits[(trail ) & 15]);
|
||||
}
|
||||
else
|
||||
return false; // invalid code point
|
||||
}
|
||||
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
|
||||
is.Take();
|
||||
os_->Put('\\');
|
||||
os_->Put(escape[(unsigned char)c]);
|
||||
if (escape[(unsigned char)c] == 'u') {
|
||||
os_->Put('0');
|
||||
os_->Put('0');
|
||||
os_->Put(hexDigits[(unsigned char)c >> 4]);
|
||||
os_->Put(hexDigits[(unsigned char)c & 0xF]);
|
||||
}
|
||||
}
|
||||
else
|
||||
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_);
|
||||
}
|
||||
os_->Put('\"');
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteStartObject() { os_->Put('{'); return true; }
|
||||
bool WriteEndObject() { os_->Put('}'); return true; }
|
||||
bool WriteStartArray() { os_->Put('['); return true; }
|
||||
bool WriteEndArray() { os_->Put(']'); return true; }
|
||||
|
||||
void Prefix(Type type) {
|
||||
(void)type;
|
||||
if (level_stack_.GetSize() != 0) { // this value is not at root
|
||||
Level* level = level_stack_.template Top<Level>();
|
||||
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(type == kObjectType || type == kArrayType);
|
||||
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
|
||||
hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream* os_;
|
||||
internal::Stack<Allocator> level_stack_;
|
||||
int doublePrecision_;
|
||||
bool hasRoot_;
|
||||
|
||||
static const int kDefaultDoublePrecision = 6;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Writer(const Writer&);
|
||||
Writer& operator=(const Writer&);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_RAPIDJSON_H_
|
||||
@@ -144,9 +144,6 @@ RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing t
|
||||
RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots
|
||||
RULE_BOOL(Character, EnableAvoidanceCap, false)
|
||||
RULE_INT(Character, AvoidanceCap, 750) // 750 Is a pretty good value, seen people dodge all attacks beyond 1,000 Avoidance
|
||||
RULE_BOOL(Character, AllowMQTarget, false) // Disables putting players in the 'hackers' list for targeting beyond the clip plane or attempting to target something untargetable
|
||||
RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound behavior
|
||||
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Mercs)
|
||||
@@ -208,7 +205,6 @@ RULE_INT(World, ExemptMaxClientsStatus, -1) // Exempt accounts from the MaxClien
|
||||
RULE_INT(World, AddMaxClientsPerIP, -1) // Maximum number of clients allowed to connect per IP address if account status is < ExemptMaxClientsStatus. Default value: -1 (feature disabled)
|
||||
RULE_INT(World, AddMaxClientsStatus, -1) // Accounts with status >= this rule will be allowed to use the amount of accounts defined in the AddMaxClientsPerIP. Default value: -1 (feature disabled)
|
||||
RULE_BOOL(World, MaxClientsSetByStatus, false) // If True, IP Limiting will be set to the status on the account as long as the status is > MaxClientsPerIP
|
||||
RULE_BOOL(World, EnableIPExemptions, false) // If True, ip_exemptions table is used, if there is no entry for the IP it will default to RuleI(World, MaxClientsPerIP)
|
||||
RULE_BOOL(World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots.
|
||||
RULE_BOOL(World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks.
|
||||
RULE_INT(World, AccountSessionLimit, -1) //Max number of characters allowed on at once from a single account (-1 is disabled)
|
||||
@@ -386,7 +382,6 @@ RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false) // ignore LAA level if true
|
||||
RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc
|
||||
RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg
|
||||
RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though
|
||||
RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the target type to single target.
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY(Combat)
|
||||
|
||||
+7
-11
@@ -193,10 +193,15 @@
|
||||
#define ServerOP_QSSendQuery 0x5016
|
||||
#define ServerOP_CZSignalNPC 0x5017
|
||||
#define ServerOP_CZSetEntityVariableByNPCTypeID 0x5018
|
||||
#define ServerOP_WWMarquee 0x5019
|
||||
|
||||
#define ServerOP_WIRemoteCall 0x5001
|
||||
#define ServerOP_WIRemoteCallResponse 0x5002
|
||||
#define ServerOP_WIRemoteCallToClient 0x5003
|
||||
#define ServerOP_WIClientSession 0x5004
|
||||
#define ServerOP_WIClientSessionResponse 0x5005
|
||||
|
||||
/* Query Serv Generic Packet Flag/Type Enumeration */
|
||||
enum { QSG_LFGuild = 0 };
|
||||
enum { QSG_LFGuild = 0 };
|
||||
enum { QSG_LFGuild_PlayerMatches = 0, QSG_LFGuild_UpdatePlayerInfo, QSG_LFGuild_RequestPlayerInfo, QSG_LFGuild_UpdateGuildInfo, QSG_LFGuild_GuildMatches,
|
||||
QSG_LFGuild_RequestGuildInfo };
|
||||
|
||||
@@ -1255,15 +1260,6 @@ struct CZMessagePlayer_Struct {
|
||||
char Message[512];
|
||||
};
|
||||
|
||||
struct WWMarquee_Struct {
|
||||
uint32 Type;
|
||||
uint32 Priority;
|
||||
uint32 FadeIn;
|
||||
uint32 FadeOut;
|
||||
uint32 Duration;
|
||||
char Message[512];
|
||||
};
|
||||
|
||||
struct CZSetEntVarByNPCTypeID_Struct {
|
||||
uint32 npctype_id;
|
||||
char id[256];
|
||||
|
||||
@@ -2052,3 +2052,27 @@ void SharedDatabase::SaveCharacterInspectMessage(uint32 character_id, const Insp
|
||||
std::string query = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message) VALUES (%u, '%s')", character_id, EscapeString(message->text).c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
}
|
||||
|
||||
bool SharedDatabase::VerifyToken(std::string token, int& status) {
|
||||
status = 0;
|
||||
if (token.length() > 64) {
|
||||
token = token.substr(0, 64);
|
||||
}
|
||||
|
||||
token = EscapeString(token);
|
||||
std::string query = StringFormat("SELECT status FROM tokens WHERE token='%s'", token.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
{
|
||||
std::cerr << "Error in SharedDatabase::VerifyToken query '" << query << "' " << results.ErrorMessage() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
status = atoi(row[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,9 @@ class SharedDatabase : public Database
|
||||
ItemInst* CreateItem(const EQEmu::ItemBase* item, int16 charges = 0, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, uint8 attuned = 0);
|
||||
ItemInst* CreateBaseItem(const EQEmu::ItemBase* item, int16 charges = 0);
|
||||
|
||||
// Web Token Verification
|
||||
bool VerifyToken(std::string token, int& status);
|
||||
|
||||
/*
|
||||
Shared Memory crap
|
||||
*/
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <streambuf>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Util {
|
||||
class MemoryBuffer : public std::streambuf
|
||||
{
|
||||
public:
|
||||
MemoryBuffer(char* base, size_t size) {
|
||||
setg(base, base, base + size);
|
||||
setp(base, base + size);
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryStreamWriter : virtual MemoryBuffer, public std::ostream
|
||||
{
|
||||
public:
|
||||
MemoryStreamWriter(char* base, size_t size) : MemoryBuffer(base, size), std::ostream(static_cast<std::streambuf*>(this)) { }
|
||||
};
|
||||
|
||||
class MemoryStreamReader : virtual MemoryBuffer, public std::istream
|
||||
{
|
||||
public:
|
||||
MemoryStreamReader(char* base, size_t size) : MemoryBuffer(base, size), std::istream(static_cast<std::streambuf*>(this)) { }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
#include "uuid.h"
|
||||
|
||||
#include <core/logsys.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <objbase.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CFUUID.h>
|
||||
#endif
|
||||
|
||||
unsigned char hexDigitToChar(char ch)
|
||||
{
|
||||
if (ch > 47 && ch < 58)
|
||||
return ch - 48;
|
||||
|
||||
if (ch > 96 && ch < 103)
|
||||
return ch - 87;
|
||||
|
||||
if (ch > 64 && ch < 71)
|
||||
return ch - 55;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char hexPairToChar(char a, char b)
|
||||
{
|
||||
return hexDigitToChar(a) * 16 + hexDigitToChar(b);
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID()
|
||||
{
|
||||
m_bytes = std::vector<char>(16, 0);
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID(const unsigned char *bytes)
|
||||
{
|
||||
m_bytes.assign(bytes, bytes + 16);
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID(const UUID &o)
|
||||
{
|
||||
m_bytes = o.m_bytes;
|
||||
}
|
||||
|
||||
EQ::Util::UUID::UUID(UUID &&o)
|
||||
{
|
||||
std::swap(m_bytes, o.m_bytes);
|
||||
}
|
||||
|
||||
EQ::Util::UUID& EQ::Util::UUID::operator=(const UUID &o)
|
||||
{
|
||||
m_bytes = o.m_bytes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EQ::Util::UUID::~UUID()
|
||||
{
|
||||
}
|
||||
|
||||
EQ::Util::UUID EQ::Util::UUID::Generate()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
GUID id;
|
||||
CoCreateGuid(&id);
|
||||
|
||||
const unsigned char buffer[16] =
|
||||
{
|
||||
static_cast<unsigned char>((id.Data1 >> 24) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data1 >> 16) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data1 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data1) & 0xff),
|
||||
static_cast<unsigned char>((id.Data2 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data2) & 0xff),
|
||||
static_cast<unsigned char>((id.Data3 >> 8) & 0xFF),
|
||||
static_cast<unsigned char>((id.Data3) & 0xFF),
|
||||
id.Data4[0],
|
||||
id.Data4[1],
|
||||
id.Data4[2],
|
||||
id.Data4[3],
|
||||
id.Data4[4],
|
||||
id.Data4[5],
|
||||
id.Data4[6],
|
||||
id.Data4[7]
|
||||
};
|
||||
|
||||
return buffer;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
uuid_t id;
|
||||
uuid_generate(id);
|
||||
return id;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
auto id = CFUUIDCreate(nullptr);
|
||||
auto bytes = CFUUIDGetUUIDBytes(id);
|
||||
|
||||
const unsigned char buffer[16] =
|
||||
{
|
||||
bytes.byte0,
|
||||
bytes.byte1,
|
||||
bytes.byte2,
|
||||
bytes.byte3,
|
||||
bytes.byte4,
|
||||
bytes.byte5,
|
||||
bytes.byte6,
|
||||
bytes.byte7,
|
||||
bytes.byte8,
|
||||
bytes.byte9,
|
||||
bytes.byte10,
|
||||
bytes.byte11,
|
||||
bytes.byte12,
|
||||
bytes.byte13,
|
||||
bytes.byte14,
|
||||
bytes.byte15
|
||||
};
|
||||
|
||||
CFRelease(id);
|
||||
|
||||
return buffer;
|
||||
#endif
|
||||
}
|
||||
|
||||
EQ::Util::UUID EQ::Util::UUID::FromString(const std::string &str)
|
||||
{
|
||||
UUID ret;
|
||||
ret.m_bytes.clear();
|
||||
|
||||
size_t i = 0;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
ret.m_bytes.push_back(hexPairToChar(str[i], str[i + 1])); ++i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EQ::Util::UUID EQ::Util::UUID::FromByteArray(const char *buffer)
|
||||
{
|
||||
return UUID((unsigned char*)buffer);
|
||||
}
|
||||
|
||||
std::string EQ::Util::UUID::ToString() const
|
||||
{
|
||||
return fmt::format("{:0<2x}{:0<2x}{:0<2x}{:0<2x}-{:0<2x}{:0<2x}-{:0<2x}{:0<2x}-{:0<2x}{:0<2x}-{:0<2x}{:0<2x}{:0<2x}{:0<2x}{:0<2x}{:0<2x}",
|
||||
(unsigned char)m_bytes[0],
|
||||
(unsigned char)m_bytes[1],
|
||||
(unsigned char)m_bytes[2],
|
||||
(unsigned char)m_bytes[3],
|
||||
(unsigned char)m_bytes[4],
|
||||
(unsigned char)m_bytes[5],
|
||||
(unsigned char)m_bytes[6],
|
||||
(unsigned char)m_bytes[7],
|
||||
(unsigned char)m_bytes[8],
|
||||
(unsigned char)m_bytes[9],
|
||||
(unsigned char)m_bytes[10],
|
||||
(unsigned char)m_bytes[11],
|
||||
(unsigned char)m_bytes[12],
|
||||
(unsigned char)m_bytes[13],
|
||||
(unsigned char)m_bytes[14],
|
||||
(unsigned char)m_bytes[15]);
|
||||
}
|
||||
|
||||
const std::vector<char>& EQ::Util::UUID::ToByteArray() const
|
||||
{
|
||||
return m_bytes;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ios>
|
||||
|
||||
namespace EQ
|
||||
{
|
||||
namespace Util
|
||||
{
|
||||
class UUID
|
||||
{
|
||||
public:
|
||||
UUID(const UUID &o);
|
||||
UUID(UUID &&o);
|
||||
UUID& operator=(const UUID &o);
|
||||
~UUID();
|
||||
|
||||
static UUID Generate();
|
||||
static UUID FromString(const std::string &str);
|
||||
static UUID FromByteArray(const char *buffer);
|
||||
|
||||
std::string ToString() const;
|
||||
const std::vector<char>& ToByteArray() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &os, const UUID &id) {
|
||||
return os << id.ToString();
|
||||
}
|
||||
private:
|
||||
UUID();
|
||||
UUID(const unsigned char *bytes);
|
||||
std::vector<char> m_bytes;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "uuid.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <rpc.h>
|
||||
#else
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
std::string CreateUUID() {
|
||||
#ifdef WIN32
|
||||
UUID uuid;
|
||||
UuidCreate(&uuid);
|
||||
unsigned char *str = nullptr;
|
||||
UuidToStringA(&uuid, &str);
|
||||
std::string s((char*)str);
|
||||
RpcStringFreeA(&str);
|
||||
return s;
|
||||
#else
|
||||
char str[64] = { 0 };
|
||||
uuid_t uuid;
|
||||
uuid_generate_random(uuid);
|
||||
uuid_unparse(uuid, str);
|
||||
return str;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef COMMON_UUID_H
|
||||
#define COMMON_UUID_H
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string CreateUUID();
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9100
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9097
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9008
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "web_interface_utils.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
std::vector<std::string> explode_string(std::string const & s, char delim)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::istringstream iss(s);
|
||||
|
||||
for (std::string token; std::getline(iss, token, delim);)
|
||||
{
|
||||
result.push_back(std::move(token));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string MakeJSON(std::string json)
|
||||
{
|
||||
StringBuffer s;
|
||||
Writer<StringBuffer> writer(s);
|
||||
writer.StartObject();
|
||||
|
||||
auto arg_c = explode_string(json, ',');
|
||||
if (arg_c.size() == 0)
|
||||
{
|
||||
auto arg_v = explode_string(json, ':');
|
||||
if (arg_v.size() > 0)
|
||||
{
|
||||
for (int j = 0; j < arg_v.size(); j++)
|
||||
{
|
||||
writer.String(arg_v[j].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < arg_c.size(); i++)
|
||||
{
|
||||
auto arg_v = explode_string(arg_c[i], ':');
|
||||
for (int j = 0; j < arg_v.size(); j++)
|
||||
{
|
||||
writer.String(arg_v[j].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.EndObject();
|
||||
return s.GetString();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* EQEMu: Everquest Server Emulator
|
||||
Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
are required to give you total support for your newly bought product;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef COMMON_WEBINTUTIL_H
|
||||
#define COMMON_WEBINTUTIL_H
|
||||
|
||||
#include "../common/global_define.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
std::vector<std::string> explode_string(std::string const & s, char delim);
|
||||
std::string MakeJSON(std::string json);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
*.*
|
||||
*
|
||||
boost/
|
||||
luaj_x86/
|
||||
luaj_x64/
|
||||
mysql_x86/
|
||||
mysql_x64/
|
||||
zlib_x86/
|
||||
zlib_x64/
|
||||
cyassl/
|
||||
websocketpp/
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
|
||||
IF(EQEMU_BUILD_LUA)
|
||||
ADD_SUBDIRECTORY(luabind)
|
||||
ENDIF(EQEMU_BUILD_LUA)
|
||||
|
||||
ADD_SUBDIRECTORY(libwebsockets)
|
||||
@@ -0,0 +1,38 @@
|
||||
#Ignore build files
|
||||
Makefile
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
libtool
|
||||
stamp-h1
|
||||
output/
|
||||
win32port/ipch/
|
||||
win32port/Debug*/
|
||||
win32port/Release*/
|
||||
win32port/server/Debug*/
|
||||
win32port/server/Release*/
|
||||
win32port/client/Debug*/
|
||||
win32port/client/Release*/
|
||||
win32port/libwebsocketswin32/Debug*/
|
||||
win32port/libwebsocketswin32/Release*/
|
||||
win32port/zlib/Debug*/
|
||||
win32port/zlib/Release*/
|
||||
*.vcxproj.user
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.suo
|
||||
*.su
|
||||
*.m4
|
||||
missing
|
||||
depcomp
|
||||
install-sh
|
||||
configure
|
||||
compile
|
||||
config.guess
|
||||
*~
|
||||
*.orig
|
||||
autom4te.cache/
|
||||
ltmain.sh
|
||||
config.sub
|
||||
ar-lib
|
||||
libwebsockets.pc
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# example Android Native Library makefile
|
||||
# contributed by Gregory Junker <ggjunker@gmail.com>
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libwebsockets
|
||||
LOCAL_CFLAGS := -DLWS_BUILTIN_GETIFADDRS
|
||||
LWS_LIB_PATH := ../../../shared/libwebsockets/lib
|
||||
LOCAL_C_INCLUDES:= $(LOCAL_PATH)/$(LWS_LIB_PATH)
|
||||
LOCAL_SRC_FILES := \
|
||||
$(LWS_LIB_PATH)/base64-decode.c \
|
||||
$(LWS_LIB_PATH)/client.c \
|
||||
$(LWS_LIB_PATH)/client-handshake.c \
|
||||
$(LWS_LIB_PATH)/client-parser.c \
|
||||
$(LWS_LIB_PATH)/daemonize.c \
|
||||
$(LWS_LIB_PATH)/extension.c \
|
||||
$(LWS_LIB_PATH)/extension-deflate-frame.c \
|
||||
$(LWS_LIB_PATH)/extension-deflate-stream.c \
|
||||
$(LWS_LIB_PATH)/getifaddrs.c \
|
||||
$(LWS_LIB_PATH)/handshake.c \
|
||||
$(LWS_LIB_PATH)/libwebsockets.c \
|
||||
$(LWS_LIB_PATH)/md5.c \
|
||||
$(LWS_LIB_PATH)/output.c \
|
||||
$(LWS_LIB_PATH)/parsers.c \
|
||||
$(LWS_LIB_PATH)/sha-1.c
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
+927
@@ -0,0 +1,927 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
if(POLICY CMP0046)
|
||||
cmake_policy(VERSION 2.8)
|
||||
# The new policy for add_dependencies is to now error if a dependency target
|
||||
# is not found. The old policy didn't care and continued through configuration
|
||||
cmake_policy(SET CMP0046 OLD)
|
||||
endif()
|
||||
|
||||
project(libwebsockets)
|
||||
|
||||
set(PACKAGE "libwebsockets")
|
||||
set(CPACK_PACKAGE_NAME "${PACKAGE}")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "3")
|
||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VENDOR "andy@warmcat.com")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
|
||||
set(SOVERSION "4.0.0")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
|
||||
set(VERSION "${CPACK_PACKAGE_VERSION}")
|
||||
|
||||
set(LWS_LIBRARY_VERSION ${CPACK_PACKAGE_VERSION})
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
|
||||
message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'")
|
||||
|
||||
# Try to find the current Git hash.
|
||||
find_package(Git)
|
||||
if(GIT_EXECUTABLE)
|
||||
execute_process(
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMAND "${GIT_EXECUTABLE}" log -n 1 --pretty=%h
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
set(LWS_BUILD_HASH ${GIT_HASH})
|
||||
message("Git commit hash: ${LWS_BUILD_HASH}")
|
||||
endif()
|
||||
|
||||
option(LWS_WITH_SSL "Include SSL support (default OpenSSL, CyaSSL if LWS_USE_CYASSL is set)" OFF)
|
||||
option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of OS installed CA root certs" ON)
|
||||
option(LWS_USE_EXTERNAL_ZLIB "Search the system for ZLib instead of using the included one (on Windows)" OFF)
|
||||
option(LWS_USE_CYASSL "Use CyaSSL replacement for OpenSSL. When settings this, you also need to specify LWS_CYASSL_LIB and LWS_CYASSL_INCLUDE_DIRS" OFF)
|
||||
option(LWS_WITHOUT_BUILTIN_GETIFADDRS "Don't use BSD getifaddrs implementation from libwebsockets if it is missing (this will result in a compilation error) ... Default is your libc provides it. On some systems such as uclibc it doesn't exist." OFF)
|
||||
option(LWS_WITHOUT_CLIENT "Don't build the client part of the library" ON)
|
||||
option(LWS_WITHOUT_SERVER "Don't build the server part of the library" OFF)
|
||||
option(LWS_LINK_TESTAPPS_DYNAMIC "Link the test apps to the shared version of the library. Default is to link statically" ON)
|
||||
option(LWS_WITHOUT_TESTAPPS "Don't build the libwebsocket-test-apps" ON)
|
||||
option(LWS_WITHOUT_TEST_SERVER "Don't build the test server" ON)
|
||||
option(LWS_WITHOUT_TEST_SERVER_EXTPOLL "Don't build the test server version that uses external poll" ON)
|
||||
option(LWS_WITHOUT_TEST_PING "Don't build the ping test application" ON)
|
||||
option(LWS_WITHOUT_TEST_CLIENT "Don't build the client test application" ON)
|
||||
option(LWS_WITHOUT_TEST_FRAGGLE "Don't build the ping test application" ON)
|
||||
option(LWS_WITHOUT_DEBUG "Don't compile debug related code" OFF)
|
||||
option(LWS_WITHOUT_EXTENSIONS "Don't compile with extensions" OFF)
|
||||
option(LWS_WITH_LATENCY "Build latency measuring code into the library" OFF)
|
||||
option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" OFF)
|
||||
option(LWS_WITH_LIBEV "Compile with support for libev" OFF)
|
||||
option(LWS_IPV6 "Compile with support for ipv6" ON)
|
||||
option(LWS_WITH_HTTP2 "Compile with support for http2" OFF)
|
||||
|
||||
# Allow the user to override installation directories.
|
||||
set(LWS_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
|
||||
set(LWS_INSTALL_BIN_DIR "." CACHE PATH "Installation directory for executables")
|
||||
set(LWS_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
|
||||
set(LWS_INSTALL_EXAMPLES_DIR "." CACHE PATH "Installation directory for example files")
|
||||
|
||||
if (LWS_WITHOUT_CLIENT AND LWS_WITHOUT_SERVER)
|
||||
message(FATAL_ERROR "Makes no sense to compile without both client or server.")
|
||||
endif()
|
||||
|
||||
# The base dir where the test-apps look for the SSL certs.
|
||||
set(LWS_OPENSSL_CLIENT_CERTS ../share CACHE PATH "Server SSL certificate directory")
|
||||
if (WIN32)
|
||||
set(LWS_OPENSSL_CLIENT_CERTS . CACHE PATH "Client SSL certificate directory")
|
||||
|
||||
if (LWS_IPV6)
|
||||
set(LWS_IPV6 OFF)
|
||||
message(WARNING "IPv6 does currently not work on Windows!")
|
||||
endif()
|
||||
else()
|
||||
set(LWS_OPENSSL_CLIENT_CERTS /etc/pki/tls/certs/ CACHE PATH "Client SSL certificate directory")
|
||||
endif()
|
||||
|
||||
set(LWS_CYASSL_LIB CACHE PATH "Path to the CyaSSL library")
|
||||
set(LWS_CYASSL_INCLUDE_DIRS CACHE PATH "Path to the CyaSSL include directory")
|
||||
|
||||
if (LWS_USE_CYASSL)
|
||||
if ("${LWS_CYASSL_LIB}" STREQUAL "" OR "${LWS_CYASSL_INCLUDE_DIRS}" STREQUAL "")
|
||||
message(FATAL_ERROR "You must set LWS_CYASSL_LIB and LWS_CYASSL_INCLUDE_DIRS when LWS_USE_CYASSL is turned on")
|
||||
endif()
|
||||
set(USE_CYASSL 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_EXTENSIONS)
|
||||
set(LWS_NO_EXTENSIONS 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SSL)
|
||||
set(LWS_OPENSSL_SUPPORT 1)
|
||||
endif()
|
||||
|
||||
if (LWS_SSL_CLIENT_USE_OS_CA_CERTS)
|
||||
set(LWS_SSL_CLIENT_USE_OS_CA_CERTS 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LATENCY)
|
||||
set(LWS_LATENCY 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_DAEMONIZE OR WIN32)
|
||||
set(LWS_NO_DAEMONIZE 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_SERVER)
|
||||
set(LWS_NO_SERVER 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_CLIENT)
|
||||
set(LWS_NO_CLIENT 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_DEBUG)
|
||||
set(_DEBUG 0)
|
||||
else()
|
||||
set(_DEBUG 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
set(LWS_USE_LIBEV 1)
|
||||
set(LWS_NO_EXTERNAL_POLL 1)
|
||||
endif()
|
||||
|
||||
if (LWS_IPV6)
|
||||
set(LWS_USE_IPV6 1)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_HTTP2)
|
||||
set(LWS_USE_HTTP2 1)
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
set(LWS_MINGW_SUPPORT 1)
|
||||
endif()
|
||||
|
||||
include_directories("${PROJECT_BINARY_DIR}")
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
# Check for different inline keyword versions.
|
||||
foreach(KEYWORD "inline" "__inline__" "__inline")
|
||||
set(CMAKE_REQUIRED_DEFINITIONS "-DKEYWORD=${KEYWORD}")
|
||||
CHECK_C_SOURCE_COMPILES(
|
||||
"
|
||||
#include <stdio.h>
|
||||
KEYWORD void a() {}
|
||||
int main(int argc, char **argv) { a(); return 0; }
|
||||
" HAVE_${KEYWORD})
|
||||
endforeach()
|
||||
|
||||
if (NOT HAVE_inline)
|
||||
if (HAVE___inline__)
|
||||
set(inline __inline__)
|
||||
elseif(HAVE___inline)
|
||||
set(inline __inline)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Put the libaries and binaries that get built into directories at the
|
||||
# top of the build tree rather than in hard-to-find leaf directories.
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
||||
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
|
||||
|
||||
# Put absolute path of dynamic libraries into the object code. Some
|
||||
# architectures, notably Mac OS X, need this.
|
||||
SET(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}")
|
||||
|
||||
# So we can include the CMake generated config file only when
|
||||
# building with CMAKE.
|
||||
add_definitions(-DCMAKE_BUILD)
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
|
||||
CHECK_FUNCTION_EXISTS(bzero HAVE_BZERO)
|
||||
CHECK_FUNCTION_EXISTS(fork HAVE_FORK)
|
||||
CHECK_FUNCTION_EXISTS(getenv HAVE_GETENV)
|
||||
CHECK_FUNCTION_EXISTS(malloc HAVE_MALLOC)
|
||||
CHECK_FUNCTION_EXISTS(memset HAVE_MEMSET)
|
||||
CHECK_FUNCTION_EXISTS(realloc HAVE_REALLOC)
|
||||
CHECK_FUNCTION_EXISTS(socket HAVE_SOCKET)
|
||||
CHECK_FUNCTION_EXISTS(strerror HAVE_STRERROR)
|
||||
CHECK_FUNCTION_EXISTS(vfork HAVE_VFORK)
|
||||
CHECK_FUNCTION_EXISTS(getifaddrs HAVE_GETIFADDRS)
|
||||
|
||||
if (NOT HAVE_GETIFADDRS)
|
||||
if (LWS_WITHOUT_BUILTIN_GETIFADDRS)
|
||||
message(FATAL_ERROR "No getifaddrs was found on the system. Turn off the LWS_WITHOUT_BUILTIN_GETIFADDRS compile option to use the supplied BSD version.")
|
||||
endif()
|
||||
|
||||
set(LWS_BUILTIN_GETIFADDRS 1)
|
||||
endif()
|
||||
|
||||
CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H)
|
||||
CHECK_INCLUDE_FILE(fcntl.h HAVE_FCNTL_H)
|
||||
CHECK_INCLUDE_FILE(in6addr.h HAVE_IN6ADDR_H)
|
||||
CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H)
|
||||
CHECK_INCLUDE_FILE(memory.h HAVE_MEMORY_H)
|
||||
CHECK_INCLUDE_FILE(netinet/in.h HAVE_NETINET_IN_H)
|
||||
CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
|
||||
CHECK_INCLUDE_FILE(stdlib.h HAVE_STDLIB_H)
|
||||
CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
|
||||
CHECK_INCLUDE_FILE(string.h HAVE_STRING_H)
|
||||
CHECK_INCLUDE_FILE(sys/prctl.h HAVE_SYS_PRCTL_H)
|
||||
CHECK_INCLUDE_FILE(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
CHECK_INCLUDE_FILE(sys/stat.h HAVE_SYS_STAT_H)
|
||||
CHECK_INCLUDE_FILE(sys/types.h HAVE_SYS_TYPES_H)
|
||||
CHECK_INCLUDE_FILE(unistd.h HAVE_UNISTD_H)
|
||||
CHECK_INCLUDE_FILE(vfork.h HAVE_VFORK_H)
|
||||
CHECK_INCLUDE_FILE(zlib.h HAVE_ZLIB_H)
|
||||
|
||||
# TODO: These can be tested if they actually work also...
|
||||
set(HAVE_WORKING_FORK HAVE_FORK)
|
||||
set(HAVE_WORKING_VFORK HAVE_VFORK)
|
||||
|
||||
CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
|
||||
|
||||
CHECK_TYPE_SIZE(pid_t PID_T_SIZE)
|
||||
CHECK_TYPE_SIZE(size_t SIZE_T_SIZE)
|
||||
|
||||
if (NOT PID_T_SIZE)
|
||||
set(pid_t int)
|
||||
endif()
|
||||
|
||||
if (NOT SIZE_T_SIZE)
|
||||
set(size_t "unsigned int")
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_MALLOC)
|
||||
set(malloc rpl_malloc)
|
||||
endif()
|
||||
|
||||
if (NOT HAVE_REALLOC)
|
||||
set(realloc rpl_realloc)
|
||||
endif()
|
||||
|
||||
# Generate the config.h that includes all the compilation settings.
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/config.h.cmake"
|
||||
"${PROJECT_BINARY_DIR}/lws_config.h")
|
||||
|
||||
if (MSVC)
|
||||
# Turn off stupid microsoft security warnings.
|
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
endif(MSVC)
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/lib")
|
||||
|
||||
# Group headers and sources.
|
||||
# Some IDEs use this for nicer file structure.
|
||||
set(HDR_PRIVATE
|
||||
lib/private-libwebsockets.h
|
||||
"${PROJECT_BINARY_DIR}/lws_config.h"
|
||||
)
|
||||
|
||||
set(HDR_PUBLIC
|
||||
"${PROJECT_SOURCE_DIR}/lib/libwebsockets.h"
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
lib/base64-decode.c
|
||||
lib/handshake.c
|
||||
lib/libwebsockets.c
|
||||
lib/service.c
|
||||
lib/pollfd.c
|
||||
lib/output.c
|
||||
lib/parsers.c
|
||||
lib/context.c
|
||||
lib/sha-1.c
|
||||
)
|
||||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
lib/client.c
|
||||
lib/client-handshake.c
|
||||
lib/client-parser.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SSL)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_HTTP2)
|
||||
list(APPEND SOURCES
|
||||
lib/ssl-http2.c
|
||||
)
|
||||
endif()
|
||||
# select the active platform files
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-win.c
|
||||
)
|
||||
else()
|
||||
list(APPEND SOURCES
|
||||
lib/lws-plat-unix.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
list(APPEND SOURCES
|
||||
lib/server.c
|
||||
lib/server-handshake.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_EXTENSIONS)
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/extension-deflate-frame.h
|
||||
lib/extension-deflate-stream.h
|
||||
)
|
||||
|
||||
list(APPEND SOURCES
|
||||
lib/extension.c
|
||||
lib/extension-deflate-frame.c
|
||||
lib/extension-deflate-stream.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
list(APPEND SOURCES
|
||||
lib/libev.c
|
||||
)
|
||||
endif(LWS_WITH_LIBEV)
|
||||
|
||||
# Add helper files for Windows.
|
||||
if (WIN32)
|
||||
set(WIN32_HELPERS_PATH win32port/win32helpers)
|
||||
include_directories(${WIN32_HELPERS_PATH})
|
||||
else(WIN32)
|
||||
# Unix.
|
||||
if (NOT LWS_WITHOUT_DAEMONIZE)
|
||||
list(APPEND SOURCES
|
||||
lib/daemonize.c
|
||||
)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
if (UNIX)
|
||||
if (NOT HAVE_GETIFADDRS)
|
||||
list(APPEND HDR_PRIVATE lib/getifaddrs.h)
|
||||
list(APPEND SOURCES lib/getifaddrs.c)
|
||||
endif()
|
||||
endif(UNIX)
|
||||
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (UNIX)
|
||||
set( CMAKE_C_FLAGS "-Wall -Werror -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" )
|
||||
else(UNIX)
|
||||
set( CMAKE_C_FLAGS "-Wall -O4 -fvisibility=hidden ${CMAKE_C_FLAGS}" )
|
||||
endif(UNIX)
|
||||
endif ()
|
||||
|
||||
source_group("Headers Private" FILES ${HDR_PRIVATE})
|
||||
source_group("Headers Public" FILES ${HDR_PUBLIC})
|
||||
source_group("Sources" FILES ${SOURCES})
|
||||
|
||||
#
|
||||
# Create the lib.
|
||||
#
|
||||
add_library(websockets STATIC
|
||||
${HDR_PRIVATE}
|
||||
${HDR_PUBLIC}
|
||||
${SOURCES})
|
||||
add_library(websockets_shared SHARED
|
||||
${HDR_PRIVATE}
|
||||
${HDR_PUBLIC}
|
||||
${SOURCES})
|
||||
|
||||
if (WIN32)
|
||||
# On Windows libs have the same file ending (.lib)
|
||||
# for both static and shared libraries, so we
|
||||
# need a unique name for the static one.
|
||||
set_target_properties(websockets
|
||||
PROPERTIES
|
||||
OUTPUT_NAME websockets_static)
|
||||
|
||||
# Compile as DLL (export function declarations)
|
||||
set_property(
|
||||
TARGET websockets_shared
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
LWS_DLL
|
||||
LWS_INTERNAL
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
# We want the shared lib to be named "libwebsockets"
|
||||
# not "libwebsocket_shared".
|
||||
set_target_properties(websockets_shared
|
||||
PROPERTIES
|
||||
OUTPUT_NAME websockets)
|
||||
|
||||
# Set the so version of the lib.
|
||||
# Equivalent to LDFLAGS=-version-info x:x:x
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
foreach(lib websockets websockets_shared)
|
||||
set_target_properties(${lib}
|
||||
PROPERTIES
|
||||
SOVERSION ${SOVERSION})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(LIB_LIST)
|
||||
|
||||
#
|
||||
# Find libraries.
|
||||
#
|
||||
|
||||
#
|
||||
# ZLIB (Only needed for deflate extensions).
|
||||
#
|
||||
if (NOT LWS_WITHOUT_EXTENSIONS)
|
||||
if (WIN32 AND NOT LWS_USE_EXTERNAL_ZLIB)
|
||||
message("Using included Zlib version")
|
||||
|
||||
# Compile ZLib if needed.
|
||||
set(WIN32_ZLIB_PATH "win32port/zlib")
|
||||
set(ZLIB_SRCS
|
||||
${WIN32_ZLIB_PATH}/adler32.c
|
||||
${WIN32_ZLIB_PATH}/compress.c
|
||||
${WIN32_ZLIB_PATH}/crc32.c
|
||||
${WIN32_ZLIB_PATH}/deflate.c
|
||||
${WIN32_ZLIB_PATH}/gzclose.c
|
||||
${WIN32_ZLIB_PATH}/gzio.c
|
||||
${WIN32_ZLIB_PATH}/gzlib.c
|
||||
${WIN32_ZLIB_PATH}/gzread.c
|
||||
${WIN32_ZLIB_PATH}/gzwrite.c
|
||||
${WIN32_ZLIB_PATH}/infback.c
|
||||
${WIN32_ZLIB_PATH}/inffast.c
|
||||
${WIN32_ZLIB_PATH}/inflate.c
|
||||
${WIN32_ZLIB_PATH}/inftrees.c
|
||||
${WIN32_ZLIB_PATH}/trees.c
|
||||
${WIN32_ZLIB_PATH}/uncompr.c
|
||||
${WIN32_ZLIB_PATH}/zutil.c
|
||||
)
|
||||
|
||||
# Create the library.
|
||||
add_library(ZLIB STATIC ${ZLIB_SRCS})
|
||||
|
||||
# Set the same variables as find_package would.
|
||||
set(ZLIB_INCLUDE_DIRS ${WIN32_ZLIB_PATH})
|
||||
if(POLICY CMP0026)
|
||||
cmake_policy(VERSION 2.8)
|
||||
# The new policy for add_dependencies is to now error if a dependency target
|
||||
# is not found. The old policy didn't care and continued through configuration
|
||||
cmake_policy(SET CMP0026 OLD)
|
||||
endif()
|
||||
get_property(ZLIB_LIBRARIES TARGET ZLIB PROPERTY LOCATION)
|
||||
set(ZLIB_FOUND 1)
|
||||
else()
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
# Make sure ZLib is compiled before the libs.
|
||||
foreach (lib websockets websockets_shared)
|
||||
add_dependencies(${lib} ZLIB)
|
||||
endforeach()
|
||||
|
||||
message(STATUS "ZLib include dirs: ${ZLIB_INCLUDE_DIRS}")
|
||||
message(STATUS "ZLib libraries: ${ZLIB_LIBRARIES}")
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
list(APPEND LIB_LIST ${ZLIB_LIBRARIES})
|
||||
endif(NOT LWS_WITHOUT_EXTENSIONS)
|
||||
|
||||
#
|
||||
# OpenSSL
|
||||
#
|
||||
if (LWS_WITH_SSL)
|
||||
message("Compiling with SSL support")
|
||||
|
||||
if (LWS_USE_CYASSL)
|
||||
# Use CyaSSL as OpenSSL replacement.
|
||||
# TODO: Add a find_package command for this also.
|
||||
message("CyaSSL include dir: ${LWS_CYASSL_INCLUDE_DIRS}")
|
||||
message("CyaSSL libraries: ${LWS_CYASSL_LIB}")
|
||||
|
||||
# Additional to the root directory we need to include
|
||||
# the cyassl/ subdirectory which contains the OpenSSL
|
||||
# compatability layer headers.
|
||||
foreach(inc ${LWS_CYASSL_INCLUDE_DIRS})
|
||||
include_directories("${inc}" "${inc}/cyassl")
|
||||
endforeach()
|
||||
|
||||
list(APPEND LIB_LIST "${LWS_CYASSL_LIB}")
|
||||
else()
|
||||
# TODO: Add support for STATIC also.
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
|
||||
message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
|
||||
|
||||
include_directories("${OPENSSL_INCLUDE_DIR}")
|
||||
list(APPEND LIB_LIST ${OPENSSL_LIBRARIES})
|
||||
|
||||
# Link against dynamic linking functions.
|
||||
# (Don't link directly to libdl since it is not needed on all platforms, it's now a part of libc).
|
||||
list(APPEND LIB_LIST ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
endif(LWS_WITH_SSL)
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
list(APPEND LIB_LIST "ev")
|
||||
endif(LWS_WITH_LIBEV)
|
||||
|
||||
#
|
||||
# Platform specific libs.
|
||||
#
|
||||
if (WINCE)
|
||||
list(APPEND LIB_LIST ws2.lib)
|
||||
elseif (WIN32)
|
||||
list(APPEND LIB_LIST ws2_32.lib)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
list(APPEND LIB_LIST m)
|
||||
endif()
|
||||
|
||||
# Setup the linking for all libs.
|
||||
foreach (lib websockets websockets_shared)
|
||||
target_link_libraries(${lib} ${LIB_LIST})
|
||||
endforeach()
|
||||
|
||||
#
|
||||
# Test applications
|
||||
#
|
||||
set(TEST_APP_LIST)
|
||||
if (NOT LWS_WITHOUT_TESTAPPS)
|
||||
#
|
||||
# Helper function for adding a test app.
|
||||
#
|
||||
macro(create_test_app TEST_NAME MAIN_SRC)
|
||||
|
||||
set(TEST_SRCS ${MAIN_SRC})
|
||||
set(TEST_HDR)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND TEST_SRCS
|
||||
${WIN32_HELPERS_PATH}/getopt.c
|
||||
${WIN32_HELPERS_PATH}/getopt_long.c
|
||||
${WIN32_HELPERS_PATH}/gettimeofday.c
|
||||
)
|
||||
|
||||
list(APPEND TEST_HDR
|
||||
${WIN32_HELPERS_PATH}/getopt.h
|
||||
${WIN32_HELPERS_PATH}/gettimeofday.h
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
source_group("Headers Private" FILES ${TEST_HDR})
|
||||
source_group("Sources" FILES ${TEST_SRCS})
|
||||
add_executable(${TEST_NAME} ${TEST_SRCS} ${TEST_HDR})
|
||||
|
||||
if (LWS_LINK_TESTAPPS_DYNAMIC)
|
||||
target_link_libraries(${TEST_NAME} websockets_shared)
|
||||
add_dependencies(${TEST_NAME} websockets_shared)
|
||||
else(LWS_LINK_TESTAPPS_DYNAMIC)
|
||||
target_link_libraries(${TEST_NAME} websockets)
|
||||
add_dependencies(${TEST_NAME} websockets)
|
||||
endif(LWS_LINK_TESTAPPS_DYNAMIC)
|
||||
|
||||
# Set test app specific defines.
|
||||
set_property(TARGET ${TEST_NAME}
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
|
||||
)
|
||||
|
||||
# Prefix the binary names with libwebsockets.
|
||||
set_target_properties(${TEST_NAME}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME libwebsockets-${TEST_NAME})
|
||||
|
||||
# Add to the list of tests.
|
||||
list(APPEND TEST_APP_LIST ${TEST_NAME})
|
||||
endmacro()
|
||||
|
||||
if (LWS_WITH_SSL AND NOT LWS_USE_CYASSL)
|
||||
message("Searching for OpenSSL executable and dlls")
|
||||
find_package(OpenSSLbins)
|
||||
message("OpenSSL executable: ${OPENSSL_EXECUTABLE}")
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
#
|
||||
# test-server
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_SERVER)
|
||||
create_test_app(test-server "test-server/test-server.c")
|
||||
endif()
|
||||
|
||||
#
|
||||
# test-server-extpoll
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_SERVER_EXTPOLL)
|
||||
create_test_app(test-server-extpoll "test-server/test-server.c")
|
||||
# Set defines for this executable only.
|
||||
set_property(
|
||||
TARGET test-server-extpoll
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
EXTERNAL_POLL
|
||||
INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/share"
|
||||
)
|
||||
|
||||
# We need to link against winsock code.
|
||||
if (WIN32)
|
||||
target_link_libraries(test-server-extpoll ws2_32.lib)
|
||||
endif(WIN32)
|
||||
endif()
|
||||
|
||||
# Data files for running the test server.
|
||||
set(TEST_SERVER_DATA
|
||||
"${PROJECT_SOURCE_DIR}/test-server/favicon.ico"
|
||||
"${PROJECT_SOURCE_DIR}/test-server/leaf.jpg"
|
||||
"${PROJECT_SOURCE_DIR}/test-server/libwebsockets.org-logo.png"
|
||||
"${PROJECT_SOURCE_DIR}/test-server/test.html")
|
||||
|
||||
# Generate self-signed SSL certs for the test-server.
|
||||
if (LWS_WITH_SSL AND OPENSSL_EXECUTABLE AND NOT LWS_WITHOUT_TEST_SERVER)
|
||||
message("Generating SSL Certificates for the test-server...")
|
||||
|
||||
set(TEST_SERVER_SSL_KEY "${PROJECT_BINARY_DIR}/libwebsockets-test-server.key.pem")
|
||||
set(TEST_SERVER_SSL_CERT "${PROJECT_BINARY_DIR}/libwebsockets-test-server.pem")
|
||||
|
||||
if (WIN32)
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/openssl_input.txt"
|
||||
"GB\n"
|
||||
"Erewhon\n"
|
||||
"All around\n"
|
||||
"libwebsockets-test\n"
|
||||
"localhost\n"
|
||||
"none@invalid.org\n\n"
|
||||
)
|
||||
|
||||
# The "type" command is a bit picky with paths.
|
||||
file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/openssl_input.txt" OPENSSL_INPUT_WIN_PATH)
|
||||
message("OPENSSL_INPUT_WIN_PATH = ${OPENSSL_INPUT_WIN_PATH}")
|
||||
message("cmd = \"${OPENSSL_EXECUTABLE}\" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout \"${TEST_SERVER_SSL_KEY}\" -out \"${TEST_SERVER_SSL_CERT}\"")
|
||||
|
||||
execute_process(
|
||||
COMMAND cmd /c type "${OPENSSL_INPUT_WIN_PATH}"
|
||||
COMMAND "${OPENSSL_EXECUTABLE}" req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
|
||||
RESULT_VARIABLE OPENSSL_RETURN_CODE)
|
||||
|
||||
message("\n")
|
||||
|
||||
if (OPENSSL_RETURN_CODE)
|
||||
message(WARNING "!!! Failed to generate SSL certificate for Test Server using cmd.exe !!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
|
||||
else()
|
||||
message("SUCCSESFULLY generated SSL certificate")
|
||||
endif()
|
||||
else()
|
||||
# Unix.
|
||||
execute_process(
|
||||
COMMAND printf "GB\\nErewhon\\nAll around\\nlibwebsockets-test\\n\\nlocalhost\\nnone@invalid.org\\n"
|
||||
COMMAND "${OPENSSL_EXECUTABLE}"
|
||||
req -new -newkey rsa:1024 -days 10000 -nodes -x509 -keyout "${TEST_SERVER_SSL_KEY}" -out "${TEST_SERVER_SSL_CERT}"
|
||||
RESULT_VARIABLE OPENSSL_RETURN_CODE)
|
||||
|
||||
if (OPENSSL_RETURN_CODE)
|
||||
message(WARNING "!!! Failed to generate SSL certificate for Test Server!!!:\nOpenSSL return code = ${OPENSSL_RETURN_CODE}")
|
||||
else()
|
||||
message("SUCCSESFULLY generated SSL certificate")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(APPEND TEST_SERVER_DATA
|
||||
"${TEST_SERVER_SSL_KEY}"
|
||||
"${TEST_SERVER_SSL_CERT}")
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET test-server
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server")
|
||||
|
||||
# Copy the file needed to run the server so that the test apps can
|
||||
# reach them from their default output location
|
||||
foreach (TEST_FILE ${TEST_SERVER_DATA})
|
||||
if (EXISTS ${TEST_FILE})
|
||||
add_custom_command(TARGET test-server
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${TEST_FILE}" "$<TARGET_FILE_DIR:test-server>/../share/libwebsockets-test-server" VERBATIM)
|
||||
endif()
|
||||
endforeach()
|
||||
endif(NOT LWS_WITHOUT_SERVER)
|
||||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
#
|
||||
# test-client
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_CLIENT)
|
||||
create_test_app(test-client "test-server/test-client.c")
|
||||
endif()
|
||||
|
||||
#
|
||||
# test-fraggle
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_FRAGGLE)
|
||||
create_test_app(test-fraggle "test-server/test-fraggle.c")
|
||||
endif()
|
||||
|
||||
#
|
||||
# test-ping
|
||||
#
|
||||
if (NOT LWS_WITHOUT_TEST_PING)
|
||||
create_test_app(test-ping "test-server/test-ping.c")
|
||||
endif()
|
||||
#
|
||||
# test-echo
|
||||
#
|
||||
if (NOT WITHOUT_TEST_ECHO)
|
||||
create_test_app(test-echo "test-server/test-echo.c")
|
||||
endif()
|
||||
|
||||
endif(NOT LWS_WITHOUT_CLIENT)
|
||||
|
||||
#
|
||||
# Copy OpenSSL dlls to the output directory on Windows.
|
||||
# (Otherwise we'll get an error when trying to run)
|
||||
#
|
||||
if (WIN32 AND LWS_WITH_SSL AND NOT LWS_USE_CYASSL)
|
||||
if(OPENSSL_BIN_FOUND)
|
||||
message("OpenSSL dlls found:")
|
||||
message(" Libeay: ${LIBEAY_BIN}")
|
||||
message(" SSLeay: ${SSLEAY_BIN}")
|
||||
|
||||
foreach(TARGET_BIN ${TEST_APP_LIST})
|
||||
add_custom_command(TARGET ${TARGET_BIN}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${LIBEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
|
||||
|
||||
add_custom_command(TARGET ${TARGET_BIN}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${SSLEAY_BIN}" "$<TARGET_FILE_DIR:${TARGET_BIN}>" VERBATIM)
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endif(NOT LWS_WITHOUT_TESTAPPS)
|
||||
|
||||
if (UNIX)
|
||||
# Generate documentation.
|
||||
# TODO: Fix this on Windows.
|
||||
message("Generating API documentation")
|
||||
file(GLOB C_FILES "${PROJECT_SOURCE_DIR}/lib/*.c")
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/doc/")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${PROJECT_SOURCE_DIR}/scripts/kernel-doc" -html ${C_FILES} ${HDR_PUBLIC}
|
||||
OUTPUT_FILE "${PROJECT_BINARY_DIR}/doc/libwebsockets-api-doc.html"
|
||||
ERROR_QUIET)
|
||||
|
||||
execute_process(
|
||||
COMMAND "${PROJECT_SOURCE_DIR}/scripts/kernel-doc" -text ${C_FILES} ${HDR_PUBLIC}
|
||||
OUTPUT_FILE "${PROJECT_BINARY_DIR}/doc/libwebsockets-api-doc.txt"
|
||||
ERROR_QUIET)
|
||||
|
||||
# Generate and install pkgconfig.
|
||||
# (This is not indented, because the tabs will be part of the output)
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/libwebsockets.pc"
|
||||
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
|
||||
exec_prefix=\${prefix}
|
||||
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
|
||||
includedir=\${prefix}/include
|
||||
|
||||
Name: libwebsockets
|
||||
Description: Websockets server and client library
|
||||
Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}
|
||||
|
||||
Libs: -L\${libdir} -lwebsockets
|
||||
Cflags: -I\${includedir}"
|
||||
)
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/libwebsockets.pc"
|
||||
DESTINATION lib${LIB_SUFFIX}/pkgconfig)
|
||||
endif(UNIX)
|
||||
|
||||
#
|
||||
# Installation preparations.
|
||||
#
|
||||
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
set(DEF_INSTALL_CMAKE_DIR cmake)
|
||||
else()
|
||||
set(DEF_INSTALL_CMAKE_DIR lib/cmake/libwebsockets)
|
||||
endif()
|
||||
|
||||
set(LWS_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
|
||||
|
||||
# Export targets (This is used for other CMake projects to easily find the libraries and include files).
|
||||
export(TARGETS websockets websockets_shared
|
||||
FILE "${PROJECT_BINARY_DIR}/LibwebsocketsTargets.cmake")
|
||||
export(PACKAGE libwebsockets)
|
||||
|
||||
# Generate the config file for the build-tree.
|
||||
set(LWS__INCLUDE_DIRS
|
||||
"${PROJECT_SOURCE_DIR}/lib"
|
||||
"${PROJECT_BINARY_DIR}")
|
||||
set(LIBWEBSOCKETS_INCLUDE_DIRS ${LWS__INCLUDE_DIRS} CACHE PATH "Libwebsockets include directories")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}/LibwebsocketsConfig.cmake
|
||||
@ONLY)
|
||||
|
||||
# Generate the config file for the installation tree.
|
||||
get_filename_component(LWS_ABSOLUTE_INSTALL_CMAKE_DIR ${LWS_INSTALL_CMAKE_DIR} ABSOLUTE)
|
||||
get_filename_component(LWS_ABSOLUTE_INSTALL_INCLUDE_DIR ${LWS_INSTALL_INCLUDE_DIR} ABSOLUTE)
|
||||
file(RELATIVE_PATH
|
||||
REL_INCLUDE_DIR
|
||||
"${LWS_ABSOLUTE_INSTALL_CMAKE_DIR}"
|
||||
"${LWS_ABSOLUTE_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the cmake dir.
|
||||
|
||||
# Note the EVENT_CMAKE_DIR is defined in JanssonConfig.cmake.in,
|
||||
# we escape it here so it's evaluated when it is included instead
|
||||
# so that the include dirs are given relative to where the
|
||||
# config file is located.
|
||||
set(LWS__INCLUDE_DIRS
|
||||
"\${LWS_CMAKE_DIR}/${REL_INCLUDE_DIR}")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake
|
||||
@ONLY)
|
||||
|
||||
# Generate version info for both build-tree and install-tree.
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/LibwebsocketsConfigVersion.cmake.in
|
||||
${PROJECT_BINARY_DIR}/LibwebsocketsConfigVersion.cmake
|
||||
@ONLY)
|
||||
|
||||
set_target_properties(websockets websockets_shared
|
||||
PROPERTIES PUBLIC_HEADER "${HDR_PUBLIC}")
|
||||
|
||||
#
|
||||
# Installation.
|
||||
#
|
||||
|
||||
# Install libs and headers.
|
||||
install(TARGETS websockets websockets_shared
|
||||
EXPORT LibwebsocketsTargets
|
||||
LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries
|
||||
ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries
|
||||
RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT libraries # Windows DLLs
|
||||
PUBLIC_HEADER DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev)
|
||||
set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
|
||||
set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files")
|
||||
|
||||
# Install test apps.
|
||||
if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_CLIENT)
|
||||
install(TARGETS test-client ${TEST_APP_LIST}
|
||||
RUNTIME DESTINATION ${LWS_INSTALL_EXAMPLES_DIR}
|
||||
COMPONENT examples)
|
||||
set(CPACK_COMPONENT_EXAMPLES_DISPLAY_NAME "Example files")
|
||||
endif()
|
||||
|
||||
# Programs shared files used by the test-server.
|
||||
if (NOT LWS_WITHOUT_TESTAPPS AND NOT LWS_WITHOUT_SERVER)
|
||||
install(FILES ${TEST_SERVER_DATA}
|
||||
DESTINATION share/libwebsockets-test-server
|
||||
COMPONENT examples)
|
||||
endif()
|
||||
|
||||
# Install exports for the install-tree.
|
||||
install(EXPORT LibwebsocketsTargets
|
||||
DESTINATION "${LWS_INSTALL_CMAKE_DIR}" COMPONENT dev)
|
||||
|
||||
# build subdir is not part of sources
|
||||
set(CPACK_SOURCE_IGNORE_FILES $(CPACK_SOURCE_IGNORE_FILES) ".git" "build" "tgz" "tar.gz")
|
||||
|
||||
# Most people are more used to "make dist" compared to "make package_source"
|
||||
add_custom_target(dist COMMAND "${CMAKE_MAKE_PROGRAM}" package_source)
|
||||
|
||||
include(UseRPMTools)
|
||||
if (RPMTools_FOUND)
|
||||
RPMTools_ADD_RPM_TARGETS(libwebsockets libwebsockets.spec)
|
||||
endif()
|
||||
|
||||
message("---------------------------------------------------------------------")
|
||||
message(" Settings: (For more help do cmake -LH <srcpath>")
|
||||
message("---------------------------------------------------------------------")
|
||||
message(" LWS_WITH_SSL = ${LWS_WITH_SSL} (SSL Support)")
|
||||
message(" LWS_SSL_CLIENT_USE_OS_CA_CERTS = ${LWS_SSL_CLIENT_USE_OS_CA_CERTS}")
|
||||
message(" LWS_USE_CYASSL = ${LWS_USE_CYASSL} (CyaSSL replacement for OpenSSL)")
|
||||
if (LWS_USE_CYASSL)
|
||||
message(" LWS_CYASSL_LIB = ${LWS_CYASSL_LIB}")
|
||||
message(" LWS_CYASSL_INCLUDE_DIRS = ${LWS_CYASSL_INCLUDE_DIRS}")
|
||||
endif()
|
||||
message(" LWS_WITHOUT_BUILTIN_GETIFADDRS = ${LWS_WITHOUT_BUILTIN_GETIFADDRS}")
|
||||
message(" LWS_WITHOUT_CLIENT = ${LWS_WITHOUT_CLIENT}")
|
||||
message(" LWS_WITHOUT_SERVER = ${LWS_WITHOUT_SERVER}")
|
||||
message(" LWS_LINK_TESTAPPS_DYNAMIC = ${LWS_LINK_TESTAPPS_DYNAMIC}")
|
||||
message(" LWS_WITHOUT_TESTAPPS = ${LWS_WITHOUT_TESTAPPS}")
|
||||
message(" LWS_WITHOUT_TEST_SERVER = ${LWS_WITHOUT_TEST_SERVER}")
|
||||
message(" LWS_WITHOUT_TEST_SERVER_EXTPOLL = ${LWS_WITHOUT_TEST_SERVER_EXTPOLL}")
|
||||
message(" LWS_WITHOUT_TEST_PING = ${LWS_WITHOUT_TEST_PING}")
|
||||
message(" LWS_WITHOUT_TEST_CLIENT = ${LWS_WITHOUT_TEST_CLIENT}")
|
||||
message(" LWS_WITHOUT_TEST_FRAGGLE = ${LWS_WITHOUT_TEST_FRAGGLE}")
|
||||
message(" LWS_WITHOUT_DEBUG = ${LWS_WITHOUT_DEBUG}")
|
||||
message(" LWS_WITHOUT_EXTENSIONS = ${LWS_WITHOUT_EXTENSIONS}")
|
||||
message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}")
|
||||
message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
|
||||
message(" LWS_USE_LIBEV = ${LWS_USE_LIBEV}")
|
||||
message(" LWS_IPV6 = ${LWS_IPV6}")
|
||||
message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")
|
||||
message("---------------------------------------------------------------------")
|
||||
|
||||
# These will be available to parent projects including libwebsockets using add_subdirectory()
|
||||
set(LIBWEBSOCKETS_LIBRARIES websocket websockets_shared CACHE STRING "Libwebsocket libraries")
|
||||
set(LIBWEBSOCKETS_LIBRARIES_STATIC websocket CACHE STRING "Libwebsocket static library")
|
||||
set(LIBWEBSOCKETS_LIBRARIES_SHARED websockets_shared CACHE STRING "Libwebsocket shared library")
|
||||
|
||||
# This must always be last!
|
||||
include(CPack)
|
||||
Vendored
+526
@@ -0,0 +1,526 @@
|
||||
Libwebsockets and included programs are provided under the terms of the GNU
|
||||
Library General Public License (LGPL) 2.1, with the following exceptions:
|
||||
|
||||
1) Static linking of programs with the libwebsockets library does not
|
||||
constitute a derivative work and does not require the author to provide
|
||||
source code for the program, use the shared libwebsockets libraries, or
|
||||
link their program against a user-supplied version of libwebsockets.
|
||||
|
||||
If you link the program to a modified version of libwebsockets, then the
|
||||
changes to libwebsockets must be provided under the terms of the LGPL in
|
||||
sections 1, 2, and 4.
|
||||
|
||||
2) You do not have to provide a copy of the libwebsockets license with
|
||||
programs that are linked to the libwebsockets library, nor do you have to
|
||||
identify the libwebsockets license in your program or documentation as
|
||||
required by section 6 of the LGPL.
|
||||
|
||||
However, programs must still identify their use of libwebsockets. The
|
||||
following example statement can be included in user documentation to
|
||||
satisfy this requirement:
|
||||
|
||||
"[program] is based in part on the work of the libwebsockets project
|
||||
(http://libwebsockets.org)"
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
This is the libwebsockets C library for lightweight websocket clients and
|
||||
servers. For support, visit
|
||||
|
||||
http://libwebsockets.org
|
||||
|
||||
and consider joining the project mailing list at
|
||||
|
||||
http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
|
||||
|
||||
You can get the latest version of the library from git
|
||||
|
||||
http://git.libwebsockets.org
|
||||
https://github.com/warmcat/libwebsockets
|
||||
|
||||
for more information:
|
||||
|
||||
README.build - information on building the library
|
||||
README.coding - information for writing code using the library
|
||||
README.test-apps - information about the test apps built with the library
|
||||
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
Introduction to CMake
|
||||
---------------------
|
||||
|
||||
CMake is a multi-platform build tool that can generate build files for many
|
||||
different target platforms. See more info at http://www.cmake.org
|
||||
|
||||
CMake also allows/recommends you to do "out of source"-builds, that is,
|
||||
the build files are separated from your sources, so there is no need to
|
||||
create elaborate clean scripts to get a clean source tree, instead you
|
||||
simply remove your build directory.
|
||||
|
||||
Libwebsockets has been tested to build successfully on the following platforms
|
||||
with SSL support (both OpenSSL/CyaSSL):
|
||||
|
||||
- Windows
|
||||
- Linux (x86 and ARM)
|
||||
- OSX
|
||||
- NetBSD
|
||||
|
||||
Building the library and test apps
|
||||
----------------------------------
|
||||
|
||||
The project settings used by CMake to generate the platform specific build
|
||||
files is called CMakeLists.txt. CMake then uses one of its "Generators" to
|
||||
output a Visual Studio project or Make file for instance. To see a list of
|
||||
the available generators for your platform, simply run the "cmake" command.
|
||||
|
||||
Note that by default OpenSSL will be linked, if you don't want SSL support
|
||||
see below on how to toggle compile options.
|
||||
|
||||
Building on Unix:
|
||||
-----------------
|
||||
|
||||
1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html
|
||||
(Most Unix distributions comes with a packaged version also)
|
||||
|
||||
2. Install OpenSSL.
|
||||
|
||||
3. Generate the build files (default is Make files):
|
||||
|
||||
cd /path/to/src
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
|
||||
(NOTE: The build/ directory can have any name and be located anywhere
|
||||
on your filesystem, and that the argument ".." given to cmake is simply
|
||||
the source directory of libwebsockets containing the CMakeLists.txt
|
||||
project file. All examples in this file assumes you use "..")
|
||||
|
||||
NOTE2
|
||||
A common option you may want to give is to set the install path, same
|
||||
as --prefix= with autotools. It defaults to /usr/local.
|
||||
You can do this by, eg
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr
|
||||
|
||||
NOTE3
|
||||
On machines that want libraries in lib64, you can also add the
|
||||
following to the cmake line
|
||||
|
||||
-DLIB_SUFFIX=64
|
||||
|
||||
NOTE4
|
||||
If you are building against a non-distro OpenSSL (eg, in order to get
|
||||
access to ALPN support only in newer OpenSSL versions) the nice way to
|
||||
express that in one cmake command is eg,
|
||||
|
||||
-DOPENSSL_ROOT_DIR=/usr/local/ssl
|
||||
|
||||
4. Finally you can build using the generated Makefile:
|
||||
|
||||
make
|
||||
|
||||
|
||||
Quirk of cmake
|
||||
--------------
|
||||
|
||||
When changing cmake options, for some reason the only way to get it to see the
|
||||
changes sometimes is delete the contents of your build directory and do the
|
||||
cmake from scratch.
|
||||
|
||||
|
||||
Building on Windows (Visual Studio)
|
||||
-----------------------------------
|
||||
1. Install CMake 2.6 or greater: http://cmake.org/cmake/resources/software.html
|
||||
|
||||
2. Install OpenSSL binaries. http://www.openssl.org/related/binaries.html
|
||||
(Preferably in the default location to make it easier for CMake to find them)
|
||||
|
||||
3. Generate the Visual studio project by opening the Visual Studio cmd prompt:
|
||||
|
||||
cd <path to src>
|
||||
md build
|
||||
cd build
|
||||
cmake -G "Visual Studio 10" ..
|
||||
|
||||
(NOTE: There is also a cmake-gui available on Windows if you prefer that)
|
||||
|
||||
4. Now you should have a generated Visual Studio Solution in your
|
||||
<path to src>/build directory, which can be used to build.
|
||||
|
||||
Setting compile options
|
||||
-----------------------
|
||||
|
||||
To set compile time flags you can either use one of the CMake gui applications
|
||||
or do it via command line.
|
||||
|
||||
Command line
|
||||
------------
|
||||
To list avaialable options (ommit the H if you don't want the help text):
|
||||
|
||||
cmake -LH ..
|
||||
|
||||
Then to set an option and build (for example turn off SSL support):
|
||||
|
||||
cmake -DLWS_WITH_SSL=0 ..
|
||||
or
|
||||
cmake -DLWS_WITH_SSL:BOOL=OFF ..
|
||||
|
||||
Unix GUI
|
||||
--------
|
||||
If you have a curses enabled build you simply type:
|
||||
(not all packages include this, my debian install does not for example).
|
||||
|
||||
ccmake
|
||||
|
||||
Windows GUI
|
||||
-----------
|
||||
On windows CMake comes with a gui application:
|
||||
Start -> Programs -> CMake -> CMake (cmake-gui)
|
||||
|
||||
CyaSSL replacement for OpenSSL
|
||||
------------------------------
|
||||
CyaSSL is a lightweight SSL library targeted at embedded system:
|
||||
http://www.yassl.com/yaSSL/Products-cyassl.html
|
||||
|
||||
It contains a OpenSSL compatability layer which makes it possible to pretty
|
||||
much link to it instead of OpenSSL, giving a much smaller footprint.
|
||||
|
||||
NOTE: cyassl needs to be compiled using the --enable-opensslextra flag for
|
||||
this to work.
|
||||
|
||||
Compiling libwebsockets with CyaSSL
|
||||
-----------------------------------
|
||||
|
||||
cmake .. -DLWS_USE_CYASSL=1 \
|
||||
-DLWS_CYASSL_INCLUDE_DIRS=/path/to/cyassl \
|
||||
-DLWS_CYASSL_LIB=/path/to/cyassl/cyassl.a ..
|
||||
|
||||
NOTE: On windows use the .lib file extension for LWS_CYASSL_LIB instead.
|
||||
|
||||
Cross compiling
|
||||
---------------
|
||||
To enable cross compiling libwebsockets using CMake you need to create
|
||||
a "Toolchain file" that you supply to CMake when generating your build files.
|
||||
CMake will then use the cross compilers and build paths specified in this file
|
||||
to look for dependencies and such.
|
||||
|
||||
Libwebsockets includes an example toolchain file cross-arm-linux-gnueabihf.cmake
|
||||
you can use as a starting point.
|
||||
|
||||
The commandline to configure for cross with this would look like
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake \
|
||||
-DWITHOUT_EXTENSIONS=1 -DWITH_SSL=0
|
||||
|
||||
The example shows how to build with no external cross lib dependencies, you
|
||||
need to proide the cross libraries otherwise.
|
||||
|
||||
NOTE: start from an EMPTY build directory if you had a non-cross build in there
|
||||
before the settings will be cached and your changes ignored.
|
||||
|
||||
Additional information on cross compilation with CMake:
|
||||
http://www.vtk.org/Wiki/CMake_Cross_Compiling
|
||||
|
||||
|
||||
Memory efficiency
|
||||
-----------------
|
||||
|
||||
Embedded server-only configuration without extensions (ie, no compression
|
||||
on websocket connections), but with full v13 websocket features and http
|
||||
server, built on ARM Cortex-A9:
|
||||
|
||||
Update at 8dac94d (2013-02-18)
|
||||
|
||||
./configure --without-client --without-extensions --disable-debug --without-daemonize
|
||||
|
||||
Context Creation, 1024 fd limit[2]: 16720 (includes 12 bytes per fd)
|
||||
Per-connection [3]: 72 bytes, +1328 during headers
|
||||
|
||||
.text .rodata .data .bss
|
||||
11512 2784 288 4
|
||||
|
||||
This shows the impact of the major configuration with/without options at
|
||||
13ba5bbc633ea962d46d using Ubuntu ARM on a PandaBoard ES.
|
||||
|
||||
These are accounting for static allocations from the library elf, there are
|
||||
additional dynamic allocations via malloc. These are a bit old now but give
|
||||
the right idea for relative "expense" of features.
|
||||
|
||||
Static allocations, ARM9
|
||||
.text .rodata .data .bss
|
||||
All (no without) 35024 9940 336 4104
|
||||
without client 25684 7144 336 4104
|
||||
without client, exts 21652 6288 288 4104
|
||||
without client, exts, debug[1] 19756 3768 288 4104
|
||||
without server 30304 8160 336 4104
|
||||
without server, exts 25382 7204 288 4104
|
||||
without server, exts, debug[1] 23712 4256 288 4104
|
||||
|
||||
[1] --disable-debug only removes messages below lwsl_notice. Since that is
|
||||
the default logging level the impact is not noticable, error, warn and notice
|
||||
logs are all still there.
|
||||
|
||||
[2] 1024 fd per process is the default limit (set by ulimit) in at least Fedora
|
||||
and Ubuntu. You can make significant savings tailoring this to actual expected
|
||||
peak fds, ie, at a limit of 20, context creation allocation reduces to 4432 +
|
||||
240 = 4672)
|
||||
|
||||
[3] known header content is freed after connection establishment
|
||||
|
||||
|
||||
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
Daemonization
|
||||
-------------
|
||||
|
||||
There's a helper api lws_daemonize built by default that does everything you
|
||||
need to daemonize well, including creating a lock file. If you're making
|
||||
what's basically a daemon, just call this early in your init to fork to a
|
||||
headless background process and exit the starting process.
|
||||
|
||||
Notice stdout, stderr, stdin are all redirected to /dev/null to enforce your
|
||||
daemon is headless, so you'll need to sort out alternative logging, by, eg,
|
||||
syslog.
|
||||
|
||||
|
||||
Maximum number of connections
|
||||
-----------------------------
|
||||
|
||||
The maximum number of connections the library can deal with is decided when
|
||||
it starts by querying the OS to find out how many file descriptors it is
|
||||
allowed to open (1024 on Fedora for example). It then allocates arrays that
|
||||
allow up to that many connections, minus whatever other file descriptors are
|
||||
in use by the user code.
|
||||
|
||||
If you want to restrict that allocation, or increase it, you can use ulimit or
|
||||
similar to change the avaiable number of file descriptors, and when restarted
|
||||
libwebsockets will adapt accordingly.
|
||||
|
||||
|
||||
Libwebsockets is singlethreaded
|
||||
-------------------------------
|
||||
|
||||
Directly performing websocket actions from other threads is not allowed.
|
||||
Aside from the internal data being inconsistent in forked() processes,
|
||||
the scope of a wsi (struct websocket) can end at any time during service
|
||||
with the socket closing and the wsi freed.
|
||||
|
||||
Websocket write activities should only take place in the
|
||||
"LWS_CALLBACK_SERVER_WRITEABLE" callback as described below.
|
||||
|
||||
Only live connections appear in the user callbacks, so this removes any
|
||||
possibility of trying to used closed and freed wsis.
|
||||
|
||||
If you need to service other socket or file descriptors as well as the
|
||||
websocket ones, you can combine them together with the websocket ones
|
||||
in one poll loop, see "External Polling Loop support" below, and
|
||||
still do it all in one thread / process context.
|
||||
|
||||
|
||||
Only send data when socket writeable
|
||||
------------------------------------
|
||||
|
||||
You should only send data on a websocket connection from the user callback
|
||||
"LWS_CALLBACK_SERVER_WRITEABLE" (or "LWS_CALLBACK_CLIENT_WRITEABLE" for
|
||||
clients).
|
||||
|
||||
If you want to send something, do not just send it but request a callback
|
||||
when the socket is writeable using
|
||||
|
||||
- libwebsocket_callback_on_writable(context, wsi) for a specific wsi, or
|
||||
- libwebsocket_callback_on_writable_all_protocol(protocol) for all connections
|
||||
using that protocol to get a callback when next writeable.
|
||||
|
||||
Usually you will get called back immediately next time around the service
|
||||
loop, but if your peer is slow or temporarily inactive the callback will be
|
||||
delayed accordingly. Generating what to write and sending it should be done
|
||||
in the ...WRITEABLE callback.
|
||||
|
||||
See the test server code for an example of how to do this.
|
||||
|
||||
|
||||
Do not rely on only your own WRITEABLE requests appearing
|
||||
---------------------------------------------------------
|
||||
|
||||
Libwebsockets may generate additional LWS_CALLBACK_CLIENT_WRITEABLE events
|
||||
if it met network conditions where it had to buffer your send data internally.
|
||||
|
||||
So your code for LWS_CALLBACK_CLIENT_WRITEABLE needs to own the decision
|
||||
about what to send, it can't assume that just because the writeable callback
|
||||
came it really is time to send something.
|
||||
|
||||
It's quite possible you get an 'extra' writeable callback at any time and
|
||||
just need to return 0 and wait for the expected callback later.
|
||||
|
||||
|
||||
Closing connections from the user side
|
||||
--------------------------------------
|
||||
|
||||
When you want to close a connection, you do it by returning -1 from a
|
||||
callback for that connection.
|
||||
|
||||
You can provoke a callback by calling libwebsocket_callback_on_writable on
|
||||
the wsi, then notice in the callback you want to close it and just return -1.
|
||||
But usually, the decision to close is made in a callback already and returning
|
||||
-1 is simple.
|
||||
|
||||
If the socket knows the connection is dead, because the peer closed or there
|
||||
was an affirmitive network error like a FIN coming, then libwebsockets will
|
||||
take care of closing the connection automatically.
|
||||
|
||||
If you have a silently dead connection, it's possible to enter a state where
|
||||
the send pipe on the connection is choked but no ack will ever come, so the
|
||||
dead connection will never become writeable. To cover that, you can use TCP
|
||||
keepalives (see later in this document)
|
||||
|
||||
|
||||
Fragmented messages
|
||||
-------------------
|
||||
|
||||
To support fragmented messages you need to check for the final
|
||||
frame of a message with libwebsocket_is_final_fragment. This
|
||||
check can be combined with libwebsockets_remaining_packet_payload
|
||||
to gather the whole contents of a message, eg:
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
{
|
||||
Client * const client = (Client *)user;
|
||||
const size_t remaining = libwebsockets_remaining_packet_payload(wsi);
|
||||
|
||||
if (!remaining && libwebsocket_is_final_fragment(wsi)) {
|
||||
if (client->HasFragments()) {
|
||||
client->AppendMessageFragment(in, len, 0);
|
||||
in = (void *)client->GetMessage();
|
||||
len = client->GetMessageLength();
|
||||
}
|
||||
|
||||
client->ProcessMessage((char *)in, len, wsi);
|
||||
client->ResetMessage();
|
||||
} else
|
||||
client->AppendMessageFragment(in, len, remaining);
|
||||
}
|
||||
break;
|
||||
|
||||
The test app llibwebsockets-test-fraggle sources also show how to
|
||||
deal with fragmented messages.
|
||||
|
||||
|
||||
Debug Logging
|
||||
-------------
|
||||
|
||||
Also using lws_set_log_level api you may provide a custom callback to actually
|
||||
emit the log string. By default, this points to an internal emit function
|
||||
that sends to stderr. Setting it to NULL leaves it as it is instead.
|
||||
|
||||
A helper function lwsl_emit_syslog() is exported from the library to simplify
|
||||
logging to syslog. You still need to use setlogmask, openlog and closelog
|
||||
in your user code.
|
||||
|
||||
The logging apis are made available for user code.
|
||||
|
||||
lwsl_err(...)
|
||||
lwsl_warn(...)
|
||||
lwsl_notice(...)
|
||||
lwsl_info(...)
|
||||
lwsl_debug(...)
|
||||
|
||||
The difference between notice and info is that notice will be logged by default
|
||||
whereas info is ignored by default.
|
||||
|
||||
|
||||
External Polling Loop support
|
||||
-----------------------------
|
||||
|
||||
libwebsockets maintains an internal poll() array for all of its
|
||||
sockets, but you can instead integrate the sockets into an
|
||||
external polling array. That's needed if libwebsockets will
|
||||
cooperate with an existing poll array maintained by another
|
||||
server.
|
||||
|
||||
Four callbacks LWS_CALLBACK_ADD_POLL_FD, LWS_CALLBACK_DEL_POLL_FD,
|
||||
LWS_CALLBACK_SET_MODE_POLL_FD and LWS_CALLBACK_CLEAR_MODE_POLL_FD
|
||||
appear in the callback for protocol 0 and allow interface code to
|
||||
manage socket descriptors in other poll loops.
|
||||
|
||||
You can pass all pollfds that need service to libwebsocket_service_fd(), even
|
||||
if the socket or file does not belong to libwebsockets it is safe.
|
||||
|
||||
If libwebsocket handled it, it zeros the pollfd revents field before returning.
|
||||
So you can let libwebsockets try and if pollfd->revents is nonzero on return,
|
||||
you know it needs handling by your code.
|
||||
|
||||
|
||||
Using with in c++ apps
|
||||
----------------------
|
||||
|
||||
The library is ready for use by C++ apps. You can get started quickly by
|
||||
copying the test server
|
||||
|
||||
$ cp test-server/test-server.c test.cpp
|
||||
|
||||
and building it in C++ like this
|
||||
|
||||
$ g++ -DINSTALL_DATADIR=\"/usr/share\" -ocpptest test.cpp -lwebsockets
|
||||
|
||||
INSTALL_DATADIR is only needed because the test server uses it as shipped, if
|
||||
you remove the references to it in your app you don't need to define it on
|
||||
the g++ line either.
|
||||
|
||||
|
||||
Availability of header information
|
||||
----------------------------------
|
||||
|
||||
From v1.2 of the library onwards, the HTTP header content is free()d as soon
|
||||
as the websocket connection is established. For websocket servers, you can
|
||||
copy interesting headers by handling LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION
|
||||
callback, for clients there's a new callback just for this purpose
|
||||
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH.
|
||||
|
||||
|
||||
TCP Keepalive
|
||||
-------------
|
||||
|
||||
It is possible for a connection which is not being used to send to die
|
||||
silently somewhere between the peer and the side not sending. In this case
|
||||
by default TCP will just not report anything and you will never get any more
|
||||
incoming data or sign the link is dead until you try to send.
|
||||
|
||||
To deal with getting a notification of that situation, you can choose to
|
||||
enable TCP keepalives on all libwebsockets sockets, when you create the
|
||||
context.
|
||||
|
||||
To enable keepalive, set the ka_time member of the context creation parameter
|
||||
struct to a nonzero value (in seconds) at context creation time. You should
|
||||
also fill ka_probes and ka_interval in that case.
|
||||
|
||||
With keepalive enabled, the TCP layer will send control packets that should
|
||||
stimulate a response from the peer without affecting link traffic. If the
|
||||
response is not coming, the socket will announce an error at poll() forcing
|
||||
a close.
|
||||
|
||||
Note that BSDs don't support keepalive time / probes / inteveral per-socket
|
||||
like Linux does. On those systems you can enable keepalive by a nonzero
|
||||
value in ka_time, but the systemwide kernel settings for the time / probes/
|
||||
interval are used, regardless of what nonzero value is in ka_time.
|
||||
|
||||
Optimizing SSL connections
|
||||
--------------------------
|
||||
|
||||
There's a member ssl_cipher_list in the lws_context_creation_info struct
|
||||
which allows the user code to restrict the possible cipher selection at
|
||||
context-creation time.
|
||||
|
||||
You might want to look into that to stop the ssl peers selecting a ciher which
|
||||
is too computationally expensive. To use it, point it to a string like
|
||||
|
||||
"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
|
||||
|
||||
if left NULL, then the "DEFAULT" set of ciphers are all possible to select.
|
||||
|
||||
|
||||
Async nature of client connections
|
||||
----------------------------------
|
||||
|
||||
When you call libwebsocket_client_connect(..) and get a wsi back, it does not
|
||||
mean your connection is active. It just mean it started trying to connect.
|
||||
|
||||
Your client connection is actually active only when you receive
|
||||
LWS_CALLBACK_CLIENT_ESTABLISHED for it.
|
||||
|
||||
There's a 5 second timeout for the connection, and it may give up or die for
|
||||
other reasons, if any of that happens you'll get a
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR callback on protocol 0 instead for the
|
||||
wsi.
|
||||
|
||||
After attempting the connection and getting back a non-NULL wsi you should
|
||||
loop calling libwebsocket_service() until one of the above callbacks occurs.
|
||||
|
||||
As usual, see test-client.c for example code.
|
||||
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
Testing server with a browser
|
||||
-----------------------------
|
||||
|
||||
If you run libwebsockets-test-server and point your browser
|
||||
(eg, Chrome) to
|
||||
|
||||
http://127.0.0.1:7681
|
||||
|
||||
It will fetch a script in the form of test.html, and then run the
|
||||
script in there on the browser to open a websocket connection.
|
||||
Incrementing numbers should appear in the browser display.
|
||||
|
||||
By default the test server logs to both stderr and syslog, you can control
|
||||
what is logged using -d <log level>, see later.
|
||||
|
||||
|
||||
Running test server as a Daemon
|
||||
-------------------------------
|
||||
|
||||
You can use the -D option on the test server to have it fork into the
|
||||
background and return immediately. In this daemonized mode all stderr is
|
||||
disabled and logging goes only to syslog, eg, /var/log/messages or similar.
|
||||
|
||||
The server maintains a lockfile at /tmp/.lwsts-lock that contains the pid
|
||||
of the master process, and deletes this file when the master process
|
||||
terminates.
|
||||
|
||||
To stop the daemon, do
|
||||
|
||||
kill `cat /tmp/.lwsts-lock`
|
||||
|
||||
If it finds a stale lock (the pid mentioned in the file does not exist
|
||||
any more) it will delete the lock and create a new one during startup.
|
||||
|
||||
If the lock is valid, the daemon will exit with a note on stderr that
|
||||
it was already running.s
|
||||
|
||||
|
||||
Using SSL on the server side
|
||||
----------------------------
|
||||
|
||||
To test it using SSL/WSS, just run the test server with
|
||||
|
||||
$ libwebsockets-test-server --ssl
|
||||
|
||||
and use the URL
|
||||
|
||||
https://127.0.0.1:7681
|
||||
|
||||
The connection will be entirely encrypted using some generated
|
||||
certificates that your browser will not accept, since they are
|
||||
not signed by any real Certificate Authority. Just accept the
|
||||
certificates in the browser and the connection will proceed
|
||||
in first https and then websocket wss, acting exactly the
|
||||
same.
|
||||
|
||||
test-server.c is all that is needed to use libwebsockets for
|
||||
serving both the script html over http and websockets.
|
||||
|
||||
|
||||
Testing websocket client support
|
||||
--------------------------------
|
||||
|
||||
If you run the test server as described above, you can also
|
||||
connect to it using the test client as well as a browser.
|
||||
|
||||
$ libwebsockets-test-client localhost
|
||||
|
||||
will by default connect to the test server on localhost:7681
|
||||
and print the dumb increment number from the server at the
|
||||
same time as drawing random circles in the mirror protocol;
|
||||
if you connect to the test server using a browser at the
|
||||
same time you will be able to see the circles being drawn.
|
||||
|
||||
|
||||
Testing simple echo
|
||||
-------------------
|
||||
|
||||
You can test against echo.websockets.org as a sanity test like
|
||||
this (the client connects to port 80 by default):
|
||||
|
||||
$ libwebsockets-test-echo --client echo.websocket.org
|
||||
|
||||
This echo test is of limited use though because it doesn't
|
||||
negotiate any protocol. You can run the same test app as a
|
||||
local server, by default on localhost:7681
|
||||
|
||||
$ libwebsockets-test-echo
|
||||
|
||||
and do the echo test against the local echo server
|
||||
|
||||
$ libwebsockets-test-echo --client localhost --port 7681
|
||||
|
||||
If you add the --ssl switch to both the client and server, you can also test
|
||||
with an encrypted link.
|
||||
|
||||
|
||||
Testing SSL on the client side
|
||||
------------------------------
|
||||
|
||||
To test SSL/WSS client action, just run the client test with
|
||||
|
||||
$ libwebsockets-test-client localhost --ssl
|
||||
|
||||
By default the client test applet is set to accept selfsigned
|
||||
certificates used by the test server, this is indicated by the
|
||||
use_ssl var being set to 2. Set it to 1 to reject any server
|
||||
certificate that it doesn't have a trusted CA cert for.
|
||||
|
||||
|
||||
Using the websocket ping utility
|
||||
--------------------------------
|
||||
|
||||
libwebsockets-test-ping connects as a client to a remote
|
||||
websocket server using 04 protocol and pings it like the
|
||||
normal unix ping utility.
|
||||
|
||||
$ libwebsockets-test-ping localhost
|
||||
handshake OK for protocol lws-mirror-protocol
|
||||
Websocket PING localhost.localdomain (127.0.0.1) 64 bytes of data.
|
||||
64 bytes from localhost: req=1 time=0.1ms
|
||||
64 bytes from localhost: req=2 time=0.1ms
|
||||
64 bytes from localhost: req=3 time=0.1ms
|
||||
64 bytes from localhost: req=4 time=0.2ms
|
||||
64 bytes from localhost: req=5 time=0.1ms
|
||||
64 bytes from localhost: req=6 time=0.2ms
|
||||
64 bytes from localhost: req=7 time=0.2ms
|
||||
64 bytes from localhost: req=8 time=0.1ms
|
||||
^C
|
||||
--- localhost.localdomain websocket ping statistics ---
|
||||
8 packets transmitted, 8 received, 0% packet loss, time 7458ms
|
||||
rtt min/avg/max = 0.110/0.185/0.218 ms
|
||||
$
|
||||
|
||||
By default it sends 64 byte payload packets using the 04
|
||||
PING packet opcode type. You can change the payload size
|
||||
using the -s= flag, up to a maximum of 125 mandated by the
|
||||
04 standard.
|
||||
|
||||
Using the lws-mirror protocol that is provided by the test
|
||||
server, libwebsockets-test-ping can also use larger payload
|
||||
sizes up to 4096 is BINARY packets; lws-mirror will copy
|
||||
them back to the client and they appear as a PONG. Use the
|
||||
-m flag to select this operation.
|
||||
|
||||
The default interval between pings is 1s, you can use the -i=
|
||||
flag to set this, including fractions like -i=0.01 for 10ms
|
||||
interval.
|
||||
|
||||
Before you can even use the PING opcode that is part of the
|
||||
standard, you must complete a handshake with a specified
|
||||
protocol. By default lws-mirror-protocol is used which is
|
||||
supported by the test server. But if you are using it on
|
||||
another server, you can specify the protcol to handshake with
|
||||
by --protocol=protocolname
|
||||
|
||||
|
||||
Fraggle test app
|
||||
----------------
|
||||
|
||||
By default it runs in server mode
|
||||
|
||||
$ libwebsockets-test-fraggle
|
||||
libwebsockets test fraggle
|
||||
(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1
|
||||
Compiled with SSL support, not using it
|
||||
Listening on port 7681
|
||||
server sees client connect
|
||||
accepted v06 connection
|
||||
Spamming 360 random fragments
|
||||
Spamming session over, len = 371913. sum = 0x2D3C0AE
|
||||
Spamming 895 random fragments
|
||||
Spamming session over, len = 875970. sum = 0x6A74DA1
|
||||
...
|
||||
|
||||
You need to run a second session in client mode, you have to
|
||||
give the -c switch and the server address at least:
|
||||
|
||||
$ libwebsockets-test-fraggle -c localhost
|
||||
libwebsockets test fraggle
|
||||
(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> licensed under LGPL2.1
|
||||
Client mode
|
||||
Connecting to localhost:7681
|
||||
denied deflate-stream extension
|
||||
handshake OK for protocol fraggle-protocol
|
||||
client connects to server
|
||||
EOM received 371913 correctly from 360 fragments
|
||||
EOM received 875970 correctly from 895 fragments
|
||||
EOM received 247140 correctly from 258 fragments
|
||||
EOM received 695451 correctly from 692 fragments
|
||||
...
|
||||
|
||||
The fraggle test sends a random number up to 1024 fragmented websocket frames
|
||||
each of a random size between 1 and 2001 bytes in a single message, then sends
|
||||
a checksum and starts sending a new randomly sized and fragmented message.
|
||||
|
||||
The fraggle test client receives the same message fragments and computes the
|
||||
same checksum using websocket framing to see when the message has ended. It
|
||||
then accepts the server checksum message and compares that to its checksum.
|
||||
|
||||
|
||||
proxy support
|
||||
-------------
|
||||
|
||||
The http_proxy environment variable is respected by the client
|
||||
connection code for both ws:// and wss://. It doesn't support
|
||||
authentication.
|
||||
|
||||
You use it like this
|
||||
|
||||
export http_proxy=myproxy.com:3128
|
||||
libwebsockets-test-client someserver.com
|
||||
|
||||
|
||||
debug logging
|
||||
-------------
|
||||
|
||||
By default logging of severity "notice", "warn" or "err" is enabled to stderr.
|
||||
|
||||
Again by default other logging is comiled in but disabled from printing.
|
||||
|
||||
If you want to eliminate the debug logging below notice in severity, use the
|
||||
--disable-debug configure option to have it removed from the code by the
|
||||
preprocesser.
|
||||
|
||||
If you want to see more detailed debug logs, you can control a bitfield to
|
||||
select which logs types may print using the lws_set_log_level() api, in the
|
||||
test apps you can use -d <number> to control this. The types of logging
|
||||
available are (OR together the numbers to select multiple)
|
||||
|
||||
1 ERR
|
||||
2 WARN
|
||||
4 NOTICE
|
||||
8 INFO
|
||||
16 DEBUG
|
||||
32 PARSER
|
||||
64 HEADER
|
||||
128 EXTENSION
|
||||
256 CLIENT
|
||||
512 LATENCY
|
||||
|
||||
|
||||
Websocket version supported
|
||||
---------------------------
|
||||
|
||||
The final IETF standard is supported for both client and server, protocol
|
||||
version 13.
|
||||
|
||||
|
||||
Latency Tracking
|
||||
----------------
|
||||
|
||||
Since libwebsockets runs using poll() and a single threaded approach, any
|
||||
unexpected latency coming from system calls would be bad news. There's now
|
||||
a latency tracking scheme that can be built in with --with-latency at
|
||||
configure-time, logging the time taken for system calls to complete and if
|
||||
the whole action did complete that time or was deferred.
|
||||
|
||||
You can see the detailed data by enabling logging level 512 (eg, -d 519 on
|
||||
the test server to see that and the usual logs), however even without that
|
||||
the "worst" latency is kept and reported to the logs with NOTICE severity
|
||||
when the context is destroyed.
|
||||
|
||||
Some care is needed interpreting them, if the action completed the first figure
|
||||
(in us) is the time taken for the whole action, which may have retried through
|
||||
the poll loop many times and will depend on network roundtrip times. High
|
||||
figures here don't indicate a problem. The figure in us reported after "lat"
|
||||
in the logging is the time taken by this particular attempt. High figures
|
||||
here may indicate a problem, or if you system is loaded with another app at
|
||||
that time, such as the browser, it may simply indicate the OS gave preferential
|
||||
treatment to the other app during that call.
|
||||
|
||||
Vendored
+621
@@ -0,0 +1,621 @@
|
||||
Changelog
|
||||
---------
|
||||
|
||||
v1.3-chrome37-firefox30
|
||||
=======================
|
||||
|
||||
.gitignore | 1 -
|
||||
CMakeLists.txt | 447 +++--
|
||||
README.build | 35 +-
|
||||
README.coding | 14 +
|
||||
changelog | 66 +
|
||||
cmake/LibwebsocketsConfig.cmake.in | 17 +
|
||||
cmake/LibwebsocketsConfigVersion.cmake.in | 11 +
|
||||
config.h.cmake | 18 +
|
||||
cross-ming.cmake | 31 +
|
||||
cross-openwrt-makefile | 91 +
|
||||
lib/client-handshake.c | 205 ++-
|
||||
lib/client-parser.c | 58 +-
|
||||
lib/client.c | 158 +-
|
||||
lib/context.c | 341 ++++
|
||||
lib/extension-deflate-frame.c | 2 +-
|
||||
lib/extension.c | 178 ++
|
||||
lib/handshake.c | 287 +---
|
||||
lib/lextable.h | 338 ++++
|
||||
lib/libev.c | 175 ++
|
||||
lib/libwebsockets.c | 2089 +++--------------------
|
||||
lib/libwebsockets.h | 253 ++-
|
||||
lib/lws-plat-unix.c | 404 +++++
|
||||
lib/lws-plat-win.c | 358 ++++
|
||||
lib/minilex.c | 530 +++---
|
||||
lib/output.c | 445 ++---
|
||||
lib/parsers.c | 682 ++++----
|
||||
lib/pollfd.c | 239 +++
|
||||
lib/private-libwebsockets.h | 501 +++++-
|
||||
lib/server-handshake.c | 274 +--
|
||||
lib/server.c | 858 ++++++++--
|
||||
lib/service.c | 517 ++++++
|
||||
lib/sha-1.c | 38 +-
|
||||
lib/ssl-http2.c | 78 +
|
||||
lib/ssl.c | 571 +++++++
|
||||
test-server/attack.sh | 101 +-
|
||||
test-server/test-client.c | 9 +-
|
||||
test-server/test-echo.c | 17 +-
|
||||
test-server/test-fraggle.c | 7 -
|
||||
test-server/test-ping.c | 12 +-
|
||||
test-server/test-server.c | 330 ++--
|
||||
test-server/test.html | 4 +-
|
||||
win32port/client/client.vcxproj | 259 ---
|
||||
win32port/client/client.vcxproj.filters | 39 -
|
||||
.../libwebsocketswin32.vcxproj.filters | 93 -
|
||||
win32port/server/server.vcxproj | 276 ---
|
||||
win32port/server/server.vcxproj.filters | 51 -
|
||||
win32port/win32helpers/gettimeofday.h | 59 +-
|
||||
win32port/win32helpers/netdb.h | 1 -
|
||||
win32port/win32helpers/strings.h | 0
|
||||
win32port/win32helpers/sys/time.h | 1 -
|
||||
win32port/win32helpers/unistd.h | 0
|
||||
win32port/win32helpers/websock-w32.c | 104 --
|
||||
win32port/win32helpers/websock-w32.h | 62 -
|
||||
win32port/win32port.sln | 100 --
|
||||
win32port/zlib/gzio.c | 3 +-
|
||||
55 files changed, 6779 insertions(+), 5059 deletions(-)
|
||||
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
POST method is supported
|
||||
|
||||
The protocol 0 / HTTP callback can now get two new kinds of callback,
|
||||
LWS_CALLBACK_HTTP_BODY (in and len are a chunk of the body of the HTTP request)
|
||||
and LWS_CALLBACK_HTTP_BODY_COMPLETION (the expected amount of body has arrived
|
||||
and been passed to the user code already). These callbacks are used with the
|
||||
post method (see the test server for details).
|
||||
|
||||
The period between the HTTP header completion and the completion of the body
|
||||
processing is protected by a 5s timeout.
|
||||
|
||||
The chunks are stored in a malloc'd buffer of size protocols[0].rx_buffer_size.
|
||||
|
||||
|
||||
New server option you can enable from user code
|
||||
LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT allows non-SSL connections to
|
||||
also be accepted on an SSL listening port. It's disabled unless you enable
|
||||
it explicitly.
|
||||
|
||||
|
||||
Two new callbacks are added in protocols[0] that are optional for allowing
|
||||
limited thread access to libwebsockets, LWS_CALLBACK_LOCK_POLL and
|
||||
LWS_CALLBACK_UNLOCK_POLL.
|
||||
|
||||
If you use them, they protect internal and external poll list changes, but if
|
||||
you want to use external thread access to libwebsocket_callback_on_writable()
|
||||
you have to implement your locking here even if you don't use external
|
||||
poll support.
|
||||
|
||||
If you will use another thread for this, take a lot of care about managing
|
||||
your list of live wsi by doing it from ESTABLISHED and CLOSED callbacks
|
||||
(with your own locking).
|
||||
|
||||
If you configure cmake with -DLWS_WITH_LIBEV=1 then the code allowing the libev
|
||||
eventloop instead of the default poll() one will also be compiled in. But to
|
||||
use it, you must also set the LWS_SERVER_OPTION_LIBEV flag on the context
|
||||
creation info struct options member.
|
||||
|
||||
IPV6 is supported and enabled by default except for Windows, you can disable
|
||||
the support at build-time by giving -DLWS_IPV6=, and disable use of it even if
|
||||
compiled in by making sure the flag LWS_SERVER_OPTION_DISABLE_IPV6 is set on
|
||||
the context creation info struct options member.
|
||||
|
||||
You can give LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS option flag to
|
||||
guarantee the OS CAs will not be used, even if that support was selected at
|
||||
build-time.
|
||||
|
||||
Optional "token limits" may be enforced by setting the member "token_limits"
|
||||
in struct lws_context_creation_info to point to a struct lws_token_limits.
|
||||
NULL means no token limits used for compatibility.
|
||||
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
Extra optional argument to libwebsockets_serve_http_file() allows injecion
|
||||
of HTTP headers into the canned response. Eg, cookies may be added like
|
||||
that without getting involved in having to send the header by hand.
|
||||
|
||||
A new info member http_proxy_address may be used at context creation time to
|
||||
set the http proxy. If non-NULL, it overrides http_proxy environment var.
|
||||
|
||||
Cmake supports LWS_SSL_CLIENT_USE_OS_CA_CERTS defaulting to on, which gets
|
||||
the client to use the OS CA Roots. If you're worried somebody with the
|
||||
ability to forge for force creation of a client cert from the root CA in
|
||||
your OS, you should disable this since your selfsigned $0 cert is a lot safer
|
||||
then...
|
||||
|
||||
|
||||
v1.23-chrome32-firefox24
|
||||
========================
|
||||
|
||||
Android.mk | 29 +
|
||||
CMakeLists.txt | 573 ++++++++----
|
||||
COPYING | 503 -----------
|
||||
INSTALL | 365 --------
|
||||
Makefile.am | 13 -
|
||||
README.build | 371 ++------
|
||||
README.coding | 63 ++
|
||||
autogen.sh | 1578 ---------------------------------
|
||||
changelog | 69 ++
|
||||
cmake/FindGit.cmake | 163 ++++
|
||||
cmake/FindOpenSSLbins.cmake | 15 +-
|
||||
cmake/UseRPMTools.cmake | 176 ++++
|
||||
config.h.cmake | 25 +-
|
||||
configure.ac | 226 -----
|
||||
cross-arm-linux-gnueabihf.cmake | 28 +
|
||||
lib/Makefile.am | 89 --
|
||||
lib/base64-decode.c | 98 +-
|
||||
lib/client-handshake.c | 123 ++-
|
||||
lib/client-parser.c | 19 +-
|
||||
lib/client.c | 145 ++-
|
||||
lib/daemonize.c | 4 +-
|
||||
lib/extension.c | 2 +-
|
||||
lib/getifaddrs.h | 4 +-
|
||||
lib/handshake.c | 76 +-
|
||||
lib/libwebsockets.c | 491 ++++++----
|
||||
lib/libwebsockets.h | 164 ++--
|
||||
lib/output.c | 214 ++++-
|
||||
lib/parsers.c | 102 +--
|
||||
lib/private-libwebsockets.h | 66 +-
|
||||
lib/server-handshake.c | 5 +-
|
||||
lib/server.c | 29 +-
|
||||
lib/sha-1.c | 2 +-
|
||||
libwebsockets-api-doc.html | 249 +++---
|
||||
libwebsockets.pc.in | 11 -
|
||||
libwebsockets.spec | 14 +-
|
||||
m4/ignore-me | 2 -
|
||||
scripts/FindLibWebSockets.cmake | 33 +
|
||||
scripts/kernel-doc | 1 +
|
||||
test-server/Makefile.am | 131 ---
|
||||
test-server/leaf.jpg | Bin 0 -> 2477518 bytes
|
||||
test-server/test-client.c | 78 +-
|
||||
test-server/test-echo.c | 33 +-
|
||||
test-server/test-fraggle.c | 26 +-
|
||||
test-server/test-ping.c | 15 +-
|
||||
test-server/test-server.c | 197 +++-
|
||||
test-server/test.html | 5 +-
|
||||
win32port/win32helpers/gettimeofday.c | 74 +-
|
||||
win32port/win32helpers/websock-w32.h | 6 +-
|
||||
48 files changed, 2493 insertions(+), 4212 deletions(-)
|
||||
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
- You can now call libwebsocket_callback_on_writable() on http connectons,
|
||||
and get a LWS_CALLBACK_HTTP_WRITEABLE callback, the same way you can
|
||||
regulate writes with a websocket protocol connection.
|
||||
|
||||
- A new member in the context creation parameter struct "ssl_cipher_list" is
|
||||
added, replacing CIPHERS_LIST_STRING. NULL means use the ssl library
|
||||
default list of ciphers.
|
||||
|
||||
- Not really an api addition, but libwebsocket_service_fd() will now zero
|
||||
the revents field of the pollfd it was called with if it handled the
|
||||
descriptor. So you can tell if it is a non-lws fd by checking revents
|
||||
after the service call... if it's still nonzero, the descriptor
|
||||
belongs to you and you need to take care of it.
|
||||
|
||||
- libwebsocket_rx_flow_allow_all_protocol(protocol) will unthrottle all
|
||||
connections with the established protocol. It's designed to be
|
||||
called from user server code when it sees it can accept more input
|
||||
and may have throttled connections using the server rx flow apis
|
||||
while it was unable to accept any other input The user server code
|
||||
then does not have to try to track while connections it choked, this
|
||||
will free up all of them in one call.
|
||||
|
||||
- there's a new, optional callback LWS_CALLBACK_CLOSED_HTTP which gets
|
||||
called when an HTTP protocol socket closes
|
||||
|
||||
- for LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION callback, the user_space alloc
|
||||
has already been done before the callback happens. That means we can
|
||||
use the user parameter to the callback to contain the user pointer, and
|
||||
move the protocol name to the "in" parameter. The docs for this
|
||||
callback are also updated to reflect how to check headers in there.
|
||||
|
||||
- libwebsocket_client_connect() is now properly nonblocking and async. See
|
||||
README.coding and test-client.c for information on the callbacks you
|
||||
can rely on controlling the async connection period with.
|
||||
|
||||
- if your OS does not support the http_proxy environment variable convention
|
||||
(eg, reportedly OSX), you can use a new api libwebsocket_set_proxy()
|
||||
to set the proxy details inbetween context creation and the connection
|
||||
action. For OSes that support http_proxy, that's used automatically.
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
- the external poll callbacks now get the socket descriptor coming from the
|
||||
"in" parameter. The user parameter provides the user_space for the
|
||||
wsi as it normally does on the other callbacks.
|
||||
LWS_CALLBACK_FILTER_NETWORK_CONNECTION also has the socket descriptor
|
||||
delivered by @in now instead of @user.
|
||||
|
||||
- libwebsocket_write() now returns -1 for error, or the amount of data
|
||||
actually accepted for send. Under load, the OS may signal it is
|
||||
ready to send new data on the socket, but have only a restricted
|
||||
amount of memory to buffer the packet compared to usual.
|
||||
|
||||
|
||||
User api removal
|
||||
----------------
|
||||
|
||||
- libwebsocket_ensure_user_space() is removed from the public api, if you
|
||||
were using it to get user_space, you need to adapt your code to only
|
||||
use user_space inside the user callback.
|
||||
|
||||
- CIPHERS_LIST_STRING is removed
|
||||
|
||||
- autotools build has been removed. See README.build for info on how to
|
||||
use CMake for your platform
|
||||
|
||||
|
||||
v1.21-chrome26-firefox18
|
||||
========================
|
||||
|
||||
- Fixes buffer overflow bug in max frame size handling if you used the
|
||||
default protocol buffer size. If you declared rx_buffer_size in your
|
||||
protocol, which is recommended anyway, your code was unaffected.
|
||||
|
||||
v1.2-chrome26-firefox18
|
||||
=======================
|
||||
|
||||
Diffstat
|
||||
--------
|
||||
|
||||
.gitignore | 16 +++
|
||||
CMakeLists.txt | 544 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
LICENSE | 526 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Makefile.am | 1 +
|
||||
README | 20 +++
|
||||
README.build | 258 ++++++++++++++++++++++++++++++++-----
|
||||
README.coding | 52 ++++++++
|
||||
changelog | 136 ++++++++++++++++++++
|
||||
cmake/FindOpenSSLbins.cmake | 33 +++++
|
||||
config.h.cmake | 173 +++++++++++++++++++++++++
|
||||
configure.ac | 22 +++-
|
||||
lib/Makefile.am | 20 ++-
|
||||
lib/base64-decode.c | 2 +-
|
||||
lib/client-handshake.c | 190 +++++++++++-----------------
|
||||
lib/client-parser.c | 88 +++++++------
|
||||
lib/client.c | 384 ++++++++++++++++++++++++++++++-------------------------
|
||||
lib/daemonize.c | 32 +++--
|
||||
lib/extension-deflate-frame.c | 58 +++++----
|
||||
lib/extension-deflate-stream.c | 19 ++-
|
||||
lib/extension-deflate-stream.h | 4 +-
|
||||
lib/extension.c | 11 +-
|
||||
lib/getifaddrs.c | 315 +++++++++++++++++++++++-----------------------
|
||||
lib/getifaddrs.h | 30 ++---
|
||||
lib/handshake.c | 124 +++++++++++-------
|
||||
lib/libwebsockets.c | 736 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------
|
||||
lib/libwebsockets.h | 237 ++++++++++++++++++++++------------
|
||||
lib/output.c | 192 +++++++++++-----------------
|
||||
lib/parsers.c | 966 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------
|
||||
lib/private-libwebsockets.h | 225 +++++++++++++++++++++------------
|
||||
lib/server-handshake.c | 82 ++++++------
|
||||
lib/server.c | 96 +++++++-------
|
||||
libwebsockets-api-doc.html | 189 ++++++++++++++++++----------
|
||||
libwebsockets.spec | 17 +--
|
||||
test-server/attack.sh | 148 ++++++++++++++++++++++
|
||||
test-server/test-client.c | 125 +++++++++---------
|
||||
test-server/test-echo.c | 31 +++--
|
||||
test-server/test-fraggle.c | 32 ++---
|
||||
test-server/test-ping.c | 52 ++++----
|
||||
test-server/test-server.c | 129 ++++++++++++-------
|
||||
win32port/libwebsocketswin32/libwebsocketswin32.vcxproj | 279 ----------------------------------------
|
||||
win32port/libwebsocketswin32/libwebsocketswin32.vcxproj.filters | 23 +++-
|
||||
41 files changed, 4398 insertions(+), 2219 deletions(-)
|
||||
|
||||
|
||||
User api additions
|
||||
------------------
|
||||
|
||||
- lws_get_library_version() returns a const char * with a string like
|
||||
"1.1 9e7f737", representing the library version from configure.ac
|
||||
and the git HEAD hash the library was built from
|
||||
|
||||
- TCP Keepalive can now optionally be applied to all lws sockets, on Linux
|
||||
also with controllable timeout, number of probes and probe interval.
|
||||
(On BSD type OS, you can only use system default settings for the
|
||||
timing and retries, although enabling it is supported by setting
|
||||
ka_time to nonzero, the exact value has no meaning.)
|
||||
This enables detection of idle connections which are logically okay,
|
||||
but are in fact dead, due to network connectivity issues at the server,
|
||||
client, or any intermediary. By default it's not enabled, but you
|
||||
can enable it by setting a non-zero timeout (in seconds) at the new
|
||||
ka_time member at context creation time.
|
||||
|
||||
- Two new optional user callbacks added, LWS_CALLBACK_PROTOCOL_DESTROY which
|
||||
is called one-time per protocol as the context is being destroyed, and
|
||||
LWS_CALLBACK_PROTOCOL_INIT which is called when the context is created
|
||||
and the protocols are added, again it's a one-time affair.
|
||||
This lets you manage per-protocol allocations properly including
|
||||
cleaning up after yourself when the server goes down.
|
||||
|
||||
User api changes
|
||||
----------------
|
||||
|
||||
- libwebsocket_create_context() has changed from taking a ton of parameters
|
||||
to just taking a pointer to a struct containing the parameters. The
|
||||
struct lws_context_creation_info is in libwebsockets.h, the members
|
||||
are in the same order as when they were parameters to the call
|
||||
previously. The test apps are all updated accordingly so you can
|
||||
see example code there.
|
||||
|
||||
- Header tokens are now deleted after the websocket connection is
|
||||
established. Not just the header data is saved, but the pointer and
|
||||
length array is also removed from (union) scope saving several hundred
|
||||
bytes per connection once it is established
|
||||
|
||||
- struct libwebsocket_protocols has a new member rx_buffer_size, this
|
||||
controls rx buffer size per connection of that protocol now. Sources
|
||||
for apps built against older versions of the library won't declare
|
||||
this in their protocols, defaulting it to 0. Zero buffer is legal,
|
||||
it causes a default buffer to be allocated (currently 4096)
|
||||
|
||||
If you want to receive only atomic frames in your user callback, you
|
||||
should set this to greater than your largest frame size. If a frame
|
||||
comes that exceeds that, no error occurs but the callback happens as
|
||||
soon as the buffer limit is reached, and again if it is reached again
|
||||
or the frame completes. You can detect that has happened by seeing
|
||||
there is still frame content pending using
|
||||
libwebsockets_remaining_packet_payload()
|
||||
|
||||
By correctly setting this, you can save a lot of memory when your
|
||||
protocol has small frames (see the test server and client sources).
|
||||
|
||||
- LWS_MAX_HEADER_LEN now defaults to 1024 and is the total amount of known
|
||||
header payload lws can cope with, that includes the GET URL, origin
|
||||
etc. Headers not understood by lws are ignored and their payload
|
||||
not included in this.
|
||||
|
||||
|
||||
User api removals
|
||||
-----------------
|
||||
|
||||
- The configuration-time option MAX_USER_RX_BUFFER has been replaced by a
|
||||
buffer size chosen per-protocol. For compatibility, there's a default
|
||||
of 4096 rx buffer, but user code should set the appropriate size for
|
||||
the protocol frames.
|
||||
|
||||
- LWS_INITIAL_HDR_ALLOC and LWS_ADDITIONAL_HDR_ALLOC are no longer needed
|
||||
and have been removed. There's a new header management scheme that
|
||||
handles them in a much more compact way.
|
||||
|
||||
- libwebsockets_hangup_on_client() is removed. If you want to close the
|
||||
connection you must do so from the user callback and by returning
|
||||
-1 from there.
|
||||
|
||||
- libwebsocket_close_and_free_session() is now private to the library code
|
||||
only and not exposed for user code. If you want to close the
|
||||
connection, you must do so from the user callback by returning -1
|
||||
from there.
|
||||
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Cmake project file added, aimed initially at Windows support: this replaces
|
||||
the visual studio project files that were in the tree until now.
|
||||
|
||||
- CyaSSL now supported in place of OpenSSL (--use-cyassl on configure)
|
||||
|
||||
- PATH_MAX or MAX_PATH no longer needed
|
||||
|
||||
- cutomizable frame rx buffer size by protocol
|
||||
|
||||
- optional TCP keepalive so dead peers can be detected, can be enabled at
|
||||
context-creation time
|
||||
|
||||
- valgrind-clean: no SSL or CyaSSL: completely clean. With OpenSSL, 88 bytes
|
||||
lost at OpenSSL library init and symptomless reports of uninitialized
|
||||
memory usage... seems to be a known and ignored problem at OpenSSL
|
||||
|
||||
- By default debug is enabled and the library is built for -O0 -g to faclitate
|
||||
that. Use --disable-debug configure option to build instead with -O4
|
||||
and no -g (debug info), obviously providing best performance and
|
||||
reduced binary size.
|
||||
|
||||
- 1.0 introduced some code to try to not deflate small frames, however this
|
||||
seems to break when confronted with a mixture of frames above and
|
||||
below the threshold, so it's removed. Veto the compression extension
|
||||
in your user callback if you will typically have very small frames.
|
||||
|
||||
- There are many memory usage improvements, both a reduction in malloc/
|
||||
realloc and architectural changes. A websocket connection now
|
||||
consumes only 296 bytes with SSL or 272 bytes without on x86_64,
|
||||
during header processing an additional 1262 bytes is allocated in a
|
||||
single malloc, but is freed when the websocket connection starts.
|
||||
The RX frame buffer defined by the protocol in user
|
||||
code is also allocated per connection, this represents the largest
|
||||
frame you can receive atomically in that protocol.
|
||||
|
||||
- On ARM9 build, just http+ws server no extensions or ssl, <12Kbytes .text
|
||||
and 112 bytes per connection (+1328 only during header processing)
|
||||
|
||||
|
||||
v1.1-chrome26-firefox18
|
||||
=======================
|
||||
|
||||
Diffstat
|
||||
--------
|
||||
|
||||
Makefile.am | 4 +
|
||||
README-test-server | 291 ---
|
||||
README.build | 239 ++
|
||||
README.coding | 138 ++
|
||||
README.rst | 72 -
|
||||
README.test-apps | 272 +++
|
||||
configure.ac | 116 +-
|
||||
lib/Makefile.am | 55 +-
|
||||
lib/base64-decode.c | 5 +-
|
||||
lib/client-handshake.c | 121 +-
|
||||
lib/client-parser.c | 394 ++++
|
||||
lib/client.c | 807 +++++++
|
||||
lib/daemonize.c | 212 ++
|
||||
lib/extension-deflate-frame.c | 132 +-
|
||||
lib/extension-deflate-stream.c | 12 +-
|
||||
lib/extension-x-google-mux.c | 1223 ----------
|
||||
lib/extension-x-google-mux.h | 96 -
|
||||
lib/extension.c | 8 -
|
||||
lib/getifaddrs.c | 271 +++
|
||||
lib/getifaddrs.h | 76 +
|
||||
lib/handshake.c | 582 +----
|
||||
lib/libwebsockets.c | 2493 ++++++---------------
|
||||
lib/libwebsockets.h | 115 +-
|
||||
lib/md5.c | 217 --
|
||||
lib/minilex.c | 440 ++++
|
||||
lib/output.c | 628 ++++++
|
||||
lib/parsers.c | 2016 +++++------------
|
||||
lib/private-libwebsockets.h | 284 +--
|
||||
lib/server-handshake.c | 275 +++
|
||||
lib/server.c | 377 ++++
|
||||
libwebsockets-api-doc.html | 300 +--
|
||||
m4/ignore-me | 2 +
|
||||
test-server/Makefile.am | 111 +-
|
||||
test-server/libwebsockets.org-logo.png | Bin 0 -> 7029 bytes
|
||||
test-server/test-client.c | 45 +-
|
||||
test-server/test-echo.c | 330 +++
|
||||
test-server/test-fraggle.c | 20 +-
|
||||
test-server/test-ping.c | 22 +-
|
||||
test-server/test-server-extpoll.c | 554 -----
|
||||
test-server/test-server.c | 349 ++-
|
||||
test-server/test.html | 3 +-
|
||||
win32port/zlib/ZLib.vcxproj | 749 ++++---
|
||||
win32port/zlib/ZLib.vcxproj.filters | 188 +-
|
||||
win32port/zlib/adler32.c | 348 ++-
|
||||
win32port/zlib/compress.c | 160 +-
|
||||
win32port/zlib/crc32.c | 867 ++++----
|
||||
win32port/zlib/crc32.h | 882 ++++----
|
||||
win32port/zlib/deflate.c | 3799 +++++++++++++++-----------------
|
||||
win32port/zlib/deflate.h | 688 +++---
|
||||
win32port/zlib/gzclose.c | 50 +-
|
||||
win32port/zlib/gzguts.h | 325 ++-
|
||||
win32port/zlib/gzlib.c | 1157 +++++-----
|
||||
win32port/zlib/gzread.c | 1242 ++++++-----
|
||||
win32port/zlib/gzwrite.c | 1096 +++++----
|
||||
win32port/zlib/infback.c | 1272 ++++++-----
|
||||
win32port/zlib/inffast.c | 680 +++---
|
||||
win32port/zlib/inffast.h | 22 +-
|
||||
win32port/zlib/inffixed.h | 188 +-
|
||||
win32port/zlib/inflate.c | 2976 +++++++++++++------------
|
||||
win32port/zlib/inflate.h | 244 +-
|
||||
win32port/zlib/inftrees.c | 636 +++---
|
||||
win32port/zlib/inftrees.h | 124 +-
|
||||
win32port/zlib/trees.c | 2468 +++++++++++----------
|
||||
win32port/zlib/trees.h | 256 +--
|
||||
win32port/zlib/uncompr.c | 118 +-
|
||||
win32port/zlib/zconf.h | 934 ++++----
|
||||
win32port/zlib/zlib.h | 3357 ++++++++++++++--------------
|
||||
win32port/zlib/zutil.c | 642 +++---
|
||||
win32port/zlib/zutil.h | 526 ++---
|
||||
69 files changed, 19556 insertions(+), 20145 deletions(-)
|
||||
|
||||
user api changes
|
||||
----------------
|
||||
|
||||
- libwebsockets_serve_http_file() now takes a context as first argument
|
||||
|
||||
- libwebsockets_get_peer_addresses() now takes a context and wsi as first
|
||||
two arguments
|
||||
|
||||
|
||||
user api additions
|
||||
------------------
|
||||
|
||||
- lwsl_...() logging apis, default to stderr but retargetable by user code;
|
||||
may be used also by user code
|
||||
|
||||
- lws_set_log_level() set which logging apis are able to emit (defaults to
|
||||
notice, warn, err severities), optionally set the emit callback
|
||||
|
||||
- lwsl_emit_syslog() helper callback emits to syslog
|
||||
|
||||
- lws_daemonize() helper code that forks the app into a headless daemon
|
||||
properly, maintains a lock file with pid in suitable for sysvinit etc to
|
||||
control lifecycle
|
||||
|
||||
- LWS_CALLBACK_HTTP_FILE_COMPLETION callback added since http file
|
||||
transfer is now asynchronous (see test server code)
|
||||
|
||||
- lws_frame_is_binary() from a wsi pointer, let you know if the received
|
||||
data was sent in BINARY mode
|
||||
|
||||
|
||||
user api removals
|
||||
-----------------
|
||||
|
||||
- libwebsockets_fork_service_loop() - no longer supported (had intractable problems)
|
||||
arrange your code to act from the user callback instead from same
|
||||
process context as the service loop
|
||||
|
||||
- libwebsockets_broadcast() - use libwebsocket_callback_on_writable[_all_protocol]()
|
||||
instead from same process context as the service loop. See the test apps
|
||||
for examples.
|
||||
|
||||
- x-google-mux() removed until someone wants it
|
||||
|
||||
- pre -v13 (ancient) protocol support removed
|
||||
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- echo test server and client compatible with echo.websocket.org added
|
||||
|
||||
- many new configure options (see README.build) to reduce footprint of the
|
||||
library to what you actually need, eg, --without-client and
|
||||
--without-server
|
||||
|
||||
- http + websocket server can build to as little as 12K .text for ARM
|
||||
|
||||
- no more MAX_CLIENTS limitation; adapts to support the max number of fds
|
||||
allowed to the process by ulimit, defaults to 1024 on Fedora and
|
||||
Ubuntu. Use ulimit to control this without needing to configure
|
||||
the library. Code here is smaller and faster.
|
||||
|
||||
- adaptive ratio of listen socket to connection socket service allows
|
||||
good behaviour under Apache ab test load. Tested with thousands
|
||||
of simultaneous connections
|
||||
|
||||
- reduction in per-connection memory footprint by moving to a union to hold
|
||||
mutually-exclusive state for the connection
|
||||
|
||||
- robustness: Out of Memory taken care of for all allocation code now
|
||||
|
||||
- internal getifaddrs option if your toolchain lacks it (some uclibc)
|
||||
|
||||
- configurable memory limit for deflate operations
|
||||
|
||||
- improvements in SSL code nonblocking operation, possible hang solved,
|
||||
some SSL operations broken down into pollable states so there is
|
||||
no library blocking, timeout coverage for SSL_connect
|
||||
|
||||
- extpoll test server merged into single test server source
|
||||
|
||||
- robustness: library should deal with all recoverable socket conditions
|
||||
|
||||
- rx flowcontrol for backpressure notification fixed and implmeneted
|
||||
correctly in the test server
|
||||
|
||||
- optimal lexical parser added for header processing; all headers in a
|
||||
single 276-byte state table
|
||||
|
||||
- latency tracking api added (configure --with-latency)
|
||||
|
||||
- Improved in-tree documentation, REAME.build, README.coding,
|
||||
README.test-apps, changelog
|
||||
|
||||
- Many small fixes
|
||||
|
||||
|
||||
v1.0-chrome25-firefox17 (6cd1ea9b005933f)
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
################################################################################
|
||||
#
|
||||
# Program: 3D Slicer
|
||||
#
|
||||
# Copyright (c) Kitware Inc.
|
||||
#
|
||||
# See COPYRIGHT.txt
|
||||
# or http://www.slicer.org/copyright/copyright.txt for details.
|
||||
#
|
||||
# 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 file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc.
|
||||
# and was partially funded by NIH grant 3P41RR013218-12S1
|
||||
#
|
||||
# AG 2013-02-18: I got it from here
|
||||
# https://github.com/Slicer/Slicer/blob/master/CMake/FindGit.cmake
|
||||
# license is BSD
|
||||
#
|
||||
################################################################################
|
||||
|
||||
#
|
||||
# The module defines the following variables:
|
||||
# GIT_EXECUTABLE - path to git command line client
|
||||
# GIT_FOUND - true if the command line client was found
|
||||
#
|
||||
# If the command line client executable is found the macro
|
||||
# GIT_WC_INFO(<dir> <var-prefix>)
|
||||
# is defined to extract information of a git working copy at
|
||||
# a given location.
|
||||
#
|
||||
# The macro defines the following variables:
|
||||
# <var-prefix>_WC_REVISION_HASH - Current SHA1 hash
|
||||
# <var-prefix>_WC_REVISION - Current SHA1 hash
|
||||
# <var-prefix>_WC_REVISION_NAME - Name associated with <var-prefix>_WC_REVISION_HASH
|
||||
# <var-prefix>_WC_URL - output of command `git config --get remote.origin.url'
|
||||
# <var-prefix>_WC_ROOT - Same value as working copy URL
|
||||
# <var-prefix>_WC_GITSVN - Set to false
|
||||
#
|
||||
# ... and also the following ones if it's a git-svn repository:
|
||||
# <var-prefix>_WC_GITSVN - Set to True if it is a
|
||||
# <var-prefix>_WC_INFO - output of command `git svn info'
|
||||
# <var-prefix>_WC_URL - url of the associated SVN repository
|
||||
# <var-prefix>_WC_ROOT - root url of the associated SVN repository
|
||||
# <var-prefix>_WC_REVISION - current SVN revision number
|
||||
# <var-prefix>_WC_LAST_CHANGED_AUTHOR - author of last commit
|
||||
# <var-prefix>_WC_LAST_CHANGED_DATE - date of last commit
|
||||
# <var-prefix>_WC_LAST_CHANGED_REV - revision of last commit
|
||||
# <var-prefix>_WC_LAST_CHANGED_LOG - last log of base revision
|
||||
#
|
||||
# Example usage:
|
||||
# find_package(Git)
|
||||
# if(GIT_FOUND)
|
||||
# GIT_WC_INFO(${PROJECT_SOURCE_DIR} Project)
|
||||
# message("Current revision is ${Project_WC_REVISION_HASH}")
|
||||
# message("git found: ${GIT_EXECUTABLE}")
|
||||
# endif()
|
||||
#
|
||||
|
||||
# Look for 'git' or 'eg' (easy git)
|
||||
#
|
||||
set(git_names git eg)
|
||||
|
||||
# Prefer .cmd variants on Windows unless running in a Makefile
|
||||
# in the MSYS shell.
|
||||
#
|
||||
if(WIN32)
|
||||
if(NOT CMAKE_GENERATOR MATCHES "MSYS")
|
||||
# Note: Due to a bug in 'git.cmd' preventing it from returning the exit code of 'git',
|
||||
# we excluded it from the list of executables to search.
|
||||
# See http://code.google.com/p/msysgit/issues/detail?id=428
|
||||
# TODO Check if 'git' exists, get the associated version, if the corresponding version
|
||||
# is known to have a working version of 'git.cmd', use it.
|
||||
set(git_names git eg.cmd eg)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(GIT_EXECUTABLE ${git_names}
|
||||
PATHS
|
||||
"C:/Program Files/Git/bin"
|
||||
"C:/Program Files (x86)/Git/bin"
|
||||
DOC "git command line client")
|
||||
mark_as_advanced(GIT_EXECUTABLE)
|
||||
|
||||
if(GIT_EXECUTABLE)
|
||||
macro(GIT_WC_INFO dir prefix)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=7 HEAD
|
||||
WORKING_DIRECTORY ${dir}
|
||||
ERROR_VARIABLE GIT_error
|
||||
OUTPUT_VARIABLE ${prefix}_WC_REVISION_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set(${prefix}_WC_REVISION ${${prefix}_WC_REVISION_HASH})
|
||||
if(NOT ${GIT_error} EQUAL 0)
|
||||
message(SEND_ERROR "Command \"${GIT_EXECUTBALE} rev-parse --verify -q --short=7 HEAD\" in directory ${dir} failed with output:\n${GIT_error}")
|
||||
else(NOT ${GIT_error} EQUAL 0)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} name-rev ${${prefix}_WC_REVISION_HASH}
|
||||
WORKING_DIRECTORY ${dir}
|
||||
OUTPUT_VARIABLE ${prefix}_WC_REVISION_NAME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif(NOT ${GIT_error} EQUAL 0)
|
||||
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} config --get remote.origin.url
|
||||
WORKING_DIRECTORY ${dir}
|
||||
OUTPUT_VARIABLE ${prefix}_WC_URL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set(${prefix}_WC_GITSVN False)
|
||||
|
||||
# Check if this git is likely to be a git-svn repository
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} config --get-regexp "^svn-remote"
|
||||
WORKING_DIRECTORY ${dir}
|
||||
OUTPUT_VARIABLE git_config_output
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(NOT "${git_config_output}" STREQUAL "")
|
||||
# In case git-svn is used, attempt to extract svn info
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} svn info
|
||||
WORKING_DIRECTORY ${dir}
|
||||
TIMEOUT 3
|
||||
ERROR_VARIABLE git_svn_info_error
|
||||
OUTPUT_VARIABLE ${prefix}_WC_INFO
|
||||
RESULT_VARIABLE git_svn_info_result
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if(${git_svn_info_result} EQUAL 0)
|
||||
set(${prefix}_WC_GITSVN True)
|
||||
string(REGEX REPLACE "^(.*\n)?URL: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_URL "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Revision: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_REVISION "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Repository Root: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_ROOT "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Last Changed Author: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_LAST_CHANGED_AUTHOR "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Last Changed Rev: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_LAST_CHANGED_REV "${${prefix}_WC_INFO}")
|
||||
string(REGEX REPLACE "^(.*\n)?Last Changed Date: ([^\n]+).*"
|
||||
"\\2" ${prefix}_WC_LAST_CHANGED_DATE "${${prefix}_WC_INFO}")
|
||||
endif(${git_svn_info_result} EQUAL 0)
|
||||
endif(NOT "${git_config_output}" STREQUAL "")
|
||||
|
||||
# If there is no 'remote.origin', default to "NA" value and print a warning message.
|
||||
if(NOT ${prefix}_WC_URL)
|
||||
message(WARNING "No remote origin set for git repository: ${dir}" )
|
||||
set( ${prefix}_WC_URL "NA" )
|
||||
else()
|
||||
set(${prefix}_WC_ROOT ${${prefix}_WC_URL})
|
||||
endif()
|
||||
|
||||
endmacro(GIT_WC_INFO)
|
||||
endif(GIT_EXECUTABLE)
|
||||
|
||||
# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE)
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
|
||||
find_program(OPENSSL_EXECUTABLE openssl openssl.exe bin/openssl.exe
|
||||
HINTS ${_OPENSSL_ROOT_HINTS}
|
||||
PATH
|
||||
/usr/bin/
|
||||
bin/
|
||||
DOC "Openssl executable")
|
||||
|
||||
mark_as_advanced(OPENSSL_EXECUTABLE)
|
||||
|
||||
# On Windows, we need to copy the OpenSSL dlls
|
||||
# to the output directory.
|
||||
if(WIN32)
|
||||
set(OPENSSL_BIN_FOUND 0)
|
||||
|
||||
find_file(LIBEAY_BIN
|
||||
NAMES
|
||||
libeay32.dll
|
||||
HINTS
|
||||
${_OPENSSL_ROOT_HINTS}
|
||||
PATH_SUFFIXES
|
||||
bin)
|
||||
|
||||
find_file(SSLEAY_BIN
|
||||
NAMES
|
||||
ssleay32.dll
|
||||
HINTS
|
||||
${_OPENSSL_ROOT_HINTS}
|
||||
PATH_SUFFIXES
|
||||
bin)
|
||||
|
||||
if(LIBEAY_BIN)
|
||||
if(SSLEAY_BIN)
|
||||
set(OPENSSL_BIN_FOUND 1)
|
||||
endif(SSLEAY_BIN)
|
||||
endif(LIBEAY_BIN)
|
||||
endif(WIN32)
|
||||
|
||||
endif(OPENSSL_FOUND)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# - Config file for the Libevent package
|
||||
# It defines the following variables
|
||||
# LIBWEBSOCKETS_INCLUDE_DIRS - include directories for FooBar
|
||||
# LIBWEBSOCKETS_LIBRARIES - libraries to link against
|
||||
|
||||
# Get the path of the current file.
|
||||
get_filename_component(LWS_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
|
||||
# Set the include directories.
|
||||
set(LIBWEBSOCKETS_INCLUDE_DIRS "@LWS__INCLUDE_DIRS@")
|
||||
|
||||
# Include the project Targets file, this contains definitions for IMPORTED targets.
|
||||
include(${LWS_CMAKE_DIR}/LibwebsocketsTargets.cmake)
|
||||
|
||||
# IMPORTED targets from LibwebsocketsTargets.cmake
|
||||
set(LIBWEBSOCKETS_LIBRARIES websockets websockets_shared)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user