diff --git a/engine/server/application/CMakeLists.txt b/engine/server/application/CMakeLists.txt index 1a543a2d..ebd82183 100644 --- a/engine/server/application/CMakeLists.txt +++ b/engine/server/application/CMakeLists.txt @@ -1,4 +1,5 @@ +add_subdirectory(ChatServer) add_subdirectory(ConnectionServer) add_subdirectory(LoginServer) add_subdirectory(LogServer) diff --git a/engine/server/application/ChatServer/CMakeLists.txt b/engine/server/application/ChatServer/CMakeLists.txt new file mode 100644 index 00000000..57b4dbe1 --- /dev/null +++ b/engine/server/application/ChatServer/CMakeLists.txt @@ -0,0 +1,6 @@ + +cmake_minimum_required(VERSION 2.8) + +project(ChatServer) + +add_subdirectory(src) diff --git a/engine/server/application/ChatServer/src/CMakeLists.txt b/engine/server/application/ChatServer/src/CMakeLists.txt new file mode 100644 index 00000000..d02b7edb --- /dev/null +++ b/engine/server/application/ChatServer/src/CMakeLists.txt @@ -0,0 +1,122 @@ + +set(SHARED_SOURCES + shared/CentralServerConnection.cpp + shared/CentralServerConnection.h + shared/ChatInterface.cpp + shared/ChatInterface.h + shared/ChatServerAvatarOwner.cpp + shared/ChatServerAvatarOwner.h + shared/ChatServer.cpp + shared/ChatServer.h + shared/ChatServerRoomOwner.cpp + shared/ChatServerRoomOwner.h + shared/ConfigChatServer.cpp + shared/ConfigChatServer.h + shared/ConnectionServerConnection.cpp + shared/ConnectionServerConnection.h + shared/CustomerServiceServerConnection.cpp + shared/CustomerServiceServerConnection.h + shared/FirstChatServer.cpp + shared/FirstChatServer.h + shared/GameServerConnection.cpp + shared/GameServerConnection.h + shared/PlanetServerConnection.h + shared/PlanetServerServerConnection.cpp + shared/ChatServerMetricsData.cpp + shared/ChatServerMetricsData.h + shared/VChatInterface.h + shared/VChatInterface.cpp +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/WinMain.cpp + ) +else() + set(PLATFORM_SOURCES + linux/main.cpp + ) +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/shared + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCommandParser/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCompression/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDatabaseInterface/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedGame/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedThread/include/public + #${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public + #${SWG_ENGINE_SOURCE_DIR}/server/library/serverKeyShare/include/public + #${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public + #${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include + #${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localization/include + #${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localizationArchive/include/public + #${SWG_EXTERNALS_SOURCE_DIR}/ours/library/singleton/include + #${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include + #${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public + #${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/platform/projects + #${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/platform/utils + #${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/udplibrary +) + +link_directories(${STLPORT_LIBDIR}) + +add_executable(ChatServer + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) + +target_link_libraries(ChatServer +# sharedCommandParser +# sharedCompression +# sharedDatabaseInterface +# sharedDatabaseInterface_oci +# sharedDebug +# sharedFile +# sharedFoundation +# sharedGame +# sharedLog +# sharedMath +# sharedMemoryManager +# sharedMessageDispatch +# sharedNetwork +# sharedNetworkMessages +# sharedRandom +# sharedSynchronization +# sharedThread +# sharedUtility +# serverKeyShare +# serverNetworkMessages +# serverUtility +# archive +# crypto +# fileInterface +# localization +# localizationArchive +# unicode +# unicodeArchive +# Base +# CommonAPI +# LoginAPI +# MonAPI2 +# udplibrary +# ${ZLIB_LIBRARY} +# ${ORACLE_LIBRARY} +) + +if(WIN32) + target_link_libraries(ChatServer mswsock ws2_32) +endif() diff --git a/engine/server/application/ChatServer/src/linux/main.cpp b/engine/server/application/ChatServer/src/linux/main.cpp new file mode 100644 index 00000000..eecd0c24 --- /dev/null +++ b/engine/server/application/ChatServer/src/linux/main.cpp @@ -0,0 +1,43 @@ +#include "FirstChatServer.h" + +#include "ConfigChatServer.h" +#include "ChatServer.h" + +#include "sharedCompression/SetupSharedCompression.h" +#include "sharedDebug/SetupSharedDebug.h" +#include "sharedFile/SetupSharedFile.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" +#include "sharedRandom/SetupSharedRandom.h" +#include "sharedThread/SetupSharedThread.h" + +// ====================================================================== + +int main(int argc, char ** argv) +{ + SetupSharedThread::install(); + SetupSharedDebug::install(1024); + + //-- setup foundation + SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game); + setupFoundationData.lpCmdLine = ConvertCommandLine(argc,argv); + SetupSharedFoundation::install (setupFoundationData); + + SetupSharedCompression::install(); + + SetupSharedFile::install(false); + SetupSharedNetworkMessages::install(); + + SetupSharedRandom::install(static_cast(time(NULL))); //lint !e1924 !e64 // NULL is a C-Style cast? + + Os::setProgramName("ChatServer"); + //setup the server + ConfigChatServer::install(); + + //-- run game + ChatServer::run(); + SetupSharedFoundation::remove(); + + return 0; +} diff --git a/engine/server/application/ChatServer/src/shared/CentralServerConnection.cpp b/engine/server/application/ChatServer/src/shared/CentralServerConnection.cpp new file mode 100644 index 00000000..b9fa2835 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/CentralServerConnection.cpp @@ -0,0 +1,126 @@ +// CentralServerConnection.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "Archive/ByteStream.h" +#include "CentralServerConnection.h" +#include "ChatServer.h" +#include "ChatInterface.h" +#include "ConfigChatServer.h" +#include "serverNetworkMessages/EnumerateServers.h" +#include "serverNetworkMessages/RenameCharacterMessage.h" +#include "serverNetworkMessages/TransferCharacterData.h" +#include "serverNetworkMessages/TransferCharacterDataArchive.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedLog/Log.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetwork/Service.h" +#include "UnicodeUtils.h" + +//----------------------------------------------------------------------- + +CentralServerConnection::CentralServerConnection(const std::string & a, const unsigned short p) : +ServerConnection(a, p, NetworkSetupData()) +{ + ChatServer::fileLog(true, "CentralServerConnection", "Connection created...listening on (%s:%d)", a.c_str(), static_cast(p)); +} + +//----------------------------------------------------------------------- + +CentralServerConnection::~CentralServerConnection() +{ +} + +//----------------------------------------------------------------------- + +void CentralServerConnection::onConnectionClosed() +{ + ChatServer::fileLog(true, "CentralServerConnection", "onConnectionClosed()"); + + ChatServer::onCentralServerConnectionClosed(); + ChatServer::quit(); +} + +//----------------------------------------------------------------------- + +void CentralServerConnection::onConnectionOpened() +{ + ChatServer::fileLog(true, "CentralServerConnection", "onConnectionOpened()"); +} + +//----------------------------------------------------------------------- + +void CentralServerConnection::onReceive(const Archive::ByteStream & message) +{ + Archive::ReadIterator ri = message.begin(); + GameNetworkMessage m(ri); + + ri = message.begin(); + + if(m.isType("EnumerateServers")) + { + static MessageDispatch::Transceiver emitter; + + EnumerateServers e(ri); + emitter.emitMessage(e); + } + else if (m.isType("CustomerServiceServerChatServerServiceAddress")) + { + GenericValueTypeMessage > msg(ri); + + ChatServer::instance().connectToCustomerServiceServer(msg.getValue().first, msg.getValue().second); + } + else if(m.isType("RequestChatTransferAvatar")) + { + GenericValueTypeMessage request(ri); + LOG("CustomerService", ("CharacterTransfer: Received RequestChatTransferAvatar from CentralServer. Forwarding request to ChatAPI. %s", request.getValue().toString().c_str())); + ChatServer::requestTransferAvatar(request.getValue()); + } + else if (m.isType("RenameCharacterMessageEx")) + { + RenameCharacterMessageEx const msg(ri); + + // if the player requested the rename, also rename the chat + // avatar, so mail, friends list, and ignore list will migrate + if ((msg.getRenameCharacterMessageSource() == RenameCharacterMessageEx::RCMS_player_request) && !msg.getLastNameChangeOnly() && !ConfigFile::getKeyBool("CharacterRename", "disableRenameChatAvatar", false)) + { + std::string const oldName(Unicode::toLower(Unicode::wideToNarrow(msg.getOldName()))); + std::string const oldNameNormalized(oldName, 0, oldName.find(' ')); + ChatAvatarId const oldAvatar("SWG", ConfigChatServer::getClusterName(), oldNameNormalized); + + std::string const newName(Unicode::toLower(Unicode::wideToNarrow(msg.getNewName()))); + std::string const newNameNormalized(newName, 0, newName.find(' ')); + ChatAvatarId const newAvatar("SWG", ConfigChatServer::getClusterName(), newNameNormalized); + + IGNORE_RETURN(ChatServer::getChatInterface()->RequestTransferAvatar(msg.getStationId(), oldAvatar.getName(), oldAvatar.getAPIAddress(), msg.getStationId(), newAvatar.getName(), newAvatar.getAPIAddress(), true, NULL)); + } + } + else if (m.isType("ChatDestroyAvatar")) + { + GenericValueTypeMessage const msg(ri); + ChatServer::getChatInterface()->DestroyAvatar(msg.getValue()); + } + else if(m.isType("AllCluserGlobalChannel")) + { + typedef std::pair, bool> PayloadType; + GenericValueTypeMessage msg(ri); + + PayloadType const & payload = msg.getValue(); + std::string const & channelName = payload.first.first; + std::string const & messageText = payload.first.second; + bool const & isRemove = payload.second; + + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer got AllCluserGlobalChannel on CentralServerConnection chan(%s) text(%s) remove(%d)", + channelName.c_str(), messageText.c_str(), (isRemove?1:0))); + ChatServer::requestBroadcastChannelMessage(channelName, messageText, isRemove); + } +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/ChatServer/src/shared/CentralServerConnection.h b/engine/server/application/ChatServer/src/shared/CentralServerConnection.h new file mode 100644 index 00000000..e45d1842 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/CentralServerConnection.h @@ -0,0 +1,30 @@ +// CentralServerConnection.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_CentralServerConnection_H +#define _INCLUDED_CentralServerConnection_H + +//----------------------------------------------------------------------- + +#include "serverUtility/ServerConnection.h" + +//----------------------------------------------------------------------- + +class CentralServerConnection : public ServerConnection +{ +public: + CentralServerConnection(const std::string & remoteAddress, const unsigned short remotePort); + ~CentralServerConnection(); + + void onConnectionClosed (); + void onConnectionOpened (); + void onReceive (const Archive::ByteStream & bs); +private: + CentralServerConnection & operator = (const CentralServerConnection & rhs); + CentralServerConnection(const CentralServerConnection & source); +};//lint !e1712 default constructor not defined for class + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_CentralServerConnection_H diff --git a/engine/server/application/ChatServer/src/shared/ChatInterface.cpp b/engine/server/application/ChatServer/src/shared/ChatInterface.cpp new file mode 100644 index 00000000..3c7cacd9 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatInterface.cpp @@ -0,0 +1,3202 @@ +// ChatInterface.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "ChatAPI/ChatAvatar.h" +#include "ChatInterface.h" +#include "ChatAPI/ChatFriendStatus.h" +#include "ChatAPI/ChatIgnoreStatus.h" +#include "ChatAPI/ChatRoom.h" +#include "ChatAPI/PersistentMessage.h" +#include "ChatAPI/ChatEnum.h" +#include "ChatServer.h" +#include "ChatServerAvatarOwner.h" +#include "ConfigChatServer.h" +#include "ConnectionServerConnection.h" +#include "GameServerConnection.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedLog/Log.h" +#include "sharedNetwork/Service.h" +#include "sharedNetworkMessages/ChatFriendsListUpdate.h" +#include "sharedNetworkMessages/ChatInstantMessageToClient.h" +#include "sharedNetworkMessages/ChatOnAddFriend.h" +#include "sharedNetworkMessages/ChatOnAddModeratorToRoom.h" +#include "sharedNetworkMessages/ChatOnBanAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnChangeFriendStatus.h" +#include "sharedNetworkMessages/ChatOnChangeIgnoreStatus.h" +#include "sharedNetworkMessages/ChatOnConnectAvatar.h" +#include "sharedNetworkMessages/ChatOnCreateRoom.h" +#include "sharedNetworkMessages/ChatOnDeleteAllPersistentMessages.h" +#include "sharedNetworkMessages/ChatOnDestroyRoom.h" +#include "sharedNetworkMessages/ChatOnEnteredRoom.h" +#include "sharedNetworkMessages/ChatOnGetFriendsList.h" +#include "sharedNetworkMessages/ChatOnGetIgnoreList.h" +#include "sharedNetworkMessages/ChatOnInviteToRoom.h" +#include "sharedNetworkMessages/ChatOnKickAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnLeaveRoom.h" +#include "sharedNetworkMessages/ChatOnReceiveRoomInvitation.h" +#include "sharedNetworkMessages/ChatOnRemoveModeratorFromRoom.h" +#include "sharedNetworkMessages/ChatOnSendInstantMessage.h" +#include "sharedNetworkMessages/ChatOnSendPersistentMessage.h" +#include "sharedNetworkMessages/ChatOnSendRoomInvitation.h" +#include "sharedNetworkMessages/ChatOnSendRoomMessage.h" +#include "sharedNetworkMessages/ChatOnUnbanAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnUninviteFromRoom.h" +#include "sharedNetworkMessages/ChatQueryRoomResults.h" +#include "sharedNetworkMessages/ChatPersistentMessageToClient.h" +#include "sharedNetworkMessages/ChatQueryRoomResults.h" +#include "sharedNetworkMessages/ChatRoomData.h" +#include "sharedNetworkMessages/ChatRoomList.h" +#include "sharedNetworkMessages/ChatRoomMessage.h" +#include "sharedNetworkMessages/ChatSystemMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "StringId.h" +#include "unicodeArchive/UnicodeArchive.h" +#include "UnicodeUtils.h" +#include + +using namespace ChatSystem; + +//---------------------------------------------------------------------- + +namespace ChatInterfaceNamespace +{ + char convertPmStatus (const int value) + { + if (value == ChatSystem::PERSISTENT_NEW) + return 'N'; + else if (value == ChatSystem::PERSISTENT_UNREAD) + return 'U'; + else if (value == ChatSystem::PERSISTENT_READ) + return 'R'; + else if (value == ChatSystem::PERSISTENT_TRASH) + return 'T'; + else if (value == ChatSystem::PERSISTENT_DELETED) + return 'D'; + + return 0; + } + + // Control log output for chat room related methods + bool const s_enableChatRoomLogs = false; + + static int s_intervalToSendHeadersToClientSeconds; + static int s_maxHeadersToSendToClientPerInterval; + + // to prevent sending duplicate room chat message + std::hash_map > s_mostRecentRoomChatMessage; +} + +using namespace ChatInterfaceNamespace; + +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- + +void splitRoomName(std::string roomName, Unicode::String &name, Unicode::String &address) +{ + if (roomName.find("SOE") != 0) + { + roomName = "SOE." + roomName; + } + + size_t pos = roomName.find("."); + while (pos != std::string::npos) + { + roomName[pos] = '+'; + pos = roomName.find("."); + } + + pos = roomName.rfind("+"); + if (pos != std::string::npos) + { + address = Unicode::narrowToWide(roomName.substr(0, pos)); + name = Unicode::narrowToWide(roomName.substr(pos+1)); + } + + /*char *tmp = roomName.c_str(); + char *loc = tmp; + + int numPlus = 0; + while (*loc != 0) + { + if (*loc == '+') + { + numPlus++; + } + if (numPlus == 3) + { + //i.e SOE.SWG.bria + *loc = 0; + address = Unicode::narrowToWide(std::string(tmp)); + name = Unicode::narrowToWide(std::string(loc+1)); + } + ++loc; + */ +} + +//----------------------------------------------------------------------- + +void makeAvatarId(const ChatUnicodeString &name, const ChatUnicodeString &addr, ChatAvatarId &id) +{ + std::string address = Unicode::wideToNarrow(Unicode::String(addr.string_data, addr.string_length)); + if ((address.find("SOE") == 0) && (address.length() > 4)) + { + address = address.substr(4); + } + else + { + DEBUG_WARNING(true, ("makeAvatarId() received an invalid address")); + } + + char text[1024]; + snprintf(text, sizeof(text), "%s", address.c_str()); + + char *loc = strstr(text, "+"); + if (loc) + { + *loc = 0; + id.gameCode = text; + id.cluster = (loc+1); + id.name = Unicode::wideToNarrow(Unicode::String(name.string_data, name.string_length)); + //tmp, due to a bug in the backend. + if (id.gameCode == "PS") + { + id.gameCode = "SWG"; + } + } +} + +//----------------------------------------------------------------------- + +void makeAvatarId(const ChatAvatar & avatar, ChatAvatarId & id) +{ + makeAvatarId(avatar.getName(), avatar.getAddress(), id); +} + +//----------------------------------------------------------------------- + +void makeRoomName(const ChatUnicodeString &roomAddress, std::string &name) +{ + std::string narrowRoomAddress = Unicode::wideToNarrow(Unicode::String(roomAddress.string_data,roomAddress.string_length)); + + if ((narrowRoomAddress.find("SOE") == 0) && (narrowRoomAddress.length() > 4)) + { + narrowRoomAddress = narrowRoomAddress.substr(4); + } + + name = narrowRoomAddress; + + size_t pos = name.find("+"); + while (pos != std::string::npos) + { + name[pos] = '.'; + pos = name.find("+"); + } +} + +//----------------------------------------------------------------------- + +void makeRoomName(const ChatRoom *room, std::string &name) +{ + name.clear(); + if (room) + { + makeRoomName(room->getAddress(), name); + } +} + +//----------------------------------------------------------------------- + +void makeRoomName(const RoomSummary *room, std::string &name) +{ + name.clear(); + if (room) + { + makeRoomName(room->getRoomAddress(), name); + } +} + +//----------------------------------------------------------------------- + +void makeRoomData(const ChatRoom & room, ChatRoomData & roomData) +{ + NOT_NULL(&room); + roomData.id = room.getRoomID(); + + if (room.getRoomAttributes() & ROOMATTR_PRIVATE) + { + roomData.roomType = CHAT_ROOM_PRIVATE; + } + else + { + roomData.roomType = CHAT_ROOM_PUBLIC; + } + + if (room.getRoomAttributes() & ROOMATTR_MODERATED) + { + roomData.moderated = 1; + } + makeRoomName(&room, roomData.path); + makeAvatarId(room.getCreatorName(), room.getCreatorAddress(), roomData.owner); + makeAvatarId(room.getCreatorName(), room.getCreatorAddress(), roomData.creator); + + roomData.title = Unicode::String(room.getRoomTopic().string_data, room.getRoomTopic().string_length); + + roomData.moderators.clear(); + + ModeratorIterator m = room.getFirstModerator(); + for(; !m.outOfBounds(); ++m) + { + ChatAvatarId id; + makeAvatarId(*(*m), id); + roomData.moderators.push_back(id); + } + + roomData.invitees.clear(); + InviteIterator i = room.getFirstInvited(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + roomData.invitees.push_back(id); + } +} + +//----------------------------------------------------------------------- + +ChatInterface::ChatInterface( const std::string & strGameCode, + const std::string & strGatewayServerIP, + const unsigned short sGatewayServerPort, + const std::string & registrarHost, + const unsigned short registrarPort) : + ChatAPI(registrarHost.c_str(), registrarPort, strGatewayServerIP.c_str(), sGatewayServerPort), + avatarMap(), + pendingAvatars(), + pendingRoomQueries(), + roomQueriesThisFrame(0), + roomList(), + deferredChatMessages(), + queuedHeaders(), + trackingRequestGetAnyAvatarForDestroy() +{ + ChatServer::fileLog(true, "ChatInterface", "connecting to API (gameCode=%s, gatewayServer=%s:%d registrar=%s:%d", strGameCode.c_str(), strGatewayServerIP.c_str(), sGatewayServerPort, registrarHost.c_str(), registrarPort); + UNREF(strGameCode); + + s_intervalToSendHeadersToClientSeconds = ConfigChatServer::getIntervalToSendHeadersToClientSeconds(); + s_maxHeadersToSendToClientPerInterval = ConfigChatServer::getMaxHeadersToSendToClientPerInterval(); +} + +//----------------------------------------------------------------------- + +ChatInterface::~ChatInterface() +{ + for (std::map > >::const_iterator iter = queuedHeaders.begin(); iter != queuedHeaders.end(); ++iter) + { + for (std::deque::const_iterator iter2 = iter->second.second.begin(); iter2 != iter->second.second.end(); ++iter2) + delete *iter2; + } + + queuedHeaders.clear(); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnConnect() +{ + ChatServer::fileLog(true, "ChatInterface", "OnConnect() ChatAPI has established connection to the ChatServer backend and is ready to accept requests. Connecting SYSTEM avatar."); + + ConnectPlayer(10, "SYSTEM", NetworkId::cms_invalid); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnDisconnect() +{ + ChatServer::fileLog(true, "ChatInterface", "OnDisconnect() ChatAPI has lost connection to the ChatServer backend. This may be followed by an OnFailoverBegin command if the connection is re-established and failover mode is initiated."); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnFailoverBegin() +{ + ChatServer::fileLog(true, "ChatInterface", "OnFailoverBegin() ChatAPI has restored connection to the ChatServer backend and is attempting failover to restore validity of its state. It is retaining its queued requests for server submission upon OnFailoverComplete."); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnFailoverComplete() +{ + ChatServer::fileLog(true, "ChatInterface", "OnFailoverComplete() ChatAPI has restored its connection to the ChatServer backend and restored its state. It is submitting the queued requests and ready to accept new requests."); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnGetRoom(unsigned track, unsigned result, const ChatRoom *room, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnGetRoom() track(%u) result(%u) room(%s)", track, result, ChatServer::getChatRoomNameNarrow(room).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetRoom"); + if (result != CHATRESULT_SUCCESS || !room) + { + return; + } + std::string roomName; + if (room) + makeRoomName(room, roomName); + //printf("!!!!!!!!!!!!got room %s\n", roomName.c_str()); + if (strstr(roomName.c_str(), "group") == NULL) + { + ChatServer::putSystemAvatarInRoom(roomName); + } + std::string lowerRoomName = toLower(roomName); + unsigned sequence = (unsigned)user; + std::hash_map::iterator f = roomList.find(lowerRoomName); + if (f != roomList.end() && room) + { + (*f).second.updateRoomData(room); + } + else + { + if (room) + { + ChatServerRoomOwner * o = new ChatServerRoomOwner(room); + + IGNORE_RETURN(roomList.insert(std::make_pair(lowerRoomName, *o))); + + delete o; + } + } + + ChatServerRoomOwner *owner = NULL; + if (room) + owner = getRoomOwner(room->getRoomID()); + + if (owner) + { + ChatAvatarId av; + std::vector avatars; + + if(room) + { + for(AvatarIterator a = room->getFirstAvatar(); !a.outOfBounds(); ++a) + { + makeAvatarId(*(*a), av); + avatars.push_back(av); + } + std::vector moderators; + for(ModeratorIterator m = room->getFirstModerator(); !m.outOfBounds(); ++m) + { + makeAvatarId(*(*m), av); + moderators.push_back(av); + } + std::vector invitees; + for(InviteIterator i = room->getFirstInvited(); !i.outOfBounds(); ++i) + { + makeAvatarId(*(*i), av); + invitees.push_back(av); + } + std::vector banned; + for(BanIterator b = room->getFirstBanned(); !b.outOfBounds(); ++b) + { + makeAvatarId(*(*b), av); + banned.push_back(av); + } + + ChatQueryRoomResults results(sequence, owner->getRoomData(), avatars, moderators, invitees, banned); + ChatServer::sendResponseForTrackId(track, results); + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::queryRoom(const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequence, const std::string & roomName) +{ + UNREF(connection); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "queryRoom() id(%s) connection(%s) sequence(%u) roomName(%s)", id.getValueString().c_str(), ChatServer::getConnectionAddress(connection).c_str(), sequence, roomName.c_str()); + + std::string tmpName = "SOE+" + roomName; + size_t pos = tmpName.find("."); + while (pos != std::string::npos) + { + tmpName[pos] = '+'; + pos = tmpName.find("."); + } + + Unicode::String wideName = Unicode::narrowToWide(tmpName); + unsigned track = RequestGetRoom(ChatUnicodeString(wideName.data(), wideName.size()), (void *)sequence); + ChatServer::instance().pendingRequests[track] = id; + +} + +//----------------------------------------------------------------------- + +const ChatServerRoomOwner * ChatInterface::getRoomByName(const std::string & roomName) const +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "getRoomByName() roomName(%s)", roomName.c_str()); + + std::string lowerRoomName = toLower(roomName); + const ChatServerRoomOwner * result = 0; + std::hash_map::const_iterator f = roomList.find(lowerRoomName); + if(f != roomList.end()) + { + result = &(*f).second; + } + return result; +} + +//----------------------------------------------------------------------- + +void ChatInterface::deferChatMessageFor(const NetworkId & id, const Archive::ByteStream & bs) +{ + ChatServer::fileLog(false, "ChatInterface", "deferChatMessageFor() id(%s)", id.getValueString().c_str()); + + std::vector & v = deferredChatMessages[id]; + v.push_back(bs); +} + +//----------------------------------------------------------------------- + +void ChatInterface::sendMessageToAvatar(const ChatAvatarId & avatar, const GameNetworkMessage & message) +{ + ChatServer::fileLog(false, "ChatInterface", "sendMessageToAvatar() avatar(%s) message(%s)", avatar.getFullName().c_str(), message.getCmdName().c_str()); + + ChatServerAvatarOwner * to = 0; + std::map::const_iterator f = avatarMap.find(avatar); + if(f != avatarMap.end()) + to = (*f).second; + if(to) + { + ConnectionServerConnection * connection = to->getPlayerConnection(); + if(connection) + { + const NetworkId & id = to->getNetworkId(); + if(id != NetworkId::cms_invalid) + { + connection->sendToClient(id, message); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::sendMessageToAvatar(const ChatAvatar & avatar, const GameNetworkMessage & message) +{ + ChatServer::fileLog(false, "ChatInterface", "sendMessageToAvatar() avatar(%s) message(%s)", ChatServer::getFullChatAvatarName(&avatar).c_str(), message.getCmdName().c_str()); + + ChatServerAvatarOwner * to = getAvatarOwner(&avatar); + + if(! to) + { + ChatAvatarId id; + makeAvatarId(avatar, id); + std::map::const_iterator f = avatarMap.find(id); + if(f != avatarMap.end()) + { + to = (*f).second; + } + } + if(to) + { + ConnectionServerConnection * connection = to->getPlayerConnection(); + if(connection) + { + const NetworkId & id = to->getNetworkId(); + if(id != NetworkId::cms_invalid) + { + connection->sendToClient(id, message); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::sendMessageToAllAvatars(const GameNetworkMessage & message) +{ + ChatServer::fileLog(false, "ChatInterface", "sendMessageToAllAvatars() message(%s)", message.getCmdName().c_str()); + + ChatServer::sendToAllConnectionServers(message); +/* + //send to all connected avatars + std::map::const_iterator f = avatarMap.begin(); + while (f != avatarMap.end()) + { + ChatServerAvatarOwner *to = (*f).second; + if(to) + { + ConnectionServerConnection * connection = to->getPlayerConnection(); + if(connection) + { + const NetworkId & id = to->getNetworkId(); + if(id != NetworkId::cms_invalid) + { + connection->sendToClient(id, message); + } + } + } + ++f; + } + + //send to all pending avatars + std::hash_map::iterator p = pendingAvatars.begin(); + while (p != pendingAvatars.end()) + { + ConnectionServerConnection * connection = + ChatServer::getConnectionForCharacter((*p).second); + if(connection) + { + const NetworkId & id = (*p).second; + if(id != NetworkId::cms_invalid) + { + connection->sendToClient(id, message); + } + } + ++p; + } + */ +} + +//----------------------------------------------------------------------- + +std::string ChatInterface::getChatName(const NetworkId &id) +{ + ChatServer::fileLog(false, "ChatInterface", "getChatName() id(%s)", id.getValueString().c_str()); + + std::hash_map::iterator i; + for (i = pendingAvatars.begin(); i != pendingAvatars.end(); ++i) + { + if (id == (*i).second) + { + return (*i).first; + } + } + static std::string tmp("somebody"); + return tmp; +} + +//----------------------------------------------------------------------- + +bool ChatInterface::sendMessageToPendingAvatar(const ChatAvatarId &id, const GameNetworkMessage &message) +{ + ChatServer::fileLog(false, "ChatInterface", "sendMessageToPendingAvatar() id(%s) message(%s)", id.getFullName().c_str(), message.getCmdName().c_str()); + + std::hash_map::iterator f = pendingAvatars.find(id.name); + if (f != pendingAvatars.end()) + { + ConnectionServerConnection * connection = + ChatServer::getConnectionForCharacter((*f).second); + + if (connection) + { + const NetworkId & id = (*f).second; + if(id != NetworkId::cms_invalid) + { + connection->sendToClient(id, message); + return true; + } + } + } + return false; +} + +//----------------------------------------------------------------------- + +const std::hash_map & ChatInterface::getRoomList() const +{ + return roomList; +} + +//----------------------------------------------------------------------- + +void ChatInterface::updateRooms() +{ + std::hash_map::const_iterator i; + for(i = roomList.begin(); i != roomList.end(); ++i) + { + ChatServerRoomOwner & roomOwner = const_cast((*i).second); + const ChatRoom *room = roomOwner.getRoom(); + if (room) + { + roomOwner.updateRoomData(room); + /* + AvatarIterator i = room->getFirstAvatar(); + if (!i.outOfBounds()) + { + ++i; + } + if (i.outOfBounds() && (!(room->getRoomAttributes() & ROOMATTR_PERSISTENT))) + { + ChatServer::removeSystemAvatarFromRoom(room); + roomOwner.flagForDelete(); + }*/ + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::requestRoomList(const NetworkId & id, ConnectionServerConnection * connection) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "requestRoomList() id(%s) connection(%s)", id.getValueString().c_str(), ChatServer::getConnectionAddress(connection).c_str()); + + if (roomQueriesThisFrame >= ConfigChatServer::getMaxRoomQueriesPerFrame()) + { +// printf("%Ld requested room query, but we've had too many queries this frame. Queuing it\n", id.getValue()); + pendingRoomQueries.insert(id); + return; + } + + ++roomQueriesThisFrame; + + std::hash_map::const_iterator i; + std::vector rooms; + const ChatAvatar * target = ChatServer::getAvatarByNetworkId(id); + ChatAvatarId requestingAvatar; + if(target) + { + makeAvatarId(*target, requestingAvatar); + for(i = roomList.begin(); i != roomList.end(); ++i) + { + ChatServerRoomOwner & roomOwner = const_cast((*i).second); + const ChatRoomData & roomData = roomOwner.getRoomData(); + if( + roomData.roomType == CHAT_ROOM_PUBLIC || //lint !e641 enum to int + roomData.creator == requestingAvatar + ) + { + rooms.push_back(roomData); + } + else + { + std::vector::const_iterator j; + for(j = roomData.invitees.begin(); j != roomData.invitees.end(); ++j) + { + if (requestingAvatar == (*j)) + { + rooms.push_back(roomData); + break; + } + } + + } + } + } + ChatRoomList r(rooms); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "requestRoomList() sending room list of %u rooms to (%s)", r.getRoomData().size(), id.getValueString().c_str()); + + if (connection) + connection->sendToClient(id, r); +} + +//----------------------------------------------------------------------- + +std::string makeCanonicalName(const std::string &characterName) +{ +/* + static const std::string dot("."); + std::string retVal; + char *str = strdup(characterName.c_str()); + char *tmp = strtok(str, "."); + if (tmp) + { + retVal = toUpper(tmp); + } + tmp = strtok(NULL, "."); + if (tmp) + { + retVal += (dot + tmp); + } + tmp = strtok(NULL, "."); + if (tmp) + { + retVal += (dot + tmp); + } + printf("canonicalized(%s -> %s)\n", characterName.c_str(), retVal.c_str()); + free(str); + return retVal; + */ + if (characterName == "SYSTEM") + { + return characterName; + } + else + { + return toLower(characterName); + } +} + +//----------------------------------------------------------------------- + +struct ConnectPlayerInfo +{ + Unicode::String name; + Unicode::String address; + unsigned int suid; +}; + +struct QueuedLoginInfo +{ + std::string name; + NetworkId id; + unsigned int suid; +}; + +static std::vector queuedLogins; + +//----------------------------------------------------------------------- + +void ChatInterface::ConnectPlayer(unsigned int suid, const std::string & characterName, const NetworkId & networkId) +{ + ChatServer::fileLog(false, "ChatInterface", "ConnectPlayer() suid(%u) characterName(%s) networkId(%s)", suid, characterName.c_str(), networkId.getValueString().c_str()); + + unsigned int loginFlowControlRate = ConfigChatServer::getLoginFlowControlRate(); + if (loginFlowControlRate && pendingAvatars.size() > loginFlowControlRate) + { + QueuedLoginInfo *info = new QueuedLoginInfo; + info->name = characterName; + info->id = networkId; + info->suid = suid; + + queuedLogins.push_back(info); + +// printf("Queuing login of avatar (%s)\n", characterName.c_str()); + return; + } + + std::string canonicalName = makeCanonicalName(characterName); + static const std::string game("SOE+SWG"); + IGNORE_RETURN(pendingAvatars.insert(std::make_pair(characterName, networkId))); + + Unicode::String name = Unicode::narrowToWide(characterName); + Unicode::String address = Unicode::narrowToWide(game + "+" + ConfigChatServer::getClusterName()); + //Unicode::String address = Unicode::narrowToWide("SOE+SWG+Test Server"); + + ConnectPlayerInfo *info = new ConnectPlayerInfo; + info->name = name; + info->address = address; + info->suid = suid; + + IGNORE_RETURN(RequestLoginAvatar(suid, ChatUnicodeString(name.data(), name.size()), ChatUnicodeString(address.data(), address.size()), (void *)info)); +} + +//----------------------------------------------------------------------- + +void ChatInterface::DestroyAvatar(const std::string & characterName) +{ + std::string const avatarName(Unicode::toLower(characterName)); + std::string const avatarNameNormalized(avatarName, 0, avatarName.find(' ')); + ChatAvatarId const avatar("SWG", ConfigChatServer::getClusterName(), avatarNameNormalized); + + // track how many times we have called RequestGetAnyAvatar() for this particular DestroyAvatar + // operation, so that we can stop if we somehow get stuck in an infinite loop + unsigned const trackID = RequestGetAnyAvatar(ChatUnicodeString(avatar.getName()), ChatUnicodeString(avatar.getAPIAddress()), NULL); + trackingRequestGetAnyAvatarForDestroy[trackID] = std::make_pair(std::make_pair(ChatUnicodeString(avatar.getName()), ChatUnicodeString(avatar.getAPIAddress())), 1); +} + +//----------------------------------------------------------------------- + +void ChatInterface::checkQueuedLogins() +{ + roomQueriesThisFrame = 0; + unsigned int loginFlowControlRate = ConfigChatServer::getLoginFlowControlRate(); + if (!loginFlowControlRate) + { + return; + } + if (queuedLogins.size() > 0) + { + while (queuedLogins.size() > 0 && pendingAvatars.size() < loginFlowControlRate) + { + std::vector::iterator i = queuedLogins.begin(); + QueuedLoginInfo *info = (*i); + + ConnectPlayer(info->suid, info->name, info->id); + +// printf("Servicing queued login of avatar (%s)\n", info->name.c_str()); + + delete info; + queuedLogins.erase(i); + } + } + + while (roomQueriesThisFrame < ConfigChatServer::getMaxRoomQueriesPerFrame() && + !pendingRoomQueries.empty()) + { + std::set::iterator i = pendingRoomQueries.begin(); +// printf("Servicing queued room query for %Ld.\n", (*i).getValue()); + ConnectionServerConnection * c = ChatServer::getConnectionForCharacter((*i)); + if (c) + { + requestRoomList((*i), c); + } + pendingRoomQueries.erase(i); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::sendQueuedHeadersToClient() +{ + const unsigned long currentTime = Clock::timeSeconds(); + const unsigned long queuedHeadersSendTime = currentTime + static_cast(s_intervalToSendHeadersToClientSeconds); + + int numberHeadersSent = 0; + const ChatPersistentMessageToClient * header = NULL; + + for (std::map > >::iterator iter = queuedHeaders.begin(); iter != queuedHeaders.end();) + { + if (iter->second.first < currentTime) + { + numberHeadersSent = 0; + + while ((!iter->second.second.empty()) && (numberHeadersSent < s_maxHeadersToSendToClientPerInterval)) + { + header = iter->second.second.front(); + iter->second.second.pop_front(); + + sendMessageToAvatar(iter->first, *header); + ++numberHeadersSent; + + delete header; + } + + iter->second.first = queuedHeadersSendTime; + } + + if (iter->second.second.empty()) + { + queuedHeaders.erase(iter++); + } + else + { + ++iter; + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::clearQueuedHeadersForAvatar(const ChatAvatarId & avatarId) +{ + std::map > >::iterator iter = queuedHeaders.find(avatarId); + + if (iter != queuedHeaders.end()) + { + for (std::deque::const_iterator iter2 = iter->second.second.begin(); iter2 != iter->second.second.end(); ++iter2) + delete *iter2; + + queuedHeaders.erase(iter); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::addQueuedHeaderForAvatar(const ChatAvatarId & avatarId, const ChatPersistentMessageToClient * header, unsigned long sendTime) +{ + if (header == NULL) + return; + + std::pair > & queuedHeader = queuedHeaders[avatarId]; + queuedHeader.first = sendTime; + queuedHeader.second.push_back(header); +} + +//----------------------------------------------------------------------- + +ChatServerAvatarOwner *ChatInterface::getAvatarOwner(const ChatAvatar *avatar) +{ + if (avatar) + { + ChatAvatarId id; + makeAvatarId(*avatar, id); + + std::map::iterator f = avatarMap.find(id); + if (f != avatarMap.end()) + { + return (*f).second; + } + } + return NULL; +} + +//----------------------------------------------------------------------- +// Response to RequestAddModerator(...) +void ChatInterface::OnAddModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddModerator() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddModerator"); + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId destId; + if (pair) + { + destId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + // Tell the player making the request whether it was successful + ChatOnAddModeratorToRoom msg(result, sequence, destId, srcId, roomName); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + // If we had a success, tell everyone else in the room about it + if (result == CHATRESULT_SUCCESS) + { + if (destRoom) + { + ChatAvatarId responseId; + { + ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId ); + if (responseAvatar) + { + makeAvatarId(*responseAvatar, responseId); + } + } + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + // We already sent a response to the avatar that made the request + if (id != responseId) + { + sendMessageToAvatar(id, msg); + } + } + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveAddModeratorRoom +// Called when srcAvatar has granted destAvatar moderator privileges in +// destRoom and this API has avatars that are in destRoom. +void ChatInterface::OnReceiveAddModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddModeratorRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveAddModeratorRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(false, "ChatInterface", "OnReceiveAddModeratorRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, destAvatar); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveAddModeratorAvatar +// Called when srcAvatar has granted destAvatar moderator privileges in +// the room described by roomName and roomAddress, and destAvatar +// is on this API. +void ChatInterface::OnReceiveAddModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddModeratorAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- +// Response to RequestRemoveModerator(...) +void ChatInterface::OnRemoveModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnRemoveModerator() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveModerator"); + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId destId; + if (pair) + { + destId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + // Tell the player making the request whether it was successful + ChatOnRemoveModeratorFromRoom msg(result, sequence, destId, srcId, roomName); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + // If we had a success, tell everyone else in the room about it + if (result == CHATRESULT_SUCCESS) + { + if (destRoom) + { + ChatAvatarId responseId; + { + ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId ); + if (responseAvatar) + { + makeAvatarId(*responseAvatar, responseId); + } + } + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + // We already sent a response to the avatar that made the request + if (id != responseId) + { + sendMessageToAvatar(id, msg); + } + } + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveRemoveModeratorRoom +// Called when srcAvatar has removed destAvatar moderator privileges in +// destRoom and this API has avatars that are in destRoom. +void ChatInterface::OnReceiveRemoveModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveModeratorRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRemoveModeratorRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveModeratorRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, 0); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveRemoveModeratorAvatar +// Called when srcAvatar has removed destAvatar moderator privileges from +// the room described by roomName and roomAddress, and destAvatar is on +// this API. +void ChatInterface::OnReceiveRemoveModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveModeratorAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnAddFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnAddFriend() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddFriend"); + UNREF(user); + if(result == CHATRESULT_SUCCESS) //lint !e641 Converting enum 'ChatResult' to int // jrandall that's what the API exposes + { + // send message to client! + ChatAvatarId d; + makeAvatarId(destName, destAddress, d); + ChatOnAddFriend chat(0, result); //lint !e713 Loss of precision (arg. no. 2) (unsigned int to int) + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat)); + } + else + { + ChatOnAddFriend failed(0, result); //lint !e713 Loss of precision (arg. no. 2) (unsigned int to int) + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, failed)); + } + + //game server support + ChatAvatarId d; + makeAvatarId(destName, destAddress, d); + + ChatServerAvatarOwner * mo = NULL; + if (srcAvatar) + mo = getAvatarOwner(srcAvatar); + + if(mo) + { + ChatOnChangeFriendStatus update(0, mo->getNetworkId(), d, true, result); + ConnectionServerConnection * mc = mo->getPlayerConnection(); + if(mc) + { + mc->sendToClient(mo->getNetworkId(), update); + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnRemoveFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnRemoveFriend() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveFriend"); + UNREF(user); + UNREF(track); + // send message to client! + ChatAvatarId d; + makeAvatarId(destName, destAddress, d); + + ChatServerAvatarOwner * mo = NULL; + if (srcAvatar) + mo = getAvatarOwner(srcAvatar); + + if(mo) + { + ChatOnChangeFriendStatus update(0, mo->getNetworkId(), d, false, result); + ConnectionServerConnection * mc = mo->getPlayerConnection(); + if(mc) + { + mc->sendToClient(mo->getNetworkId(), update); + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnIgnoreStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatIgnoreStatus *ignoreList, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnIgnoreStatus() track(%u) result(%u) srcAvatar(%s) listLength(%u)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), listLength); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnIgnoreStatus"); + UNREF(user); + UNREF(result); +// REPORT_LOG(true, ("OnIgnoreStatus(%u)\n", result)); + if (track != 0 && result == CHATRESULT_SUCCESS) + { + std::vector idList; + + if (ignoreList) + { + for (unsigned i = 0; i < listLength; ++i) + { + ChatAvatarId id; + makeAvatarId(ignoreList[i].getName(), ignoreList[i].getAddress(), id); + idList.push_back(id); + } + } + + ChatServerAvatarOwner * mo = NULL; + if (srcAvatar) + mo = getAvatarOwner(srcAvatar); + if(mo) + { + ChatOnGetIgnoreList msg(mo->getNetworkId(), idList); + ConnectionServerConnection * mc = mo->getPlayerConnection(); + if(mc) + { + mc->sendToClient(mo->getNetworkId(), msg); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnFriendStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatFriendStatus *friendList, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnFriendStatus() track(%u) result(%u) srcAvatar(%s) listLength(%u)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), listLength); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnFriendStatus"); + UNREF(user); + UNREF(result); + if (track != 0 && result == CHATRESULT_SUCCESS) + { + std::vector idList; + if (friendList) + { + for (unsigned i = 0; i < listLength; ++i) + { + ChatAvatarId id; + makeAvatarId(friendList[i].getName(), friendList[i].getAddress(), id); + idList.push_back(id); + } + } + ChatServerAvatarOwner * mo = NULL; + if (srcAvatar) + mo = getAvatarOwner(srcAvatar); + if(mo) + { + ChatOnGetFriendsList msg(mo->getNetworkId(), idList); + ConnectionServerConnection * mc = mo->getPlayerConnection(); + if(mc) + { + mc->sendToClient(mo->getNetworkId(), msg); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveFriendLogin(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar) +{ + ChatServer::fileLog(false, "ChatInterface", "OnReceiveFriendLogin() srcAvatar(%s) srcAddress(%s) destAvatar(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(srcAddress).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveFriendLogin"); + UNREF(srcAddress); + ChatServerAvatarOwner * owner = NULL; + if (destAvatar) + owner = getAvatarOwner(destAvatar); + if(owner) + { + ConnectionServerConnection * connection = owner->getPlayerConnection(); + if(connection) + { + const NetworkId & id = owner->getNetworkId(); + if((id != NetworkId::cms_invalid) && (srcAvatar)) + { + ChatAvatarId d; + makeAvatarId(*srcAvatar, d); + ChatFriendsListUpdate update(d, true); + connection->sendToClient(id, update); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveFriendLogout(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar) +{ + ChatServer::fileLog(false, "ChatInterface", "OnReceiveFriendLogout() srcAvatar(%s) srcAddress(%s) destAvatar(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(srcAddress).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveFriendLogout"); + UNREF(srcAddress); + ChatServerAvatarOwner * owner = NULL; + if (destAvatar) + owner = getAvatarOwner(destAvatar); + if(owner) + { + ConnectionServerConnection * connection = owner->getPlayerConnection(); + if(connection) + { + const NetworkId & id = owner->getNetworkId(); + if((id != NetworkId::cms_invalid) && (srcAvatar)) + { + ChatAvatarId d; + makeAvatarId(*srcAvatar, d); + ChatFriendsListUpdate update(d, false); + connection->sendToClient(id, update); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnAddIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnAddIgnore() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddIgnore"); + UNREF(user); + + if(srcAvatar) + { + //game server support + ChatAvatarId d; + makeAvatarId(destName, destAddress, d); + ChatAvatarId r; + makeAvatarId(*srcAvatar, r); + + ChatServerAvatarOwner * mo = getAvatarOwner(srcAvatar); + if(mo) + { + ChatOnChangeIgnoreStatus update(0, mo->getNetworkId(), d, true, result); + ConnectionServerConnection * mc = mo->getPlayerConnection(); + if(mc) + { + mc->sendToClient(mo->getNetworkId(), update); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnRemoveIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnRemoveIgnore() track(%u) result(%u) srcAvatar(%s) destName(%s) destAddress(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::toNarrowString(destName).c_str(), ChatServer::toNarrowString(destAddress).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveIgnore"); + UNREF(user); + + //game server support + ChatAvatarId d; + makeAvatarId(destName, destAddress, d); + + ChatServerAvatarOwner * mo = NULL; + if (srcAvatar) + mo = getAvatarOwner(srcAvatar); + if(mo) + { + ChatOnChangeIgnoreStatus update(0, mo->getNetworkId(), d, false, result); + ConnectionServerConnection * mc = mo->getPlayerConnection(); + if(mc) + { + mc->sendToClient(mo->getNetworkId(), update); + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnLoginAvatar() track(%u) result(%u) newAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(newAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnLoginAvatar"); + + static unsigned lastTrack = 12345678; + if (track == lastTrack) + { + DEBUG_WARNING(true, ("Received duplicate track")); + return; + } + lastTrack = track; + + if (newAvatar) + s_mostRecentRoomChatMessage.erase(newAvatar->getAvatarID()); + + // login to destroy chat avatar + std::map, int> >::const_iterator iterFind = trackingRequestGetAnyAvatarForDestroy.find(track); + if (iterFind != trackingRequestGetAnyAvatarForDestroy.end()) + { + if ((result == CHATRESULT_SUCCESS) && newAvatar) + { + // destroy chat avatar + unsigned const trackID = RequestDestroyAvatar(newAvatar, NULL); + trackingRequestGetAnyAvatarForDestroy[trackID] = iterFind->second; + } + + trackingRequestGetAnyAvatarForDestroy.erase(track); + return; + } + + ConnectPlayerInfo *info = (ConnectPlayerInfo *)user; + if (info) + { + if (result == 1) //timeout + { +// printf("!!!!!!!!!!avatar login timed out, trying again\n"); + ConnectPlayerInfo *info2 = new ConnectPlayerInfo; + info2->name = info->name; + info2->address = info->address; + info2->suid = info->suid; + IGNORE_RETURN(RequestLoginAvatar(info->suid, ChatUnicodeString(info->name.data(), info->name.size()), ChatUnicodeString(info->address.data(), info->address.size()), (void *)info2)); + delete info; + return; + } + } +// ChatAvatarId foobar; +// if (newAvatar) +// { +// makeAvatarId(*newAvatar, foobar); +// } +// printf("OnLoginAvatar(%u) for %s.%s.%s\n", result, foobar.gameCode.c_str(), foobar.cluster.c_str(), foobar.name.c_str()); + //DEBUG_WARNING(result != CHATRESULT_SUCCESS, ("Chat Connect avatar %s.%s.%s failed! : %s\n", avatar.GetGameCode().c_str(), avatar.GetGameServerName().c_str(), avatar.GetCharacterName().c_str(), getChatResultCodeName(resultCode).c_str())); //lint !e641 converting enum to int + // is this the special system avatar? + + if (result != CHATRESULT_SUCCESS) + { + + ChatAvatarId failedAvatarId; + makeAvatarId(ChatUnicodeString(info->name.data(), info->name.size()), ChatUnicodeString(info->address.data(), info->address.size()), failedAvatarId); + std::hash_map::iterator f = pendingAvatars.find(failedAvatarId.name); + if (f != pendingAvatars.end()) + { + pendingAvatars.erase(f); + } + DEBUG_WARNING(result != CHATRESULT_SUCCESS, ("Chat Connect avatar failed for %s.%s.%s! : %u\n", failedAvatarId.gameCode.c_str(),failedAvatarId.cluster.c_str(), failedAvatarId.name.c_str(), result)); //lint !e641 converting enum to int + delete info; + return; + } + delete info; + + ChatAvatarId id; + if (newAvatar) + makeAvatarId(*newAvatar, id); + + if(id == ChatServer::getSystemAvatarId()) + { + //REPORT_LOG(true, ("\"System avatar\" load confirmed\n")); + if (newAvatar) + { + ChatServer::fileLog(true, "ChatInterface", "OnLoginAvatar() ChatAPI SYSTEM avatar connected with name=(%s), address=(%s), server=(%s), gateway=(%s), loginLocation=(%s)", + Unicode::wideToNarrow(Unicode::String(newAvatar->getName().string_data, newAvatar->getName().string_length)).c_str(), + Unicode::wideToNarrow(Unicode::String(newAvatar->getAddress().string_data, newAvatar->getAddress().string_length)).c_str(), + Unicode::wideToNarrow(Unicode::String(newAvatar->getServer().string_data, newAvatar->getServer().string_length)).c_str(), + Unicode::wideToNarrow(Unicode::String(newAvatar->getGateway().string_data, newAvatar->getGateway().string_length)).c_str(), + Unicode::wideToNarrow(Unicode::String(newAvatar->getLoginLocation().string_data, newAvatar->getLoginLocation().string_length)).c_str()); + + ChatServer::setOwnerSystem(newAvatar); + static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG"); + static Unicode::String wideFilter = Unicode::narrowToWide(""); + static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size()); + static ChatUnicodeString filter(wideFilter.data(), wideFilter.size()); + IGNORE_RETURN(RequestGetRoomSummaries(swgNode, filter, NULL)); + } + } + else + { + // look up a connection for this avatar + std::hash_map::iterator f = pendingAvatars.find(id.name); + if(f != pendingAvatars.end()) + { + GenericValueTypeMessage const avatarConnectedMessage("ChatAvatarConnected", (*f).second); + ChatServer::broadcastToGameServers(avatarConnectedMessage); + ConnectionServerConnection * c = ChatServer::getConnectionForCharacter((*f).second); + if(c && newAvatar) + { + ChatServerAvatarOwner * owner = new ChatServerAvatarOwner(c, (*f).second); + ChatAvatarId avId; + makeAvatarId(*newAvatar, avId); + avatarMap[avId] = owner; + + if(ChatServer::isGod(f->second)) + { + RequestSetAvatarAttributes(newAvatar, AVATARATTR_GM, NULL); + } + else + { + RequestSetAvatarAttributes(newAvatar, 0, NULL); + } + + ChatServer::chatConnectedAvatar((*f).second, *newAvatar); + + // flush chat messages pending for this avatar + std::hash_map, NetworkId::Hash >::iterator df = deferredChatMessages.find((*f).second); + if(df != deferredChatMessages.end()) + { + std::vector & v = (*df).second; + std::vector::const_iterator i; + for(i = v.begin(); i != v.end(); ++i) + { + const_cast(c)->onReceive((*i)); + } + deferredChatMessages.erase(df); + } + //ChatServer::getFriendsList(id); + + clearQueuedHeadersForAvatar(avId); + IGNORE_RETURN(RequestGetPersistentHeaders(newAvatar, NULL)); + //REPORT_LOG(true, ("Connection to chat system for %s.%s.%s confirmed\n", avatar.GetGameCode().c_str(), avatar.GetGameServerName().c_str(), avatar.GetCharacterName().c_str())); + }//lint !e429 Custodial pointer 'owner' has not been freed or returned // jrandall avatar owns it + pendingAvatars.erase(f); + } + else + { + // no way to route messages to avatar, they disconnected between + // the time they connected to the connection server and the time + // this message arrived from the chat backend. + if (newAvatar) + IGNORE_RETURN(RequestLogoutAvatar(newAvatar, NULL)); + } + } + ChatOnConnectAvatar const connect; + sendMessageToAvatar(id, connect); + + + // make my owner object +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnCreateRoom(unsigned track,unsigned result, const ChatRoom *newRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnCreateRoom() track(%u) result(%u) newRoom(%s)", track, result, ChatServer::getChatRoomNameNarrow(newRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnCreateRoom"); + UNREF(user); + + unsigned sequence = (unsigned)user; + static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG"); + static Unicode::String wideFilter = Unicode::narrowToWide(""); + static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size()); + static ChatUnicodeString filter(wideFilter.data(), wideFilter.size()); + //printf("!!!!Calling GetRoomSummaries from OnCreateRoom\n"); + //IGNORE_RETURN(RequestGetRoomSummaries(swgNode, filter, NULL)); + + ChatRoomData roomData; + + if((result == CHATRESULT_SUCCESS) && (newRoom)) //lint !e641 enum to int + { + ChatServerRoomOwner * o = new ChatServerRoomOwner(newRoom); + + roomData = o->getRoomData(); + + //Unicode::String wideRoomName(newRoom->getRoomName().string_data, newRoom->getRoomName().string_length); + std::string roomName; + makeRoomName(newRoom, roomName); + if (strstr(roomName.c_str(), "group") == NULL) + { + ChatServer::putSystemAvatarInRoom(roomName); + } + std::string lowerRoomName = toLower(roomName); + IGNORE_RETURN(roomList.insert(std::make_pair(lowerRoomName, *o))); + //REPORT_LOG(true, ("OnCreateRoom(%s) confirmed\n", roomData.path.c_str())); + delete o; + ChatServer::onCreateRoomSuccess(lowerRoomName, newRoom->getRoomID()); + } //lint !e429 Pointer 'o' not freed or returned: Set in SetRoomOwnerPtr + + ChatOnCreateRoom const c(sequence, result, roomData); + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, c)); + + Connection * const connection = safe_cast(ChatServer::getGameServerConnection(sequence)); + if (connection) + { + static Archive::ByteStream a; + a.clear(); + c.pack(a); + connection->send(a, true); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnGetRoomSummaries(unsigned track, unsigned result, unsigned numFoundRooms, RoomSummary *foundRooms, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnGetRoomSummaries() track(%u) result(%u) numFoundRooms(%u)", track, result, numFoundRooms); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetRoomSummaries"); + UNREF(track); + UNREF(result); + UNREF(user); + + if (foundRooms) + { + for (unsigned i = 0; i < numFoundRooms; ++i) + { + std::string roomName; + makeRoomName(&(foundRooms[i]), roomName); + + std::string lowerRoomName = toLower(roomName); + std::hash_map::const_iterator f = roomList.find(lowerRoomName); + if(f == roomList.end()) + { + RequestGetRoom(foundRooms[i].getRoomAddress(), NULL); + //ChatServerRoomOwner * o = new ChatServerRoomOwner((*i)); + //(*i)->SetRoomOwnerPtr(o); + //IGNORE_RETURN(roomList.insert(std::make_pair(lowerRoomName, *o))); + //printf("insert %s, roomList size = %u\n", lowerRoomName.c_str(), roomList.size()); + } //lint !e429 pointer not freed or returned, it is set as ownerPtr + } + } +} + +//----------------------------------------------------------------------- + +const ChatServerRoomOwner *ChatInterface::getRoomOwner(const std::string & roomName) +{ + std::string lowerName = toLower(roomName); + std::hash_map::const_iterator f = roomList.find(lowerName); + if(f != roomList.end()) + { + return &((*f).second); + } + return NULL; +} + +//----------------------------------------------------------------------- + +ChatServerRoomOwner *ChatInterface::getRoomOwner(unsigned roomId) +{ + std::hash_map::iterator f = roomList.begin(); + while (f != roomList.end()) + { + if ((*f).second.getRoomData().id == roomId) + { + return &((*f).second); + } + ++f; + } + return NULL; +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveDestroyRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveDestroyRoom() srcAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveDestroyRoom"); + ChatAvatarId destroyer; + if (srcAvatar) + makeAvatarId(*srcAvatar, destroyer); + + if (destRoom) + { + const ChatOnDestroyRoom c(0, 0, destRoom->getRoomID(), destroyer); + AvatarIterator i = destRoom->getFirstAvatar(); + + /*for(; !i.outOfBounds(); ++i) + { + sendMessageToAvatar(*(*i), c); + }*/ + sendMessageToAllAvatars(c); + + std::string roomName; + makeRoomName(destRoom, roomName); + std::string lowerName = toLower(roomName); + std::hash_map::iterator f = roomList.find(lowerName); + if(f != roomList.end()) + { + roomList.erase(f); + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnDestroyRoom(unsigned track, unsigned result, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnDestroyRoom() track(%u) result(%u)", track, result); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnDestroyRoom"); + static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG"); + static Unicode::String wideFilter = Unicode::narrowToWide(""); + static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size()); + static ChatUnicodeString filter(wideFilter.data(), wideFilter.size()); + //IGNORE_RETURN(RequestGetRoomSummaries(swgNode, filter, NULL)); + + ChatAvatarId destroyer; + + RoomOwnerSequencePair *pair = (RoomOwnerSequencePair *)user; + + const ChatServerRoomOwner * owner = NULL; + unsigned sequence = 0; + if (pair) + { + owner = pair->roomOwner; + sequence = pair->sequence; + + delete pair; + pair = 0; + } + + if (owner) + { + const ChatOnDestroyRoom c(sequence, result, owner->getRoomData().id, destroyer); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, c); + + if (result == CHATRESULT_SUCCESS) + { + std::string lowerName = toLower(owner->getRoomData().path); + std::hash_map::iterator f = roomList.find(lowerName); + if(f != roomList.end()) + { + roomList.erase(f); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnLogoutAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnLogoutAvatar() track(%u) result(%u) oldAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(oldAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnLogoutAvatar"); + UNREF(user); + UNREF(result); + UNREF(track); + if (!oldAvatar) + { + return; + } + + s_mostRecentRoomChatMessage.erase(oldAvatar->getAvatarID()); + + /*ChatAvatarId id; + makeAvatarId(*oldAvatar, id); + std::map::iterator f = avatarMap.find(id); + if(f != avatarMap.end()) + {*/ + ChatServer::disconnectAvatar(*oldAvatar); + //} + + ChatAvatarId id; + makeAvatarId(*oldAvatar, id); + clearQueuedHeadersForAvatar(id); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnDestroyAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user) +{ + UNREF(user); + + std::map, int> >::const_iterator iterFind = trackingRequestGetAnyAvatarForDestroy.find(track); + if (iterFind != trackingRequestGetAnyAvatarForDestroy.end()) + { + if ((result == CHATRESULT_SUCCESS) && oldAvatar) + { + // stop if it looks like we're in an infinite loop + if (iterFind->second.second <= 25) + { + unsigned const trackID = RequestGetAnyAvatar(iterFind->second.first.first, iterFind->second.first.second, NULL); + trackingRequestGetAnyAvatarForDestroy[trackID] = std::make_pair(iterFind->second.first, (iterFind->second.second + 1)); + } + } + + trackingRequestGetAnyAvatarForDestroy.erase(track); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnGetAnyAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, bool loggedIn, void *user) +{ + UNREF(user); + + std::map, int> >::const_iterator iterFind = trackingRequestGetAnyAvatarForDestroy.find(track); + if (iterFind != trackingRequestGetAnyAvatarForDestroy.end()) + { + if ((result == CHATRESULT_SUCCESS) && foundAvatar) + { + // can only destroy the avatar if he is logged in + if (loggedIn) + { + unsigned const trackID = RequestDestroyAvatar(foundAvatar, NULL); + trackingRequestGetAnyAvatarForDestroy[trackID] = iterFind->second; + } + // log in the chat avatar so we can destroy him + else + { + unsigned const trackID = RequestLoginAvatar(foundAvatar->getUserID(), foundAvatar->getName(), foundAvatar->getAddress(), NULL); + trackingRequestGetAnyAvatarForDestroy[trackID] = iterFind->second; + } + } + + trackingRequestGetAnyAvatarForDestroy.erase(track); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveForcedLogout(const ChatAvatar *oldAvatar) +{ + ChatServer::fileLog(false, "ChatInterface", "OnReceiveForcedLogout() oldAvatar(%s)", ChatServer::getFullChatAvatarName(oldAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveForcedLogout"); + if ((oldAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnReceiveForcedLogout with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + ChatAvatarId id; + makeAvatarId(*oldAvatar, id); + std::map::iterator f = avatarMap.find(id); + if(f != avatarMap.end()) + { + ChatServer::disconnectAvatar(*oldAvatar); + } + else + { + DEBUG_WARNING(true, ("We received a forced logout for an avatar who is awaiting login. Usually this will happen on slow boxes when you log out and back in quickly, exploiting a race condition in the backend. No harm should come from this.")); + } +} + +//----------------------------------------------------------------------- +// Response to RequestEnterRoom(...) +void ChatInterface::OnEnterRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnEnterRoom() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnEnterRoom"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnEnterRoom with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + unsigned sequence = (unsigned)user; + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + unsigned roomId = 0; + if (destRoom) + { + roomId = destRoom->getRoomID(); + } + + // If we had a success, we need to tell the client about the room + // so that they have the information to process entering the room + if (result == CHATRESULT_SUCCESS) + { + // Send the room data for the room the avatar has entered + // since the room may be private and may be unknown to the player + if (destRoom) + { + ChatServerRoomOwner *roomOwner = getRoomOwner(destRoom->getRoomID()); + if (roomOwner) + { + std::vector rooms; + + ChatRoomData data = roomOwner->getRoomData(); + rooms.push_back(data); + + ChatRoomList r(rooms); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnEnterRoom() sending room list of %u rooms to (%s)", r.getRoomData().size(), ChatServer::getFullChatAvatarName(srcAvatar).c_str()); + sendMessageToAvatar(srcId, r); + } + } + } + + // Tell the client that made the request the results + ChatOnEnteredRoom const msg(sequence, result, roomId, srcId); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + // If we had a success, tell everyone else in the room about it + if (result == CHATRESULT_SUCCESS) + { + // Tell the client that entered the room if they did not make the request + ChatServerAvatarOwner * const owner = getAvatarOwner(srcAvatar); + if (owner && (owner->getNetworkId() != responseNetworkId)) + { + sendMessageToAvatar(srcId, msg); + } + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Let everyone in the room know the client entered the room + if (roomName.find(".system") == roomName.npos) + { + ChatAvatarId responseId; + { + ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId ); + if (responseAvatar) + { + makeAvatarId(*responseAvatar, responseId); + } + } + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + // We already sent a response to the avatar that made the request + if ((id != responseId) && (id != srcId)) + { + sendMessageToAvatar(id, msg); + } + } + } + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveEnterRoom +// Called when srcAvatar has entered destRoom and this API has avatars +// that are in destRoom. If srcAvatar is on this API and no others from +// this API are in the room, this is not called. +void ChatInterface::OnReceiveEnterRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveEnterRoom() srcAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveEnterRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveEnterRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, srcAvatar); + } + } +} + +//----------------------------------------------------------------------- +// The OnReceive___() callbacks for chat rooms get called for every +// Chat API that has avatars in the room. So limit updates to the +// avatars that are located on this Chat API. +void ChatInterface::updateRoomForThisChatAPI(const ChatRoom *room, const ChatAvatar *additionalAvatar) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "updateRoomForThisChatAPI() room(%s)", ChatServer::getChatRoomNameNarrow(room).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - updateRoomForThisChatAPI"); + + if (room) + { + ChatServerRoomOwner *owner = getRoomOwner(room->getRoomID()); + if (owner) + { + owner->updateRoomData(room); + + ChatAvatarId av; + std::vector avatars; + + for(AvatarIterator a = room->getFirstAvatar(); !a.outOfBounds(); ++a) + { + makeAvatarId(*(*a), av); + avatars.push_back(av); + } + + std::vector moderators; + for(ModeratorIterator m = room->getFirstModerator(); !m.outOfBounds(); ++m) + { + makeAvatarId(*(*m), av); + moderators.push_back(av); + } + + std::vector invitees; + for(InviteIterator i = room->getFirstInvited(); !i.outOfBounds(); ++i) + { + makeAvatarId(*(*i), av); + invitees.push_back(av); + } + + std::vector banned; + for(BanIterator b = room->getFirstBanned(); !b.outOfBounds(); ++b) + { + makeAvatarId(*(*b), av); + banned.push_back(av); + } + + ChatAvatarId additionalAvatarId; + if (additionalAvatar) + { + makeAvatarId(*additionalAvatar, additionalAvatarId); + } + + // We only want to update the additional avatar once + bool wasAdditionalAvatarUpdated = false; + + ChatQueryRoomResults results(0, owner->getRoomData(), avatars, moderators, invitees, banned); + for(AvatarIterator avs = room->getFirstAvatar(); !avs.outOfBounds(); ++avs) + { + makeAvatarId(*(*avs), av); + + // Only send to avatars for this Chat API + if (av.cluster == ChatServer::getSystemAvatarId().cluster) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "updateRoomForThisChatAPI() sending room members (%u avatars, %u moderators, %u invitees, %u banned) to (%s)", + avatars.size(), moderators.size(), invitees.size(), banned.size(), av.getFullName().c_str()); + sendMessageToAvatar(av, results); + + if (additionalAvatar && (av == additionalAvatarId)) + { + wasAdditionalAvatarUpdated = true; + } + } + } + + if (additionalAvatar && !wasAdditionalAvatarUpdated) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "updateRoomForThisChatAPI() sending room members (%u avatars, %u moderators, %u invitees, %u banned) to (%s)", + avatars.size(), moderators.size(), invitees.size(), banned.size(), additionalAvatarId.getFullName().c_str()); + sendMessageToAvatar(additionalAvatarId, results); + } + } + } +} + +//----------------------------------------------------------------------- +// Response to RequestAddBan(...) +void ChatInterface::OnAddBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddBan() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddBan"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnAddBan with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId destId; + if (pair) + { + destId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + // Tell the player making the request whether the ban was successful + ChatOnBanAvatarFromRoom const msg(sequence, result, roomName, srcId, destId); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + // If we had a success, tell everyone else in the room about it + if (result == CHATRESULT_SUCCESS) + { + if (destRoom) + { + ChatAvatarId responseId; + { + ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId ); + if (responseAvatar) + { + makeAvatarId(*responseAvatar, responseId); + } + } + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + // We already sent a response to the avatar that made the request + if (id != responseId) + { + sendMessageToAvatar(id, msg); + } + } + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveAddBanRoom +// Called when srcAvatar has banned destAvatar from destRoom and this +// API has avatars that are in destRoom. +void ChatInterface::OnReceiveAddBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddBanRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // NOTE: Do not put anything in this callback that uses destAvatar. + // Currently there is a bug where the address and name are not set correctly in destAvatar. + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveAddBanRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddBanRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, destAvatar); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveAddBanAvatar +// Called when srcAvatar has banned destAvatar from the room described by +// roomName and roomAddress, and destAvatar is on this API. +void ChatInterface::OnReceiveAddBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddBanAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- +// Response to RequestRemoveBan(...) +void ChatInterface::OnRemoveBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnRemoveBan() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveBan"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnRemoveBan with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId destId; + if (pair) + { + destId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + // Tell the player making the request whether the ban was successful + ChatOnUnbanAvatarFromRoom const msg(sequence, result, roomName, srcId, destId); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + // If we had a success, tell everyone else in the room about it + if (result == CHATRESULT_SUCCESS) + { + if (destRoom) + { + ChatAvatarId responseId; + { + ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId ); + if (responseAvatar) + { + makeAvatarId(*responseAvatar, responseId); + } + } + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + // We already sent a response to the avatar that made the request + if (id != responseId) + { + sendMessageToAvatar(id, msg); + } + } + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveRemoveBanRoom +// Called when srcAvatar has removed the ban on destAvatar from +// destRoom and this API has avatars that are in destRoom. +void ChatInterface::OnReceiveRemoveBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveBanRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRemoveBanRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveBanRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, destAvatar); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveRemoveBanAvatar +// Called when srcAvatar has removed the ban on destAvatar from +// the room described by roomName and roomAddress, and destAvatar is on +// this API. +void ChatInterface::OnReceiveRemoveBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveBanAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- +// Response to RequestAddInvite(...) +void ChatInterface::OnAddInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddInvite() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnAddInvite"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnAddInvite with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId destId; + if (pair) + { + destId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + // Tell the player making the request whether the invite was successful + ChatOnInviteToRoom const msg(result, roomName, srcId, destId); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + if (result == CHATRESULT_SUCCESS) + { + if (destRoom) + { + // Calling this on a room will cause the API to cache the room + // and to receive room updates for the room. + RequestGetRoom(destRoom->getAddress(), NULL); + + // Send the room data for the room the avatar was invited to join + // since the room may be private and may be unknown to the player + ChatServerRoomOwner const * const roomOwner = getRoomOwner(destRoom->getRoomID()); + if (roomOwner) + { + std::vector rooms; + + ChatRoomData data = roomOwner->getRoomData(); + rooms.push_back(data); + + ChatRoomList const r(rooms); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnAddInvite() sending room list of %u rooms to (%s)", r.getRoomData().size(), destId.getFullName().c_str()); + sendMessageToAvatar(destId, r); + } + } + + // Tell the invited person about the invitation + ChatOnReceiveRoomInvitation const chat(roomName, srcId); + sendMessageToAvatar(destId, chat); + } +} + +//----------------------------------------------------------------------- +// OnReceiveAddInviteRoom +// Called when srcAvatar has invited destAvatar to destRoom and this +// API has avatars that are in this room. +void ChatInterface::OnReceiveAddInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddInviteRoom() srcAvatar(%s) destAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveAddInviteRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddInviteRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, 0); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveAddInviteAvatar +// Called when srcAvatar has invited destAvatar to the room described +// by roomName and roomAddress, and destAvatar is on this API. +void ChatInterface::OnReceiveAddInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveAddInviteAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- +// Response to RequestRemoveInvite(...) +void ChatInterface::OnRemoveInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnRemoveInvite() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnRemoveInvite"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnRemoveInvite with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId inviteeId; + if (pair) + { + inviteeId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + ChatAvatarId invitorId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, invitorId); + } + + //if the sequence is 0, the message initiated from the game server. Don't + //bother telling the client that something failed when they didn't even + //ask to do it. + if (sequence != 0) + { + ChatOnUninviteFromRoom const msg(sequence, result, roomName, invitorId, inviteeId); + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, msg)); + } + else + { + // We still need to somehow remove the pending request from the queue + IGNORE_RETURN(ChatServer::getAvatarIdForTrackId(track)); + } +} + +//----------------------------------------------------------------------- +// OnReceiveRemoveInviteRoom +// Called when srcAvatar has uninvited destAvatar from destRoom and +// this API has avatars that are in this room. +void ChatInterface::OnReceiveRemoveInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveInviteRoom() srcAvatar(%s) destAvatar(%s) chatRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRemoveInviteRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveInviteRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, 0); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveRemoveInviteAvatar +// Called when srcAvatar has uninvited destAvatar from the room +// described by roomName and roomAddress, and destAvatar is on +// this API. +void ChatInterface::OnReceiveRemoveInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveRemoveInviteAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- +// Response to RequestLeaveRoom(...) +void ChatInterface::OnLeaveRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnLeaveRoom() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnLeaveRoom"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnLeaveRoom with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + unsigned sequence = (unsigned)user; + + ChatAvatarId id; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, id); + } + + unsigned roomId = 0; + if (destRoom) + { + roomId = destRoom->getRoomID(); + } + + // Tell the person requesting to leave the success of the request + ChatOnLeaveRoom const msg(sequence, result, roomId, id); + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, msg)); + + // We'll tell everyone else in the room about it in OnReceiveLeaveRoom() +} + +//----------------------------------------------------------------------- +// OnReceiveLeaveRoom +// Called when srcAvatar has left destRoom and this API has avatars +// that are in destRoom. +void ChatInterface::OnReceiveLeaveRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveLeaveRoom() srcAvatar(%s) destRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveLeaveRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator const f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveLeaveRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, srcAvatar); + } + // If we didn't send the updated room information, then just send the + // message to everyone in the room that the person has left the room + else if ((f != roomList.end()) && srcAvatar) + { + ChatAvatarId srcAvatarId; + makeAvatarId(*srcAvatar, srcAvatarId); + ChatOnLeaveRoom const msg(0, CHATRESULT_SUCCESS, destRoom->getRoomID(), srcAvatarId); + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + sendMessageToAvatar(id, msg); + } + } + } +} + +//----------------------------------------------------------------------- +// Response to RequestKickAvatar(...) +void ChatInterface::OnKickAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnKickAvatar() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnKickAvatar"); + + AvatarIdSequencePair *pair = (AvatarIdSequencePair *)user; + + unsigned sequence = 0; + ChatAvatarId kickedId; + if (pair) + { + kickedId = pair->avatar; + sequence = pair->sequence; + + delete pair; + pair = NULL; + } + + std::string roomName; + if (destRoom) + { + makeRoomName(destRoom, roomName); + } + + ChatAvatarId srcId; + if (srcAvatar) + { + makeAvatarId(*srcAvatar, srcId); + } + + // Tell the person making the kick request whether it was successful + ChatOnKickAvatarFromRoom const msg(result, kickedId, srcId, roomName); + NetworkId responseNetworkId = ChatServer::sendResponseForTrackId(track, msg); + + // If we had a success, tell everyone else in the room about it + if (result == CHATRESULT_SUCCESS) + { + if (destRoom) + { + ChatAvatarId responseId; + { + ChatAvatar const * const responseAvatar = ChatServer::getAvatarByNetworkId( responseNetworkId ); + if (responseAvatar) + { + makeAvatarId(*responseAvatar, responseId); + } + } + + AvatarIterator i = destRoom->getFirstAvatar(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId id; + makeAvatarId(*(*i), id); + + // We already sent a response to the avatar that made the request + if (id != responseId) + { + sendMessageToAvatar(id, msg); + } + } + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveKickRoom +// Called when destAvatar has been kicked by srcAvatar from destRoom +// and this API has avatars that are in destRoom. +void ChatInterface::OnReceiveKickRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveKickRoom() srcAvatar(%s) destAvatar(%s) chatRoom(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveKickRoom"); + + if (destRoom) + { + std::string roomName; + makeRoomName(destRoom, roomName); + + // Update info about the room + std::hash_map::iterator f = roomList.find(toLower(roomName)); + if(f != roomList.end()) + (*f).second.updateRoomData(destRoom); + + // See who created the room + ChatAvatarId creatorAvatarId; + makeAvatarId(destRoom->getCreatorName(), destRoom->getCreatorAddress(), creatorAvatarId); + + // Clients don't want to know who belongs to the system created rooms + // NOTE: The name for the system avatar should be the same for all clusters + if (!Unicode::caseInsensitiveCompare(creatorAvatarId.getName(), ChatServer::getSystemAvatarId().getName())) + { + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveKickRoom() updating clients with member info for chatRoom(%s)", ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + // Tell all the avatars in the room the new member info + updateRoomForThisChatAPI(destRoom, destAvatar); + } + } +} + +//----------------------------------------------------------------------- +// OnReceiveKickAvatar +// Called when destAvatar has been kicked by srcAvatar from the room +// described by roomName and roomAddress, and destAvatar is on +// this API. +void ChatInterface::OnReceiveKickAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatInterface", "OnReceiveKickAvatar() srcAvatar(%s) destAvatar(%s) roomName(%s) roomAddress(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::toNarrowString(roomName).c_str(), ChatServer::toNarrowString(roomAddress).c_str()); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnGetPersistentMessage(unsigned track, unsigned result, ChatAvatar *destAvatar, const PersistentHeader *header, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnGetPersistentMessage() track(%u) result(%u) destAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(destAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetPersistentMessage"); + if (result == CHATRESULT_SUCCESS && (destAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnGetPersistentMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + UNREF(user); + UNREF(track); + + if (!destAvatar || !header) + { + return; + } + + if(result == CHATRESULT_SUCCESS) //lint !e641 Converting enum 'ChatResult' to int // jrandall That's what is passed to this method by the ChatAPI + { + ChatAvatarId fromId; + fromId.name = Unicode::wideToNarrow(Unicode::String(header->getFromName().string_data, header->getFromName().string_length)); + std::string tmpAddress = Unicode::wideToNarrow(Unicode::String(header->getFromAddress().string_data, header->getFromAddress().string_length)); + char *str = (char *)tmpAddress.c_str(); + char *loc = strstr(str, "."); + if (loc) + { + *loc = 0; + fromId.gameCode = str; + fromId.cluster = loc+1; + } + Unicode::String subject = (Unicode::String(header->getSubject().string_data, header->getSubject().string_length)); + //printf("PM from OnGetPersistentMessage\n"); + const ChatPersistentMessageToClient m( + header->getMessageID(), + convertPmStatus (header->getStatus()), + fromId.gameCode, + fromId.cluster, + fromId.name, + subject, + Unicode::String(msg.string_data, msg.string_length), + Unicode::String(oob.string_data, oob.string_length), + header->getSentTime() + ); + ChatAvatarId toId; + makeAvatarId(*destAvatar, toId); + sendMessageToAvatar(toId, m); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnGetPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnGetPersistentHeaders() track(%u) result(%u) destAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(destAvatar).c_str(), listLength); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnGetPersistentHeaders"); + if (result == CHATRESULT_SUCCESS && (destAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnGetPersistentHeaders with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + UNREF(track); + UNREF(user); + if(result == CHATRESULT_SUCCESS) //lint !e641 Converting enum 'ChatResult' to int // jrandall That's what is passed to this method by the ChatAPI + { + if (!destAvatar || !list) + { + return; + } + ChatAvatarId toAvatar; + makeAvatarId(*destAvatar, toAvatar); + + LOG("CustomerService", ("Login:retrieved %u persistent message headers for %s", listLength, toAvatar.getFullName().c_str())); + + clearQueuedHeadersForAvatar(toAvatar); + + int numberHeadersSent = 0; + const unsigned long queuedHeadersSendTime = Clock::timeSeconds() + static_cast(s_intervalToSendHeadersToClientSeconds); + + for(unsigned i = 0; i < listLength; ++i) + { + ChatAvatarId fromId; + makeAvatarId(list[i].getFromName(), list[i].getFromAddress(), fromId); + Unicode::String subject(list[i].getSubject().string_data, list[i].getSubject().string_length); + //printf("PM from OnGetPersistentHeaders\n"); + + if (numberHeadersSent < s_maxHeadersToSendToClientPerInterval) + { + const ChatPersistentMessageToClient m( + list[i].getMessageID(), + convertPmStatus (list[i].getStatus()), + fromId.gameCode, + fromId.cluster, + fromId.name, + subject, + list[i].getSentTime()); + + sendMessageToAvatar(toAvatar, m); + + ++numberHeadersSent; + } + else + { + const ChatPersistentMessageToClient * m = new ChatPersistentMessageToClient( + list[i].getMessageID(), + convertPmStatus (list[i].getStatus()), + fromId.gameCode, + fromId.cluster, + fromId.name, + subject, + list[i].getSentTime()); + + addQueuedHeaderForAvatar(toAvatar, m, queuedHeadersSendTime); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceivePersistentMessage(const ChatAvatar *destAvatar, const PersistentHeader *header) +{ + ChatServer::fileLog(false, "ChatInterface", "OnReceivePersistentMessage() destAvatar(%s)", ChatServer::getFullChatAvatarName(destAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceivePersistentMessage"); + if ((destAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnREceivePersistentMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + if (!destAvatar || !header) + { + return; + } + ChatAvatarId toAvatar; + makeAvatarId(*destAvatar, toAvatar); + + ChatAvatarId fromId; + makeAvatarId(header->getFromName(), header->getFromAddress(), fromId); + Unicode::String subject(header->getSubject().string_data, header->getSubject().string_length); + //printf("PM from OnReceivePersistentMessage\n"); + const ChatPersistentMessageToClient m( + header->getMessageID(), + convertPmStatus (header->getStatus()), + fromId.gameCode, + fromId.cluster, + fromId.name, + subject, + header->getSentTime()); + sendMessageToAvatar(toAvatar, m); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnSendRoomMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnSendRoomMessage() track(%u) result(%u) srcAvatar(%s) destRoom(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnSendRoomMessage"); + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL || destRoom == NULL)) + { + DEBUG_WARNING(true, ("We received an OnsendRoomMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + UNREF(srcAvatar); + UNREF(destRoom); + unsigned sequence = (unsigned)user; + ChatOnSendRoomMessage chat(sequence, result); + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat)); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob, unsigned messageID) +{ + ChatServer::fileLog(false, "ChatInterface", "OnReceiveRoomMessage() srcAvatar(%s) destAvatar(%s) destRoom(%s) messageID(%u)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str(), ChatServer::getChatRoomNameNarrow(destRoom).c_str(), messageID); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveRoomMessage"); + if(! srcAvatar || ! destAvatar || ! destRoom) + { + DEBUG_WARNING(true, ("We received an OnREceiveRoomMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + + // check to prevent sending duplicate room chat message + { + unsigned const destAvatarId = destAvatar->getAvatarID(); + unsigned const destRoomId = destRoom->getRoomID(); + std::hash_map >::iterator const iterFind = s_mostRecentRoomChatMessage.find(destAvatarId); + if (iterFind != s_mostRecentRoomChatMessage.end()) + { + if ((iterFind->second.first == destRoomId) && (iterFind->second.second == messageID)) + return; + + iterFind->second.first = destRoomId; + iterFind->second.second = messageID; + } + else + { + s_mostRecentRoomChatMessage.insert(std::make_pair(destAvatarId, std::make_pair(destRoomId, messageID))); + } + } + + ChatAvatarId fromId; + makeAvatarId(*srcAvatar, fromId); + GameNetworkMessage * gnm = 0; + Unicode::String ustrMessage(msg.string_data, msg.string_length); + Unicode::String outOfBand(oob.string_data, oob.string_length); + ChatSystemMessage chat(ChatSystemMessage::BROADCAST, ustrMessage, outOfBand); //lint !e641 enum to int + ChatRoomMessage m(destRoom->getRoomID(), fromId, ustrMessage, outOfBand); + + if(fromId == ChatServer::getSystemAvatarId()) + { + gnm = &chat; + } + else + { + gnm = &m; + } + + ChatAvatarId toId; + makeAvatarId(*destAvatar, toId); + + sendMessageToAvatar(toId, *gnm); + + // don't log planet-wide chat + const std::string chatRoomName = toLower(ChatServer::getChatRoomNameNarrow(destRoom)); + if(chatRoomName != "auction" && chatRoomName != "planet") + { + Unicode::String const wideTo(Unicode::narrowToWide(toId.getFullName())); + Unicode::String const wideFrom(Unicode::narrowToWide(fromId.getFullName())); + + ChatServer::instance().logChatMessage(wideTo, wideFrom, Unicode::emptyString, ChatServer::toUnicodeString(msg), ChatServer::getChatRoomName(destRoom)); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnSendInstantMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnSendInstantMessage() track(%u) result(%u) srcAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnSendInstantMessage"); + + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnSendInstantMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + UNREF(srcAvatar); + + unsigned sequence = (unsigned)user; + + ChatOnSendInstantMessage chat(sequence, result); + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat)); +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveInstantMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +{ + ChatServer::fileLog(false, "ChatInterface", "OnReceiveInstantMessage() srcAvatar(%s) destAvatar(%s)", ChatServer::getFullChatAvatarName(srcAvatar).c_str(), ChatServer::getFullChatAvatarName(destAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveInstantMessage"); + if ((srcAvatar == NULL || destAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnReceiveInstantMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + if (!srcAvatar || !destAvatar) + { + return; + } + ChatAvatarId fromId; + makeAvatarId(*srcAvatar, fromId); + ChatAvatarId toId; + makeAvatarId(*destAvatar, toId); + if(fromId == ChatServer::getSystemAvatarId()) + { + ChatSystemMessage chat( + ChatSystemMessage::PERSONAL, + Unicode::String(msg.string_data, msg.string_length), + Unicode::String(oob.string_data, oob.string_length)); //lint !e641 enum to int + sendMessageToAvatar(toId, chat); + } + else + { + + ChatInstantMessageToClient chat(fromId, Unicode::String(msg.string_data, msg.string_length), + Unicode::String(oob.string_data, oob.string_length)); + sendMessageToAvatar(toId, chat); + Unicode::String const wideTo(Unicode::narrowToWide(toId.getFullName())); + Unicode::String const wideFrom(Unicode::narrowToWide(fromId.getFullName())); + ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, ChatServer::toUnicodeString(msg), ChatServer::getChannelTell()); + ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, ChatServer::toUnicodeString(msg), ChatServer::getChannelTell()); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + ChatServer::fileLog(false, "ChatInterface", "OnSendPersistentMessage() track(%u) result(%u) srcAvatar(%s)", track, result, ChatServer::getFullChatAvatarName(srcAvatar).c_str()); + + PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnSendPersistentMessage"); + if (result == CHATRESULT_SUCCESS && (srcAvatar == NULL)) + { + DEBUG_WARNING(true, ("We received an OnSendPersistentMessage with a success result code but NULL data. This is an error that the API should never give.")); + return; + } + unsigned sequence = (unsigned)user; + UNREF(srcAvatar); + ChatOnSendPersistentMessage chat(sequence, result); + IGNORE_RETURN(ChatServer::sendResponseForTrackId(track, chat)); +} + +//----------------------------------------------------------------------- + +const NetworkId & ChatInterface::getNetworkIdByAvatarId(const ChatAvatarId &id) +{ + std::map::iterator f = avatarMap.find(id); + if(f != avatarMap.end()) + { + ChatServerAvatarOwner * o = (*f).second; + if (o) + { + return o->getNetworkId(); + } + } + else + { + //tmp hack because of the tolower thing + ChatAvatarId lowerId = id; + lowerId.name = toLower(id.name); + f = avatarMap.find(lowerId); + if(f != avatarMap.end()) + { + ChatServerAvatarOwner * o = (*f).second; + if (o) + { + return o->getNetworkId(); + } + } + } + static NetworkId badId; + return badId; +} + +//----------------------------------------------------------------------- + +void ChatInterface::disconnectPlayer (const ChatAvatarId & id) +{ + ChatServer::fileLog(false, "ChatInterface", "disconnectPlayer() id(%s)", id.getFullName().c_str()); + + std::map::iterator f = avatarMap.find(id); + if(f != avatarMap.end()) + { + ChatServerAvatarOwner * o = (*f).second; + delete o; + avatarMap.erase(f); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnUpdatePersistentMessages(unsigned track, unsigned result, const ChatAvatar *targetAvatar, void *user) +{ + UNREF(track); + + // Get the target chat avatar id + + ChatAvatarId targetChatAvatarId; + + if (targetAvatar != NULL) + { + makeAvatarId(*targetAvatar, targetChatAvatarId); + } + + // Get the source chat avatar id + + ChatAvatarId sourceChatAvatarId; + NetworkId const *tmpNetworkId = reinterpret_cast(user); + + if (tmpNetworkId != NULL) + { + ChatAvatar const *sourceAvatar = ChatServer::getAvatarByNetworkId(*tmpNetworkId); + + if (sourceAvatar != NULL) + { + makeAvatarId(*sourceAvatar, sourceChatAvatarId); + } + + delete tmpNetworkId; + tmpNetworkId = NULL; + } + + ChatServer::fileLog(false, "ChatInterface", "OnUpdatePersistentMessage() track(%u) result(%u) sourceAvatar(%s) targetAvatar(%s)", track, result, sourceChatAvatarId.getFullName().c_str(), targetChatAvatarId.getFullName().c_str()); + + // Send a response to the person (source) who issued this message + + if ( !targetChatAvatarId.getFullName().empty() + && !sourceChatAvatarId.getFullName().empty()) + { + std::string const &targetName = targetChatAvatarId.name; + bool const success = (result == CHATRESULT_SUCCESS); + + ChatOnDeleteAllPersistentMessages msg(targetName, success); + sendMessageToAvatar(sourceChatAvatarId, msg); + } + else + { + ChatServer::fileLog(false, "ChatInterface", "OnUpdatePersistentMessage() Unable to resolve source(%s) and target(%s).", sourceChatAvatarId.getFullName().c_str(), targetChatAvatarId.getFullName().c_str()); + } +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnReceiveUnregisterRoomReady(const ChatRoom *destRoom) +{ + UNREF(destRoom); + + // Overloading default so we don't get a warning messsage +} + +//----------------------------------------------------------------------- + +void ChatInterface::OnTransferAvatar(unsigned track, unsigned result, unsigned oldUserID, unsigned newUserID, const ChatUnicodeString &oldName, const ChatUnicodeString &newName, const ChatUnicodeString &oldAddress, const ChatUnicodeString &newAddress, void *user) +{ + UNREF(user); + LOG("CustomerService", ("CharacterTransfer: Received OnTransferAvatar(%d, %d, %d, %d, %s, %s, %s, %s)", track, result, oldUserID, newUserID, oldName.c_str(), newName.c_str(), oldAddress.c_str(), newAddress.c_str())); + LOG("CustomerService", ("Player: Received OnTransferAvatar(%d, %d, %d, %d, %s, %s, %s, %s)", track, result, oldUserID, newUserID, oldName.c_str(), newName.c_str(), oldAddress.c_str(), newAddress.c_str())); + + // if the chat avatar rename was successful, tell each game server that has + // a connected character that has the chat avatar on his friends list or ignore + // list to refresh the friends list and ignore list to update the friends list + // and ignore list with the new chat avatar name + if ((result == CHATRESULT_SUCCESS) && (oldAddress == newAddress) && (oldName != newName)) + { + ChatAvatarId const dummyAvatar("SWG", ConfigChatServer::getClusterName(), "dummy"); + if (oldAddress == dummyAvatar.getAPIAddress()) + { + GenericValueTypeMessage > const chatAvatarRenamed("ChatAvatarRenamed", std::make_pair(std::string(oldName.c_str()), std::string(newName.c_str()))); + ChatServer::broadcastToGameServers(chatAvatarRenamed); + } + } +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/ChatServer/src/shared/ChatInterface.h b/engine/server/application/ChatServer/src/shared/ChatInterface.h new file mode 100644 index 00000000..79e97a5e --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatInterface.h @@ -0,0 +1,257 @@ + +// ChatInterface.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ChatInterface_H +#define _INCLUDED_ChatInterface_H + +//----------------------------------------------------------------------- + +#include "ChatAPI/ChatAPI.h" +#include "ChatServerAvatarOwner.h" +#include "ChatServerRoomOwner.h" +#include +#include +#include +#include +#include +#include "sharedNetworkMessages/ChatRoomData.h" +#include "sharedFoundation/NetworkId.h" + +class ChatPersistentMessageToClient; +class ConnectionServerConnection; +class GameNetworkMessage; + +namespace Archive +{ + class ByteStream; +} + +void makeAvatarId(const ChatAvatar & avatar, ChatAvatarId & id); + +using namespace ChatSystem; + +class ChatInterface : public ChatAPI +{ +public: + ChatInterface (const std::string & strGameCode, + const std::string & strGatewayServerIP, + const unsigned short sGatewayServerPort, + const std::string & registrarHost, + const unsigned short registrarPort + ); + + virtual ~ChatInterface (); //lint !e1510 base class 'ChatAPI' has no destructor // jrandall - this is beyond my control + + const NetworkId & getNetworkIdByAvatarId(const ChatAvatarId &id); + ChatServerAvatarOwner *getAvatarOwner(const ChatAvatar *avatar); + void disconnectPlayer (const ChatAvatarId & avatarId); + const std::hash_map & getRoomList () const; + + const ChatServerRoomOwner *getRoomOwner(const std::string &roomName); + ChatServerRoomOwner *getRoomOwner(unsigned roomId); + const ChatServerRoomOwner * getRoomByName (const std::string & roomName) const; + + void checkQueuedLogins(); + + void sendQueuedHeadersToClient(); + void clearQueuedHeadersForAvatar(const ChatAvatarId & avatarId); + void addQueuedHeaderForAvatar(const ChatAvatarId & avatarId, const ChatPersistentMessageToClient * header, unsigned long sendTime); + + void sendMessageToAvatar (const ChatAvatar & avatar, const GameNetworkMessage & message); + void sendMessageToAvatar (const ChatAvatarId & avatar, const GameNetworkMessage & message); + void requestRoomList (const NetworkId & id, ConnectionServerConnection * connection); + void deferChatMessageFor (const NetworkId & id, const Archive::ByteStream & bs); + void sendMessageToAllAvatars (const GameNetworkMessage & message); + bool sendMessageToPendingAvatar(const ChatAvatarId &id, const GameNetworkMessage &message); + + std::string getChatName(const NetworkId &id); + + void queryRoom (const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequenceId, const std::string & roomName); + void updateRoomForThisChatAPI(const ChatRoom *room, const ChatAvatar *additionalAvatar); + void updateRooms(); + + void ConnectPlayer(const unsigned int suid, const std::string & characterName, const NetworkId & networkId); + void DestroyAvatar(const std::string & characterName); + + virtual void OnConnect(); + virtual void OnDisconnect(); + + virtual void OnFailoverBegin(); + virtual void OnFailoverComplete(); + + virtual void OnSendRoomMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob, unsigned messageID); + + virtual void OnAddFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnRemoveFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnFriendStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatFriendStatus *friendList, void *user); + virtual void OnReceiveFriendLogin(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar); + virtual void OnReceiveFriendLogout(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar); + + virtual void OnAddIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnRemoveIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnIgnoreStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatIgnoreStatus *ignoreList, void *user); + + virtual void OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, void *user); + virtual void OnLogoutAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user); + virtual void OnDestroyAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user); + virtual void OnGetAnyAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, bool loggedIn, void *user); + + virtual void OnCreateRoom(unsigned track,unsigned result, const ChatRoom *newRoom, void *user); + virtual void OnDestroyRoom(unsigned track, unsigned result, void *user); + virtual void OnReceiveDestroyRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + virtual void OnEnterRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveEnterRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + virtual void OnAddInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveAddInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveAddInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnRemoveInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveRemoveInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveRemoveInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnLeaveRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveLeaveRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + virtual void OnKickAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveKickRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveKickAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnGetPersistentMessage(unsigned track, unsigned result, ChatAvatar *destAvatar, const PersistentHeader *header, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + virtual void OnSendInstantMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnReceiveInstantMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + + virtual void OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnGetRoomSummaries(unsigned track, unsigned result, unsigned numFoundRooms, RoomSummary *foundRooms, void *user); + virtual void OnGetRoom(unsigned track, unsigned result, const ChatRoom *room, void *user); + + virtual void OnAddModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveAddModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveAddModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnRemoveModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveRemoveModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveRemoveModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnGetPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user); + + virtual void OnReceiveForcedLogout(const ChatAvatar *oldAvatar); + + virtual void OnReceivePersistentMessage(const ChatAvatar *destAvatar, const PersistentHeader *header); + + virtual void OnAddBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveAddBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveAddBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnRemoveBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnReceiveRemoveBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + virtual void OnReceiveRemoveBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + virtual void OnUpdatePersistentMessages(unsigned track, unsigned result, const ChatAvatar *targetAvatar, void *user); + virtual void OnReceiveUnregisterRoomReady(const ChatRoom *destRoom); + virtual void OnTransferAvatar(unsigned track, unsigned result, unsigned oldUserID, unsigned newUserID, const ChatUnicodeString &oldName, const ChatUnicodeString &newName, const ChatUnicodeString &oldAddress, const ChatUnicodeString &newAddress, void *user); + +private: + std::map avatarMap; + std::hash_map pendingAvatars; + std::set pendingRoomQueries; + int roomQueriesThisFrame; + std::hash_map roomList; + std::hash_map, NetworkId::Hash > deferredChatMessages; + std::map > > queuedHeaders; + std::map, int> > trackingRequestGetAnyAvatarForDestroy; +}; + +#if 0 + +//----------------------------------------------------------------------- + +class ChatInterface : public ChatAPI +{ +public: + ChatInterface (const std::string & strGameCode, + const std::string & strGatewayServerIP, + const unsigned short sGatewayServerPort, + const std::string & strBackupGatewayServerIP, + const unsigned short sBackupGatewayServerPort + ); + + virtual ~ChatInterface (); //lint !e1510 base class 'ChatAPI' has no destructor // jrandall - this is beyond my control + + + void checkRoomExpirations (); + void ConnectPlayer (const unsigned int suid, const std::string & characterName, const NetworkId & networkId); + void deferChatMessageFor (const NetworkId & id, const Archive::ByteStream & bs); + void destroyRoomByName (const std::string & roomName); + + const std::hash_map & getRoomList () const; + const ChatServerAvatarOwner *findAvatar(const ChatAvatarId & avatarId); + + void leaveRoom (const ChatAvatarId & avatarId, const std::string & roomName); + + //--- ChatAPI virtual overrides + virtual void OnConnectAvatar (const std::string & track, const unsigned int resultCode, const ChatAvatar & avatar); + virtual void OnAddFriend (const unsigned int sequence, const std::string & track, const unsigned int nResultCode, const ChatAvatar & requestingAvatar, const ChatAvatar & friendAvatar); + virtual void OnRemoveFriend (const unsigned int sequence, const std::string & track, const unsigned int nResultCode, const ChatAvatar & requestingAvatar, const ChatAvatar & friendAvatar); + virtual void OnAddIgnore (const unsigned int sequence, const std::string & track, const unsigned int nResultCode, const ChatAvatar & requestingAvatar, const ChatAvatar & ignoreAvatar); + virtual void OnRemoveIgnore (const unsigned int sequence, const std::string & track, const unsigned int nResultCode, const ChatAvatar & requestingAvatar, const ChatAvatar & ignoreAvatar); + virtual void OnAddRoomModerator (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatRoom & room, const unsigned int nRequestingAvatarUID, const ChatAvatar & moderator); + virtual void OnCreateRoom (const unsigned int sequence, const std::string & track, const unsigned int nResultCode, const ChatRoom & room); + virtual void OnDestroyRoom (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatRoom & room, const std::string & strCharacterName, const std::string & strGameServerName, const std::string & strGameCode); + virtual void OnDisconnectAvatar (const std::string & track, const unsigned int nResultCode, const ChatAvatar & toAvatar); + virtual void OnDisconnectAvatarNotify (const ChatAvatar & toAvatar); + virtual void OnEnterRoom (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatRoom & room, const ChatAvatar & avatar); + virtual void OnLeaveRoom (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatRoom & room, const ChatAvatar & avatar); + virtual void OnReceiveInstantMessage (const ChatAvatar & toAvatar, const ChatAvatar & fromAvatar, const Unicode::String & ustrMessage, const Unicode::String & oob); + virtual void OnReceivePersistentMessage (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatPersistentMessage & message); + virtual void OnReceivePersistentMessageHeader (const ChatPersistentMessageHeader & header); + virtual void OnReceivePersistentMessageHeaders (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatAvatar & toAvatar, const std::vector & headers); + virtual void OnReceiveRoomMessage (const unsigned int nSequenceID, const ChatRoom & room, const std::string & strFromCharacterName, const std::string & strFromGameServerName, const std::string & strFromGameCode, const Unicode::String & ustrMessage, const Unicode::String & outOfBand, unsigned messageID); + virtual void OnConnect (const unsigned int resultCode); + virtual void OnReceiveRooms (const std::string & track, const unsigned int nResultCode, const std::vector & rooms); + virtual void OnRemoveRoomModerator (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatRoom & room, const unsigned int nRequestingAvatarUID, const ChatAvatar & moderator); + virtual void OnSendInstantMessage (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatAvatar & sendingAvatar); + virtual void OnSendPersistentMessage (const unsigned int nSequenceID, const std::string & track, const unsigned int nResultCode, const ChatAvatar& sendingAvatar); + virtual void OnSendRoomMessage (const unsigned int sequence, const std::string & track, const unsigned int resultCode); + virtual void OnUpdateFriendStatus (const ChatAvatar & toAvatar, const ChatAvatar & fromAvatar, const bool bIsConnected); + virtual void OnReceiveRoomInvitation (const std::string & strRoomName, const ChatAvatar & invitorAvatar, const ChatAvatar & inviteeAvatar); + virtual void OnSendRoomInvitation (const unsigned int sequence, const std::string & track, const unsigned int resultCode, const ChatRoom & room, const bool isOnline, const ChatAvatar & invitor, const ChatAvatar & invitee); + + const ChatServerRoomOwner * getRoomByName (const std::string & roomName) const; + + void disconnectPlayer (const ChatAvatarId & avatarId); + void queryRoom (const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequenceId, const std::string & roomName); + void queryRoom (const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequenceId, const unsigned int roomId); + void requestRoomList (const NetworkId & id, ConnectionServerConnection * connection); + void sendMessageToAllAvatars (const GameNetworkMessage & message); + bool sendMessageToPendingAvatar(const ChatAvatarId &id, const GameNetworkMessage &message); + +private: + void sendMessageToAvatar (const ChatAvatar & avatar, const GameNetworkMessage & message); + void sendMessageToAvatar (const ChatAvatarId & avatar, const GameNetworkMessage & message); + +private: + ChatInterface & operator = (const ChatInterface & rhs); + ChatInterface(const ChatInterface & source); + std::hash_map pendingAvatars; + std::hash_map, NetworkId::Hash > deferredChatMessages; + std::hash_map roomList; + std::map avatarMap; + time_t lastRoomCheck; + +}; //lint !e1712 default constructor not defined for class + +#endif + +std::string toLower(const std::string & source); +std::string toUpper(const std::string & source); +void makeRoomData(const ChatRoom & room, ChatRoomData & roomData); +void makeRoomData(const RoomSummary & room, ChatRoomData & roomData); + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ChatInterface_H diff --git a/engine/server/application/ChatServer/src/shared/ChatServer.cpp b/engine/server/application/ChatServer/src/shared/ChatServer.cpp new file mode 100644 index 00000000..22a017e7 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServer.cpp @@ -0,0 +1,3087 @@ +// ChatServer.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "ChatServer.h" + +#include "CentralServerConnection.h" +#include "ChatInterface.h" +#include "ChatServerMetricsData.h" +#include "ConfigChatServer.h" +#include "ConnectionServerConnection.h" +#include "CustomerServiceServerConnection.h" +#include "GameServerConnection.h" +#include "PlanetServerConnection.h" +#include "UnicodeUtils.h" +#include "serverMetrics/MetricsManager.h" +#include "serverNetworkMessages/ChatConnectAvatar.h" +#include "serverNetworkMessages/ChatServerOnline.h" +#include "serverNetworkMessages/EnumerateServers.h" +#include "serverNetworkMessages/TransferCharacterData.h" +#include "serverUtility/ChatLogManager.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedFoundation/Os.h" +#include "sharedLog/Log.h" +#include "sharedLog/SetupSharedLog.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetwork/ConfigSharedNetwork.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetwork/Service.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include "sharedNetworkMessages/ChatInstantMessageToClient.h" +#include "sharedNetworkMessages/ChatOnAddModeratorToRoom.h" +#include "sharedNetworkMessages/ChatOnBanAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnCreateRoom.h" +#include "sharedNetworkMessages/ChatOnDestroyRoom.h" +#include "sharedNetworkMessages/ChatOnEnteredRoom.h" +#include "sharedNetworkMessages/ChatOnGetFriendsList.h" +#include "sharedNetworkMessages/ChatOnGetIgnoreList.h" +#include "sharedNetworkMessages/ChatOnInviteToRoom.h" +#include "sharedNetworkMessages/ChatOnInviteGroupToRoom.h" +#include "sharedNetworkMessages/ChatOnKickAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnLeaveRoom.h" +#include "sharedNetworkMessages/ChatOnRemoveModeratorFromRoom.h" +#include "sharedNetworkMessages/ChatOnRequestLog.h" +#include "sharedNetworkMessages/ChatOnSendInstantMessage.h" +#include "sharedNetworkMessages/ChatOnSendRoomMessage.h" +#include "sharedNetworkMessages/ChatOnUnbanAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnUninviteFromRoom.h" +#include "sharedNetworkMessages/ChatSystemMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/VoiceChatMiscMessages.h" +#include "serverUtility/ConfigServerUtility.h" +#include "ChatAPI/ChatAPI.h" + +#include "VChatInterface.h" + +#include +#include + +//----------------------------------------------------------------------- + +namespace ChatServerNamespace +{ + ChatServerMetricsData * s_chatServerMetricsData = 0; + + typedef std::list > MessageList; + typedef std::hash_map PlayerMessageList; + PlayerMessageList s_playerMessageList; + + void cleanChatLog(); + + time_t const chatMessageCleanTime = 60; + time_t chatMessageCleanTimer = 0; + Unicode::String const s_channelTell = Unicode::narrowToWide("tell"); + Unicode::String const s_channelEmail = Unicode::narrowToWide("email"); + bool s_loggingEnabled = false; + + std::set > s_pendingEntersByName; + std::set > > s_pendingEntersById; + + Unicode::String getRoomAddress(const std::string & roomName) + { + std::string fullName = roomName; + size_t dotPos = 0; + while(dotPos != std::string::npos) + { + dotPos = fullName.find('.'); + if(dotPos != std::string::npos) + { + fullName[dotPos] = '+'; + } + } + + if(fullName.find(ConfigChatServer::getClusterName()) == std::string::npos) + { + fullName = ConfigChatServer::getClusterName() + '+' + fullName; + } + if(fullName.find(ConfigChatServer::getGameCode()) == std::string::npos) + { + fullName = ConfigChatServer::getGameCode() + '+' + fullName; + } + if(fullName.find("SOE") == std::string::npos) + { + fullName = "SOE+" + fullName; + } + return Unicode::narrowToWide(fullName); + } + + ChatUnicodeString makeChatUnicodeString(const Unicode::String & source) + { + return ChatUnicodeString(source.c_str(), source.length()); + } + + std::set s_godClients; + std::set s_notSubscribedClients; + + // Control log output for chat room related methods + bool const s_enableChatRoomLogs = false; +} + +using namespace ChatServerNamespace; + + +//----------------------------------------------------------------------- + +void ChatServerNamespace::cleanChatLog() +{ + PlayerMessageList::iterator iterPlayerMessageList = s_playerMessageList.begin(); + + time_t const spatialChatLogTime = static_cast(ConfigServerUtility::getChatLogMinutes() * 60); + time_t const currentTime = Os::getRealSystemTime(); + + for (; iterPlayerMessageList != s_playerMessageList.end(); ++iterPlayerMessageList) + { + MessageList &messageList = iterPlayerMessageList->second; + int chatLogCount = static_cast(messageList.size()); + + MessageList::iterator iterMessageList = messageList.begin(); + while (!messageList.empty()) + { + time_t const messageTime = iterMessageList->second; + + if (messageTime < (currentTime - spatialChatLogTime) || (chatLogCount > ConfigServerUtility::getPlayerMaxChatLogLines())) + { + iterMessageList = messageList.erase(iterMessageList); + --chatLogCount; + } + else + { + break; + } + } + } +} + +//----------------------------------------------------------------------- + +ChatServer *ChatServer::m_instance = NULL; + +#include + +void splitRoomName(std::string roomName, Unicode::String &name, Unicode::String &address); + +//----------------------------------------------------------------------- + +std::string toLower(const std::string & source) +{ + std::string lower; + size_t i; + for(i = 0; i < source.length(); ++i) + { + char a = static_cast(tolower(source[i])); + lower += a; + } + return lower; +} + +//----------------------------------------------------------------------- + +std::string toUpper(const std::string & source) +{ + std::string upper; + size_t i; + for(i = 0; i < source.length(); ++i) + { + char a = static_cast(toupper(source[i])); + upper += a; + } + return upper; +} + +//----------------------------------------------------------------------- + +void ChatServer::update() +{ + PROFILER_BLOCK_DEFINE(profileBlockMainLoop, "main loop"); + PROFILER_BLOCK_ENTER(profileBlockMainLoop); + static unsigned int lastTime = 0; +unsigned int t1 = Clock::timeMs(); + NetworkHandler::update(); +unsigned int t2 = Clock::timeMs(); + + chatInterface->checkQueuedLogins(); + chatInterface->sendQueuedHeadersToClient(); + +if ((t2 - t1) > (1000 * 5)) +{ + DEBUG_WARNING(true, ("\n\n\n\n\nNetworkHandler::update() took %i ms\n\n\n\n\n", (t2 - t1))); +} + + NetworkHandler::dispatch(); +unsigned int t3 = Clock::timeMs(); +if ((t3 - t2) > (1000 * 5)) +{ + DEBUG_WARNING(true, ("\n\n\n\n\nNetworkHandler::dispatch() took %i ms\n\n\n\n\n", (t3 - t2))); +} + if (lastTime != 0) + { + unsigned int time = Clock::timeMs(); + if ((time - lastTime) > (1000)) + { + //DEBUG_WARNING(true, ("\n\n\n\n\n\nLong Chat Frame (%i ms)\n\n\n\n", (time - lastTime))); + } + } + lastTime = Clock::timeMs(); + chatInterface->Process(); + voiceChatInterface->Process(); + + PROFILER_BLOCK_LEAVE(profileBlockMainLoop); + + if (!Os::update()) + done = true; + + Os::sleep(1); + static int i = 0; + if (i % 600 == 0) + { + instance().chatInterface->updateRooms(); + } + if (i % 6000 == 0) + { + static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG"); + static Unicode::String wideFilter = Unicode::narrowToWide(""); + static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size()); + static ChatUnicodeString filter(wideFilter.data(), wideFilter.size()); + instance().chatInterface->RequestGetRoomSummaries(swgNode, filter, NULL); + } + + ++i; + + NetworkHandler::clearBytesThisFrame(); + if(s_chatServerMetricsData) + MetricsManager::update(Clock::frameTime() * 1000); + + + // Clear the chat log every once in a while + + if ((chatMessageCleanTimer + chatMessageCleanTime) > Os::getRealSystemTime()) + { + chatMessageCleanTimer = Os::getRealSystemTime(); + cleanChatLog(); + } +} + +//----------------------------------------------------------------------- + +ChatServer::ChatServer() : +pendingRequests(), +callback(new MessageDispatch::Callback), +centralServerConnection(new CentralServerConnection(ConfigChatServer::getCentralServerAddress(), ConfigChatServer::getCentralServerPort())), +chatAvatars(), +chatInterface(0), +voiceChatInterface(0), +clientMap(), +gameServerConnectionMap(), +connectionServerConnections(), +done(false), +gameService(0), +planetService(), +ownerSystem(0), +systemAvatarId("SWG", ConfigChatServer::getClusterName(), "SYSTEM"), +customerServiceServerConnection(NULL), +m_gameServerConnectionRegistry(), +m_voiceChatIdMap() +{ + s_loggingEnabled = ConfigChatServer::isLoggingEnabled(); + DebugFlags::registerFlag(s_loggingEnabled, "ChatServer", "loggingEnabled"); + SetupSharedLog::install("SwgChatServer"); + + NetworkSetupData setup; + setup.maxConnections = 100; + setup.port = 0; + setup.bindInterface = ConfigChatServer::getGameServiceBindInterface(); + gameService = new Service(ConnectionAllocator(), setup); + setup.bindInterface = ConfigChatServer::getPlanetServiceBindInterface(); + planetService = new Service(ConnectionAllocator(), setup); + + const std::string getGameCode = ConfigChatServer::getGameCode(); + const std::string getGatewayServerIP = ConfigChatServer::getGatewayServerIP(); + const std::string getBackupGatewayServerIP = ConfigChatServer::getBackupGatewayServerIP(); + chatInterface = new ChatInterface(getGameCode, getGatewayServerIP, ConfigChatServer::getGatewayServerPort(), ConfigChatServer::getRegistrarHost(), static_cast(ConfigChatServer::getRegistrarPort())); + + + std::string vChatHost; + int numConnectionStrings = ConfigChatServer::getNumberOfVoiceChatGateways(); + for(int i = 0; i < numConnectionStrings; ++i) + { + if(i != 0) + { + vChatHost += " "; + } + vChatHost += ConfigChatServer::getVoiceChatGateway(i); + } + voiceChatInterface = new VChatInterface(vChatHost.c_str()); + + callback->connect(*this, &ChatServer::onEnumerateServers); //lint !e1025 !e1703 !e1514 !e64 !e1058 !e118 // jrandall lint is confused, the compiler resolves this just fine //lint !e1703 // jrandall, really, this is fine! + + + ChatServer::fileLog(true, "ChatServer", "ChatServer() VChat host: %s", vChatHost.c_str()); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigChatServer::getCentralServerAddress() %s", ConfigChatServer::getCentralServerAddress()); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigChatServer::getCentralServerPort() %d", ConfigChatServer::getCentralServerPort()); + + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getReportUdpDisconnects() %s", ConfigSharedNetwork::getReportUdpDisconnects() ? "yes" : "no"); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getReportTcpDisconnects() %s", ConfigSharedNetwork::getReportTcpDisconnects() ? "yes" : "no"); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionConstructionDestruction() %s", ConfigSharedNetwork::getLogConnectionConstructionDestruction() ? "yes" : "no"); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionOpenedClosed() %s", ConfigSharedNetwork::getLogConnectionOpenedClosed() ? "yes" : "no"); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionDeferredMessagesWarning() %s", ConfigSharedNetwork::getLogConnectionDeferredMessagesWarning() ? "yes" : "no"); + ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionDeferredMessagesWarningInterval() %d", ConfigSharedNetwork::getLogConnectionDeferredMessagesWarningInterval()); + + s_chatServerMetricsData = new ChatServerMetricsData(); + MetricsManager::install(s_chatServerMetricsData, false, "ChatServer" , "", 0); +// ownerSystem = new ChatAvatar("SWG", ConfigChatServer::getClusterName(), "SYSTEM"); +} + +//----------------------------------------------------------------------- + +ChatServer::~ChatServer() +{ + std::set::const_iterator i; + for(i = connectionServerConnections.begin(); i != connectionServerConnections.end(); ++i) + { + ConnectionServerConnection * c = (*i); + delete c; + } + if(centralServerConnection) + centralServerConnection->disconnect(); + // need to delete these before NetworkHandler::remove() is called in ::run() + //delete gameService; + //delete planetService; + delete callback; + delete voiceChatInterface; + delete chatInterface; + ownerSystem = 0; //lint !e423 deletion is taken care of in the OnDestroy + delete s_chatServerMetricsData; + MetricsManager::remove(); +} + +//----------------------------------------------------------------------- + +bool ChatServer::getChatLog(Unicode::String const &player, std::vector &chatLog) +{ + Unicode::String const lowerPlayer(Unicode::toLower(player)); + ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() player(%s)", Unicode::wideToNarrow(lowerPlayer).c_str()); + bool result = false; + + PlayerMessageList::const_iterator iterPlayerMessageList = s_playerMessageList.find(lowerPlayer); + + if (iterPlayerMessageList != s_playerMessageList.end()) + { + result = true; + cleanChatLog(); + + MessageList::const_iterator iterMessageList = iterPlayerMessageList->second.begin(); + + chatLog.clear(); + + for (; iterMessageList != iterPlayerMessageList->second.end(); ++iterMessageList) + { + int const messageIndex = iterMessageList->first; + ChatLogEntry chatLogEntry; + + if (ChatLogManager::getChatMessage(messageIndex, chatLogEntry.m_from, chatLogEntry.m_to, chatLogEntry.m_message, chatLogEntry.m_channel, chatLogEntry.m_time)) + { + chatLog.push_back(chatLogEntry); + } + else + { + DEBUG_WARNING(true, ("Unable to find chat log message(%d)", messageIndex)); + } + } + } + + ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() Found %u chat log messages for player(%s)", chatLog.size(), Unicode::wideToNarrow(lowerPlayer).c_str()); + + if (s_loggingEnabled) + { + ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() -- BEGIN Player List --"); + + iterPlayerMessageList = s_playerMessageList.begin(); + int count = 0; + + for (; iterPlayerMessageList != s_playerMessageList.end(); ++iterPlayerMessageList) + { + ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() [%d] player(%s)", ++count, Unicode::wideToNarrow(iterPlayerMessageList->first).c_str()); + } + + ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() -- END Player List --"); + } + + return result; +} + +//----------------------------------------------------------------------- + +void ChatServer::deferChatMessageFor(const NetworkId & id, const Archive::ByteStream & bs) +{ + instance().chatInterface->deferChatMessageFor(id, bs); +} + +//----------------------------------------------------------------------- + +void ChatServer::sendToClient(const NetworkId & id, const GameNetworkMessage & message) +{ + ChatServer::fileLog(false, "ChatServer", "sendToClient() id(%s) message(%s)", id.getValueString().c_str(), message.getCmdName().c_str()); + + std::hash_map::const_iterator f = instance().clientMap.find(id); + if(f != instance().clientMap.end()) + { + (*f).second->sendToClient(id, message); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::setOwnerSystem(const ChatAvatar * o) +{ + ChatServer::fileLog(false, "ChatServer", "setOwnerSystem() "); + + instance().ownerSystem = o; //lint !e423 deletion is taken care of in the OnDestroy + const Service * s = getGameService(); + if(s) + { + ChatServerOnline cso(s->getBindAddress(), s->getBindPort()); + Archive::ByteStream bs; + cso.pack(bs); + + Connection *connection = safe_cast(instance().centralServerConnection); + + if (connection != NULL) + { + connection->send(bs, true); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::onEnumerateServers(const EnumerateServers & e) +{ + if(e.getAdd()) + { + switch(e.getServerType()) + { + case EnumerateServers::CONNECTION_SERVER: + { +//printf("!!!adding connection server, chat was told to connect to port %i!!!!\n", +// e.getPort()); + + static int count = 0; + ++count; + + ConnectionServerConnection * c = new ConnectionServerConnection(e.getAddress(), e.getPort()); + + if (c != NULL) + { + if ( !e.getAddress().empty() + && (e.getPort() != 0)) + { + ChatServer::fileLog(true, "ChatServer", "onEnumerateServers() count(%d) address(%s)", count, getConnectionAddress(c).c_str()); + + IGNORE_RETURN(connectionServerConnections.insert(c)); + s_chatServerMetricsData->setConnectionServerConnectionCount(instance().connectionServerConnections.size()); + } + else + { + ChatServer::fileLog(true, "ChatServer", "onEnumerateServers() count(%d) Empty server address", count); + } + } + else + { + ChatServer::fileLog(true, "ChatServer", "onEnumerateServers() count(%d) NULL connection", count); + } + }//lint !e429 Custodial pointer 'c' (line 232) has not been freed or returned //jrandall tracked by connectionServerConnections + break; + default: + break; + } + } + else + { + // remove the server + } +} + +//----------------------------------------------------------------------- + +ChatServer & ChatServer::instance() +{ + static ChatServer s; + m_instance = &s; + return *m_instance; +} + +//----------------------------------------------------------------------- + +void ChatServer::quit() +{ + instance().done = true; +} + +//----------------------------------------------------------------------- + +void ChatServer::reconnectToCentralServer() +{ + ChatServer::fileLog(true, "ChatServer", "reconnectToCentralServer()"); + + if (instance().centralServerConnection) + instance().centralServerConnection->disconnect(); + + instance().centralServerConnection = new CentralServerConnection(ConfigChatServer::getCentralServerAddress(), ConfigChatServer::getCentralServerPort()); +} + +//----------------------------------------------------------------------- + +void ChatServer::onCentralServerConnectionClosed() +{ + instance().centralServerConnection = 0; +} + +//----------------------------------------------------------------------- + +const ChatAvatarId & ChatServer::getSystemAvatarId() +{ + return instance().systemAvatarId; +} + +//----------------------------------------------------------------------- + +const Service * ChatServer::getGameService() +{ + return instance().gameService; +} + +//----------------------------------------------------------------------- + +void ChatServer::run() +{ + NetworkHandler::install(); + + Clock::setFrameRateLimit(20.0f); + + // create default rooms + + NetworkId id = NetworkId::cms_invalid; + +// LOG("ServerStartup",("ChatServer starting")); + + int const numberOfCreateRooms = ConfigChatServer::getNumberOfCreateRooms(); + for (int i = 0; i < numberOfCreateRooms; ++i) + { + char const * const p = ConfigChatServer::getCreateRoom(i); + if (p) + { + createRoom(id, 0, std::string(p), false, true, ""); + } + } + + while(! instance().done) + { + instance().update(); + } + + instance().removeServices(); + NetworkHandler::remove(); +} + +void ChatServer::removeServices() +{ + delete gameService; + gameService = 0; + delete planetService; + planetService = 0; +} + +//----------------------------------------------------------------------- + +ChatAvatarId ChatServer::getAvatarIdForTrackId(unsigned trackId) +{ + ChatServer & server = instance(); + std::hash_map::iterator f = server.pendingRequests.find(trackId); + if(f != server.pendingRequests.end()) + { + const ChatAvatar *avatar = getAvatarByNetworkId((*f).second); + if (avatar) + { + ChatAvatarId avatarId; + makeAvatarId(*avatar, avatarId); + return avatarId; + } + server.pendingRequests.erase(f); + } + static const ChatAvatarId badId; + return badId; +} + +//----------------------------------------------------------------------- + +const ChatAvatar * ChatServer::getAvatarByNetworkId(const NetworkId & id) +{ + if (id.getValue() == 0) + { + return NULL; + } + const ChatAvatar * result = 0; + ChatAvatarList::const_iterator f = instance().chatAvatars.find(id); + if(f != instance().chatAvatars.end()) + { + result = &((*f).second.chatAvatar); + } + return result; +} + +//----------------------------------------------------------------------- + +ChatServer::AvatarExtendedData * ChatServer::getAvatarExtendedDataByNetworkId(const NetworkId & id) +{ + if (id.getValue() == 0) + { + return NULL; + } + ChatServer::AvatarExtendedData * result = 0; + ChatAvatarList::iterator f = instance().chatAvatars.find(id); + if(f != instance().chatAvatars.end()) + { + result = &((*f).second); + } + return result; +} + +//----------------------------------------------------------------------- + +const NetworkId & ChatServer::getNetworkIdByAvatarId(const ChatAvatarId & id) +{ + PROFILER_AUTO_BLOCK_DEFINE("ChatServer - getNetworkIdByAvatarId"); + /*ChatAvatarList::const_iterator f; + for (f = instance().chatAvatars.begin(); f != instance().chatAvatars.end(); ++f) + { + ChatAvatarId av; + makeAvatarId((*f).second.chatAvatar, av); + if (av == id) + { + return f->first; + } + } + static NetworkId badId; + return badId; + */ + return instance().chatInterface->getNetworkIdByAvatarId(id); +} + +//----------------------------------------------------------------------- + +NetworkId ChatServer::sendResponseForTrackId(unsigned trackId, const GameNetworkMessage & response) +{ + NetworkId id; + ChatServer & server = instance(); + std::hash_map::iterator f = server.pendingRequests.find(trackId); + if(f != server.pendingRequests.end()) + { + id = (*f).second; + std::hash_map::const_iterator c = server.clientMap.find((*f).second); + if(c != server.clientMap.end()) + { + ConnectionServerConnection * conn = (*c).second; + conn->sendToClient((*f).second, response); + } + server.pendingRequests.erase(f); + } + return id; +} + +//----------------------------------------------------------------------- + +GameServerConnection *ChatServer::getGameServerConnection(unsigned int sequence) +{ + GameServerConnection * result = 0; + std::hash_map::iterator f = instance().gameServerConnectionMap.find(sequence); + if(f != instance().gameServerConnectionMap.end()) + { + result = (*f).second; + instance().gameServerConnectionMap.erase(f); + } + return result; + +} + +//----------------------------------------------------------------------- + +void ChatServer::addGameServerConnection(unsigned int sequence, GameServerConnection *connection) +{ + IGNORE_RETURN(instance().gameServerConnectionMap.insert(std::make_pair(sequence, connection))); + s_chatServerMetricsData->setGameServerConnectionCount(instance().gameServerConnectionMap.size()); +} + +//----------------------------------------------------------------------- + +void ChatServer::clearGameServerConnection(const GameServerConnection *connection) +{ + std::vector removeKeyList; + std::hash_map::const_iterator i; + for(i = instance().gameServerConnectionMap.begin(); i != instance().gameServerConnectionMap.end(); ++i) + { + if ((*i).second == connection) + { + removeKeyList.push_back((*i).first); + } + } + + std::vector::const_iterator j; + for (j = removeKeyList.begin(); j != removeKeyList.end(); ++j) + { + IGNORE_RETURN(instance().gameServerConnectionMap.erase((*j))); + } + s_chatServerMetricsData->setGameServerConnectionCount(instance().gameServerConnectionMap.size()); +} + +//----------------------------------------------------------------------- + +ConnectionServerConnection * ChatServer::getConnectionForCharacter(const NetworkId & characterId) +{ + ConnectionServerConnection * result = 0; + std::hash_map::iterator f = instance().clientMap.find(characterId); + if(f != instance().clientMap.end()) + { + result = (*f).second; + } + return result; +} + + +//----------------------------------------------------------------------- + +void splitChatAvatarId(const ChatAvatarId &id, Unicode::String &name, Unicode::String &address) +{ + name = Unicode::narrowToWide(id.name); + address = Unicode::narrowToWide("SOE+" + id.gameCode + "+" + id.cluster); +} + +//----------------------------------------------------------------------- + +void canonicalizeAvatarId(const ChatAvatarId &id) +{ + ChatAvatarId &hack = const_cast(id); + hack.gameCode = toUpper(hack.gameCode); + hack.name = toLower(hack.name); +} + +//----------------------------------------------------------------------- + +void ChatServer::addFriend(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & friendId) +{ + UNREF(sequence); + ChatServer::fileLog(false, "ChatServer", "addFriend() id(%s) sequence(%u) friendId(%s)", id.getValueString().c_str(), sequence, friendId.getFullName().c_str()); + + const ChatAvatar * from = getAvatarByNetworkId(id); + + if(from) + { + Unicode::String friendName; + Unicode::String friendAddress; + + canonicalizeAvatarId(friendId); + splitChatAvatarId(friendId, friendName, friendAddress); + + unsigned track = instance().chatInterface->RequestAddFriend(from, ChatUnicodeString(friendName.data(), friendName.length()), + ChatUnicodeString(friendAddress.data(), friendAddress.length()), + false, NULL); + instance().pendingRequests[track] = id; + } + else + { + ChatServer::fileLog(true, "ChatServer", "addFriend() ERROR: avatar not found(%s)", id.getValueString().c_str()); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::removeFriend(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & friendId) +{ + UNREF(sequence); + ChatServer::fileLog(false, "ChatServer", "removeFriend() id(%s) sequence(%u) friendId(%s)", id.getValueString().c_str(), sequence, friendId.getFullName().c_str()); + + const ChatAvatar * from = getAvatarByNetworkId(id); + + if(from) + { + Unicode::String friendName; + Unicode::String friendAddress; + + canonicalizeAvatarId(friendId); + splitChatAvatarId(friendId, friendName, friendAddress); + + unsigned track = instance().chatInterface->RequestRemoveFriend(from, ChatUnicodeString(friendName.data(), friendName.length()), + ChatUnicodeString(friendAddress.data(), friendAddress.length()), NULL); + instance().pendingRequests[track] = id; + } + else + { + ChatServer::fileLog(true, "ChatServer", "removeFriend() ERROR: avatar not found(%s)", id.getValueString().c_str()); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::getFriendsList(const ChatAvatarId &characterName) +{ + ChatServer::fileLog(false, "ChatServer", "getFriendsList() characterName(%s)", characterName.getFullName().c_str()); + + const NetworkId &id = getNetworkIdByAvatarId(characterName); + const ChatAvatar *avatar = getAvatarByNetworkId(id); + if (avatar) + { + unsigned track = instance().chatInterface->RequestFriendStatus(avatar, NULL); + instance().pendingRequests[track] = id; + } + else + { + ChatServer::fileLog(true, "ChatServer", "getFriendsList() ERROR: avatar not found(%s)", characterName.getFullName().c_str()); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::addIgnore(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & ignoreId) +{ + UNREF(sequence); + ChatServer::fileLog(false, "ChatServer", "addIgnore() id(%s) sequence(%u) ignoreId(%s)", id.getValueString().c_str(), sequence, ignoreId.getFullName().c_str()); + + const ChatAvatar * from = getAvatarByNetworkId(id); + + if(from) + { + Unicode::String ignoreName; + Unicode::String ignoreAddress; + + canonicalizeAvatarId(ignoreId); + splitChatAvatarId(ignoreId, ignoreName, ignoreAddress); + + unsigned track = instance().chatInterface->RequestAddIgnore(from, ChatUnicodeString(ignoreName.data(), ignoreName.length()), + ChatUnicodeString(ignoreAddress.data(), ignoreAddress.length()), + NULL); + instance().pendingRequests[track] = id; + } + else + { + ChatServer::fileLog(true, "ChatServer", "addIgnore() ERROR: avatar not found(%s)", id.getValueString().c_str()); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::removeIgnore(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & ignoreId) +{ + UNREF(sequence); + ChatServer::fileLog(false, "ChatServer", "removeIgnore() id(%s) sequence(%u) ignoreId(%s)", id.getValueString().c_str(), sequence, ignoreId.getFullName().c_str()); + + const ChatAvatar * from = getAvatarByNetworkId(id); + + if(from) + { + Unicode::String ignoreName; + Unicode::String ignoreAddress; + + canonicalizeAvatarId(ignoreId); + splitChatAvatarId(ignoreId, ignoreName, ignoreAddress); + + unsigned track = instance().chatInterface->RequestRemoveIgnore(from, ChatUnicodeString(ignoreName.data(), ignoreName.length()), + ChatUnicodeString(ignoreAddress.data(), ignoreAddress.length()), NULL); + instance().pendingRequests[track] = id; + } + else + { + ChatServer::fileLog(true, "ChatServer", "removeIgnore() ERROR: avatar not found(%s)", id.getValueString().c_str()); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::getIgnoreList(const ChatAvatarId &characterName) +{ + canonicalizeAvatarId(characterName); + ChatServer::fileLog(false, "ChatServer", "getIgnoreList() characterName(%s)", characterName.getFullName().c_str()); + + const NetworkId &id = getNetworkIdByAvatarId(characterName); + const ChatAvatar *avatar = getAvatarByNetworkId(id); + + if (avatar) + { + unsigned track = instance().chatInterface->RequestIgnoreStatus(avatar, NULL); + instance().pendingRequests[track] = id; + } + else + { + ChatServer::fileLog(true, "ChatServer", "getIgnoreList() ERROR: avatar not found(%s)", characterName.getFullName().c_str()); + } +} + + +//----------------------------------------------------------------------- + +void ChatServer::addModeratorToRoom(const unsigned int sequenceId, const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName) +{ + canonicalizeAvatarId(avatarId); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "addModeratorToRoom() sequenceId(%u) id(%s) avatarId(%s) roomName(%s)", sequenceId, id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str()); + + const ChatAvatar * from = getAvatarByNetworkId(id); + if(from) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + Unicode::String moderatorName; + Unicode::String moderatorAddress; + splitChatAvatarId(avatarId, moderatorName, moderatorAddress); + + // Remove the avatar from the ban list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequenceId, avatarId); + + instance().chatInterface->RequestRemoveBan(from, moderatorName, moderatorAddress, roomOwner->getAddress(), (void *)pair); + } + + // Try to make the avatar a moderator + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequenceId, avatarId); + + unsigned track = instance().chatInterface->RequestAddModerator(from, moderatorName, moderatorAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = id; + } + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId fromId; + makeAvatarId(*from, fromId); + + ChatOnAddModeratorToRoom msg(errorCode, sequenceId, fromId, avatarId, roomName); + instance().chatInterface->sendMessageToAvatar(fromId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::removeModeratorFromRoom(const unsigned int sequenceId, const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName) +{ + canonicalizeAvatarId(avatarId); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeModeratorFromRoom() sequenceId(%u) id(%s) avatarId(%s) roomName(%s)", sequenceId, id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str()); + + const ChatAvatar * from = getAvatarByNetworkId(id); + if(from) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + Unicode::String moderatorName; + Unicode::String moderatorAddress; + splitChatAvatarId(avatarId, moderatorName, moderatorAddress); + + // User data so that we remember who is being removed as a moderator + AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequenceId, avatarId); + + unsigned track = instance().chatInterface->RequestRemoveModerator(from, moderatorName, moderatorAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = id; + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId fromId; + makeAvatarId(*from, fromId); + + ChatOnRemoveModeratorFromRoom msg(errorCode, sequenceId, fromId, avatarId, roomName); + instance().chatInterface->sendMessageToAvatar(fromId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::chatConnectedAvatar(const NetworkId & id, const ChatAvatar & newAvatar) +{ + ChatServer::fileLog(false, "ChatServer", "chatConnectedAvatar() id(%s) newAvatar(%s)", id.getValueString().c_str(), getFullChatAvatarName(&newAvatar).c_str()); + + AvatarExtendedData aed; + aed.chatAvatar = newAvatar; + aed.isSubscribed = (s_notSubscribedClients.count(id) == 0); + aed.spatialCharCount = 0; + aed.nonSpatialCharCount = 0; + aed.chatSpamTimeEndInterval = 0; + aed.chatSpamNextTimeToSyncWithGameServer = 0; + aed.chatSpamNextTimeToNotifyPlayerWhenLimited = 0; + aed.unsquelchTime = 0; + + IGNORE_RETURN(instance().chatAvatars.insert(std::make_pair(id, aed))); +} + +//----------------------------------------------------------------------- + +void ChatServer::connectPlayer(ConnectionServerConnection * connection, const unsigned int suid, const std::string & characterName, const NetworkId & networkId, bool isSecure, bool isSubscribed) +{ + ChatServer::fileLog(false, "ChatServer", "connectPlayer() address(%s) suid(%u) characterName(%s) networkId(%s)", getConnectionAddress(connection).c_str(), suid, characterName.c_str(), networkId.getValueString().c_str()); + + std::hash_map::iterator cf = instance().clientMap.find(networkId); + if (cf != instance().clientMap.end()) + { + DEBUG_WARNING(true, ("We received a chat login attempt for a player (%s) that we think is already logged in. We're going to try to log out the old avatar then log in the new one.", characterName.c_str())); + //instance().disconnectPlayer(networkId); + instance().clientMap[networkId] = connection; + return; + } + + IGNORE_RETURN(instance().clientMap.insert(std::make_pair(networkId, connection))); + instance().chatInterface->ConnectPlayer(suid, toLower(characterName), networkId); + + uint32 voiceStatus = VoiceChatStatus::SC_VoiceStatusUnknown; + if(isSubscribed || isSecure) + { + getVChatInterface()->requestConnectPlayer(suid, characterName, networkId); + voiceStatus = VoiceChatStatus::SC_VoiceEnabled; + } + else + { + voiceStatus = VoiceChatStatus::SC_VoiceClientIsTrial; + } + + VoiceChatStatus msg(voiceStatus); + sendToClient(networkId, msg); + + s_chatServerMetricsData->setClientCount(instance().clientMap.size()); + if(isSecure) + { + s_godClients.insert(networkId); + } + if (!isSubscribed) + { + s_notSubscribedClients.insert(networkId); + } +} + +int countDots(const std::string &str) +{ + int num = 0; + for (unsigned i = 0; i < str.length(); ++i) + { + if (str[i] == '.') + { + ++num; + } + } + return num; +} + +//----------------------------------------------------------------------- + +void ChatServer::createRoom(const NetworkId & id, const unsigned int sequence, const std::string & roomName, const bool isModerated, const bool isPublic, const std::string & title) +{ + if(roomName.empty()) + return; + + if(roomName.find("..") != std::string::npos || + roomName.find(" ") != std::string::npos || + roomName[0] == '.') + { + return; + } + + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "createRoom() id(%s) sequence(%u) roomName(%s) isModerated(%s) isPublic(%s) title(%s)", id.getValueString().c_str(), sequence, roomName.c_str(), isModerated ? "yes" : "no", isPublic ? "yes" : "no", title.c_str()); + + RoomParams roomParams; + + std::string baseName = std::string("SWG.") + ConfigChatServer::getClusterName(); + if (roomName == baseName || roomName == toLower(baseName)) + { + return; + } + + if(toLower(roomName).find(toLower(baseName)) != 0) + return; + + int numDots = countDots(roomName); + if (numDots > 1) + { + size_t lastDot = roomName.rfind('.'); + if (lastDot != std::string::npos) + { + std::string parent = roomName.substr(0, lastDot); + const ChatServerRoomOwner *room = + instance().chatInterface->getRoomOwner(parent); + if (!room) + { + //REPORT_LOG(true, ("Creating parent room %s\n", parent.c_str())); + createRoom(id, 0, parent, isModerated, isPublic, ""); + } + + } + } + + //printf("Creating room %s\n", roomName.c_str()); + + unsigned roomAttr = 0; + + static Archive::ByteStream a; + const ChatAvatar * owner = 0; + bool isSystemOwner = false; + + //REPORT_LOG(true, ("createRoom(%s, %s)\n", id.getValueString().c_str(), roomName.c_str())); + if(id != NetworkId::cms_invalid) + { + owner = getAvatarByNetworkId(id); + } + else + { + isSystemOwner = true; + owner = instance().ownerSystem; + //REPORT_LOG(true, ("System is creating a room: %s\n", roomName.c_str())); + } + + if (!owner) + { + return; + } + + if (isModerated) + { + roomAttr |= ROOMATTR_MODERATED; + } + + if (!isPublic) + { + roomAttr |= ROOMATTR_PRIVATE; + } + if (isSystemOwner && (strstr(roomName.c_str(), "system") != NULL)) + { + roomAttr |= ROOMATTR_PERSISTENT; + } + + std::string tmpRoomName = roomName; + + Unicode::String wideRoomName; + Unicode::String wideRoomAddress; + splitRoomName(tmpRoomName, wideRoomName, wideRoomAddress); + + std::string narrowRoomName = Unicode::wideToNarrow(wideRoomName); + std::string narrowRoomAddress = Unicode::wideToNarrow(wideRoomAddress); + + Unicode::String wideTitle = Unicode::narrowToWide(title); + + roomParams.setRoomName(ChatUnicodeString(wideRoomName.data(), wideRoomName.size())); + roomParams.setRoomTopic(ChatUnicodeString(wideTitle.data(), wideTitle.size())); + roomParams.setRoomAttributes(roomAttr); + + + //instance().voiceChatInterface->GetChannel(narrowRoomAddress,narrowRoomName,"text","",0,false,0); + + + unsigned track = instance().chatInterface->RequestCreateRoom(owner, roomParams, ChatUnicodeString(wideRoomAddress.data(), wideRoomAddress.size()), (void *)sequence); //lint !e641 Converting enum 'ChatRoomType' to int + if(id != NetworkId::cms_invalid) + instance().pendingRequests[track] = id; +} + +//----------------------------------------------------------------------- +void ChatServer::deleteAllPersistentMessages(const NetworkId &sourceNetworkId, const NetworkId &targetNetworkId) +{ + ChatServer::fileLog(false, "ChatServer", "deleteAllPersistentMessages() sourceNetworkId(%s) targetNetworkId(%s)", sourceNetworkId.getValueString().c_str(), targetNetworkId.getValueString().c_str()); + + ChatAvatar const *avatar = getAvatarByNetworkId(targetNetworkId); + + if (avatar != NULL) + { + { + NetworkId *tmpNetworkId = new NetworkId(sourceNetworkId); + instance().chatInterface->RequestUpdatePersistentMessages(avatar, PERSISTENT_NEW, PERSISTENT_DELETED, reinterpret_cast(tmpNetworkId)); + } + + { + NetworkId *tmpNetworkId = new NetworkId(sourceNetworkId); + instance().chatInterface->RequestUpdatePersistentMessages(avatar, PERSISTENT_UNREAD, PERSISTENT_DELETED, reinterpret_cast(tmpNetworkId)); + } + + { + NetworkId *tmpNetworkId = new NetworkId(sourceNetworkId); + instance().chatInterface->RequestUpdatePersistentMessages(avatar, PERSISTENT_READ, PERSISTENT_DELETED, reinterpret_cast(tmpNetworkId)); + } + } + else + { + DEBUG_REPORT_LOG(true, ("ChatServer::deleteAllPersistentMessages() Unable to resolve target avatar.\n")); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::deletePersistentMessage(const NetworkId &id, const unsigned int messageId) +{ + ChatServer::fileLog(false, "ChatServer", "deletePersistentMessage() id(%s) messageId(%u)", id.getValueString().c_str(), messageId); + + const ChatAvatar *avatar = getAvatarByNetworkId(id); + if (avatar) + { + instance().chatInterface->RequestUpdatePersistentMessage(avatar, messageId, PERSISTENT_DELETED, NULL); + } +} + +//----------------------------------------------------------------------- + +ChatInterface *ChatServer::getChatInterface() +{ + return instance().chatInterface; +} + + +//----------------------------------------------------------------------- + +void ChatServer::destroyRoom(const NetworkId & id, const unsigned int sequence, const unsigned int roomId) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "destroyRoom() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId); + +/* const ChatAvatar * avatar = getAvatarByNetworkId(id); + if(avatar) + { + ChatAvatarId destroyer(avatar->GetGameCode(), avatar->GetGameServerName(), avatar->GetCharacterName()); + + // can this avatar destroy the room? + std::hash_map::const_iterator i; + for(i = instance().chatInterface->getRoomList().begin(); i != instance().chatInterface->getRoomList().end(); ++i) + { + if((*i).second.getRoomData().id == roomId) + { + bool removeRoom = false; + if((*i).second.getRoomData().owner == destroyer) + removeRoom = true; + else if((*i).second.getRoomData().creator == destroyer) + removeRoom = true; + + if(removeRoom) + { + std::string track = instance().chatInterface->DestroyRoom(sequence, roomId, avatar->GetCharacterName(), avatar->GetGameServerName(), avatar->GetGameCode()); + instance().pendingRequests[track] = id; + } + else + { + ChatOnDestroyRoom destroy(sequence, CHAT_RESULT_FAIL_INSUFFICIENT_PRIVILEGES, roomId, destroyer); //lint !e641 enum to int + sendToClient(id, destroy); + } + break; + } + } + }*/ + const ChatServerRoomOwner *owner = instance().chatInterface->getRoomOwner(roomId); + const ChatAvatar *avatar = getAvatarByNetworkId(id); + if (avatar && owner) + { + RoomOwnerSequencePair *pair = new RoomOwnerSequencePair(sequence, owner); + unsigned track = instance().chatInterface->RequestDestroyRoom(avatar, owner->getAddress(), (void *)pair); + instance().pendingRequests[track] = id; + } +} + +//----------------------------------------------------------------------- + +void ChatServer::destroyRoom(const std::string & roomName) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "destroyRoom() roomName(%s)", roomName.c_str()); + + if ((strstr(roomName.c_str(), ConfigChatServer::getClusterName()) != NULL) || + (strstr(roomName.c_str(), toLower(std::string(ConfigChatServer::getClusterName() ) ).c_str() ) )) + { + if ((strstr(roomName.c_str(), "GroupChat") != NULL) || (strstr(roomName.c_str(), "groupchat") != NULL)) + { + size_t pos = roomName.rfind("."); + if (pos != roomName.npos) + { + std::string tmpRoomName = roomName.substr(0, pos); + char lastChar = tmpRoomName[strlen(tmpRoomName.c_str()) - 1]; + if (lastChar >= '0' && lastChar <= '9') + { + ChatServer::destroyRoom(tmpRoomName); + return; + } + } + } + } + const ChatServerRoomOwner *owner = instance().chatInterface->getRoomOwner(roomName); + if (!instance().ownerSystem) + { + DEBUG_WARNING(true, ("Chat ownerSystem is NULL")); + return; + } + if (owner) + { + RoomOwnerSequencePair *pair = new RoomOwnerSequencePair(0, owner); + static Unicode::String wideAddr = Unicode::narrowToWide(std::string("SWG") + "+" + ConfigChatServer::getClusterName()); + static ChatUnicodeString chatAddr(wideAddr.data(), wideAddr.size()); + instance().chatInterface->RequestDestroyRoom(instance().ownerSystem, owner->getAddress(), (void *)pair); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::disconnectAvatar(const ChatAvatar & avatar) +{ + ChatServer::fileLog(false, "ChatServer", "disconnectAvatar() avatar(%s)", ChatServer::getFullChatAvatarName(&avatar).c_str()); + + if (&avatar == instance().ownerSystem) + { + instance().ownerSystem = NULL; + } + ChatAvatarList::iterator i; + for(i = instance().chatAvatars.begin(); i != instance().chatAvatars.end(); ++i) + { + if((*i).second.chatAvatar.getAvatarID() == avatar.getAvatarID()) + { + disconnectPlayer((*i).first); + break; + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::disconnectPlayer(const NetworkId & id) +{ + ChatServer::fileLog(false, "ChatServer", "disconnectPlayer() id(%s)", id.getValueString().c_str()); + + ChatAvatarList::iterator f = instance().chatAvatars.find(id); + if(f != instance().chatAvatars.end()) + { + ChatServerAvatarOwner *owner = instance().chatInterface->getAvatarOwner(&((*f).second.chatAvatar)); + + ChatAvatarId avatarId; + makeAvatarId((*f).second.chatAvatar, avatarId); + instance().chatInterface->disconnectPlayer(avatarId); + instance().chatInterface->RequestLogoutAvatar(&((*f).second.chatAvatar), (void *)owner); + instance().chatAvatars.erase(f); + } + + std::hash_map::iterator cf = instance().clientMap.find(id); + if(cf != instance().clientMap.end()) + { + instance().clientMap.erase(cf); + } + s_chatServerMetricsData->setClientCount(instance().clientMap.size()); + + VoiceChatAvatarList::iterator voiceMapItr = instance().m_voiceChatIdMap.find(id); + if(voiceMapItr != instance().m_voiceChatIdMap.end()) + { + std::map::iterator nameMapItr = instance().m_voiceChatNameToIdMap.find(toLower(voiceMapItr->second.playerName)); + if(nameMapItr != instance().m_voiceChatNameToIdMap.end()) + { + instance().m_voiceChatNameToIdMap.erase(nameMapItr); + } + + nameMapItr = instance().m_voiceLoginNameToIdMap.find(toLower(voiceMapItr->second.loginName)); + if(nameMapItr != instance().m_voiceLoginNameToIdMap.end()) + { + instance().m_voiceLoginNameToIdMap.erase(nameMapItr); + } + + instance().m_voiceChatIdMap.erase(voiceMapItr); + } + + s_godClients.erase(id); + s_notSubscribedClients.erase(id); +} + +//----------------------------------------------------------------------- + +void ChatServer::enterRoom(const NetworkId & id, const unsigned int sequence, const unsigned int roomId) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "enterRoom() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId); + + //REPORT_LOG(true, ("EnterRoom(%s, %u)\n", id.getValueString().c_str(), roomId)); + const ChatAvatar * avatar = getAvatarByNetworkId(id); + const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomId); + + if(avatar && room) + { + unsigned track = instance().chatInterface->RequestEnterRoom(avatar, room->getAddress(), (void *)sequence); + instance().pendingRequests[track] = id; + } + else + { + s_pendingEntersById.insert(std::make_pair(id, std::make_pair(sequence, roomId))); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::enterRoom(const ChatAvatarId & id, const std::string & roomName, bool forceCreate, bool createPrivate) +{ + canonicalizeAvatarId(id); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "enterRoom() id(%s) roomName(%s)", id.getFullName().c_str(), roomName.c_str()); + + const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomName); + const ChatAvatar *avatar = getAvatarByNetworkId(getNetworkIdByAvatarId(id)); + if (room && avatar) + { + instance().chatInterface->RequestEnterRoom(avatar, room->getAddress(), NULL); + } + else + { + if(! room) + { + if(forceCreate) + { + // create a room for the avatar and wait for the OnCreateRoom to return + createRoom(NetworkId::cms_invalid, 0, roomName, false, !createPrivate, ""); + s_pendingEntersByName.insert(std::make_pair(toLower(roomName), id)); // for game server generated requests + } + } + //REPORT_LOG(!room, ("room is not found\n")); + //REPORT_LOG(!avatar, ("avatar is not found\n")); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::putSystemAvatarInRoom(const std::string & roomName) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "putSystemAvatarInRoom() roomName(%s)", roomName.c_str()); + + const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomName); + if (room && instance().ownerSystem) + { + instance().chatInterface->RequestEnterRoom(instance().ownerSystem, room->getAddress(), NULL); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::enterRoom(const NetworkId & id, const unsigned int sequence, const std::string & roomName) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "enterRoom() id(%s) sequence(%u) roomName(%s)", id.getValueString().c_str(), sequence, roomName.c_str()); + + //REPORT_LOG(true, ("enterRoom3(%s, %s)\n", id.getValueString().c_str(), roomName.c_str())); + const ChatAvatar * avatar = getAvatarByNetworkId(id); + if(avatar) + { + unsigned errorCode = CHATRESULT_SUCCESS; + unsigned roomId = 0; + + const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + // We can now get a room ID + roomId = roomOwner->getRoomData().id; + + // prevent players from requesting to enter/leave system rooms + if((roomName.rfind(".") != std::string::npos)) + { + std::string leaf = roomName.substr(0, roomName.rfind(".")); + std::string lowerLeaf = toLower(leaf); + if(lowerLeaf != toLower(ChatRoomTypes::ROOM_SYSTEM)) + { + const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomName); + if (room) + { + unsigned track = instance().chatInterface->RequestEnterRoom(avatar, room->getAddress(), (void *)sequence); + instance().pendingRequests[track] = id; + + return; + } + } + } + + errorCode = CHATRESULT_ROOM_UNKNOWNFAILURE; + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId avatarId; + makeAvatarId(*avatar, avatarId); + + ChatOnEnteredRoom fail(sequence, errorCode, roomId, avatarId); //lint !e641 enum to int + sendToClient(id, fail); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::unbanFromRoom(const unsigned sequence, const NetworkId &banner, const ChatAvatarId &bannee, const std::string &roomName) +{ + canonicalizeAvatarId(bannee); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "unbanFromRoom() sequence(%u) banner(%s) bannee(%s) roomName(%s)", sequence, banner.getValueString().c_str(), bannee.getFullName().c_str(), roomName.c_str()); + + const ChatAvatar *bannerAvatar = getAvatarByNetworkId(banner); + if (bannerAvatar) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + Unicode::String banName; + Unicode::String banAddress; + splitChatAvatarId(bannee, banName, banAddress); + + AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequence, bannee); + + unsigned track = instance().chatInterface->RequestRemoveBan(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = banner; + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId bannerAvatarId; + makeAvatarId(*bannerAvatar, bannerAvatarId); + + ChatOnUnbanAvatarFromRoom msg(sequence, errorCode, roomName, bannerAvatarId, bannee); + instance().chatInterface->sendMessageToAvatar(bannerAvatarId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::banFromRoom(const unsigned sequence, const NetworkId &banner, const ChatAvatarId &bannee, const std::string &roomName) +{ + canonicalizeAvatarId(bannee); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "banFromRoom() sequence(%u) banner(%s) bannee(%s) roomName(%s)", sequence, banner.getValueString().c_str(), bannee.getFullName().c_str(), roomName.c_str()); + + // can't ban god accounts + NetworkId networkId = getNetworkIdByAvatarId(bannee); + if(isGod(networkId)) + { + return; + } + + const ChatAvatar *bannerAvatar = getAvatarByNetworkId(banner); + if (bannerAvatar) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + Unicode::String banName; + Unicode::String banAddress; + splitChatAvatarId(bannee, banName, banAddress); + + // Remove the bannee from the invited list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, bannee); + instance().chatInterface->RequestRemoveInvite(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair); + } + + // Remove the bannee from the moderator list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, bannee); + instance().chatInterface->RequestRemoveModerator(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair); + } + + // Ban the avatar + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequence, bannee); + + unsigned track = instance().chatInterface->RequestAddBan(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = banner; + } + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId bannerAvatarId; + makeAvatarId(*bannerAvatar, bannerAvatarId); + + ChatOnBanAvatarFromRoom msg(sequence, errorCode, roomName, bannerAvatarId, bannee); + instance().chatInterface->sendMessageToAvatar(bannerAvatarId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::invite(const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName) +{ + canonicalizeAvatarId(avatarId); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "invite() id(%s) avatar(%s) roomName(%s)", id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str()); + + // Try to get an invitor + ChatAvatar const * invitor = NULL; + if (id != NetworkId::cms_invalid) + { + invitor = getAvatarByNetworkId(id); + } + else + { + invitor = instance().ownerSystem; + } + + if (invitor) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + Unicode::String inviteName; + Unicode::String inviteAddress; + splitChatAvatarId(avatarId, inviteName, inviteAddress); + + // Remove the avatar from the banned list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId); + + instance().chatInterface->RequestRemoveBan(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair); + } + + // Invite the avatar + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId); + + unsigned track = instance().chatInterface->RequestAddInvite(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = id; + } + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId invitorId; + makeAvatarId(*invitor, invitorId); + + ChatOnInviteToRoom msg(errorCode, roomName, invitorId, avatarId); + instance().chatInterface->sendMessageToAvatar(invitorId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::inviteGroupMembers(const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName, const stdvector::fwd & members) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "inviteGroupMembers() id(%s) avatarId(%s) roomName(%s) number of members (%u)", id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str(), members.size()); + + // Try to get an invitor + ChatAvatar const * const invitor = getAvatarByNetworkId(id); + if (invitor) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + // Invite each member + for (unsigned i = 0; i < members.size(); ++i) + { + NetworkId const & memberNetworkId = members[i]; + ChatAvatar const * const memberAvatar = getAvatarByNetworkId(memberNetworkId); + if (memberAvatar) + { + ChatAvatarId memberId; + makeAvatarId(*memberAvatar, memberId); + + // Break up the member name + Unicode::String inviteName; + Unicode::String inviteAddress; + splitChatAvatarId(memberId, inviteName, inviteAddress); + + // Remove the avatar from the banned list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, memberId); + + instance().chatInterface->RequestRemoveBan(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair); + } + + // Invite the avatar + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, memberId); + + unsigned track = instance().chatInterface->RequestAddInvite(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = id; + } + } + } + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId invitorId; + makeAvatarId(*invitor, invitorId); + + ChatOnInviteGroupToRoom msg(errorCode, roomName, invitorId, avatarId); + instance().chatInterface->sendMessageToAvatar(invitorId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::removeSystemAvatarFromRoom(const ChatRoom *room) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeSystemAvatarFromRoom() room(%s)", (room != NULL) ? toNarrowString(room->getRoomName()).c_str() : "NULL"); + + if (!room || !instance().ownerSystem) + { + return; + } + + AvatarIterator i = room->getFirstAvatar(); + if (!i.outOfBounds()) + { + if ((*i) != instance().ownerSystem) + { + return; + } + } + + instance().chatInterface->RequestLeaveRoom(instance().ownerSystem, room->getAddress(), NULL); +} + +//----------------------------------------------------------------------- + +void ChatServer::leaveRoom(const NetworkId & id, const unsigned int sequence, const unsigned int roomId) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "leaveRoom() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId); + + const ChatAvatar * avatar = getAvatarByNetworkId(id); + if (avatar) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + // Try to get the room + ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomId); + if (roomOwner) + { + unsigned track = instance().chatInterface->RequestLeaveRoom(avatar, roomOwner->getAddress(), (void *)sequence); + instance().pendingRequests[track] = id; + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId avatarId; + makeAvatarId(*avatar, avatarId); + + ChatOnLeaveRoom msg(sequence, errorCode, roomId, avatarId); + instance().chatInterface->sendMessageToAvatar(avatarId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::removeAvatarFromRoom(const NetworkId & id, const ChatAvatarId & avatarName, const std::string & roomName) +{ + canonicalizeAvatarId(avatarName); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeAvatarFromRoom() id(%s) avatarName(%s) roomName(%s)", id.getValueString().c_str(), avatarName.getFullName().c_str(), roomName.c_str()); + + const ChatAvatar * avatar = getAvatarByNetworkId(id); + ChatAvatarId removerId; + makeAvatarId(*avatar, removerId); + size_t pos = roomName.rfind("."); + std::string leaf; + if(pos != std::string::npos) + { + leaf = toLower(roomName.substr(pos)); + } + //REPORT_LOG(true, ("removeAvatarFromRoom()\n")); + + if(avatar) + { + bool removeAvatar = false; + if(avatarName == removerId) + { + // avatar is attempting to remove self from the room + if(leaf != ".system") + removeAvatar = true; + } + else if(isGod(id)) + { + removeAvatar = true; + } + else + { + const ChatServerRoomOwner * r = instance().chatInterface->getRoomByName(roomName); + if(r) + { + // if the avatar is the room owner, remove the target + if( r->getRoomData().owner == removerId ) + { + removeAvatar = true; + } + // if the avatar is the room creator, remove the target + else if( r->getRoomData().creator == removerId ) + { + removeAvatar = true; + } + // if the avatar is a moderator, remove the target + else + { +/*MLSTODO if(r->getRoom()) + { + AvatarIterator i = r->getRoom()->getFirstModerator(); + for(; !i.outOfBounds(); ++i) + { + ChatAvatarId tmpAvatarId; + makeAvatarId(*(*i), tmpAvatarId); + if(tmpAvatarId == removerId) + { + removeAvatar = true; + break; + } + } + } + */ + } + } + } + if(removeAvatar) + { + const ChatServerRoomOwner * r = instance().chatInterface->getRoomByName(roomName); + const NetworkId &id = getNetworkIdByAvatarId(avatarName); + if (r) + { + leaveRoom(id, 0, r->getRoomData().id); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::removeAvatarFromRoom(const ChatAvatarId & avatarName, const std::string & roomName) +{ + canonicalizeAvatarId(avatarName); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeAvatarFromRoom() avatarName(%s) roomName(%s)", avatarName.getFullName().c_str(), roomName.c_str()); + + const ChatServerRoomOwner * r = instance().chatInterface->getRoomByName(roomName); + const NetworkId &id = getNetworkIdByAvatarId(avatarName); + if (r) + { + leaveRoom(id, 0, r->getRoomData().id); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::kickAvatarFromRoom(const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName) +{ + canonicalizeAvatarId(avatarId); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "kickAvatarFromRoom() moderator(%s) avatarName(%s) roomName(%s)", id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str()); + + unsigned errorCode = CHATRESULT_SUCCESS; + + ChatAvatar const * const moderatorChatAvatar = getAvatarByNetworkId(id); + if (moderatorChatAvatar) + { + ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomByName(roomName); + if (roomOwner) + { + Unicode::String kickName; + Unicode::String kickAddress; + splitChatAvatarId(avatarId, kickName, kickAddress); + + // Remove the avatar from the invited list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId); + instance().chatInterface->RequestRemoveInvite(moderatorChatAvatar, kickName, kickAddress, roomOwner->getAddress(), (void *)pair); + } + + // Remove the avatar from the moderator list + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId); + instance().chatInterface->RequestRemoveModerator(moderatorChatAvatar, kickName, kickAddress, roomOwner->getAddress(), (void *)pair); + } + + // Kick the avatar from the room + { + AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId); + + unsigned track = instance().chatInterface->RequestKickAvatar(moderatorChatAvatar, kickName, kickAddress, roomOwner->getAddress(), (void*)pair); + instance().pendingRequests[track] = id; + } + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId moderatorAvatarId; + makeAvatarId(*moderatorChatAvatar, moderatorAvatarId); + + ChatOnKickAvatarFromRoom msg(errorCode, moderatorAvatarId, avatarId, roomName); + instance().chatInterface->sendMessageToAvatar(moderatorAvatarId, msg); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::queryRoom(const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequence, const std::string & roomName) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "queryRoom() id(%s) roomName(%s)", id.getValueString().c_str(), roomName.c_str()); + + instance().chatInterface->queryRoom(id, connection, sequence, roomName); +} + +//----------------------------------------------------------------------- + +void ChatServer::requestPersistentMessage(const NetworkId &id, const unsigned int sequence, const unsigned int messageId) +{ + ChatServer::fileLog(false, "ChatServer", "requestPersistentMessage() id(%s) sequence(%u) messageId(%u)", id.getValueString().c_str(), sequence, messageId); + + const ChatAvatar * avatar = getAvatarByNetworkId(id); + + if (avatar) + { + IGNORE_RETURN(instance().chatInterface->RequestGetPersistentMessage(avatar, messageId, (void *)sequence)); + } + else + { + LOG("ChatServer", ("requestPersistentMessage() id(%s) Unable to resolve network id to ChatAvatar, request failed", id.getValueString().c_str())); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::requestRoomList(const NetworkId & id, ConnectionServerConnection * connection) +{ + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "requestRoomList() id(%s) connection(%s)", id.getValueString().c_str(), getConnectionAddress(connection).c_str()); + + instance().chatInterface->requestRoomList(id, connection); +} + +//----------------------------------------------------------------------- + +//This is for system messages only +void ChatServer::sendInstantMessage(const ChatAvatarId & from, const ChatAvatarId & to, const Unicode::String & message, const Unicode::String & outOfBand) +{ + canonicalizeAvatarId(from); + canonicalizeAvatarId(to); + ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() from(%s) to(%s)", from.getFullName().c_str(), to.getFullName().c_str()); + + const NetworkId &toNetworkId = getNetworkIdByAvatarId(to); + const ChatAvatar * toAvatar = getAvatarByNetworkId(toNetworkId); + + if (toAvatar != NULL) + { + ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() resolved tell locally"); + + ChatAvatarId toId; + makeAvatarId(*toAvatar, toId); + ChatSystemMessage chat(ChatSystemMessage::PERSONAL, message, outOfBand); //lint !e641 enum to int + instance().chatInterface->sendMessageToAvatar(toId, chat); + } + else + { + ChatSystemMessage chat(ChatSystemMessage::PERSONAL, message, outOfBand); //lint !e641 enum to int + + bool success = instance().chatInterface->sendMessageToPendingAvatar(to, chat); + + if (!success) + { + //I don't know who this is, send it to the chat api + const NetworkId &fromNetworkId = getNetworkIdByAvatarId(from); + const ChatAvatar * fromAvatar = getAvatarByNetworkId(fromNetworkId); + if (fromAvatar) + { + ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() sending tell through chat API"); + + Unicode::String friendName; + Unicode::String friendAddress; + + splitChatAvatarId(to, friendName, friendAddress); + IGNORE_RETURN(instance().chatInterface->RequestSendInstantMessage(fromAvatar, + ChatUnicodeString(friendName.data(), friendName.size()), + ChatUnicodeString(friendAddress.data(), friendAddress.size()), + ChatUnicodeString(message.data(), message.size()), ChatUnicodeString(outOfBand.data(), outOfBand.size()), NULL)); + } + } + } + + Unicode::String const wideTo(Unicode::narrowToWide(to.getFullName())); + Unicode::String const wideFrom(Unicode::narrowToWide(from.getFullName())); + + if(from != getSystemAvatarId()) + { + ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, message, s_channelTell); + ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, message, s_channelTell); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::sendInstantMessage(const NetworkId & fromId, const unsigned int sequence, const ChatAvatarId & n, const Unicode::String & message, const Unicode::String & oob) +{ + canonicalizeAvatarId(n); + ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() fromId(%s) sequence(%u) toName(%s)", fromId.getValueString().c_str(), sequence, n.getFullName().c_str()); + + ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(fromId); + if (aed) + { + // see if player is squelched + if (aed->unsquelchTime != 0) + { + if (aed->unsquelchTime < 0) // squelched indefinitely + { + return; + } + else if (::time(NULL) < aed->unsquelchTime) // still in squelch period + { + return; + } + else // squelch has expired + { + aed->unsquelchTime = 0; + } + } + + unsigned int const maxTellLength = 512; + + if(message.length() < maxTellLength) + { + const ChatAvatar * from = &(aed->chatAvatar); + const NetworkId &toNetworkId = getNetworkIdByAvatarId(n); + const ChatAvatar * toAvatar = getAvatarByNetworkId(toNetworkId); + ChatAvatarId fromAvatarId; + + Unicode::String wideFrom; + Unicode::String wideTo; + + if (from != NULL) + { + makeAvatarId(*from, fromAvatarId); + wideFrom = (Unicode::narrowToWide(fromAvatarId.getFullName())); + } + + ChatAvatarId toAvatarId; + if (toAvatar != NULL) + { + ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() resolved tell locally"); + + makeAvatarId(*toAvatar, toAvatarId); + wideTo = Unicode::narrowToWide(toAvatarId.getFullName()); + + if (from) + { + ChatInstantMessageToClient chat(fromAvatarId, message, oob); + instance().chatInterface->sendMessageToAvatar(toAvatarId, chat); + + ChatOnSendInstantMessage chat2(sequence, 0); + IGNORE_RETURN(instance().chatInterface->sendMessageToAvatar(fromAvatarId, chat2)); + } + + if(fromAvatarId != getSystemAvatarId()) + { + ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, message, s_channelTell); + } + } + else + { + ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() sending tell through chat API"); + + wideTo = Unicode::narrowToWide(n.getFullName()); + Unicode::String friendName; + Unicode::String friendAddress; + + splitChatAvatarId(n, friendName, friendAddress); + + unsigned track = instance().chatInterface->RequestSendInstantMessage(from, + ChatUnicodeString(friendName.data(), friendName.size()), + ChatUnicodeString(friendAddress.data(), friendAddress.size()), + ChatUnicodeString(message.data(), message.size()), ChatUnicodeString(oob.data(), oob.size()), (void *)sequence); + + instance().pendingRequests[track] = fromId; + } + + if(fromAvatarId != getSystemAvatarId()) + { + ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, message, s_channelTell); + } + } + else + { + ChatServer::fileLog(true, "ChatServer", "sendInstantMessage() ERROR: Unable to send tell longer than %u", maxTellLength); + + //ChatOnSendInstantMessage chat(sequence, CHAT_RESULT_FAIL_INSUFFICIENT_PRIVILEGES); //lint !e641 enum to int + //sendToClient(fromId, chat); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::sendPersistentMessage(const ChatAvatarId & from, const ChatAvatarId & to, const Unicode::String & subject, const Unicode::String & message, const Unicode::String & oob) +{ + canonicalizeAvatarId(from); + canonicalizeAvatarId(to); + + ChatServer::fileLog(false, "ChatServer", "sendPersistentMessage() from(%s) to(%s) subject(%s)", from.getFullName().c_str(), to.getFullName().c_str(), Unicode::wideToNarrow(subject).c_str()); + + Unicode::String wideFromName(Unicode::narrowToWide(from.name)); + Unicode::String friendName; + Unicode::String friendAddress; + + splitChatAvatarId(to, friendName, friendAddress); + instance().chatInterface->RequestSendPersistentMessage( + ChatUnicodeString(wideFromName.data(), wideFromName.size()), + ChatUnicodeString(friendName.data(), friendName.size()), + ChatUnicodeString(friendAddress.data(), friendAddress.size()), + ChatUnicodeString(subject.data(), subject.size()), + ChatUnicodeString(message.data(), message.size()), + ChatUnicodeString(oob.data(), oob.size()), + NULL + ); + + Unicode::String log; + log.append(Unicode::narrowToWide("[subject] ")); + log.append(subject); + log.append(Unicode::narrowToWide(" ")); + log.append(Unicode::narrowToWide("[message] ")); + log.append(message); + + Unicode::String const wideTo(Unicode::narrowToWide(to.getFullName())); + Unicode::String const wideFrom(Unicode::narrowToWide(from.getFullName())); + + ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, log, ChatServer::getChannelEmail()); + ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, log, ChatServer::getChannelEmail()); +} + +//----------------------------------------------------------------------- + +void ChatServer::sendPersistentMessage(const NetworkId & fromId, const unsigned int sequenceId, const ChatAvatarId & to, const Unicode::String & subject, const Unicode::String & message, const Unicode::String & oob) +{ + canonicalizeAvatarId(to); + + ChatServer::fileLog(false, "ChatServer", "sendPersistentMessage() fromId(%s) sequence(%u) to(%s) subject(%s)", fromId.getValueString().c_str(), sequenceId, to.getFullName().c_str(), Unicode::wideToNarrow(subject).c_str()); + +// printf("Sending a message to %s.%s.%s\n", to.gameCode.c_str(), +// to.cluster.c_str(), to.name.c_str()); + UNREF(sequenceId); + ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(fromId); + const ChatAvatar * from = (aed ? &(aed->chatAvatar) : NULL); + if(from) + { + // see if player is squelched + if (aed->unsquelchTime != 0) + { + if (aed->unsquelchTime < 0) // squelched indefinitely + { + return; + } + else if (::time(NULL) < aed->unsquelchTime) // still in squelch period + { + return; + } + else // squelch has expired + { + aed->unsquelchTime = 0; + } + } + + Unicode::String friendName; + Unicode::String friendAddress; + + splitChatAvatarId(to, friendName, friendAddress); + unsigned track = instance().chatInterface->RequestSendPersistentMessage( + from, + ChatUnicodeString(friendName.data(), friendName.size()), + ChatUnicodeString(friendAddress.data(), friendAddress.size()), + ChatUnicodeString(subject.data(), subject.size()), + ChatUnicodeString(message.data(), message.size()), + ChatUnicodeString(oob.data(), oob.size()), + (void *)sequenceId + ); + instance().pendingRequests[track] = fromId; + } + + ChatAvatarId fromAvatarId; + + if (from != NULL) + { + makeAvatarId(*from, fromAvatarId); + } + + Unicode::String log; + log.append(Unicode::narrowToWide("[subject] ")); + log.append(subject); + log.append(Unicode::narrowToWide(" ")); + log.append(Unicode::narrowToWide("[message] ")); + log.append(message); + + Unicode::String const wideTo(Unicode::narrowToWide(to.getFullName())); + Unicode::String const wideFrom(Unicode::narrowToWide(fromAvatarId.getFullName())); + + ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, log, ChatServer::getChannelEmail()); + ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, log, ChatServer::getChannelEmail()); +} + +//----------------------------------------------------------------------- +//for system avatars +void ChatServer::sendRoomMessage(const ChatAvatarId &id, const std::string & roomName, const Unicode::String & msg, const Unicode::String & oob) +{ + if(! msg.empty() || !oob.empty()) + { + UNREF(id); + ChatServer::fileLog(false, "ChatServer", "sendRoomMessage() id(%s) roomName(%s)", id.getFullName().c_str(), roomName.c_str()); + + if (!instance().ownerSystem) + { + DEBUG_WARNING(true, ("Chat ownerSystem is NULL")); + return; + } + // get room id + std::string lowerName = toLower(roomName); + std::hash_map::const_iterator f = instance().chatInterface->getRoomList().find(lowerName); + if(f != instance().chatInterface->getRoomList().end()) + { + const ChatAvatar *sender = instance().ownerSystem; + + IGNORE_RETURN(instance().chatInterface->RequestSendRoomMessage(sender, (*f).second.getAddress(), ChatUnicodeString(msg.data(), msg.size()), ChatUnicodeString(oob.data(), oob.size()), NULL)); + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::sendRoomMessage(const NetworkId & id, const unsigned int sequence, const unsigned int roomId, const Unicode::String &msg, const Unicode::String & oob) +{ + if(!msg.empty() || !oob.empty()) + { + ChatServer::fileLog(false, "ChatServer", "sendRoomMessage() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId); + + UNREF(sequence); + ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(id); + const ChatAvatar * sender = (aed ? &(aed->chatAvatar) : NULL); + const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomId); + if(sender && room) + { + if(msg.length() < 512) + { + // track amount of room chat for the character, except for group chat + time_t timeNow = 0; + bool allowToSpeak = true; + bool squelched = false; + if (!room->isGroupChatRoom()) + { + // update chat character count + aed->nonSpatialCharCount += msg.size(); + + // sync chat character count with game server + timeNow = ::time(NULL); + if ((timeNow > aed->chatSpamNextTimeToSyncWithGameServer) || (timeNow > aed->chatSpamTimeEndInterval)) + { + GenericValueTypeMessage, std::pair > > chatStatistics("ChatStatisticsCS", std::make_pair(std::make_pair(id, static_cast(aed->chatSpamTimeEndInterval)), std::make_pair(aed->spatialCharCount, aed->nonSpatialCharCount))); + sendToClient(id, chatStatistics); + aed->chatSpamNextTimeToSyncWithGameServer = timeNow + ConfigChatServer::getChatStatisticsReportIntervalSeconds(); + } + + // see if player has exceeded chat limit + if (ConfigChatServer::getChatSpamLimiterEnabledForFreeTrial() && + !aed->isSubscribed && + (aed->chatSpamTimeEndInterval > timeNow) && + ((aed->spatialCharCount + aed->nonSpatialCharCount) > ConfigChatServer::getChatSpamLimiterNumCharacters())) + { + allowToSpeak = false; + } + } + + // see if player is squelched + if (allowToSpeak && (aed->unsquelchTime != 0)) + { + if (aed->unsquelchTime < 0) // squelched indefinitely + { + allowToSpeak = false; + squelched = true; + } + else if (::time(NULL) < aed->unsquelchTime) // still in squelch period + { + allowToSpeak = false; + squelched = true; + } + else // squelch has expired + { + aed->unsquelchTime = 0; + } + } + + if (allowToSpeak) + { + // character allowed to talk + unsigned track = instance().chatInterface->RequestSendRoomMessage(sender, room->getAddress(), ChatUnicodeString(msg.data(), msg.size()), ChatUnicodeString(oob.data(), oob.size()), (void *)sequence); + instance().pendingRequests[track] = id; + } + else if (!squelched && (ConfigChatServer::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() > 0) && (timeNow >= aed->chatSpamNextTimeToNotifyPlayerWhenLimited)) + { + // send message telling character he can no longer talk + GenericValueTypeMessage csl("ChatSpamLimited", static_cast(aed->chatSpamTimeEndInterval - timeNow)); + sendToClient(id, csl); + + aed->chatSpamNextTimeToNotifyPlayerWhenLimited = timeNow + ConfigChatServer::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds(); + } + } + else + { + //ChatOnSendRoomMessage chat(sequence, CHAT_RESULT_FAIL_INSUFFICIENT_PRIVILEGES); //lint !e641 enum to int + //sendToClient(id, chat); + } + } + } +} + +//----------------------------------------------------------------------- + +void ChatServer::sendStandardRoomMessage(const ChatAvatarId &senderId, const std::string & roomName, const Unicode::String & msg, const Unicode::String & oob) +{ + if(!msg.empty() || !oob.empty()) + { + canonicalizeAvatarId(senderId); + ChatServer::fileLog(false, "ChatServer", "sendStandardRoomMessage() senderId(%s) roomName(%s)", senderId.getFullName().c_str(), roomName.c_str()); + + std::string systemRoom = toLower(std::string("SWG.") + ConfigChatServer::getClusterName() + std::string(".system")); + + // get room id + std::string lowerName = toLower(roomName); + if (lowerName == systemRoom) + { + ChatSystemMessage chat(ChatSystemMessage::BROADCAST, msg, + oob); //lint !e641 enum to int + instance().chatInterface->sendMessageToAllAvatars(chat); + return; + } + + std::hash_map::const_iterator f = instance().chatInterface->getRoomList().find(lowerName); + if(f != instance().chatInterface->getRoomList().end()) + { + const ChatAvatar *sender; + + if (senderId.name == "SYSTEM" || senderId.name == "system") + { + sender = instance().ownerSystem; + } + else + { + sender = getAvatarByNetworkId(getNetworkIdByAvatarId(senderId)); + } + if (sender) + { + IGNORE_RETURN(instance().chatInterface->RequestSendRoomMessage(sender, (*f).second.getAddress(), ChatUnicodeString(msg.data(), msg.size()), ChatUnicodeString(oob.data(), oob.size()), NULL)); + } + } + } +} + + +//----------------------------------------------------------------------- + +void ChatServer::uninvite(const NetworkId &id , const unsigned int sequence, const ChatAvatarId &avatarId , const std::string &roomName ) +{ + canonicalizeAvatarId(avatarId); + ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "uninvite() id(%s) sequence(%u) avatarId(%s) roomName(%s)", id.getValueString().c_str(), sequence, avatarId.getFullName().c_str(), roomName.c_str()); + + // Try to get the invitor + ChatAvatar const * invitor = getAvatarByNetworkId(id); + if (invitor) + { + unsigned errorCode = CHATRESULT_SUCCESS; + + // Try to get the room + ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomName); + if (roomOwner) + { + Unicode::String inviteName; + Unicode::String inviteAddress; + splitChatAvatarId(avatarId, inviteName, inviteAddress); + + AvatarIdSequencePair * pair = new AvatarIdSequencePair(sequence, avatarId); + + unsigned track = instance().chatInterface->RequestRemoveInvite(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair); + instance().pendingRequests[track] = id; + } + else + { + errorCode = CHATRESULT_ADDRESSNOTROOM; + } + + if (errorCode != CHATRESULT_SUCCESS) + { + ChatAvatarId invitorId; + makeAvatarId(*invitor, invitorId); + + ChatOnUninviteFromRoom msg(sequence, errorCode, roomName, invitorId, avatarId); + instance().chatInterface->sendMessageToAvatar(invitorId, msg); + } + } +} + + +//----------------------------------------------------------------------- + +void ChatServer::removeConnectionServerConnection(ConnectionServerConnection * target) +{ + ChatServer::fileLog(false, "ChatServer", "removeConnectionServerConnection() target(%s)", getConnectionAddress(target).c_str()); + + std::hash_map tmpList = instance().clientMap; + std::hash_map::const_iterator i; + for(i = tmpList.begin(); i != tmpList.end(); ++i) + { + if((*i).second == target) + disconnectPlayer((*i).first); + std::hash_map::iterator f = instance().clientMap.find((*i).first); + if (f != instance().clientMap.end()) + { + instance().clientMap.erase(f); + } + } + + std::set::iterator ci = instance().connectionServerConnections.find(target); + if (ci != instance().connectionServerConnections.end()) + { + instance().connectionServerConnections.erase(ci); + } + s_chatServerMetricsData->setConnectionServerConnectionCount(instance().connectionServerConnections.size()); +} + +//----------------------------------------------------------------------- + +void ChatServer::sendToAllConnectionServers(const GameNetworkMessage &message) +{ + ChatServer::fileLog(false, "ChatServer", "sendToAllConnectionServers() message(%s)", message.getCmdName().c_str()); + + std::set::const_iterator i; + for(i = instance().connectionServerConnections.begin(); i != instance().connectionServerConnections.end(); ++i) + { + ConnectionServerConnection * c = (*i); + c->sendToClient(NetworkId::cms_invalid, message); + } +} + +// ---------------------------------------------------------------------- + +void ChatServer::broadcastToGameServers(const GameNetworkMessage &message) +{ + ChatServer::fileLog(false, "ChatServer", "broadcastToGameServers() message(%s)", message.getCmdName().c_str()); + + if (instance().gameService) + { + static Archive::ByteStream bs; + bs.clear(); + message.pack(bs); + instance().gameService->broadcast(bs, true); + } +} + +// ---------------------------------------------------------------------- + +std::string ChatServer::getFullChatAvatarName(ChatAvatar const *chatAvatar) +{ + std::string result; + + if (chatAvatar != NULL) + { + result += toNarrowString(chatAvatar->getName()); + result += '.'; + result += toNarrowString(chatAvatar->getAddress()); + } + else + { + result = "NULL"; + } + + return result; +} + +// ---------------------------------------------------------------------- + +std::string ChatServer::toNarrowString(ChatUnicodeString const &chatUnicodeString) +{ + std::string result; + + for (unsigned int index = 0; index < chatUnicodeString.string_length; ++index) + { + result += static_cast(chatUnicodeString.string_data[index]); + } + + return result; +} + +// ---------------------------------------------------------------------- + +std::string ChatServer::getConnectionAddress(Connection const *connection) +{ + std::string result; + + if (connection != NULL) + { + char text[256]; + snprintf(text, sizeof(text), "%s:%d", connection->getRemoteAddress().c_str(), connection->getRemotePort()); + result = text; + } + else + { + result = "NULL"; + } + + return result; +} + +// ---------------------------------------------------------------------- + +std::string ChatServer::getChatRoomNameNarrow(ChatRoom const *chatRoom) +{ + return Unicode::wideToNarrow(getChatRoomName(chatRoom)); +} + +// ---------------------------------------------------------------------- + +Unicode::String ChatServer::getChatRoomName(ChatRoom const *chatRoom) +{ + Unicode::String result; + + if (chatRoom != NULL) + { + result = toUnicodeString(chatRoom->getRoomName()); + } + else + { + result = Unicode::narrowToWide("NULL"); + } + + return result; +} + +// ---------------------------------------------------------------------- + +void ChatServer::clearCustomerServiceServerConnection() +{ + if (instance().customerServiceServerConnection != NULL) + { + instance().customerServiceServerConnection->disconnect(); + } + + instance().customerServiceServerConnection = NULL; +} + +// ---------------------------------------------------------------------- + +void ChatServer::connectToCustomerServiceServer(const std::string &address, const unsigned short port) +{ + //DEBUG_REPORT_LOG(true, ("***ChatServer::connectToCustomerServiceServer() address(%s) port(%d)\n", address.c_str(), port)); + + if (instance().customerServiceServerConnection != NULL) + { + instance().customerServiceServerConnection->disconnect(); + } + + instance().customerServiceServerConnection = new CustomerServiceServerConnection(address, port); +} + +// ---------------------------------------------------------------------- + +bool ChatServer::isValidChatAvatarName(Unicode::String const &chatAvatarName) +{ + // This function is retarded. We need to get an API call to determine if a chat avatar name is valid + + std::string lowerNarrowName(Unicode::toLower(Unicode::wideToNarrow(chatAvatarName))); + + //DEBUG_REPORT_LOG(true, ("ChatServer::isValidChatAvatarName() chatAvatarName(%s)\n", lowerNarrowName.c_str())); + + bool result = false; + ChatAvatarList::const_iterator iterChatAvatars = instance().chatAvatars.begin(); + + for (; iterChatAvatars != instance().chatAvatars.end(); ++iterChatAvatars) + { + ChatAvatar const *chatAvatar = &(iterChatAvatars->second.chatAvatar); + + if (toNarrowString(chatAvatar->getName()) == lowerNarrowName) + { + result = true; + break; + } + } + + if (result == false) + { + // How many dots are in this name + + int dotCount = 0; + + for (unsigned int i = 0; i < lowerNarrowName.length(); ++i) + { + if (lowerNarrowName[i] == '.') + { + ++dotCount; + } + } + + // Tack on extra code info for the name match + + Unicode::String const wideDot(Unicode::narrowToWide(".")); + Unicode::String searchAvatarName; + + if (dotCount == 0) + { + searchAvatarName = Unicode::narrowToWide(instance().systemAvatarId.gameCode) + wideDot + Unicode::narrowToWide(instance().systemAvatarId.cluster) + wideDot + chatAvatarName; + } + else if (dotCount == 1) + { + searchAvatarName = Unicode::narrowToWide(instance().systemAvatarId.gameCode) + wideDot + chatAvatarName; + } + else + { + searchAvatarName = chatAvatarName; + } + + result = ChatLogManager::isPlayerInLogs(searchAvatarName); + } + + return result; +} + +// ---------------------------------------------------------------------- + +void ChatServer::logChatMessage(Unicode::String const &logPlayer, Unicode::String const &fromPlayer, Unicode::String const &toPlayer, Unicode::String const &text, Unicode::String const &channel) +{ + DEBUG_WARNING(toPlayer.empty(), ("toPlayer is NULL")); + + Unicode::String lowerLogPlayer(Unicode::toLower(logPlayer)); + Unicode::String lowerFromPlayer(Unicode::toLower(fromPlayer)); + Unicode::String lowerToPlayer(Unicode::toLower(toPlayer)); + + ChatServer::fileLog(false, "ChatServer", "logChatMessage() logPlayer(%s) fromPlayer(%s) toPlayer(%s) channel(%s) text(%s)", Unicode::wideToNarrow(lowerLogPlayer).c_str(), Unicode::wideToNarrow(lowerFromPlayer).c_str(), Unicode::wideToNarrow(lowerToPlayer).c_str(), Unicode::wideToNarrow(channel).c_str(), Unicode::wideToNarrow(text).c_str()); + + int const messageIndex = ChatLogManager::getNextMessageIndex(); + time_t const time = Os::getRealSystemTime(); + + ChatLogManager::logChat(lowerFromPlayer, lowerToPlayer, text, channel, messageIndex, time); + + PlayerMessageList::iterator iterPlayerMessageList = s_playerMessageList.find(lowerLogPlayer); + + if (iterPlayerMessageList != s_playerMessageList.end()) + { + // The player already has some messages logged, append the message + + iterPlayerMessageList->second.push_back(std::make_pair(messageIndex, time)); + + ChatServer::fileLog(false, "ChatServer", "logChatMessage() player(%s) messageIndex(%d) time(%u) messageCount(%u)", Unicode::wideToNarrow(lowerLogPlayer).c_str(), messageIndex, time, iterPlayerMessageList->second.size()); + } + else + { + // The player does not have any message logged, add the first one + + MessageList messageList; + messageList.push_back(std::make_pair(messageIndex, time)); + + s_playerMessageList.insert(std::make_pair(lowerLogPlayer, messageList)); + + ChatServer::fileLog(false, "ChatServer", "logChatMessage() player(%s) messageIndex(%d) time(%u) first message entered", Unicode::wideToNarrow(lowerLogPlayer).c_str(), messageIndex, time); + } +} + +// ---------------------------------------------------------------------- + +Unicode::String ChatServer::toUnicodeString(ChatUnicodeString const &chatUnicodeString) +{ + return Unicode::String(chatUnicodeString.string_data, chatUnicodeString.string_length); +} + +// ---------------------------------------------------------------------- + +Unicode::String const &ChatServer::getChannelTell() +{ + return s_channelTell; +} + +// ---------------------------------------------------------------------- + +Unicode::String const &ChatServer::getChannelEmail() +{ + return s_channelEmail; +} + +// ---------------------------------------------------------------------- + +void ChatServer::fileLog(bool const forceLog, char const * const label, char const * const format, ...) +{ + if ( forceLog + || s_loggingEnabled) + { + char text[8192]; + + va_list va; + va_start(va, format); + _vsnprintf(text, sizeof(text), format, va); + text[sizeof(text) - 1] = '\0'; + va_end(va); + + LOG(label, (text)); + } +} + +// ---------------------------------------------------------------------- + +void ChatServer::requestTransferAvatar(const TransferCharacterData & request) +{ + if(instance().chatInterface) + { + ChatAvatarId sourceAvatar("SWG", request.getSourceGalaxy(), request.getSourceCharacterName()); + + std::string destination = request.getDestinationGalaxy(); + if(destination.empty()) + destination = request.getSourceGalaxy(); + + ChatAvatarId destinationAvatar("SWG", destination, request.getDestinationCharacterName()); + + instance().chatInterface->RequestTransferAvatar(request.getSourceStationId(), makeChatUnicodeString(sourceAvatar.getName()), makeChatUnicodeString(sourceAvatar.getAPIAddress()), request.getDestinationStationId(), makeChatUnicodeString(destinationAvatar.getName()), makeChatUnicodeString(destinationAvatar.getAPIAddress()), true, NULL); + } +} + +// ---------------------------------------------------------------------- + +void ChatServer::onCreateRoomSuccess(const std::string & lowerName, const unsigned int roomId) +{ + std::set >::iterator nameIter; + for(nameIter = s_pendingEntersByName.begin(); nameIter != s_pendingEntersByName.end();) + { + if(nameIter->first == lowerName) + { + enterRoom(nameIter->second, nameIter->first, false, false); + s_pendingEntersByName.erase(nameIter++); + } + else + { + ++nameIter; + } + } + + std::set > >::iterator idIter; + for(idIter = s_pendingEntersById.begin(); idIter != s_pendingEntersById.end();) + { + if(idIter->second.second == roomId) + { + enterRoom(idIter->first, idIter->second.first, idIter->second.second); + s_pendingEntersById.erase(idIter++); + } + else + { + ++idIter; + } + } +} + +// ---------------------------------------------------------------------- + +bool ChatServer::isGod(const NetworkId & networkId) +{ + bool result = false; + if(s_godClients.find(networkId) != s_godClients.end()) + { + result = true; + } + return result; +} + +// ---------------------------------------------------------------------- + +void ChatServer::setUnsquelchTime(NetworkId const & character, time_t unsquelchTime) +{ + ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(character); + if (aed) + { + aed->unsquelchTime = unsquelchTime; + } +} + +// ---------------------------------------------------------------------- + +void ChatServer::handleChatStatisticsFromGameServer(NetworkId const & character, time_t unsquelchTime, time_t chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters) +{ + // update character chat data with chat data from game server + ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(character); + if (aed) + { + // squelch state is tracked by the game server + aed->unsquelchTime = unsquelchTime; + + // spatial chat is tracked by the game server + aed->spatialCharCount = spatialNumCharacters; + + // we are out of sync with the game server, so use + // all information passed from game server + if (aed->chatSpamTimeEndInterval != chatSpamTimeEndInterval) + { + aed->nonSpatialCharCount = nonSpatialNumCharacters; + aed->chatSpamTimeEndInterval = chatSpamTimeEndInterval; + } + // we are in sync with the game server, and we have additional + // non-spatial chat to report to the game server + else if (aed->nonSpatialCharCount != nonSpatialNumCharacters) + { + time_t const timeNow = ::time(NULL); + if (timeNow > aed->chatSpamNextTimeToSyncWithGameServer) + { + GenericValueTypeMessage, std::pair > > chatStatistics("ChatStatisticsCS", std::make_pair(std::make_pair(character, static_cast(aed->chatSpamTimeEndInterval)), std::make_pair(aed->spatialCharCount, aed->nonSpatialCharCount))); + sendToClient(character, chatStatistics); + aed->chatSpamNextTimeToSyncWithGameServer = timeNow + ConfigChatServer::getChatStatisticsReportIntervalSeconds(); + } + } + } +} + +// ====================================================================== + +VChatInterface* ChatServer::getVChatInterface() +{ + return instance().voiceChatInterface; +} + +// ---------------------------------------------------------------------- + +unsigned ChatServer::registerGameServerConnection(GameServerConnection *connection) +{ + static unsigned nextId = 0; + + ++nextId; + m_gameServerConnectionRegistry.insert(std::make_pair(nextId, connection)); + return nextId; +} + +//----------------------------------------------------------------------- + +void ChatServer::unregisterGameServerConnection(unsigned const connectionId) +{ + GameServerMap::iterator i = m_gameServerConnectionRegistry.find(connectionId); + if(i != m_gameServerConnectionRegistry.end()) + { + m_gameServerConnectionRegistry.erase(i); + } +} + +// ---------------------------------------------------------------------- + +void ChatServer::sendToGameServerById(unsigned const connectionId, GameNetworkMessage const & message) +{ + GameServerConnection* connection = getGameServerConnectionFromId(connectionId); + if(connection) + { + connection->send(message, true); + } + else + { + DEBUG_WARNING(true, ("VoiceChatServer::sendToGameServer could not find connection")); + } +} + +//----------------------------------------------------------------------- + +GameServerConnection *ChatServer::getGameServerConnectionFromId(unsigned int sequence) +{ + GameServerConnection * result = NULL; + std::hash_map::iterator f = m_gameServerConnectionRegistry.find(sequence); + if(f != m_gameServerConnectionRegistry.end()) + { + result = (*f).second; + } + return result; + +} + +//----------------------------------------------------------------------- + +void ChatServer::sendResponse(ReturnAddress const & requester, const GameNetworkMessage & response) +{ + fileLog(false, "ChatServer", "sendResponse() target(%s) responseType(%s)", requester.debugString().c_str(), response.getCmdName().c_str()); + + switch(requester.type) + { + case ReturnAddress::RAT_invalid: break; + case ReturnAddress::RAT_client: + { + sendToClient(requester.clientId, response); + } + break; + case ReturnAddress::RAT_gameserver: + { + sendToGameServerById(requester.gameServerId, response); + } + break; + default: + DEBUG_WARNING(true, ("ChatServer: Trying to send a response to a return address of unknown type.")); + } +} + +//----------------------------------------------------------------------- +//voice chat actions +//TODO: remove these and integrate their functionality where it should rightly go +void ChatServer::requestGetChannel(ReturnAddress const & requester, std::string const &roomName, bool isPublic, bool isPersistant, uint32 limit, std::list const & moderators) +{ + fileLog(false, "ChatServer", "request to create room from(%s) name(%s)", requester.debugString().c_str(), roomName.c_str()); + + //TODO: real passwords and descriptions? + const std::string description = ""; + const std::string password = ""; + + getVChatInterface()->requestGetChannel(roomName, description, password, limit, isPublic, isPersistant, moderators, requester); +} + + +void ChatServer::requestChannelInfo(ReturnAddress const & requester, std::string const &roomName) +{ + fileLog(false, "ChatServer", "request for channel info from (%s) channel (%s)", requester.debugString().c_str(), roomName.c_str()); + getVChatInterface()->requestChannelInfo(roomName, requester); +} + + +//----------------------------------------------------------------------- + +void ChatServer::requestDeleteChannel(ReturnAddress const & requester, std::string const & roomName) +{ + getVChatInterface()->requestDeleteChannel(roomName, requester); +} + +//----------------------------------------------------------------------- + +void ChatServer::requestAddClientToChannel(const NetworkId & id, std::string const & playerName, std::string const &roomName, bool forceShortlist) +{ + fileLog(false, "ChatServer", "requestAddClientToChannel id(%s) name(%s) roomName(%s) forceShortlist(%i)", id.getValueString().c_str(), playerName.c_str(), roomName.c_str(), forceShortlist ? 1 : 0); + getVChatInterface()->addClientToChannel(roomName, id, playerName, forceShortlist); +} + +//----------------------------------------------------------------------- + +void ChatServer::requestRemoveClientFromChannel(const NetworkId & id, std::string const & playerName, std::string const &roomName) +{ + fileLog(false, "ChatServer", "requestRemoveClientFromChannel id(%s) name(%s) roomName(%s)", id.getValueString().c_str(), playerName.c_str(), roomName.c_str()); + getVChatInterface()->removeClientFromChannel(roomName, id, playerName); +} + +//----------------------------------------------------------------------- + +void ChatServer::requestChannelCommand(ReturnAddress const & requester, + const std::string &srcUserName, const std::string &destUserName, const std::string &destChannelAddress, + unsigned command,unsigned banTimeout) +{ + getVChatInterface()->requestChannelCommand(requester, srcUserName, destUserName, destChannelAddress, command, banTimeout); +} + +//----------------------------------------------------------------------- + +void ChatServer::requestBroadcastChannelMessage(std::string const & channelName, std::string const & textMessage, bool isRemove) +{ + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer::requestBroadcastGlobalChannel chan(%s) text(%s)", channelName.c_str(), textMessage.c_str())); + getVChatInterface()->broadcastGlobalChannelMessage(channelName, textMessage, isRemove); +} + +//----------------------------------------------------------------------- + +bool ChatServer::getVoiceChatLoginInfoFromId(NetworkId const & id, std::string & userName, std::string & playerName) +{ + if(id.getValue() != 0) + { + VoiceChatAvatarList::const_iterator i = instance().m_voiceChatIdMap.find(id); + if(i != instance().m_voiceChatIdMap.end()) + { + userName = i->second.loginName; + playerName = i->second.playerName; + return true; + } + } + return false; +} + +//----------------------------------------------------------------------- + +bool ChatServer::getVoiceChatLoginInfoFromName(std::string const & playerName, NetworkId & id) +{ + std::map::const_iterator i = instance().m_voiceChatNameToIdMap.find(toLower(playerName)); + if(i != instance().m_voiceChatNameToIdMap.end()) + { + id = i->second; + return true; + } + + return false; +} + +//----------------------------------------------------------------------- + +bool ChatServer::getVoiceChatLoginInfoFromLoginName(std::string const & loginName, NetworkId & id) +{ + std::map::const_iterator i = instance().m_voiceLoginNameToIdMap.find(toLower(loginName)); + if(i != instance().m_voiceLoginNameToIdMap.end()) + { + id = i->second; + return true; + } + + return false; +} +//----------------------------------------------------------------------- + +void ChatServer::voiceChatGotLoginInfo(NetworkId const & id, std::string const & userName, std::string const & playerName) +{ + if(id.getValue() != 0) + { + VoiceChatAvatarData data; + data.loginName = userName; + data.playerName = playerName; + instance().m_voiceChatIdMap.insert(std::make_pair(id, data)); + instance().m_voiceChatNameToIdMap.insert(std::make_pair(toLower(playerName), id)); + instance().m_voiceLoginNameToIdMap.insert(std::make_pair(toLower(userName), id)); + } +} + +//----------------------------------------------------------------------- + +void ChatServer::requestInvitePlayerToChannel(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName) +{ + if(channelName == getVChatInterface()->buildPersonalChannelName(sourceId)) + { + getVChatInterface()->requestInvite(sourceId, targetId, channelName); + } +} + +void ChatServer::requestKickPlayerFromChannel(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName) +{ + if(channelName == getVChatInterface()->buildPersonalChannelName(sourceId)) + { + getVChatInterface()->requestKick(sourceId, targetId, channelName); + } +} + diff --git a/engine/server/application/ChatServer/src/shared/ChatServer.h b/engine/server/application/ChatServer/src/shared/ChatServer.h new file mode 100644 index 00000000..dc79ab20 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServer.h @@ -0,0 +1,301 @@ +// ChatServer.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ChatServer_H +#define _INCLUDED_ChatServer_H + +//----------------------------------------------------------------------- + +#include "ChatAPI/ChatAvatar.h" +#include "ChatAPI/ChatAPI.h" +#include "sharedFoundation/NetworkId.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include +#include +#include +#include +#include +#include +#include "unicodeArchive/UnicodeArchive.h" + +//----------------------------------------------------------------------- + +class CentralServerConnection; +class ChatInterface; +class Connection; +class ConnectionServerConnection; +class EnumerateServers; +class Service; +class GameNetworkMessage; +class GameServerConnection; +class ChatServerRoomOwner; +class CustomerServiceServerConnection; +struct ChatLogEntry; +class TransferCharacterData; +class VChatInterface; + +using namespace ChatSystem; + + +namespace MessageDispatch { + class Callback; +} + +struct AvatarSequencePair +{ + AvatarSequencePair(unsigned s, const ChatAvatar *a) : sequence(s), avatar(a) {} + unsigned sequence; + const ChatAvatar *avatar; +}; + +struct AvatarIdSequencePair +{ + AvatarIdSequencePair(unsigned s, const ChatAvatarId &a) : sequence(s), avatar(a) {} + unsigned sequence; + const ChatAvatarId avatar; + +private: + AvatarIdSequencePair(AvatarIdSequencePair const &); + AvatarIdSequencePair & operator =(AvatarIdSequencePair const &); +}; + +struct RoomOwnerSequencePair +{ + RoomOwnerSequencePair(unsigned s, const ChatServerRoomOwner * r) : sequence(s), roomOwner(r) {} + unsigned sequence; + const ChatServerRoomOwner *roomOwner; +}; + +struct ReturnAddress; + +class ChatServer +{ +public: + ChatServer(); + ~ChatServer(); + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + + void sendResponse(ReturnAddress const & requester, const GameNetworkMessage & response); + + GameServerConnection * getGameServerConnectionFromId(unsigned int connectionId); + unsigned registerGameServerConnection(GameServerConnection * connection); + void unregisterGameServerConnection(unsigned const connectionId); + void sendToGameServerById(unsigned const connectionId, GameNetworkMessage const & message); + + static VChatInterface* getVChatInterface(); + + //TODO: remove these and integrate their functionality where it should rightly go (voice and text should be unified) + static void requestGetChannel(ReturnAddress const & requester, std::string const &roomName, bool isPublic, bool isPersistant, uint32 limit, std::list const & moderators); + static void requestChannelInfo(ReturnAddress const & requester, std::string const &roomName); + static void requestDeleteChannel(ReturnAddress const & requester, std::string const & roomName); + static void requestAddClientToChannel(const NetworkId & id, std::string const & playerName, std::string const &roomName, bool forceShortlist); + static void requestRemoveClientFromChannel(const NetworkId & id, std::string const & playerName, std::string const &roomName); + static void requestChannelCommand(ReturnAddress const & requester, const std::string &srcUserName, const std::string &destUserName, + const std::string &destChannelAddress, unsigned command, unsigned banTimeout); + + static void requestBroadcastChannelMessage(std::string const & channelName, std::string const & textMessage, bool isRemove); + + static bool getVoiceChatLoginInfoFromId(NetworkId const & id, std::string & userName, std::string & playerName); + static bool getVoiceChatLoginInfoFromName(std::string const & playerName, NetworkId & id); + static bool getVoiceChatLoginInfoFromLoginName(std::string const & loginName, NetworkId & id); + static void voiceChatGotLoginInfo(NetworkId const & id, std::string const & userName, std::string const & playerName); + + static void requestInvitePlayerToChannel(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName); + static void requestKickPlayerFromChannel(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName); + + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + + + std::hash_map pendingRequests; + static ChatServer & instance (); + + static bool isValidChatAvatarName(Unicode::String const &chatName); + static std::string getFullChatAvatarName(ChatAvatar const *chatAvatar); + static std::string toNarrowString(ChatUnicodeString const &chatUnicodeString); + static std::string getConnectionAddress(Connection const *connection); + static Unicode::String getChatRoomName(ChatRoom const *chatRoom); + static std::string getChatRoomNameNarrow(ChatRoom const *chatRoom); + static Unicode::String toUnicodeString(ChatUnicodeString const &chatUnicodeString); + + static const ChatAvatar * getAvatarByNetworkId (const NetworkId & id); + static const NetworkId & getNetworkIdByAvatarId(const ChatAvatarId & id); + static NetworkId sendResponseForTrackId (unsigned trackId, const GameNetworkMessage & msg); + static ChatInterface * getChatInterface(); + + static void setOwnerSystem (const ChatAvatar * ownerSystem); + static ConnectionServerConnection * getConnectionForCharacter(const NetworkId & characterId); + static const ChatAvatarId & getSystemAvatarId (); + static const Service * getGameService (); + static GameServerConnection * getGameServerConnection(unsigned int sequence); + static void addGameServerConnection(unsigned int sequence, GameServerConnection *connection); + + static void clearGameServerConnection(const GameServerConnection *connection); + static void clearCustomerServiceServerConnection(); + + static void connectToCustomerServiceServer(const std::string &address, const unsigned short port); + + static void sendToClient (const NetworkId & id, const GameNetworkMessage & msg); + static void deferChatMessageFor (const NetworkId &, const Archive::ByteStream &); + + static ChatAvatarId getAvatarIdForTrackId (unsigned trackId); + + static void reconnectToCentralServer (); + static void onCentralServerConnectionClosed(); + + static void run (); + static void quit (); + static void chatConnectedAvatar (const NetworkId & id, const ChatAvatar & avatar); + + static void connectPlayer (ConnectionServerConnection * connection, const unsigned int suid, const std::string & characterName, const NetworkId & networkId, const bool isSecure, const bool isSubscribed); + static void createRoom (const NetworkId & id, const unsigned int sequence, const std::string & name, const bool isModerated, const bool isPublic, const std::string & title); + static void putSystemAvatarInRoom (const std::string & roomName); + static void enterRoom (const NetworkId & id, const unsigned int sequence, const std::string & roomName); + static void enterRoom (const NetworkId & id, const unsigned int sequence, const unsigned int roomId); + static void enterRoom (const ChatAvatarId & id, const std::string & roomName, bool forceCreate, bool createPrivate); + static void sendInstantMessage (const NetworkId & fromId, const unsigned int sequence, const ChatAvatarId & to, const Unicode::String & message, const Unicode::String & oob); + static void sendInstantMessage (const ChatAvatarId & from, const ChatAvatarId & to, const Unicode::String & message, const Unicode::String & oob); + static void leaveRoom (const NetworkId & id, const unsigned int sequence, const unsigned int roomId); + static void removeAvatarFromRoom (const NetworkId & requestor, const ChatAvatarId & avatarId, const std::string & roomName); + static void removeSystemAvatarFromRoom(const ChatRoom *room); + static void removeAvatarFromRoom (const ChatAvatarId & avatarId, const std::string & roomName); + static void kickAvatarFromRoom (const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName); + static void sendRoomMessage (const NetworkId & id, const unsigned int sequence, const unsigned int roomId, const Unicode::String & message, const Unicode::String & oob); + static void sendRoomMessage (const ChatAvatarId & from, const std::string & roomName, const Unicode::String & message, const Unicode::String & oob); + static void sendStandardRoomMessage (const ChatAvatarId & from, const std::string & roomName, const Unicode::String & message, const Unicode::String & oob); + static void destroyRoom (const NetworkId & id, const unsigned int sequence, const unsigned int roomId); + static void destroyRoom (const std::string & roomName); + static void addFriend (const NetworkId & id, const unsigned int sequence, const ChatAvatarId & friendName); + static void removeFriend (const NetworkId & id, const unsigned int sequence, const ChatAvatarId & friendName); + static void getFriendsList (const ChatAvatarId & characterName); + static void addIgnore (const NetworkId & id, const unsigned int sequence, const ChatAvatarId & ignoreName); + static void removeIgnore (const NetworkId & id, const unsigned int sequence, const ChatAvatarId & ignoreName); + static void getIgnoreList (const ChatAvatarId & characterName); + static void disconnectAvatar (const ChatAvatar &); + static void disconnectPlayer (const NetworkId &); + static void invite (const NetworkId & id, const ChatAvatarId & avatar, const std::string & roomName); + static void inviteGroupMembers (const NetworkId & id, const ChatAvatarId & avatar, const std::string & roomName, const stdvector::fwd & members); + static void uninvite (const NetworkId & id, const unsigned int sequence, const ChatAvatarId & avatar, const std::string & roomName); + static void queryRoom (const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequence, const std::string & roomName); + static void requestRoomList (const NetworkId & id, ConnectionServerConnection * connection); + static void addModeratorToRoom (const unsigned int sequenceId, const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName); + static void removeModeratorFromRoom (const unsigned int sequenceId, const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName); + static void deletePersistentMessage (const NetworkId & ownerId, const unsigned int messageId); + static void deleteAllPersistentMessages(const NetworkId &sourceNetworkId, const NetworkId &targetNetworkId); + static void sendPersistentMessage (const NetworkId & fromId, const unsigned int sequence, const ChatAvatarId & to, const Unicode::String & subject, const Unicode::String & message, const Unicode::String & oob); + static void sendPersistentMessage (const ChatAvatarId & from, const ChatAvatarId & to, const Unicode::String & subject, const Unicode::String & message, const Unicode::String & oob); + static void requestPersistentMessage (const NetworkId &id, const unsigned int sequence, const unsigned int messageId); + static void banFromRoom (const unsigned sequence, const NetworkId &banner, const ChatAvatarId &bannee, const std::string &roomName); + static void unbanFromRoom (const unsigned sequence, const NetworkId &banner, const ChatAvatarId &bannee, const std::string &roomName); + static void removeConnectionServerConnection(ConnectionServerConnection * target); + + static void sendToAllConnectionServers(const GameNetworkMessage &message); + static void broadcastToGameServers(const GameNetworkMessage &message); + + static bool getChatLog(Unicode::String const &player, std::vector &chatLog); + static void logChatMessage(Unicode::String const &logPlayer, Unicode::String const &fromPlayer, Unicode::String const &toPlayer, Unicode::String const &text, Unicode::String const &channel); + static Unicode::String const &getChannelTell(); + static Unicode::String const &getChannelEmail(); + + static void fileLog(bool const forceLog, char const * const label, char const * const format, ...); + static void requestTransferAvatar(const TransferCharacterData & request); + static void onCreateRoomSuccess(const std::string & lowerName, const unsigned int roomId); + static bool isGod(const NetworkId & networkId); + + static void setUnsquelchTime(NetworkId const & character, time_t unsquelchTime); + static void handleChatStatisticsFromGameServer(NetworkId const & character, time_t unsquelchTime, time_t chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters); +private: + + void onEnumerateServers(const EnumerateServers &); + void update(); + void removeServices(); + + struct AvatarExtendedData + { + ChatAvatar chatAvatar; + bool isSubscribed; + int spatialCharCount; + int nonSpatialCharCount; + time_t chatSpamTimeEndInterval; + time_t chatSpamNextTimeToSyncWithGameServer; + time_t chatSpamNextTimeToNotifyPlayerWhenLimited; + time_t unsquelchTime; + }; + typedef std::hash_map ChatAvatarList; + + + struct VoiceChatAvatarData + { + std::string loginName; + std::string playerName; + }; + + typedef std::hash_map VoiceChatAvatarList; + + static AvatarExtendedData * getAvatarExtendedDataByNetworkId(const NetworkId & id); + + MessageDispatch::Callback * callback; + CentralServerConnection * centralServerConnection; + ChatAvatarList chatAvatars; + ChatInterface * chatInterface; + VChatInterface * voiceChatInterface; + std::hash_map clientMap; + std::hash_map gameServerConnectionMap; + std::set connectionServerConnections; + + bool done; + Service * gameService; + Service * planetService; + const ChatAvatar * ownerSystem; + ChatAvatarId systemAvatarId; + static ChatServer * m_instance; + CustomerServiceServerConnection *customerServiceServerConnection; + + typedef std::hash_map GameServerMap; + GameServerMap m_gameServerConnectionRegistry; + VoiceChatAvatarList m_voiceChatIdMap; + std::map m_voiceChatNameToIdMap; + std::map m_voiceLoginNameToIdMap; + + // Disabled + + ChatServer &operator =(ChatServer const &); +}; + +/* +class ChatServer +{ +public: + + + + +private: + ChatServer & operator = (const ChatServer & rhs); + ChatServer(const ChatServer & source); + +private: + MessageDispatch::Callback * callback; + CentralServerConnection * centralServerConnection; + std::hash_map chatAvatars; + ChatInterface * chatInterface; + std::hash_map clientMap; + std::hash_map gameServerConnectionMap; + std::set connectionServerConnections; + bool done; + Service * gameService; + Service * planetService; + const ChatAvatar * ownerSystem; + ChatAvatarId systemAvatarId; + std::hash_map pendingRequests; + static ChatServer * m_instance; + +};*/ + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ChatServer_H diff --git a/engine/server/application/ChatServer/src/shared/ChatServerAvatarOwner.cpp b/engine/server/application/ChatServer/src/shared/ChatServerAvatarOwner.cpp new file mode 100644 index 00000000..aea3302c --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServerAvatarOwner.cpp @@ -0,0 +1,40 @@ +// ChatServerAvatarOwner.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "ChatServerAvatarOwner.h" +#include "ConnectionServerConnection.h" + +//----------------------------------------------------------------------- + +ChatServerAvatarOwner::ChatServerAvatarOwner(ConnectionServerConnection * c, const NetworkId & n) : +networkId(n), +playerConnection(c) +{ + c->addAvatar(this); +} + +//----------------------------------------------------------------------- + +ChatServerAvatarOwner::~ChatServerAvatarOwner() +{ + if(playerConnection) + { + playerConnection->removeAvatar(this); + } + + playerConnection = 0; +} + +//----------------------------------------------------------------------- + +void ChatServerAvatarOwner::setPlayerConnection(ConnectionServerConnection * c) +{ + playerConnection = c; +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/ChatServer/src/shared/ChatServerAvatarOwner.h b/engine/server/application/ChatServer/src/shared/ChatServerAvatarOwner.h new file mode 100644 index 00000000..80d7c65d --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServerAvatarOwner.h @@ -0,0 +1,50 @@ +// ChatServerAvatarOwner.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ChatServerAvatarOwner_H +#define _INCLUDED_ChatServerAvatarOwner_H + +//----------------------------------------------------------------------- + +#include "ChatAPI/ChatAvatar.h" +#include "sharedFoundation/NetworkId.h" + +class ConnectionServerConnection; + +//----------------------------------------------------------------------- + +class ChatServerAvatarOwner +{ +public: + explicit ChatServerAvatarOwner(ConnectionServerConnection * playerConnection, const NetworkId & networkId); + ~ChatServerAvatarOwner(); + + const NetworkId & getNetworkId () const; + ConnectionServerConnection * getPlayerConnection (); + void setPlayerConnection (ConnectionServerConnection *); + +private: + ChatServerAvatarOwner & operator = (const ChatServerAvatarOwner & rhs); + ChatServerAvatarOwner(const ChatServerAvatarOwner & source); + NetworkId networkId; + ConnectionServerConnection * playerConnection; +}; //lint !e1712 default constructor not defined for class + +//----------------------------------------------------------------------- + +inline const NetworkId & ChatServerAvatarOwner::getNetworkId() const +{ + return networkId; +} + +//----------------------------------------------------------------------- + +inline ConnectionServerConnection * ChatServerAvatarOwner::getPlayerConnection() +{ + return playerConnection; +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ChatServerAvatarOwner_H diff --git a/engine/server/application/ChatServer/src/shared/ChatServerMetricsData.cpp b/engine/server/application/ChatServer/src/shared/ChatServerMetricsData.cpp new file mode 100644 index 00000000..b5cce005 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServerMetricsData.cpp @@ -0,0 +1,55 @@ +//ChatServerMetricsData.cpp +//Copyright 2002 Sony Online Entertainment + +#include "FirstChatServer.h" +#include "ChatServerMetricsData.h" + +//----------------------------------------------------------------------- + +ChatServerMetricsData::ChatServerMetricsData() : +MetricsData(), +m_clientCount(0), +m_connectionServerCount(0), +m_gameServerCount(0) +{ + MetricsPair p; + ADD_METRICS_DATA(clientCount, 0, false); + ADD_METRICS_DATA(connectionServerCount, 0, false); + ADD_METRICS_DATA(gameServerCount, 0, false); +} + +//----------------------------------------------------------------------- + +ChatServerMetricsData::~ChatServerMetricsData() +{ +} + +//----------------------------------------------------------------------- + +void ChatServerMetricsData::setClientCount(const int clientCount) +{ + m_data[m_clientCount].m_value = clientCount; +} + +//----------------------------------------------------------------------- + +void ChatServerMetricsData::setConnectionServerConnectionCount(const int connectionServerConnectionCount) +{ + m_data[m_connectionServerCount].m_value = connectionServerConnectionCount; +} + +//----------------------------------------------------------------------- + +void ChatServerMetricsData::setGameServerConnectionCount(const int gameServerConnectionCount) +{ + m_data[m_gameServerCount].m_value = gameServerConnectionCount; +} + +//----------------------------------------------------------------------- + +void ChatServerMetricsData::updateData() +{ + MetricsData::updateData(); +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/ChatServer/src/shared/ChatServerMetricsData.h b/engine/server/application/ChatServer/src/shared/ChatServerMetricsData.h new file mode 100644 index 00000000..3bf5be80 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServerMetricsData.h @@ -0,0 +1,39 @@ +//ChatServerMetricsData.h +//Copyright 2002 Sony Online Entertainment + + +#ifndef _ChatServerMetricsData_H +#define _ChatServerMetricsData_H + +//----------------------------------------------------------------------- + +#include "serverMetrics/MetricsData.h" + +//----------------------------------------------------------------------- + +class ChatServerMetricsData : public MetricsData +{ +public: + ChatServerMetricsData(); + ~ChatServerMetricsData(); + + virtual void updateData(); + void setClientCount(const int clientCount); + void setConnectionServerConnectionCount(const int connectionServerConnectionCount); + void setGameServerConnectionCount(const int gameServerConnectionCount); + +private: + + // Disabled. + ChatServerMetricsData(const ChatServerMetricsData&); + ChatServerMetricsData &operator =(const ChatServerMetricsData&); + +private: + unsigned long m_clientCount; + unsigned long m_connectionServerCount; + unsigned long m_gameServerCount; +}; + + +//----------------------------------------------------------------------- +#endif diff --git a/engine/server/application/ChatServer/src/shared/ChatServerRoomOwner.cpp b/engine/server/application/ChatServer/src/shared/ChatServerRoomOwner.cpp new file mode 100644 index 00000000..091a78ac --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServerRoomOwner.cpp @@ -0,0 +1,175 @@ +// ChatServerRoomOwner.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "ChatServerRoomOwner.h" +#include "ChatInterface.h" +#include "ChatServer.h" +#include "UnicodeUtils.h" + +//----------------------------------------------------------------------- + +ChatServerRoomOwner::ChatServerRoomOwner(const ChatRoom * r) : +roomID(r->getRoomID()), +roomData(), +lastUsed(time(0)), +lastPopulated(time(0)), +wideRoomAddress(r->getAddress().string_data, r->getAddress().string_length), +roomAddress(wideRoomAddress.data(), wideRoomAddress.size()), +flaggedForDelete(false), +groupChatRoom(false) +{ + if(r) + { + makeRoomData(*r, roomData); + if (!_stricmp(ChatServer::getChatRoomNameNarrow(r).c_str(), ChatRoomTypes::ROOM_GROUP.c_str()) && !_stricmp(Unicode::wideToNarrow(ChatServer::toUnicodeString(r->getCreatorName())).c_str(), "SYSTEM")) + groupChatRoom = true; + else + groupChatRoom = false; + } + else + { + groupChatRoom = false; + } +} + +//----------------------------------------------------------------------- + +ChatServerRoomOwner::ChatServerRoomOwner(const ChatServerRoomOwner & source) : +roomID(source.roomID), +roomData(source.roomData), +lastUsed(time(0)), +lastPopulated(time(0)), +wideRoomAddress(source.wideRoomAddress), +roomAddress(wideRoomAddress.data(), wideRoomAddress.size()), +flaggedForDelete(false), +groupChatRoom(source.groupChatRoom) +{ +} + +//----------------------------------------------------------------------- + +ChatServerRoomOwner::~ChatServerRoomOwner() +{ + roomID = 0; + lastUsed = 0; + lastPopulated = 0; +} + +//----------------------------------------------------------------------- + +ChatServerRoomOwner & ChatServerRoomOwner::operator = (const ChatServerRoomOwner & rhs) +{ + if(this != &rhs) + { + // make assignments if right hand side is not this instance + roomID = rhs.roomID; + roomData = rhs.roomData; + lastUsed = rhs.lastUsed; + lastPopulated = rhs.lastPopulated; + wideRoomAddress = rhs.wideRoomAddress; + roomAddress = wideRoomAddress; + flaggedForDelete = rhs.flaggedForDelete; + groupChatRoom = rhs.groupChatRoom; + } + return *this; +} + +//----------------------------------------------------------------------- + +const ChatRoom * ChatServerRoomOwner::getRoom() const +{ + ChatInterface * const chatInterface = ChatServer::getChatInterface(); + if (chatInterface) + return chatInterface->getRoom(roomID); + + return NULL; +} + +//----------------------------------------------------------------------- + +const ChatRoomData & ChatServerRoomOwner::getRoomData() const +{ + return roomData; +} + +//----------------------------------------------------------------------- + +void ChatServerRoomOwner::updateRoomData() +{ + ChatRoom const * const room = getRoom(); + if(room) + { + makeRoomData(*room, roomData); + if (!_stricmp(ChatServer::getChatRoomNameNarrow(room).c_str(), ChatRoomTypes::ROOM_GROUP.c_str()) && !_stricmp(Unicode::wideToNarrow(ChatServer::toUnicodeString(room->getCreatorName())).c_str(), "SYSTEM")) + groupChatRoom = true; + else + groupChatRoom = false; + } + else + { + groupChatRoom = false; + } +} + +//----------------------------------------------------------------------- + +void ChatServerRoomOwner::updateRoomData(const ChatRoom *newRoom) +{ + if(newRoom) + { + roomID = newRoom->getRoomID(), + makeRoomData(*newRoom, roomData); + if (!_stricmp(ChatServer::getChatRoomNameNarrow(newRoom).c_str(), ChatRoomTypes::ROOM_GROUP.c_str()) && !_stricmp(Unicode::wideToNarrow(ChatServer::toUnicodeString(newRoom->getCreatorName())).c_str(), "SYSTEM")) + groupChatRoom = true; + else + groupChatRoom = false; + } +} + +//----------------------------------------------------------------------- + +const ChatUnicodeString & ChatServerRoomOwner::getAddress() const +{ + return roomAddress; +} + +//----------------------------------------------------------------------- + +void ChatServerRoomOwner::touch() +{ + lastUsed = time(0); +} + +//----------------------------------------------------------------------- + +time_t ChatServerRoomOwner::getLastUsed() const +{ + return lastUsed; +} + +//----------------------------------------------------------------------- + +bool ChatServerRoomOwner::isFlaggedForDelete() const +{ + return flaggedForDelete; +} + +//----------------------------------------------------------------------- + +void ChatServerRoomOwner::flagForDelete() +{ + flaggedForDelete = true; +} + +//----------------------------------------------------------------------- + +time_t ChatServerRoomOwner::getLastPopulated() +{ + return lastPopulated; +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/ChatServer/src/shared/ChatServerRoomOwner.h b/engine/server/application/ChatServer/src/shared/ChatServerRoomOwner.h new file mode 100644 index 00000000..786f8955 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ChatServerRoomOwner.h @@ -0,0 +1,58 @@ +// ChatServerRoomOwner.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ChatServerRoomOwner_H +#define _INCLUDED_ChatServerRoomOwner_H + +//----------------------------------------------------------------------- + +#include "ChatAPI/ChatRoom.h" +#include "sharedNetworkMessages/ChatRoomData.h" + +using namespace ChatSystem; + +//----------------------------------------------------------------------- + +class ChatServerRoomOwner +{ +public: + explicit ChatServerRoomOwner(const ChatRoom * room); + virtual ~ChatServerRoomOwner(); + ChatServerRoomOwner & operator = (const ChatServerRoomOwner & rhs); + ChatServerRoomOwner(const ChatServerRoomOwner & source); + + const ChatRoom * getRoom () const; + const ChatRoomData & getRoomData () const; + void updateRoomData (); + void updateRoomData (const ChatRoom *room); + void touch (); + time_t getLastUsed () const; + time_t getLastPopulated(); + const ChatUnicodeString & getAddress () const; + void flagForDelete(); + bool isFlaggedForDelete() const; + bool isGroupChatRoom() const; + +private: + + unsigned roomID; + ChatRoomData roomData; + time_t lastUsed; + time_t lastPopulated; + Unicode::String wideRoomAddress; + ChatUnicodeString roomAddress; + bool flaggedForDelete; + bool groupChatRoom; +};//lint !e1712 default constructor not defined for class + +//----------------------------------------------------------------------- + +inline bool ChatServerRoomOwner::isGroupChatRoom() const +{ + return groupChatRoom; +} + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ChatServerRoomOwner_H diff --git a/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp b/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp new file mode 100644 index 00000000..b0cf04b3 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp @@ -0,0 +1,148 @@ +// ConfigChatServer.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigChatServer.h" + +//----------------------------------------------------------------------- + +ConfigChatServer::Data * ConfigChatServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ChatServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ChatServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ChatServer", #a, b)) + +//Commented out so lint doesn't whine that we're not using them +//#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("ChatServer", #a, b)) + +// ====================================================================== + +namespace ConfigChatServerNamespace +{ + typedef std::vector StringPtrArray; + StringPtrArray ms_createRoom; // ConfigFile owns the pointer + StringPtrArray ms_voiceGateways; +} + +using namespace ConfigChatServerNamespace; + +// ====================================================================== + +int ConfigChatServer::getNumberOfCreateRooms() +{ + return static_cast(ms_createRoom.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigChatServer::getCreateRoom(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCreateRooms()); + return ms_createRoom[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +int ConfigChatServer::getNumberOfVoiceChatGateways() +{ + return static_cast(ms_voiceGateways.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigChatServer::getVoiceChatGateway(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVoiceChatGateways()); + return ms_voiceGateways[static_cast(index)]; +} + +void ConfigChatServer::install(void) +{ + ConfigServerUtility::install(); + + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + data = new ConfigChatServer::Data; + + KEY_STRING (backupGatewayServerIP, "swo-dev8.station.sony.com"); + KEY_INT (backupGatewayServerPort, 15150); + KEY_STRING (clusterName, "devcluster"); + KEY_STRING (centralServerAddress, "swo-dev8.station.sony.com"); + KEY_INT (centralServerPort, 61232); + KEY_STRING (gameCode, "SWG"); + KEY_STRING (gatewayServerIP, "sdplatdev1.station.sony.com"); + KEY_INT (gatewayServerPort, 5001); + KEY_INT (roomInactivityTimeout, 60 * 60 * 24 * 3); + KEY_INT (roomUnpopulatedTimeout, 60 * 5); + KEY_STRING (gameServiceBindInterface, ""); + KEY_STRING (planetServiceBindInterface, ""); + KEY_INT (loginFlowControlRate, 50); + KEY_INT (maxRoomQueriesPerFrame, 5); + KEY_BOOL (loggingEnabled, false); + KEY_STRING (registrarHost, "sdplatdev1.station.sony.com"); + KEY_INT (registrarPort, 5000); + KEY_INT (intervalToSendHeadersToClientSeconds, 1); + KEY_INT (maxHeadersToSendToClientPerInterval, 100); + KEY_INT (chatStatisticsReportIntervalSeconds, 60); + KEY_INT (chatSpamLimiterNumCharacters, 400); + KEY_BOOL (chatSpamLimiterEnabledForFreeTrial, true); + KEY_INT (chatSpamNotifyPlayerWhenLimitedIntervalSeconds, 30); // <= 0 to disable + KEY_BOOL (voiceChatLoggingEnabled, false); + KEY_INT (voiceChatRoomListRefresh, 600000); + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("ChatServer", "createRoom", index++, 0); + if (result != 0) + { + ms_createRoom.push_back(result); + } + } + while (result); + + index = 0; + result = 0; + do + { + result = ConfigFile::getKeyString("ChatServer", "voiceChatGateway", index++, 0); + if(result != 0) + { + ms_voiceGateways.push_back(result); + } + } while(result); + + if(ms_voiceGateways.empty()) + { + static char const * const defaultGateway = "sdt-plattestsys1:9102"; + ms_voiceGateways.push_back(defaultGateway); + } +} + +//----------------------------------------------------------------------- + +void ConfigChatServer::remove(void) +{ + delete data; + data = 0; + ConfigServerUtility::remove(); +} + +//----------------------------------------------------------------------- + +bool ConfigChatServer::isLoggingEnabled() +{ + return data->loggingEnabled; +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/ChatServer/src/shared/ConfigChatServer.h b/engine/server/application/ChatServer/src/shared/ConfigChatServer.h new file mode 100644 index 00000000..9c6d8303 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ConfigChatServer.h @@ -0,0 +1,247 @@ +// ConfigChatServer.h +// copyright 2000 Verant Interactive +// Author: Justin Randall + +#ifndef _ConfigChatServer_H +#define _ConfigChatServer_H + +//----------------------------------------------------------------------- + +class ConfigChatServer +{ +public: + struct Data + { + const char * backupGatewayServerIP; + int backupGatewayServerPort; + const char * clusterName; + const char * centralServerAddress; + int centralServerPort; + const char * gameCode; + const char * gatewayServerIP; + int gatewayServerPort; + time_t roomInactivityTimeout; + time_t roomUnpopulatedTimeout; + const char * gameServiceBindInterface; + const char * planetServiceBindInterface; + int loginFlowControlRate; + int maxRoomQueriesPerFrame; + bool loggingEnabled; + const char * registrarHost; + int registrarPort; + int intervalToSendHeadersToClientSeconds; + int maxHeadersToSendToClientPerInterval; + int chatStatisticsReportIntervalSeconds; + int chatSpamLimiterNumCharacters; + bool chatSpamLimiterEnabledForFreeTrial; + int chatSpamNotifyPlayerWhenLimitedIntervalSeconds; + bool voiceChatLoggingEnabled; + int voiceChatRoomListRefresh; + }; + + static const char * getBackupGatewayServerIP (); + static const unsigned short getBackupGatewayServerPort (); + static const char * getCentralServerAddress (); + static const unsigned short getCentralServerPort (); + static const char * getClusterName (); + static const char * getGameCode (); + static const char * getGatewayServerIP (); + static const unsigned short getGatewayServerPort (); + static const time_t getRoomInactivityTimeout (); + static const time_t getRoomUnpopulatedTimeout (); + static const char * getGameServiceBindInterface (); + static const char * getPlanetServiceBindInterface (); + static int getLoginFlowControlRate (); + static int getMaxRoomQueriesPerFrame (); + static void install (); + static void remove (); + static bool isLoggingEnabled(); + static const char * getRegistrarHost (); + static int getRegistrarPort (); + static int getNumberOfCreateRooms(); + static char const * getCreateRoom(int index); + static int getIntervalToSendHeadersToClientSeconds(); + static int getMaxHeadersToSendToClientPerInterval(); + static int getChatStatisticsReportIntervalSeconds(); + static int getChatSpamLimiterNumCharacters(); + static bool getChatSpamLimiterEnabledForFreeTrial(); + static int getChatSpamNotifyPlayerWhenLimitedIntervalSeconds(); + static bool getVoiceChatLoggingEnabled(); + static int getVChatRoomListRefresh(); + static int getNumberOfVoiceChatGateways(); + static char const * getVoiceChatGateway(int index); + + +private: + static Data * data; +}; + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getBackupGatewayServerIP() +{ + return data->backupGatewayServerIP; +} + +//----------------------------------------------------------------------- + +inline const unsigned short ConfigChatServer::getBackupGatewayServerPort() +{ + return static_cast(data->backupGatewayServerPort); +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getCentralServerAddress() +{ + return data->centralServerAddress; +} + +//----------------------------------------------------------------------- + +inline const unsigned short ConfigChatServer::getCentralServerPort() +{ + return static_cast(data->centralServerPort); +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getClusterName() +{ + return data->clusterName; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getGameCode() +{ + return data->gameCode; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getGatewayServerIP() +{ + return data->gatewayServerIP; +} + +//----------------------------------------------------------------------- + +inline const unsigned short ConfigChatServer::getGatewayServerPort() +{ + return static_cast(data->gatewayServerPort); +} + +//----------------------------------------------------------------------- + +inline const time_t ConfigChatServer::getRoomInactivityTimeout() +{ + return static_cast(data->roomInactivityTimeout); +} + +//----------------------------------------------------------------------- + +inline const time_t ConfigChatServer::getRoomUnpopulatedTimeout() +{ + return static_cast(data->roomUnpopulatedTimeout); +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getGameServiceBindInterface() +{ + return data->gameServiceBindInterface; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getPlanetServiceBindInterface() +{ + return data->planetServiceBindInterface; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getLoginFlowControlRate() +{ + return data->loginFlowControlRate; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getMaxRoomQueriesPerFrame() +{ + return data->maxRoomQueriesPerFrame; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigChatServer::getRegistrarHost() +{ + return data->registrarHost; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getRegistrarPort() +{ + return data->registrarPort; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getIntervalToSendHeadersToClientSeconds() +{ + return data->intervalToSendHeadersToClientSeconds; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getMaxHeadersToSendToClientPerInterval() +{ + return data->maxHeadersToSendToClientPerInterval; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getChatStatisticsReportIntervalSeconds() +{ + return data->chatStatisticsReportIntervalSeconds; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getChatSpamLimiterNumCharacters() +{ + return data->chatSpamLimiterNumCharacters; +} + +//----------------------------------------------------------------------- + +inline bool ConfigChatServer::getChatSpamLimiterEnabledForFreeTrial() +{ + return data->chatSpamLimiterEnabledForFreeTrial; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() +{ + return data->chatSpamNotifyPlayerWhenLimitedIntervalSeconds; +} + +//----------------------------------------------------------------------- + +inline bool ConfigChatServer::getVoiceChatLoggingEnabled() +{ + return data->voiceChatLoggingEnabled; +} + +//----------------------------------------------------------------------- + +inline int ConfigChatServer::getVChatRoomListRefresh() +{ + return data->voiceChatRoomListRefresh; +} + +#endif // _ConfigChatServer_H diff --git a/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp b/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp new file mode 100644 index 00000000..d4e36d1d --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp @@ -0,0 +1,480 @@ +// ConnectionServerConnection.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- +#include "FirstChatServer.h" + +#include "ChatInterface.h" +#include "ChatServer.h" +#include "ChatServerAvatarOwner.h" +#include "ConfigChatServer.h" +#include "ConnectionServerConnection.h" +#include "VChatInterface.h" +#include "serverNetworkMessages/ChatConnectAvatar.h" +#include "serverNetworkMessages/ChatDisconnectAvatar.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedLog/Log.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetworkMessages/ChatAddFriend.h" +#include "sharedNetworkMessages/ChatAddModeratorToRoom.h" +#include "sharedNetworkMessages/ChatBanAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatCreateRoom.h" +#include "sharedNetworkMessages/ChatDeletePersistentMessage.h" +#include "sharedNetworkMessages/ChatDeleteAllPersistentMessages.h" +#include "sharedNetworkMessages/ChatDestroyRoom.h" +#include "sharedNetworkMessages/ChatEnterRoom.h" +#include "sharedNetworkMessages/ChatEnterRoomById.h" +#include "sharedNetworkMessages/ChatInstantMessageToCharacter.h" +#include "sharedNetworkMessages/ChatInstantMessageToClient.h" +#include "sharedNetworkMessages/ChatInviteAvatarToRoom.h" +#include "sharedNetworkMessages/ChatKickAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnSendInstantMessage.h" +#include "sharedNetworkMessages/ChatQueryRoom.h" +#include "sharedNetworkMessages/ChatPersistentMessageToClient.h" +#include "sharedNetworkMessages/ChatPersistentMessageToServer.h" +#include "sharedNetworkMessages/ChatRemoveAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatRemoveModeratorFromRoom.h" +#include "sharedNetworkMessages/ChatRequestPersistentMessage.h" +#include "sharedNetworkMessages/ChatSendToRoom.h" +#include "sharedNetworkMessages/ChatUnbanAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatUninviteFromRoom.h" +#include "sharedNetworkMessages/VerifyPlayerNameMessage.h" +#include "sharedNetworkMessages/VerifyPlayerNameResponseMessage.h" +#include "sharedNetworkMessages/VoiceChatMiscMessages.h" +#include "UnicodeUtils.h" + +//----------------------------------------------------------------------- + +ConnectionServerConnection::ConnectionServerConnection(const std::string & a, const unsigned short p) : +ServerConnection(a, p, NetworkSetupData()), +m_avatars() +{ + ChatServer::fileLog(true, "ConnectionServerConnection", "Connection created...listening on (%s:%d)", a.c_str(), static_cast(p)); +} + +//----------------------------------------------------------------------- + +ConnectionServerConnection::~ConnectionServerConnection() +{ + ChatServer::fileLog(true, "ConnectionServerConnection", "~ConnectionServerConnection() - %s:%d", getRemoteAddress().c_str(), getRemotePort()); + + std::set::iterator i; + for(i = m_avatars.begin(); i != m_avatars.end(); ++i) + { + (*i)->setPlayerConnection(0); + } + + ChatServer::removeConnectionServerConnection(this); +} + +//----------------------------------------------------------------------- + +void ConnectionServerConnection::onConnectionClosed() +{ + ChatServer::fileLog(true, "ConnectionServerConnection", "onConnectionClosed()"); +} + +//----------------------------------------------------------------------- + +void ConnectionServerConnection::onConnectionOpened() +{ + ChatServer::fileLog(true, "ConnectionServerConnection", "onConnectionOpened()"); +} + +//----------------------------------------------------------------------- + +void ConnectionServerConnection::onReceive(const Archive::ByteStream & message) +{ + Archive::ReadIterator ri = message.begin(); + GameNetworkMessage m(ri); + /* + static int count = 0; + if ((count % 10) == 0) + { + ChatServer::getChatInterface()->Process(); + } + ++count;*/ + + ri = message.begin(); + + //LOG("ConnectionServerConnection", ("onReceive() message(%s)", m.getCmdName().c_str())); + + if(m.isType("ChatConnectAvatar")) + { +//printf("ConnectionServerConnection -- ChatConnectAvatar\n"); + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatConnectAvatar"); + ChatConnectAvatar c(ri); + // break surname from last name + std::string name = c.getCharacterName(); + size_t pos = name.find_first_of(" "); + if(pos != std::string::npos) + name = name.substr(0, pos); + ChatServer::connectPlayer(this, c.getStationId(), name, c.getCharacterId(), c.getIsSecure(), c.getIsSubscribed()); + } + else if(m.isType("ChatDisconnectAvatar")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatDisconnectAvatar"); +//printf("ConnectionServerConnection -- ChatDisconnectAvatar\n"); + static MessageDispatch::Transceiver disconn; + ChatDisconnectAvatar d(ri); + disconn.emitMessage(d); + ChatServer::disconnectPlayer(d.getCharacterId()); + } + else if(m.isType("GameClientMessage")) + { + // chat message forwarded by the connection server + GameClientMessage c(ri); + //deliverMessageToClientObject(c.getNetworkId(), c.getByteStream()); + Archive::ReadIterator cri = c.getByteStream().begin(); + GameNetworkMessage cm(cri); + std::vector::const_iterator i; + for(i = c.getDistributionList().begin(); i != c.getDistributionList().end(); ++i) + { + const ChatAvatar * avatar = ChatServer::getAvatarByNetworkId(*i); + if (!avatar && cm.isType("ChatInstantMessageToCharacter")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatInstantMessageToCharacter"); + //printf("!Sending via the shortcut\n"); + cri = c.getByteStream().begin(); + + static const std::string gameType("SWG"); + if(cm.isType("ChatInstantMessageToCharacter")) + { + // deliver IM to character + ChatInstantMessageToCharacter chat(cri); + ChatAvatarId characterName = chat.getCharacterName(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + + ChatAvatarId fromName; + fromName.gameCode = "SWG"; + fromName.cluster = ConfigChatServer::getClusterName(); + fromName.name = ChatServer::getChatInterface()->getChatName((*i)); + + ChatInstantMessageToClient msg(fromName, chat.getMessage(), chat.getOutOfBand()); + bool sent = ChatServer::getChatInterface()->sendMessageToPendingAvatar(characterName, msg); + if (!sent) + { + ChatServer::getChatInterface()->sendMessageToAvatar(characterName, msg); + } + + ChatOnSendInstantMessage response(chat.getSequence(), 0); + ChatServer::getChatInterface()->sendMessageToPendingAvatar(fromName, response); + return; + } + } + if(avatar) + { + cri = c.getByteStream().begin(); + + static const std::string gameType("SWG"); + + if(cm.isType("ChatDeleteAllPersistentMessages")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatDeleteAllPersistentMessages"); + ChatDeleteAllPersistentMessages chatDeleteAllPersistentMessages(cri); + ChatServer::deleteAllPersistentMessages(chatDeleteAllPersistentMessages.getSourceNetworkId(), chatDeleteAllPersistentMessages.getTargetNetworkId()); + } + else if(cm.isType("ChatInstantMessageToCharacter")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatInstantMessageToCharacter"); +//printf("ConnectionServerConnection -- ChatInstantMessageToCharacter\n"); + // deliver IM to character + ChatInstantMessageToCharacter chat(cri); + ChatAvatarId characterName = chat.getCharacterName(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + + ChatServer::sendInstantMessage(*i, chat.getSequence(), characterName, chat.getMessage(), chat.getOutOfBand()); + } + else if(cm.isType("ChatQueryRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatQueryRoom"); +//printf("ConnectionServerConnection -- ChatQueryRoom\n"); + ChatQueryRoom chat(cri); + ChatServer::queryRoom((*i), this, chat.getSequence(), chat.getRoomName()); + } + else if(cm.isType("ChatPersistentMessageToServer")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatPeristentMessageToServer"); +//printf("ConnectionServerConnection -- ChatPersistentMessageToServer\n"); + ChatPersistentMessageToServer chat(cri); + ChatAvatarId characterName = chat.getToCharacterName(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + + ChatServer::sendPersistentMessage((*i), chat.getSequence(), characterName, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); + } + else if(cm.isType("ChatRequestPersistentMessage")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatRequestPersistentMessage"); +//printf("ConnectionServerConnection -- ChatRequestPersistentMessage\n"); + ChatRequestPersistentMessage chat(cri); + ChatServer::requestPersistentMessage((*i), chat.getSequence(), chat.getMessageId()); + } + else if(cm.isType("ChatDeletePersistentMessage")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatDeletePersistentMessage"); +//printf("ConnectionServerConnection -- ChatDeletePersistentMessage\n"); + ChatDeletePersistentMessage chat(cri); + ChatServer::deletePersistentMessage((*i), chat.getMessageId()); + } + else if(cm.isType("ChatCreateRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatCreateRoom"); +//printf("ConnectionServerConnection -- ChatCreateRoom\n"); + ChatCreateRoom chat(cri); + ChatServer::createRoom((*i), chat.getSequence(), chat.getRoomName(), chat.getIsModerated(), chat.getIsPublic(), chat.getRoomTitle()); + } + else if(cm.isType("ChatEnterRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatEnterRoom"); +//printf("ConnectionServerConnection -- ChatEnterRoom\n"); + // entering a room by name + ChatEnterRoom chat(cri); + ChatServer::enterRoom((*i), chat.getSequence(), chat.getRoomName()); + } + else if(cm.isType("ChatEnterRoomById")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatEnterRoomById"); +//printf("ConnectionServerConnection -- ChatEnterRoomById\n"); + // entering a room by room id + ChatEnterRoomById chat(cri); + ChatServer::enterRoom((*i), chat.getSequence(), chat.getRoomId()); + + } + else if(cm.isType("ChatSendToRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatSendToRoom"); +//printf("ConnectionServerConnection -- ChatSendToRoom\n"); + ChatSendToRoom chat(cri); + ChatServer::sendRoomMessage((*i), chat.getSequence(), chat.getRoomId(), chat.getMessage(), chat.getOutOfBand()); + } + else if(cm.isType("ChatRequestRoomList")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatRequestRoomList"); +//printf("ConnectionServerConnection -- ChatRequestRoomList\n"); + ChatServer::requestRoomList((*i), this); + } + else if(cm.isType("ChatDestroyRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatDestroyRoom"); +//printf("ConnectionServerConnection -- ChatDestroyRoom\n"); + ChatDestroyRoom chat(cri); + ChatServer::destroyRoom((*i), chat.getSequence(), chat.getRoomId()); + } + else if(cm.isType("ChatAddModeratorToRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatAddModeratorToRoom"); +//printf("ConnectionServerConnection -- ChatAddModeratorToRoom\n"); + ChatAddModeratorToRoom chat(cri); + ChatServer::addModeratorToRoom(chat.getSequenceId(), (*i), chat.getAvatarId(), chat.getRoomName()); + } + else if(cm.isType("ChatRemoveModeratorFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatRemoveModeratorFromRoom"); +//printf("ConnectionServerConnection -- ChatREmoveModeratorFromRoom\n"); + ChatRemoveModeratorFromRoom chat(cri); + ChatAvatarId characterName = chat.getAvatarId(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::removeModeratorFromRoom(chat.getSequenceId(), (*i), characterName, chat.getRoomName()); + } + else if(cm.isType("ChatRemoveAvatarFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatRemoveAvatarFromRoom"); +//printf("ConnectionServerConnection -- ChatREmoveAvatarFromRoom\n"); + ChatRemoveAvatarFromRoom chat(cri); + ChatServer::removeAvatarFromRoom((*i), chat.getAvatarId(), chat.getRoomName()); + } + else if(cm.isType("ChatKickAvatarFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatKickAvatarFromRoom"); +//printf("ConnectionServerConnection -- ChatKickAvatarFromRoom\n"); + ChatKickAvatarFromRoom chat(cri); + ChatServer::kickAvatarFromRoom((*i), chat.getAvatarId(), chat.getRoomName()); + } + else if(cm.isType("ChatAddFriend")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatAddFriend"); +//printf("ConnectionServerConnection -- ChatAddFriend\n"); + ChatAddFriend chat(ri); + ChatServer::addFriend((*i), chat.getSequence(), chat.getCharacterName()); + } + else if(cm.isType("ChatInviteAvatarToRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatInviteAvatarToRoom"); +//printf("ConnectionServerConnection -- ChatInviteAvatarToRoom\n"); + ChatInviteAvatarToRoom chat(cri); + ChatAvatarId characterName = chat.getAvatarId(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::invite((*i), characterName, chat.getRoomName()); + } + else if(cm.isType("ChatUninviteFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatUninviteFromRoom"); +//printf("ConnectionServerConnection -- ChatUninviteAvatarToRoom\n"); + ChatUninviteFromRoom chat(cri); + ChatAvatarId characterName = chat.getAvatar(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::uninvite((*i), chat.getSequence(), characterName, chat.getRoomName()); + } + else if(cm.isType("ChatBanAvatarFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatBanAvatarFromRoom"); +//printf("ConnectionServerConnection -- ChatBanAvatarFromRoom\n"); + ChatBanAvatarFromRoom chat(cri); + ChatAvatarId characterName = chat.getAvatarId(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::banFromRoom(chat.getSequence(), (*i), characterName, chat.getRoomName()); + } + else if(cm.isType("ChatUnbanAvatarFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - ChatUnbanAvatarFromRoom"); +//printf("ConnectionServerConnection -- ChatUnbanAvatarFromRoom\n"); + ChatUnbanAvatarFromRoom chat(cri); + ChatAvatarId characterName = chat.getAvatarId(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::unbanFromRoom(chat.getSequence(), (*i), characterName, chat.getRoomName()); + } + else if(cm.isType("VerifyPlayerNameMessage")) + { + PROFILER_AUTO_BLOCK_DEFINE("ConnectionServer - VerifyPlayerNameMessage"); + VerifyPlayerNameMessage message(cri); + + bool const valid = ChatServer::isValidChatAvatarName(message.getPlayerName()); + + VerifyPlayerNameResponseMessage response(valid, message.getPlayerName()); + + ChatServer::fileLog(true, "ConnectionServerConnection", "onReceive() message(VerifyPlayerNameMessage) name(%s) valid(%s)", Unicode::wideToNarrow(message.getPlayerName()).c_str(), (valid ? "yes" : "no")); + + sendToClient(message.getSourceNetworkId(), response); + } + + //messages to allow personal channels + else if (cm.isType(VoiceChatRequestPersonalChannel::cms_name)) + { + VoiceChatRequestPersonalChannel message(cri); + + std::string userName, playerName; + if(ChatServer::getVoiceChatLoginInfoFromId(message.getOwner(), userName, playerName)) + { + std::list modlist; + modlist.push_back(userName); + + if(message.getShouldCreate()) + { + // 400 is the current vivox channel size limit when this was written + ChatServer::requestGetChannel(message.getOwner(), ChatServer::getVChatInterface()->buildPersonalChannelName(message.getOwner()), false, false, 400, modlist); + } + else + { + ChatServer::getVChatInterface()->sendChannelData(message.getOwner(), ChatServer::getVChatInterface()->buildPersonalChannelName(message.getOwner()), "", true, true); + } + } + //@TODO: error message? + } + else if (cm.isType(VoiceChatInvite::cms_name)) + { + VoiceChatInvite message(cri); + if(message.getChannelName() == ChatServer::getVChatInterface()->buildPersonalChannelName(message.getRequester())) + { + NetworkId targetId = message.getInviteeId(); + std::string const & targetName = message.getInviteeName(); + if(targetId.isValid() || + !targetName.empty() && ChatServer::getVoiceChatLoginInfoFromName(targetName, targetId)) + { + ChatServer::requestInvitePlayerToChannel(message.getRequester(), targetId, message.getChannelName()); + } + } + //@TODO: error message? + } + else if (cm.isType(VoiceChatKick::cms_name)) + { + VoiceChatKick message(cri); + if(message.getChannelName() == ChatServer::getVChatInterface()->buildPersonalChannelName(message.getRequester())) + { + NetworkId targetId = message.getKickeeId(); + std::string const & targetName = message.getKickeeName(); + if(targetId.isValid() || + !targetName.empty() && ChatServer::getVoiceChatLoginInfoFromName(targetName, targetId)) + { + ChatServer::requestKickPlayerFromChannel(message.getRequester(), targetId, message.getChannelName()); + } + } + //@TODO: error message? + } + else if (cm.isType(VoiceChatRequestChannelInfo::cms_name)) + { + VoiceChatRequestChannelInfo message(cri); + ChatServer::requestChannelInfo(message.getRequester(), message.getChannelName()); + } + } + + // @todo : how is a message sent to anyone with a station account? + + else + { + // defer until avatar is connected to chat backend + ChatServer::deferChatMessageFor((*i), message); + } + + } + } + +} + +//----------------------------------------------------------------------- + +void ConnectionServerConnection::sendToClient(const NetworkId & clientId, const GameNetworkMessage & message) +{ + static std::vector v; + v.clear(); + v.push_back(clientId); + GameClientMessage msg(v, true, message); + ServerConnection::send(msg, true); +} + + +//----------------------------------------------------------------------- + +void ConnectionServerConnection::addAvatar(ChatServerAvatarOwner * a) +{ + m_avatars.insert(a); +} + +//----------------------------------------------------------------------- + +void ConnectionServerConnection::removeAvatar(ChatServerAvatarOwner * a) +{ + std::set::iterator f = m_avatars.find(a); + if(f != m_avatars.end()) + m_avatars.erase(f); +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.h b/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.h new file mode 100644 index 00000000..cf6866b6 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.h @@ -0,0 +1,41 @@ +// ConnectionServerConnection.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_ConnectionServerConnection_H +#define _INCLUDED_ConnectionServerConnection_H + +//----------------------------------------------------------------------- + +#include "serverUtility/ServerConnection.h" +#include + +//----------------------------------------------------------------------- + +class ChatServerAvatarOwner; +class GameNetworkMessage; + +class ConnectionServerConnection : public ServerConnection +{ +public: + ConnectionServerConnection(const std::string & remoteAddress, const unsigned short remotePort); + ~ConnectionServerConnection(); + + void addAvatar (ChatServerAvatarOwner * avatar); + void onConnectionClosed (); + void onConnectionOpened (); + void onReceive (const Archive::ByteStream & bs); + void removeAvatar (ChatServerAvatarOwner * avatar); + void sendToClient (const NetworkId & clientId, const GameNetworkMessage & message); + +private: + ConnectionServerConnection & operator = (const ConnectionServerConnection & rhs); + ConnectionServerConnection(const ConnectionServerConnection & source); + + std::set m_avatars; + +}; //lint !e1712 default constructor not defined for class + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_ConnectionServerConnection_H diff --git a/engine/server/application/ChatServer/src/shared/CustomerServiceServerConnection.cpp b/engine/server/application/ChatServer/src/shared/CustomerServiceServerConnection.cpp new file mode 100644 index 00000000..7ca8d87e --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/CustomerServiceServerConnection.cpp @@ -0,0 +1,61 @@ +// CustomerServiceServerConnection.cpp +// Copyright 2004, Sony Online Entertainment Inc., all rights reserved. + +#include "FirstChatServer.h" +#include "CustomerServiceServerConnection.h" + +#include "ChatInterface.h" +#include "ChatServer.h" +#include "sharedLog/Log.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetworkMessages/ChatRequestLog.h" +#include "sharedNetworkMessages/ChatOnRequestLog.h" + +//---------------------------------------------------------------------- +CustomerServiceServerConnection::CustomerServiceServerConnection(const std::string & a, const unsigned short p) +: ServerConnection(a, p, NetworkSetupData()) +{ + ChatServer::fileLog(true, "CSServerConnection", "Connection created...listening on (%s:%d)", a.c_str(), static_cast(p)); +} + +//----------------------------------------------------------------------- +CustomerServiceServerConnection::~CustomerServiceServerConnection() +{ +} + +//----------------------------------------------------------------------- +void CustomerServiceServerConnection::onConnectionClosed() +{ + ChatServer::fileLog(true, "CSServerConnection", "onConnectionClosed()"); + + ChatServer::clearCustomerServiceServerConnection(); +} + +//----------------------------------------------------------------------- +void CustomerServiceServerConnection::onConnectionOpened() +{ + ChatServer::fileLog(true, "CSServerConnection", "onConnectionOpened()"); +} + +//----------------------------------------------------------------------- +void CustomerServiceServerConnection::onReceive(const Archive::ByteStream & message) +{ + Archive::ReadIterator ri = message.begin(); + GameNetworkMessage gameNetworkMessage(ri); + + if (gameNetworkMessage.isType("ChatRequestLog")) + { + ri = message.begin(); + ChatRequestLog chatRequestLog(ri); + + std::vector chatLog; + ChatServer::getChatLog(chatRequestLog.getPlayer(), chatLog); + + ChatServer::fileLog(true, "CSServerConnection", "onReceive() message(ChatRequestLog) player(%s) sequenceId(%i) chatLogSize(%i)", Unicode::wideToNarrow(chatRequestLog.getPlayer()).c_str(), chatRequestLog.getSequence(), chatLog.size()); + + ChatOnRequestLog chatOnRequestLog(chatRequestLog.getSequence(), chatLog); + send(chatOnRequestLog, true); + } +} + +//----------------------------------------------------------------------- diff --git a/engine/server/application/ChatServer/src/shared/CustomerServiceServerConnection.h b/engine/server/application/ChatServer/src/shared/CustomerServiceServerConnection.h new file mode 100644 index 00000000..66c0691d --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/CustomerServiceServerConnection.h @@ -0,0 +1,33 @@ +// CustomerServiceServerConnection.h +// Copyright 2004, Sony Online Entertainment Inc., all rights reserved. + +#ifndef INCLUDED_CustomerServiceServerConnection_H +#define INCLUDED_CustomerServiceServerConnection_H + +//----------------------------------------------------------------------- + +#include "serverUtility/ServerConnection.h" + +//----------------------------------------------------------------------- + +class CustomerServiceServerConnection : public ServerConnection +{ +public: + + CustomerServiceServerConnection(const std::string & remoteAddress, const unsigned short remotePort); + virtual ~CustomerServiceServerConnection(); + + void onConnectionClosed(); + void onConnectionOpened(); + void onReceive(const Archive::ByteStream & bs); + +private: + + CustomerServiceServerConnection(); + CustomerServiceServerConnection & operator = (const CustomerServiceServerConnection & rhs); + CustomerServiceServerConnection(const CustomerServiceServerConnection & source); +}; + +//----------------------------------------------------------------------- + +#endif // INCLUDED_CustomerServiceServerConnection_H diff --git a/engine/server/application/ChatServer/src/shared/FirstChatServer.cpp b/engine/server/application/ChatServer/src/shared/FirstChatServer.cpp new file mode 100644 index 00000000..22094104 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/FirstChatServer.cpp @@ -0,0 +1,7 @@ +// FirstChatServer.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" + diff --git a/engine/server/application/ChatServer/src/shared/FirstChatServer.h b/engine/server/application/ChatServer/src/shared/FirstChatServer.h new file mode 100644 index 00000000..9f323402 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/FirstChatServer.h @@ -0,0 +1,35 @@ +// FirstChatServer.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_FirstChatServer_H +#define _INCLUDED_FirstChatServer_H + +//----------------------------------------------------------------------- + +#pragma warning ( disable : 4702 ) + +#include "sharedFoundation/FirstSharedFoundation.h" + +// hack for gcc 3.4.x-3.5.0 bug +#if defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ > 3) +class TransferCharacterData; +namespace Archive +{ + class ByteStream; + class ReadIterator; + void get(ReadIterator &, TransferCharacterData &); + void put(ByteStream &, TransferCharacterData const &); +} +#endif + +#include "Archive/ByteStream.h" +#include "sharedFoundation/NetworkId.h" +#include "sharedNetwork/Connection.h" +#include "ChatAPI/ChatAPI.h" +#include +#include + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_FirstChatServer_H diff --git a/engine/server/application/ChatServer/src/shared/GameServerConnection.cpp b/engine/server/application/ChatServer/src/shared/GameServerConnection.cpp new file mode 100644 index 00000000..66ff3951 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/GameServerConnection.cpp @@ -0,0 +1,397 @@ +// GameServerConnection.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "ChatInterface.h" +#include "ChatServer.h" +#include "ConfigChatServer.h" +#include "GameServerConnection.h" +#include "VChatInterface.h" +#include "sharedDebug/Profiler.h" +#include "sharedLog/Log.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include "sharedNetworkMessages/ChatAvatarIdArchive.h" +#include "sharedNetworkMessages/ChatChangeFriendStatus.h" +#include "sharedNetworkMessages/ChatChangeIgnoreStatus.h" +#include "sharedNetworkMessages/ChatCreateRoom.h" +#include "sharedNetworkMessages/ChatDeleteAllPersistentMessages.h" +#include "sharedNetworkMessages/ChatDestroyRoomByName.h" +#include "sharedNetworkMessages/ChatDestroyRoomByName.h" +#include "sharedNetworkMessages/ChatGetFriendsList.h" +#include "sharedNetworkMessages/ChatGetIgnoreList.h" +#include "sharedNetworkMessages/ChatInviteAvatarToRoom.h" +#include "sharedNetworkMessages/ChatInviteGroupMembersToRoom.h" +#include "sharedNetworkMessages/ChatMessageFromGame.h" +#include "sharedNetworkMessages/GameNetworkMessage.h" +#include "sharedNetworkMessages/ChatPutAvatarInRoom.h" +#include "sharedNetworkMessages/ChatRemoveAvatarFromRoom.h" +#include "sharedNetworkMessages/ChatOnRequestLog.h" +#include "sharedNetworkMessages/ChatRequestLog.h" +#include "sharedNetworkMessages/ChatUninviteFromRoom.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "UnicodeUtils.h" + +#include "sharedNetworkMessages/VoiceChatChannelInfo.h" +#include "sharedNetworkMessages/VoiceChatMiscMessages.h" + +#include +#include + +//---------------------------------------------------------------------- + +GameServerConnection::GameServerConnection(UdpConnectionMT * u, TcpClient * t) : +ServerConnection (u, t), +m_gameCode ("SWG"), //@todo: this class must not depend on SWG +m_connectionId(0) +{ + ChatServer::fileLog(true, "GameServerConnection", "Connection created...listening on (%s:%d)", getRemoteAddress().c_str(), static_cast(getRemotePort())); +} + +//----------------------------------------------------------------------- + +GameServerConnection::~GameServerConnection() +{ + if(ChatServer::instance().getGameServerConnectionFromId(m_connectionId)) + { + ChatServer::fileLog(true, "GameServerConnection", "~GameServerConnection still registered myID(%u) %p",m_connectionId, this); + } + else + { + ChatServer::fileLog(true, "GameServerConnection", "~GameServerConnection not registered anymore myID(%u) %p",m_connectionId, this); + } + + ChatServer::instance().unregisterGameServerConnection(m_connectionId); +} + +//----------------------------------------------------------------------- + +void GameServerConnection::onConnectionClosed() +{ + ChatServer::fileLog(true, "GameServerConnection", "onConnectionClosed() myID(%u) %p",m_connectionId, this); + + ChatServer::clearGameServerConnection(this); + ChatServer::instance().unregisterGameServerConnection(m_connectionId); +} + +//----------------------------------------------------------------------- + +void GameServerConnection::onConnectionOpened() +{ + if(m_connectionId == 0) + { + m_connectionId = ChatServer::instance().registerGameServerConnection(this); + ChatServer::fileLog(true, "GameServerConnection", "onConnectionOpened() new registration myID(%u) %p",m_connectionId, this); + } + else + { + ChatServer::fileLog(true, "GameServerConnection", "onConnectionOpened() ALREADY REGISTERED myID(%u) %p",m_connectionId, this); + } +} + +//----------------------------------------------------------------------- + +void GameServerConnection::onReceive(const Archive::ByteStream & message) +{ + Archive::ReadIterator ri = message.begin(); + GameNetworkMessage gameNetworkMessage(ri); + ri = message.begin(); + + static int count = 0; + if ((count % 10) == 0) + { + ChatServer::getChatInterface()->Process(); + } + ++count; + + //LOG("GameServerConnection", ("onReceive - %s", gameNetworkMessage.getCmdName().c_str())); + //DEBUG_REPORT_LOG(true, ("***ChatServ: GameServerConnection::onReceive() message(%s)\n", gameNetworkMessage.getCmdName().c_str())); + + if(gameNetworkMessage.isType("ChatDeleteAllPersistentMessages")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatDeleteAllPersistentMessages"); + ChatDeleteAllPersistentMessages chatDeleteAllPersistentMessages(ri); + ChatServer::deleteAllPersistentMessages(chatDeleteAllPersistentMessages.getSourceNetworkId(), chatDeleteAllPersistentMessages.getTargetNetworkId()); + } + else if(gameNetworkMessage.isType("ChatCreateRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatCreateRoom"); +//printf("GameServerConnection -- ChatCreateRoom\n"); + ChatCreateRoom chat(ri); + unsigned int sequence = chat.getSequence(); + ChatServer::addGameServerConnection(sequence, this); + ChatServer::createRoom(NetworkId::cms_invalid, sequence, chat.getRoomName(), chat.getIsModerated(), chat.getIsPublic(), chat.getRoomTitle()); + } + else if(gameNetworkMessage.isType("ChatRequestLog")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatRequestLog"); + ChatRequestLog chatRequestLog(ri); + std::vector chatLog; + ChatServer::getChatLog(chatRequestLog.getPlayer(), chatLog); + + ChatOnRequestLog chatOnRequestLog(chatRequestLog.getSequence(), chatLog); + + static Archive::ByteStream a; + a.clear(); + chatOnRequestLog.pack(a); + + (static_cast(this))->send(a, true); + } + else if(gameNetworkMessage.isType("ChatDestroyRoomByName")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatDestroyRoomByName"); +//printf("GameServerConnection -- ChatDestroyRoomByName\n"); + ChatDestroyRoomByName chat(ri); + ChatServer::destroyRoom(chat.getRoomPath()); + } + else if(gameNetworkMessage.isType("ChatPutAvatarInRoom")) + { +//printf("GameServerConnection -- ChatPutAvatarInRoom\n"); + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatPutAvatarInRoom"); + ChatPutAvatarInRoom chat(ri); + ChatAvatarId id; + id.cluster = ConfigChatServer::getClusterName(); + id.gameCode = m_gameCode; + id.name = chat.getAvatarName(); + size_t pos = id.name.find(" "); + if(pos != std::string::npos) + id.name = id.name.substr(0, pos); + ChatServer::enterRoom(id, chat.getRoomName(), chat.getForceCreate(), chat.getCreatePrivate()); + + } + else if(gameNetworkMessage.isType("ChatInviteAvatarToRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatInviteAvatarToRoom"); +//printf("GameServerConnection -- ChatInviteAvatarToRoom\n"); + ChatInviteAvatarToRoom chat(ri); + ChatAvatarId characterName = chat.getAvatarId(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::invite(NetworkId::cms_invalid, characterName, chat.getRoomName()); + } + else if(gameNetworkMessage.isType("ChatInviteGroupMembersToRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatInviteGroupMembersToRoom"); +//printf("GameServerConnection -- ChatInviteGroupMembersToRoom\n"); + ChatInviteGroupMembersToRoom chat(ri); + ChatServer::inviteGroupMembers(chat.getInvitorNetworkId(), chat.getGroupLeaderId(), chat.getRoomName(), chat.getInvitedMembers()); + } + else if(gameNetworkMessage.isType("ChatUninviteFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatUninviteAvatarToRoom"); +//printf("GameServerConnection -- ChatUninviteAvatarFromRoom\n"); + ChatUninviteFromRoom chat(ri); + ChatAvatarId characterName = chat.getAvatar(); + if(characterName.gameCode == "") + characterName.gameCode = "SWG"; + if(characterName.cluster == "") + characterName.cluster = ConfigChatServer::getClusterName(); + ChatServer::uninvite(ChatServer::getNetworkIdByAvatarId(characterName), chat.getSequence(), characterName, chat.getRoomName()); + } + else if (gameNetworkMessage.isType("ChatChangeFriendStatus")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatChangeFriendStatus"); +//printf("GameServerConnection -- ChatChangeFriendStatus\n"); + ChatChangeFriendStatus chat(ri); + + if (chat.getAdd()) + { + ChatServer::addFriend( + ChatServer::getNetworkIdByAvatarId(chat.getCharacterName()), + chat.getSequence(), chat.getFriendName()); + } + else + { + ChatServer::removeFriend( + ChatServer::getNetworkIdByAvatarId(chat.getCharacterName()), + chat.getSequence(), chat.getFriendName()); + } + + } + else if (gameNetworkMessage.isType("ChatGetFriendsList")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatGetFriendsList"); +//printf("GameServerConnection -- ChatGetFriendsList\n"); + ChatGetFriendsList chat(ri); + + ChatServer::getFriendsList(chat.getCharacterName()); + } + else if (gameNetworkMessage.isType("ChatChangeIgnoreStatus")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatChangeIgnoreStatus"); +//printf("GameServerConnection -- ChatChangeIgnoreStatus\n"); + ChatChangeIgnoreStatus chat(ri); + + if (chat.getIgnore()) + { + ChatServer::addIgnore( + ChatServer::getNetworkIdByAvatarId(chat.getCharacterName()), + chat.getSequence(), chat.getIgnoreName()); + } + else + { + ChatServer::removeIgnore( + ChatServer::getNetworkIdByAvatarId(chat.getCharacterName()), + chat.getSequence(), chat.getIgnoreName()); + } + + } + else if (gameNetworkMessage.isType("ChatGetIgnoreList")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatGetIgnoreList"); +//printf("GameServerConnection -- ChatGetIgnoreList\n"); + ChatGetIgnoreList chat(ri); + + ChatServer::getIgnoreList(chat.getCharacterName()); + } + else if(gameNetworkMessage.isType("ChatRemoveAvatarFromRoom")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatRemoveAvatarFromRoom"); +//printf("GameServerConnection -- ChatRemoveAvatarFromRoom\n"); + ChatRemoveAvatarFromRoom chat(ri); + ChatAvatarId id = chat.getAvatarId(); + size_t pos = id.name.find(" "); + if(pos != std::string::npos) + id.name = id.name.substr(0, pos); + ChatServer::removeAvatarFromRoom(id, chat.getRoomName()); + } + else if(gameNetworkMessage.isType("ChatMessageFromGame")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatMessageFromGame"); +//printf("GameServerConnection -- ChatMessageFromGame\n"); + ChatMessageFromGame chat(ri); + std::string recipient = chat.getTo(); + size_t pos = recipient.find(" "); + if (pos != std::string::npos) + { + recipient = recipient.substr(0, pos); + } + switch(chat.getMessageType()) + { + case ChatMessageFromGame::INSTANT: + { + ChatAvatarId from(chat.getFrom()); + if (from.cluster.empty()) + from.cluster = ConfigChatServer::getClusterName(); + if (from.gameCode.empty()) + from.gameCode = m_gameCode; + + ChatAvatarId to(recipient); + if (to.cluster.empty()) + to.cluster = ConfigChatServer::getClusterName(); + if (to.gameCode.empty()) + to.gameCode = m_gameCode; + + ChatServer::sendInstantMessage(from, to, chat.getMessage(), chat.getOutOfBand()); + } + break; + case ChatMessageFromGame::PERSISTENT: + { + ChatAvatarId from(chat.getFrom()); + if (from.cluster.empty()) + from.cluster = ConfigChatServer::getClusterName(); + if (from.gameCode.empty()) + from.gameCode = m_gameCode; + + ChatAvatarId to(recipient); + if (to.cluster.empty()) + to.cluster = ConfigChatServer::getClusterName(); + if (to.gameCode.empty()) + to.gameCode = m_gameCode; + + ChatServer::sendPersistentMessage(from, to, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); + } + break; + case ChatMessageFromGame::ROOM: + { + ChatAvatarId from(chat.getFrom()); + if (from.cluster.empty()) + from.cluster = ConfigChatServer::getClusterName(); + if (from.gameCode.empty()) + from.gameCode = m_gameCode; + + ChatServer::sendStandardRoomMessage(from, chat.getRoom(), chat.getMessage(), chat.getOutOfBand()); + } + break; + default: + REPORT_LOG(true, ("Unkown Game Chat Message type\n")); + break; + } + } + else if (gameNetworkMessage.isType("SetUnsquelchTime")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - SetUnsquelchTime"); +//printf("GameServerConnection -- SetUnsquelchTime\n"); + GenericValueTypeMessage > setUnsquelchTime(ri); + + ChatServer::setUnsquelchTime(setUnsquelchTime.getValue().first, static_cast(setUnsquelchTime.getValue().second)); + } + else if (gameNetworkMessage.isType("ChatStatisticsGS")) + { + PROFILER_AUTO_BLOCK_DEFINE("GameServerConnection - ChatStatisticsGS"); +//printf("GameServerConnection -- ChatStatisticsGS\n"); + GenericValueTypeMessage, int>, std::pair > > chatStatistics(ri); + + ChatServer::handleChatStatisticsFromGameServer(chatStatistics.getValue().first.first.first, static_cast(chatStatistics.getValue().first.first.second), static_cast(chatStatistics.getValue().first.second), chatStatistics.getValue().second.first, chatStatistics.getValue().second.second); + } + //it eats at my soul to participate in this elseif chain + else if (gameNetworkMessage.isType(VoiceChatGetChannel::cms_name)) + { + Archive::ReadIterator ri = message.begin(); + VoiceChatGetChannel createRoomMessage(ri); + std::list mods; + ChatServer::instance().requestGetChannel(ReturnAddress(m_connectionId),createRoomMessage.getRoomName(), createRoomMessage.getIsPublic(), createRoomMessage.getIsPersistant(), createRoomMessage.getLimit(), mods); + } + else if (gameNetworkMessage.isType(VoiceChatDeleteChannel::cms_name)) + { + Archive::ReadIterator ri = message.begin(); + VoiceChatDeleteChannel destroyRoomMessage(ri); + ChatServer::instance().requestDeleteChannel(ReturnAddress(m_connectionId),destroyRoomMessage.getRoomName()); + } + else if (gameNetworkMessage.isType(VoiceChatAddClientToChannel::cms_name)) + { + Archive::ReadIterator ri = message.begin(); + VoiceChatAddClientToChannel addMessage(ri); + ChatServer::instance().requestAddClientToChannel(addMessage.getClientId(), addMessage.getClientName(), addMessage.getChannelName(), addMessage.getForceShortlist()); + } + else if (gameNetworkMessage.isType(VoiceChatRemoveClientFromChannel::cms_name)) + { + Archive::ReadIterator ri = message.begin(); + VoiceChatRemoveClientFromChannel msg(ri); + ChatServer::instance().requestRemoveClientFromChannel(msg.getClientId(), msg.getClientName(), msg.getChannelName()); + } + else if (gameNetworkMessage.isType(VoiceChatChannelCommand::cms_name)) + { + Archive::ReadIterator ri = message.begin(); + VoiceChatChannelCommand msg(ri); + ChatServer::instance().requestChannelCommand(ReturnAddress(m_connectionId), msg.getSourceUserName(),msg.getTargetUserName(),msg.getChannelName(),msg.getCommandType(),msg.getBanTimeout()); + } + else if (gameNetworkMessage.isType("BroadcastGlobalChannel")) + { + Archive::ReadIterator ri = message.begin(); + + typedef std::pair, bool> PayloadType; + GenericValueTypeMessage msg(ri); + + PayloadType const & payload = msg.getValue(); + std::string const & channelName = payload.first.first; + std::string const & messageText = payload.first.second; + bool const & isRemove = payload.second; + + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer got BroadcastGlobalChannel on GameServerConnection chan(%s) text(%s) remove(%d)", + channelName.c_str(), messageText.c_str(), (isRemove?1:0))); + ChatServer::requestBroadcastChannelMessage(channelName, messageText, isRemove); + } + else if (gameNetworkMessage.isType("ChatDestroyAvatar")) + { + GenericValueTypeMessage const msg(ri); + ChatServer::getChatInterface()->DestroyAvatar(msg.getValue()); + } +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/ChatServer/src/shared/GameServerConnection.h b/engine/server/application/ChatServer/src/shared/GameServerConnection.h new file mode 100644 index 00000000..c5950342 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/GameServerConnection.h @@ -0,0 +1,36 @@ +// GameServerConnection.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_GameServerConnection_H +#define _INCLUDED_GameServerConnection_H + +//----------------------------------------------------------------------- + +#include "serverUtility/ServerConnection.h" + +//----------------------------------------------------------------------- + +class GameServerConnection : public ServerConnection +{ +public: + GameServerConnection(UdpConnectionMT *, TcpClient *); + virtual ~GameServerConnection(); + + void onConnectionClosed (); + void onConnectionOpened (); + void onReceive (const Archive::ByteStream & bs); + +private: + GameServerConnection(); + GameServerConnection & operator = (const GameServerConnection & rhs); + GameServerConnection(const GameServerConnection & source); + + std::string m_gameCode; + unsigned m_connectionId; + +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_GameServerConnection_H diff --git a/engine/server/application/ChatServer/src/shared/PlanetServerConnection.h b/engine/server/application/ChatServer/src/shared/PlanetServerConnection.h new file mode 100644 index 00000000..ff1bd04c --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/PlanetServerConnection.h @@ -0,0 +1,32 @@ +// PlanetServerConnection.h +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _INCLUDED_PlanetServerConnection_H +#define _INCLUDED_PlanetServerConnection_H + +//----------------------------------------------------------------------- + +#include "serverUtility/ServerConnection.h" + +//----------------------------------------------------------------------- + +class PlanetServerConnection : public ServerConnection +{ +public: + PlanetServerConnection(UdpConnectionMT *, TcpClient *); + virtual ~PlanetServerConnection(); + + void onConnectionClosed (); + void onConnectionOpened (); + void onReceive (const Archive::ByteStream & bs); + +private: + PlanetServerConnection(); + PlanetServerConnection & operator = (const PlanetServerConnection & rhs); + PlanetServerConnection(const PlanetServerConnection & source); +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_PlanetServerConnection_H diff --git a/engine/server/application/ChatServer/src/shared/PlanetServerServerConnection.cpp b/engine/server/application/ChatServer/src/shared/PlanetServerServerConnection.cpp new file mode 100644 index 00000000..32bd9452 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/PlanetServerServerConnection.cpp @@ -0,0 +1,42 @@ +// PlanetServerConnection.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "PlanetServerConnection.h" + +//----------------------------------------------------------------------- + +PlanetServerConnection::PlanetServerConnection(UdpConnectionMT * u, TcpClient * t) : +ServerConnection(u, t) +{ +} + +//----------------------------------------------------------------------- + +PlanetServerConnection::~PlanetServerConnection() +{ +} + +//----------------------------------------------------------------------- + +void PlanetServerConnection::onConnectionClosed() +{ +} + +//----------------------------------------------------------------------- + +void PlanetServerConnection::onConnectionOpened() +{ +} + +//----------------------------------------------------------------------- + +void PlanetServerConnection::onReceive(const Archive::ByteStream &) +{ +} + +//----------------------------------------------------------------------- + diff --git a/engine/server/application/ChatServer/src/shared/VChatInterface.cpp b/engine/server/application/ChatServer/src/shared/VChatInterface.cpp new file mode 100644 index 00000000..f0b96b3f --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/VChatInterface.cpp @@ -0,0 +1,915 @@ +//VChatInterface.cpp + +#include "FirstChatServer.h" +#include "VChatInterface.h" + +#include "ChatInterface.h" //included for toLower... +#include "ChatServer.h" +#include "ConfigChatServer.h" + +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedLog/Log.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/VoiceChatChannelInfo.h" +#include "sharedNetworkMessages/VoiceChatOnGetAccount.h" +#include "sharedNetworkMessages/VoiceChatMiscMessages.h" + +char const * const ms_logLable = "VChatInterface"; +std::string const ms_systemAvatarName("SYSTEM"); +static bool ms_voiceLoggingEnabled = false; +static unsigned const timeoutRetryLimit = 1; + + +//user structures + +//used for GetChannel calls +struct GetChannelInfoStruct +{ + ReturnAddress requester; + std::string channelName; + std::string password; + bool isPublic; + bool persistant; + std::list moderators; +}; + +struct DeleteChannelInfo +{ + ReturnAddress requester; + std::string channelName; +}; + +struct ChannelCommandInfo +{ + ReturnAddress requester; + std::string srcUserName; + std::string destUserName; + std::string destChannelAddress; + uint32 command; + uint32 banTimeout; +}; + +struct GetAccountInfo +{ + std::string avatarName; + NetworkId id; + unsigned suid; + unsigned failedAttempts; +}; + +//used for GetChannelInfo calls +struct GetChannelInfoInfo +{ + ReturnAddress requester; + std::string channelName; + bool isGlobalBroadcast; + std::string textMessage; +}; + + +VChatInterface::VChatInterface(const char * hostList) +: VChatAPI(hostList), + m_channelData(), + m_globalChannels(), + m_connected(false), + m_connectionFailedCount(0) +{ + ChatServer::fileLog(true, ms_logLable, "Creating interface hostlist=%s", hostList); + ms_voiceLoggingEnabled = ConfigChatServer::getVoiceChatLoggingEnabled(); +} + +VChatInterface::~VChatInterface() +{ + ChatServer::fileLog(true, ms_logLable, "Destroying interface"); +} + +std::string systemNameHelper() +{ + std::string temp; + VChatSystem::CreateUserName(ms_systemAvatarName, ConfigChatServer::getClusterName(), temp); + return temp; +} + +std::string const & VChatInterface::getSystemLoginName() +{ + static std::string const adminName (systemNameHelper()); + return adminName; +} + +std::string VChatInterface::buildPersonalChannelName(NetworkId const & ownerId) +{ + std::string ownerLogin, ownerPlayerName; + if(!ChatServer::getVoiceChatLoginInfoFromId(ownerId, ownerLogin, ownerPlayerName)) + { + ownerPlayerName = ownerId.getValueString(); + } + + std::string outstr = ConfigChatServer::getGameCode(); + outstr += "."; + outstr += ConfigChatServer::getClusterName(); + outstr += ".private."; + outstr += ownerPlayerName; + + return outstr; +} + + +bool VChatInterface::findChannelDataByName(std::string const & name, VChatSystem::Channel & data) +{ + ChannelDataMap::iterator i = m_channelData.find(toLower(name)); + if(i != m_channelData.end()) + { + data = i->second; + return true; + } + return false; +} + +void VChatInterface::setChannelData(VChatSystem::Channel const & data) +{ + m_channelData[toLower(data.m_channelName)] = data; +} + +bool VChatInterface::eraseChannelData(std::string const & name) +{ + ChannelDataMap::iterator i = m_channelData.find(toLower(name)); + if(i != m_channelData.end()) + { + m_channelData.erase(i); + return true; + } + return false; +} + +void VChatInterface::requestInvite(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestInvite roomName(%s) sourceId(%s) targetId(%s)", + channelName.c_str(), sourceId.getValueString().c_str(), targetId.getValueString().c_str()); + + std::string srcUserName, targetUserName, tmp; + if(ChatServer::getVoiceChatLoginInfoFromId(sourceId, srcUserName, tmp) && ChatServer::getVoiceChatLoginInfoFromId(targetId, targetUserName, tmp)) + { + //@TODO: if this fails clients will be confused + requestChannelCommand(ReturnAddress(), srcUserName, targetUserName, channelName, VChatSystem::COMMAND_ADD_ACL, 0); + } + + VChatSystem::Channel data; + if(findChannelDataByName(channelName,data)) + { + VoiceChatInvite msg(sourceId, targetId, channelName, data.m_channelURI); + ChatServer::sendToClient(targetId, msg); + } +} + +void VChatInterface::requestKick(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestKick roomName(%s) sourceId(%s) targetId(%s)", + channelName.c_str(), sourceId.getValueString().c_str(), targetId.getValueString().c_str()); + + std::string srcUserName, targetUserName, tmp; + if(ChatServer::getVoiceChatLoginInfoFromId(sourceId, srcUserName, tmp) && ChatServer::getVoiceChatLoginInfoFromId(targetId, targetUserName, tmp)) + { + //@TODO: if this fails clients will be confused + requestChannelCommand(ReturnAddress(), srcUserName, targetUserName, channelName, VChatSystem::COMMAND_DELETE_ACL, 0); + requestChannelCommand(ReturnAddress(), srcUserName, targetUserName, channelName, VChatSystem::COMMAND_HANGUP, 0); + } + + VChatSystem::Channel data; + if(findChannelDataByName(channelName,data)) + { + VoiceChatKick msg(sourceId, targetId, channelName); + ChatServer::sendToClient(targetId, msg); + } +} + + +bool VChatInterface::addClientToChannel(std::string const & roomName, NetworkId const & id, std::string const & playerName, bool forceShortlist) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "AddClientToChannel roomName(%s) clientId(%s) playerName(%s) forceShortlist(%i)", + roomName.c_str(), id.getValueString().c_str(), playerName.c_str(), forceShortlist ? 1 : 0); + + std::string userName, tmp; + if(!ChatServer::getVoiceChatLoginInfoFromId(id, userName, tmp)) + { + //try to recover with the passed in player name + VChatSystem::CreateUserName(playerName, ConfigChatServer::getClusterName(), userName); + } + requestChannelCommand(ReturnAddress(), "", userName, roomName, VChatSystem::COMMAND_ADD_ACL, 0); + + VChatSystem::Channel data; + if(findChannelDataByName(roomName,data)) + { + uint32 flags = forceShortlist ? VoiceChatChannelInfo::CIF_ForcedShortlist : VoiceChatChannelInfo::CIF_None; + VoiceChatChannelInfo msg(data.m_channelName, data.m_channelName, data.m_channelURI, data.m_channelPassword, "", flags); + ChatServer::sendToClient(id, msg); + + return true; + } + else + { + //no channel data... + //TODO: get the channel and add the client? + } + return false; +} + +bool VChatInterface::removeClientFromChannel(std::string const & roomName, NetworkId const & id, std::string const & playerName) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "removeClientFromChannel roomName(%s) clientId(%s) playerName(%s)", + roomName.c_str(), id.getValueString().c_str(), playerName.c_str()); + + std::string userName, tmp; + if(!ChatServer::getVoiceChatLoginInfoFromId(id, userName, tmp)) + { + //try to recover with the passed in player name + VChatSystem::CreateUserName(playerName, ConfigChatServer::getClusterName(), userName); + } + requestChannelCommand(ReturnAddress(), "", userName, roomName, VChatSystem::COMMAND_DELETE_ACL, 0); + requestChannelCommand(ReturnAddress(), "", userName, roomName, VChatSystem::COMMAND_HANGUP, 0); + + VChatSystem::Channel data; + if(findChannelDataByName(roomName,data)) + { + uint32 flags = VoiceChatChannelInfo::CIF_AutoJoin | VoiceChatChannelInfo::CIF_LeaveChannel; + VoiceChatChannelInfo msg(data.m_channelName, data.m_channelName, data.m_channelURI, data.m_channelPassword, "", flags); + ChatServer::sendToClient(id, msg); + + return true; + } + else + { + //we couldn't find the channel, but for a removal we just need the name anyhow + uint32 flags = VoiceChatChannelInfo::CIF_AutoJoin | VoiceChatChannelInfo::CIF_LeaveChannel | VoiceChatChannelInfo::CIF_ChannelDoesNotExist; + VoiceChatChannelInfo msg(roomName, roomName, "", "", "", flags); + ChatServer::sendToClient(id, msg); + } + return false; +} + +void VChatInterface::sendChannelData(ReturnAddress const & toWhom, std::string const & channelName, std::string const & messageText, bool targetIsModerator, bool notifyIfNoChannel, bool doGetChannelInfo) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "sendChannelData roomName(%s) target(%s)", + channelName.c_str(), toWhom.debugString().c_str()); + + VChatSystem::Channel data; + if(findChannelDataByName(channelName, data)) + { + uint32 flags = targetIsModerator ? VoiceChatChannelInfo::CIF_TargetModerator : VoiceChatChannelInfo::CIF_None; + VoiceChatChannelInfo msg(data.m_channelName, data.m_channelName, data.m_channelURI, data.m_channelPassword, messageText, flags); + ChatServer::instance().sendResponse(toWhom, msg); + } + else if (doGetChannelInfo) + { + requestChannelInfo(channelName, toWhom, false, messageText); + } + else if (notifyIfNoChannel) + { + uint32 flags = VoiceChatChannelInfo::CIF_ChannelDoesNotExist; + if(targetIsModerator) flags |= VoiceChatChannelInfo::CIF_TargetModerator; + VoiceChatChannelInfo msg(channelName, channelName, "", "", messageText, flags); + ChatServer::instance().sendResponse(toWhom, msg); + } +} + + +unsigned VChatInterface::requestGetChannel(const std::string &channelName, + const std::string &description, + const std::string &password, + unsigned limit, + bool isPublic, + bool persistent, + std::list const & moderators, + ReturnAddress const & requester) +{ + if(requester.type == ReturnAddress::RAT_gameserver && requester.gameServerId == 0) + { + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestGetChannel called with a bad return address(%s)", requester.debugString().c_str()); + } + + PendingGetChannelRequest newReq; + newReq.m_channelName = channelName; + newReq.m_description = description; + newReq.m_password = password; + newReq.m_limit = limit; + newReq.m_isPublic = isPublic; + newReq.m_persistent = persistent; + newReq.m_moderators = moderators; + newReq.m_requester = requester; + + PendingGetChannelRequestMap::iterator itr = m_pendingGetChannelRequests.find(channelName); + if(itr != m_pendingGetChannelRequests.end() && !itr->second.empty()) + { + itr->second.push_back(newReq); + return 0; + } + else + { + m_pendingGetChannelRequests[channelName].push_back(newReq); + } + + return internalGetChannel(channelName, description, password, limit, isPublic, persistent, moderators, requester); +} + +unsigned VChatInterface::internalGetChannel(const std::string &channelName, + const std::string &description, + const std::string &password, + unsigned limit, + bool isPublic, + bool persistent, + std::list const & moderators, + ReturnAddress const & requester) +{ + GetChannelInfoStruct * info = new GetChannelInfoStruct; + info->requester = requester; + info->channelName = channelName; + info->password = password; + info->isPublic = isPublic; + info->persistant = persistent; + info->moderators = moderators; + + //This is dumb. vchat should be consistant about qualifying channel names. + std::string shortName, server, game; + VChatSystem::GetChannelComponents(channelName,shortName,server,game); + DEBUG_WARNING(game != ConfigChatServer::getGameCode(),("Channel create request with mismatched game code %s (should be %s)", game.c_str(), ConfigChatServer::getGameCode())); + DEBUG_WARNING(server != ConfigChatServer::getClusterName(),("Channel create request with mismatched cluster name %s (should be %s)", server.c_str(), ConfigChatServer::getClusterName())); + + unsigned track = VChatAPI::GetChannelV2(shortName, game, server, description, password, limit, persistent, (void*)info); + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestGetChannel track(%d) requester(%s) name(%s) desc(%s) pass(%s) public(%s) persist(%s)", + track, requester.debugString().c_str(), channelName.c_str(), description.c_str(), password.c_str(), isPublic?"true":"false", persistent?"true":"false"); + + return track; +} + +unsigned VChatInterface::requestDeleteChannel(std::string const &channelName, ReturnAddress const & requester) +{ + if(requester.type == ReturnAddress::RAT_gameserver && requester.gameServerId == 0) + { + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestDeleteChannel called with a bad return address"); + } + + DeleteChannelInfo * info = new DeleteChannelInfo; + info->requester = requester; + info->channelName = channelName; + + //dumb + std::string shortName, server, game; + VChatSystem::GetChannelComponents(channelName,shortName,server,game); + DEBUG_WARNING(game != ConfigChatServer::getGameCode(),("Channel delete request with mismatched game code %s (should be %s)", game.c_str(), ConfigChatServer::getGameCode())); + DEBUG_WARNING(server != ConfigChatServer::getClusterName(),("Channel delete request with mismatched cluster name %s (should be %s)", server.c_str(), ConfigChatServer::getClusterName())); + + unsigned track = VChatAPI::DeleteChannel(shortName, game, server, info); + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestDeleteChannel track(%d) requester(%s) name(%s)", + track, requester.debugString().c_str(), channelName.c_str()); + + return track; +} + +unsigned VChatInterface::requestChannelCommand(ReturnAddress const & requester, + const std::string &srcUserName, + const std::string &destUserName, + const std::string &destChannelAddress, + unsigned command, + unsigned banTimeout) +{ + ChannelCommandInfo * info = new ChannelCommandInfo; + info->requester = requester; + info->srcUserName = srcUserName; + info->destUserName = destUserName; + info->destChannelAddress = destChannelAddress; + info->command = command; + info->banTimeout = banTimeout; + + if(command == VChatSystem::COMMAND_ADD_ACL) + checkForCharacterChannelAdd(destUserName, destChannelAddress); + else if (command == VChatSystem::COMMAND_DELETE_ACL) + checkForCharacterChannelRemove(destUserName, destChannelAddress); + + uint32 track = VChatAPI::ChannelCommand(srcUserName, destUserName, destChannelAddress, command, banTimeout, info); + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestChannelCommand: track(%u) returnAddress(%s) src(%s) dest(%s) chan(%s) cmd(%u) banTimeout(%u)", + track, requester.debugString().c_str(), srcUserName.c_str(), destUserName.c_str(), destChannelAddress.c_str(), command, banTimeout); + + return track; +} + +unsigned VChatInterface::requestConnectPlayer(unsigned suid, std::string const & characterName, NetworkId const & netId, unsigned previousAttempts) +{ + GetAccountInfo *info = new GetAccountInfo; + info->avatarName = characterName; + info->id = netId; + info->suid = suid; + info->failedAttempts = previousAttempts; + + uint32 track = VChatAPI::GetAccount(characterName, ConfigChatServer::getGameCode(), ConfigChatServer::getClusterName(), suid, 0,(void*)info); + ChatServer::fileLog(ms_voiceLoggingEnabled,ms_logLable, "requestConnectPlayer: track(%d) suid(%u) name(%s) netId(%s) failedAttempts(%u)", + track, suid, characterName.c_str(), netId.getValueString().c_str(), previousAttempts); + return track; +} + +unsigned VChatInterface::requestChannelInfo(std::string const & channelName, ReturnAddress const & requester, bool isGlobalBroadcast, std::string const & broadcastMessage) +{ + GetChannelInfoInfo *info = new GetChannelInfoInfo; + info->requester = requester; + info->channelName = channelName; + info->isGlobalBroadcast = isGlobalBroadcast; + info->textMessage = broadcastMessage; + + //split the name since we can't request any random channel... + std::string shortName, server, game; + VChatSystem::GetChannelComponents(info->channelName, shortName, server, game); + + uint32 track = VChatAPI::GetChannelInfo(shortName, game, server, (void*)info); + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "requestChannelInfo: track(%d) channel(%s) requester(%s)", + track, info->channelName.c_str(), info->requester.debugString().c_str()); + + return track; +} + +void VChatInterface::OnConnectionOpened( const char * address ) +{ + m_connected = true; + m_connectionFailedCount = 0; + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnConnectionOpened: %s", address); + + + uint32 track = VChatAPI::GetAccount(ms_systemAvatarName, ConfigChatServer::getGameCode(), ConfigChatServer::getClusterName(), 0, 0, NULL); + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "Creating system avatar: %s track(%u)", getSystemLoginName().c_str(), track); +} + +void VChatInterface::OnConnectionFailed( const char * address ) +{ + m_connected = false; + ++m_connectionFailedCount; + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnConnectionFailed: %s failedCount(%d)", + address, m_connectionFailedCount); +} + +void VChatInterface::OnConnectionClosed( const char * address, const char * reason ) +{ + m_connected = false; + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnConnectionClosed: %s, %s", address, reason); +} + +void VChatInterface::OnConnectionShutdownNotified( const char * address, unsigned outstandingRequests ) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnConnectionShutdownNotified: address: %s, outstanding requests: %u", address, outstandingRequests); +} + +void VChatInterface::OnGetAccount(unsigned track, unsigned result, unsigned userID, unsigned accountID, + const std::string &voicePassword, const std::string &encodedVoiceAccount, + const std::string &URI, void *user) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnGetAccount() track(%u) result(%u) userID(%u) accountID(%u) password(%s) encoded(%s) uri(%s)", + track, result, userID, accountID, voicePassword.c_str(), encodedVoiceAccount.c_str(), URI.c_str()); + + GetAccountInfo *info = (GetAccountInfo *)user; + if(!info) + { + return; + } + + if (result == VChatSystem::RESULT_TIMEOUT) + { + if(info->failedAttempts < timeoutRetryLimit) + { + requestConnectPlayer(info->suid,info->avatarName,info->id, info->failedAttempts+1); + delete info; + info = NULL; + return; + } + } + + unsigned msgResult = result == VChatSystem::RESULT_SUCCESS ? VoiceChatOnGetAccount::GAR_SUCCESS : VoiceChatOnGetAccount::GAR_FAILURE; + + ChatServer::voiceChatGotLoginInfo(info->id, encodedVoiceAccount, info->avatarName); + + VoiceChatOnGetAccount const msg(msgResult, encodedVoiceAccount, voicePassword, URI); + ChatServer::sendToClient(info->id, msg); + + //send the private channel if it exists (but don't create it at this point) + std::list modlist; + modlist.push_back(encodedVoiceAccount); + sendChannelData(info->id, buildPersonalChannelName(info->id), "", true, false, false); + + //send the current global channels + for(GlobalChannelMap::const_iterator i = m_globalChannels.begin(); i != m_globalChannels.end(); ++i) + { + sendChannelData(info->id, (*i).first, (*i).second, false, false, true); + } + + delete info; + info = NULL; +} + +void VChatInterface::OnGetChannelV2(unsigned track, unsigned result, + const std::string &channelName, const std::string &channelURI, + unsigned channelID, unsigned isNewChannel, void *user) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnGetChannel: track(%u) result(%u) chanName(%s) chanURI(%s) chanID(%d)", + track, result, channelName.c_str(), channelURI.c_str(), channelID); + + GetChannelInfoStruct * info = (GetChannelInfoStruct*)user; + if (info) + { + bool success = (result == VChatSystem::RESULT_SUCCESS); + + //we might have gotten good data even if creation failed...interesting... + VChatSystem::Channel data; + if (!channelURI.empty()) + { + + // If a channel is persisted, we want to add it to our character channel list. Currently the only persisted channel in SWG is guilds. + if(info->persistant) + { + // Do we already have this channel on record? + VoiceChannelIdMap::iterator iter = m_voiceChatChannelNameToNetworkIdMap.find(toLower(channelName)); + if(iter == m_voiceChatChannelNameToNetworkIdMap.end()) + { + // Create a new record for this channel. + m_voiceChatChannelNameToNetworkIdMap.insert(std::make_pair(toLower(channelName), std::vector())); + } + } + + //if this is a newly created channel add the system avatar to it + if (isNewChannel) + { + requestChannelCommand(ReturnAddress(), "", getSystemLoginName(), channelName, VChatSystem::COMMAND_ADD_ACL, 0); + } + + //Always add the moderators just in case something failed in the past and we are now in a bad state + for(std::list::const_iterator i = info->moderators.begin(); i != info->moderators.end(); ++i) + { + requestChannelCommand(ReturnAddress(), "", *i, channelName, VChatSystem::COMMAND_ADD_MODERATOR, 0); + requestChannelCommand(ReturnAddress(), "", *i, channelName, VChatSystem::COMMAND_ADD_ACL, 0); + } + + data.m_channelName = channelName; + data.m_channelPassword = info->password; + data.m_channelURI = channelURI; + data.m_channelID = channelID; + setChannelData(data); + } + + VoiceChatOnGetChannel response(channelName, channelURI, info->password, info->isPublic, info->persistant, success); + + ChatServer::instance().sendResponse(info->requester, response); + + delete info; + } + + //check for any queued requests for this channel so we can fire them off now + PendingGetChannelRequestMap::iterator itr = m_pendingGetChannelRequests.find(channelName); + if(itr != m_pendingGetChannelRequests.end()) + { + //If we don't make it in here then something is very messed up in the request list as + // any request that is outstanding should be the front of the list. + + std::list & thelist = itr->second; + + if(!thelist.empty()) + { + //We should always hit this block. If we didn't, something is VERY wrong. + thelist.pop_front(); + } + else + WARNING(true, ("OnGetChannelV2: Received a response for a channel that has no pending request! This is bad!!!")); + + std::list::iterator nextItr = thelist.begin(); + if(nextItr != thelist.end()) + { + PendingGetChannelRequest const & req = *nextItr; + internalGetChannel(req.m_channelName, req.m_description, req.m_password, req.m_limit, req.m_isPublic, req.m_persistent, req.m_moderators, req.m_requester); + } + + if(thelist.empty()) + { + m_pendingGetChannelRequests.erase(itr); + } + } + else + WARNING(true, ("OnGetChannelV2: Received a response for a channel that isn't in our pending request map! BAD!")); +} + +void VChatInterface::OnChannelCommand(unsigned track, unsigned result, void *user) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnChannelCommand: track(%u) result(%u)", track, result); + + + ChannelCommandInfo * info = (ChannelCommandInfo*)user; + if(info) + { + VoiceChatOnChannelCommand response(info->srcUserName,info->destUserName,info->destChannelAddress,info->command,info->banTimeout,result); + ChatServer::instance().sendResponse(info->requester, response); + + delete info; + } +} + +void VChatInterface::OnGetAllChannels(unsigned track, unsigned result, const VChatSystem::ChannelVec_t & channels, void *user) +{ + UNREF(user); + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "====OnGetAllChannels==== track(%u) count(%u)", track, channels.size()); + + static uint32 failedCount = 0; + + if(result == VChatSystem::RESULT_SUCCESS) + { + failedCount = 0; + m_channelData.clear(); + + for(VChatSystem::ChannelVec_t::const_iterator i = channels.begin(); i != channels.end(); ++i) + { + VChatSystem::Channel const & data = *i; + setChannelData(data); + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "name(%s) uri(%s) pass(%s) id(%d) type(%d)", + data.m_channelName.c_str(), data.m_channelURI.c_str(), data.m_channelPassword.c_str(), data.m_channelID, data.m_channelType); + } + } + else + { + bool shouldRetry = result == VChatSystem::RESULT_TIMEOUT && failedCount < timeoutRetryLimit; + + ++failedCount; + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "failed, code(%u) count(%d) retry(%s)", result, failedCount, shouldRetry?"yes":"no"); + + if(shouldRetry) + { + GetAllChannels(NULL); + } + } + + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "========================"); +} + +void VChatInterface::OnDeleteChannel(unsigned track, unsigned result, void *user) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnDeleteChannel: track(%u) result(%u)", track, result); + + DeleteChannelInfo * info = (DeleteChannelInfo*)user; + if(info) + { + //TODO: send the response + eraseChannelData(info->channelName); + + delete info; + } +} + +void VChatInterface::OnGetChannelInfo(unsigned track, unsigned result, const std::string & channelName, + const std::string & channelURI, unsigned channelID, void * user) +{ + ChatServer::fileLog(ms_voiceLoggingEnabled, ms_logLable, "OnGetChannelInfo: track(%u) result(%u) chanName(%s) chanURI(%s) chanID(%d)", + track, result, channelName.c_str(), channelURI.c_str(), channelID); + + GetChannelInfoInfo * info = (GetChannelInfoInfo*)user; + if(info) + { + bool const channelExists = result == VChatSystem::RESULT_SUCCESS; //? + + uint32 flags = channelExists ? VoiceChatChannelInfo::CIF_None : VoiceChatChannelInfo::CIF_ChannelDoesNotExist; + + VoiceChatChannelInfo msg (channelName, channelName, channelURI, "", info->textMessage, flags); + + if(info->isGlobalBroadcast) + { + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer: sending to all clients chan(%s) text(%s)", channelName.c_str(), info->textMessage.c_str())); + ChatServer::instance().sendToAllConnectionServers(msg); + } + else + { + ChatServer::instance().sendResponse(info->requester, msg); + } + + // cache the channel data + if(channelExists) + { + VChatSystem::Channel data; + data.m_channelName = channelName; + data.m_channelPassword = ""; // none of the channels have passwords at this point so this is a safe assumption + data.m_channelURI = channelURI; + data.m_channelID = channelID; + setChannelData(data); + } + + delete info; + info = 0; + } +} + + +void VChatInterface::broadcastGlobalChannelMessage(std::string const & channelName, std::string const & textMessage, bool isRemove) +{ + if(channelName.empty()) + { + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer: no channel, sending text only message chan(%s) text(%s) remove(%d)", + channelName.c_str(), textMessage.c_str(),(isRemove?1:0))); + GenericValueTypeMessage msg("VCBroadcastMessage",textMessage); + ChatServer::instance().sendToAllConnectionServers(msg); + } + else + { + GlobalChannelMap::iterator entryItr = m_globalChannels.find(channelName); + + if(entryItr == m_globalChannels.end()) + { + if(!isRemove) + { + m_globalChannels.insert(std::make_pair(channelName, textMessage)); + } + } + else + { + if(isRemove) + { + m_globalChannels.erase(entryItr); + } + } + + VChatSystem::Channel data; + if(findChannelDataByName(channelName, data)) + { + uint32 flags = isRemove ? VoiceChatChannelInfo::CIF_LeaveChannel | VoiceChatChannelInfo::CIF_AutoJoin : VoiceChatChannelInfo::CIF_None; + VoiceChatChannelInfo msg (data.m_channelName, data.m_channelName, data.m_channelURI, data.m_channelPassword, textMessage, flags); + + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer found channel data. sending to all clients chan(%s) text(%s) remove(%d)", + channelName.c_str(), textMessage.c_str(),(isRemove?1:0))); + ChatServer::instance().sendToAllConnectionServers(msg); + } + else + { + if(isRemove) + { + uint32 flags = VoiceChatChannelInfo::CIF_LeaveChannel | VoiceChatChannelInfo::CIF_AutoJoin; + VoiceChatChannelInfo msg (channelName, channelName, "", "", textMessage, flags); + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer: didn't find channel data sending remove to all clients chan(%s) text(%s)", channelName.c_str(), textMessage.c_str())); + ChatServer::instance().sendToAllConnectionServers(msg); + } + else + { + LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer: didn't find channel data asking vchat for channel chan(%s) text(%s)", channelName.c_str(), textMessage.c_str())); + requestChannelInfo(channelName, ReturnAddress(), true, textMessage); + } + + } + } +} + +void VChatInterface::OnAddCharacterChannel(unsigned int /*track*/, unsigned int /*result*/, void * /*user*/) +{ + +} + +void VChatInterface::OnRemoveCharacterChannel(unsigned int /*track*/, unsigned int /*result*/, void * /*user*/) +{ + +} + +void VChatInterface::OnGetCharacterChannel(unsigned int /*track*/, unsigned int /*result*/, const VChatSystem::CharacterChannelVec_t & /*characterChannels*/, void * /*user*/) +{ + +} + +void VChatInterface::OnUpdateCharacterChannel(unsigned int /*track*/, unsigned int /*result*/, void * /*user*/) +{ + +} + +void VChatInterface::checkForCharacterChannelAdd(std::string const & name, std::string const & channelName) +{ + + // No persistant channels right now. Skip the add check. + if(m_voiceChatChannelNameToNetworkIdMap.empty()) + return; + + // Can we get a valid player OID? + NetworkId playerOID = NetworkId::cms_invalid; + if(ChatServer::getVoiceChatLoginInfoFromLoginName(name, playerOID) && playerOID != NetworkId::cms_invalid) + { + // Are we tracking this channel? + if(m_voiceChatChannelNameToNetworkIdMap.find(toLower(channelName)) == m_voiceChatChannelNameToNetworkIdMap.end()) + return; + + VChatSystem::Channel data; + if(findChannelDataByName(channelName, data)) // See if we can get valid channel data. + { + const ChatAvatar * avatar = ChatServer::getAvatarByNetworkId(playerOID); + if(avatar) + { + // Store the OIDs of players in our channel. + bool insert = true; + VoiceChannelIdMap::iterator iter = m_voiceChatChannelNameToNetworkIdMap.find(toLower(channelName)); + if(iter != m_voiceChatChannelNameToNetworkIdMap.end()) + { + // do we have the OID on record? + std::vector::iterator OIDIter = (*iter).second.begin(); + for(; OIDIter != (*iter).second.end(); ++OIDIter) // Holy crap does this suck. + { + if((*OIDIter) == playerOID) + { + // Yup. + insert = false; + break; + } + } + + if((*iter).second.empty()) + insert = true; + + if(insert) // Nope, add it and send off the create character channel message. + { + AddCharacterChannel(avatar->getUserID(), + avatar->getAvatarID(), + std::string(avatar->getName().c_str()), + parseWorldName(std::string(avatar->getServer().c_str())), + "SWG", + "guild", + data.m_channelName, //"A Guild chat channel." + data.m_channelPassword, + data.m_channelURI, + "en_US", + NULL); + + (*iter).second.push_back(playerOID); + + return; + } + + + } + } + } + } +} + +void VChatInterface::checkForCharacterChannelRemove(std::string const & name, std::string const & channelName) +{ + // No persistant channels right now. Skip the clean up. + if(m_voiceChatChannelNameToNetworkIdMap.empty()) + return; + + NetworkId playerOID = NetworkId::cms_invalid; + // Verify we can get an OID for this user. + if(ChatServer::getVoiceChatLoginInfoFromLoginName(name, playerOID) && playerOID != NetworkId::cms_invalid) + { + // Clean up any character channels this player may have. + + // Do we have a record for this channel? + VoiceChannelIdMap::iterator chanIter = m_voiceChatChannelNameToNetworkIdMap.find(toLower(channelName)); + if(chanIter != m_voiceChatChannelNameToNetworkIdMap.end()) + { + // Is this user in our OID list? + std::vector::iterator iter = (*chanIter).second.begin(); + for(; iter != (*chanIter).second.end(); ) + { + if((*iter) == playerOID) // Yup, let's remove him. + { + const ChatAvatar * avatar = ChatServer::getAvatarByNetworkId(playerOID); + if(avatar) + { + RemoveCharacterChannel(avatar->getUserID(), + avatar->getAvatarID(), + std::string(avatar->getName().c_str()), + parseWorldName(std::string(avatar->getServer().c_str())), + "SWG", + "guild", + NULL); + } + + iter = (*chanIter).second.erase(iter); + + if((*chanIter).second.empty()) + { + // No more OIDs to track, clean this channel up. + m_voiceChatChannelNameToNetworkIdMap.erase(chanIter); + return; + } + break; + } + else + ++iter; + } + } + } +} + +std::string VChatInterface::parseWorldName(std::string const & input) +{ + static std::string const worldCode = "SWG+"; + std::string output; + + std::string::size_type findIndex = input.find(worldCode); + if(findIndex != std::string::npos) + { + findIndex += strlen(worldCode.c_str()); + output = input.substr(findIndex); + } + else + output = input; + + return output; +} diff --git a/engine/server/application/ChatServer/src/shared/VChatInterface.h b/engine/server/application/ChatServer/src/shared/VChatInterface.h new file mode 100644 index 00000000..2e3987a3 --- /dev/null +++ b/engine/server/application/ChatServer/src/shared/VChatInterface.h @@ -0,0 +1,252 @@ +// VChatInterface.h + +#ifndef _INCLUDED_VChatInterface_H +#define _INCLUDED_VChatInterface_H + +#include "sharedFoundation/NetworkId.h" + +#include +#include +#include +#include + +#pragma warning(disable:4100 4244) +#include "VChatAPI/VChatAPI.h" +#pragma warning(default:4100 4244) + +struct ReturnAddress +{ + enum ReturnAddressType + { + RAT_invalid, + RAT_client, + RAT_gameserver, + }; + + ReturnAddressType type; + NetworkId clientId; + unsigned gameServerId; + + ReturnAddress() : type(RAT_invalid), clientId(), gameServerId(0) {} + ReturnAddress(NetworkId const & id):type(RAT_client), clientId(id), gameServerId(0) {} + ReturnAddress(unsigned const id) : type(RAT_gameserver), clientId(), gameServerId(id) {} + inline std::string ReturnAddress::debugString() const + { + switch(type) + { + case RAT_invalid: return "invalid"; break; + case RAT_client: return std::string("client") + clientId.getValueString(); break; + case RAT_gameserver: + { + std::stringstream ss; + ss << "gameserver"; + ss << gameServerId; + return ss.str(); + } + break; + default: return "unknown type"; + } + } +}; + +//----------------------------------------------------------------------- + +class VChatInterface : public VChatSystem::VChatAPI +{ + +public: + + VChatInterface(const char * hostList); + virtual ~VChatInterface(); + + //functions that need looking at before this goes final + bool addClientToChannel(std::string const & roomName, NetworkId const & id, std::string const & playerName, bool forceShortlist = false); + bool removeClientFromChannel(std::string const & roomName, NetworkId const & id, std::string const & playerName); + + void sendChannelData(ReturnAddress const & toWhom, std::string const & channelName, std::string const & messageText, bool targetIsModerator, bool notifyIfNoChannel, bool doGetChannelInfo = false); + + //personal channel stuff + std::string buildPersonalChannelName(NetworkId const & ownerId); + void requestInvite(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName); + void requestKick(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName); + + void broadcastGlobalChannelMessage(std::string const & channelName, std::string const & textMessage, bool isRemove); + + //end questionable functions + + inline bool isConnected() { return m_connected; } + + ////////////// + // Requests // + ////////////// + + unsigned requestGetChannel(const std::string &channelName, + const std::string &description, + const std::string &password, + unsigned limit, + bool isPublic, + bool persistent, + std::list const & moderators, + ReturnAddress const & requester); + + unsigned requestDeleteChannel(const std::string &channelName, ReturnAddress const & requester); + + unsigned requestChannelCommand(ReturnAddress const & request, + const std::string &srcUserName, + const std::string &destUserName, + const std::string &destChannelAddress, + unsigned command, + unsigned banTimeout); + + unsigned requestConnectPlayer(unsigned suid, std::string const & characterName, NetworkId const & netId, unsigned previousAttempts = 0); + + unsigned requestChannelInfo(std::string const & channelName, ReturnAddress const & requester, bool isForGlobalBroadcast = false, std::string const & messageText = ""); + + /////////////// + // Callbacks // + /////////////// + virtual void OnConnectionOpened( const char * address ); + virtual void OnConnectionFailed( const char * address ); + virtual void OnConnectionClosed( const char * address, const char * reason ); + virtual void OnConnectionShutdownNotified( const char * address, unsigned outstandingRequests ); + + virtual void OnGetAccount(unsigned track, + unsigned result, + unsigned userID, + unsigned accountID, + const std::string &voicePassword, + const std::string &encodedVoiceAccount, + const std::string &URI, + void *user); + + virtual void OnGetChannelV2(unsigned track, + unsigned result, + const std::string &channelName, + const std::string &channelURI, + unsigned channelID, + unsigned isNewChannel, + void *user); + + virtual void OnChannelCommand(unsigned track, + unsigned result, + void *user); + + virtual void OnGetAllChannels(unsigned track, + unsigned result, + const VChatSystem::ChannelVec_t & channels, + void *user); + + virtual void OnDeleteChannel(unsigned track, + unsigned result, + void *user); + + virtual void OnGetChannelInfo(unsigned track, + unsigned result, + const std::string & channelName, + const std::string & channelURI, + unsigned channelID, + void * user); + + virtual void OnAddCharacterChannel(unsigned int track, + unsigned int result, + void * user); + + virtual void OnRemoveCharacterChannel(unsigned track, + unsigned result, + void *user); + + virtual void OnGetCharacterChannel(unsigned track, + unsigned result, + const VChatSystem::CharacterChannelVec_t &characterChannels, + void * user); + + virtual void OnUpdateCharacterChannel(unsigned track, + unsigned result, + void *user); + + //callbacks for things we don't care about but have to implement + //because they are virtual in vchatapi + virtual void OnGetProximityChannel (unsigned /*track*/, + unsigned /*result*/, + const std::string & /*channelName*/, + const std::string & /*channelURI*/, + unsigned /*channelID*/, + void * /*user*/) {}; + + + virtual void OnDeactivateVoiceAccount(unsigned /*track*/, + unsigned /*result*/, + void * /*user*/) {}; + + virtual void OnChangePassword(unsigned /*track*/, + unsigned /*result*/, + void * /*user*/) {}; + + virtual void OnSetUserData( unsigned /*track*/, + unsigned /*result*/, + void * /*user*/) {}; + + virtual void OnSetBanStatus(unsigned /*track*/, + unsigned /*result*/, + void * /*user*/) {}; + + virtual void OnGetChannel(unsigned /*track*/, + unsigned /*result*/, + const std::string & /*channelName*/, + const std::string & /*channelURI*/, + unsigned /*channelID*/, + void * /*user*/) {}; + +private: + + std::string const & getSystemLoginName(); + std::string parseWorldName(std::string const & input); + + // these functions all convert the name to lower case for the lookup + // but preserves case in the data + bool findChannelDataByName(std::string const & name, VChatSystem::Channel & data); + void setChannelData(VChatSystem::Channel const & data); + bool eraseChannelData(std::string const & name); + + //Helper functions for character channel management. + void checkForCharacterChannelAdd(std::string const & name, std::string const & channelName); + void checkForCharacterChannelRemove(std::string const & name, std::string const & channelName); + + unsigned internalGetChannel(const std::string &channelName, + const std::string &description, + const std::string &password, + unsigned limit, + bool isPublic, + bool persistent, + std::list const & moderators, + ReturnAddress const & requester); + + + typedef std::map ChannelDataMap; + ChannelDataMap m_channelData; + typedef std::map GlobalChannelMap; + GlobalChannelMap m_globalChannels; + bool m_connected; + uint32 m_connectionFailedCount; + typedef std::map > VoiceChannelIdMap; + VoiceChannelIdMap m_voiceChatChannelNameToNetworkIdMap; + + struct PendingGetChannelRequest + { + std::string m_channelName; + std::string m_description; + std::string m_password; + unsigned int m_limit; + bool m_isPublic; + bool m_persistent; + std::list m_moderators; + ReturnAddress m_requester; + }; + + typedef std::map > PendingGetChannelRequestMap; + PendingGetChannelRequestMap m_pendingGetChannelRequests; +}; + +//----------------------------------------------------------------------- + +#endif // _INCLUDED_VChatInterface_H diff --git a/engine/server/application/ChatServer/src/win32/WinMain.cpp b/engine/server/application/ChatServer/src/win32/WinMain.cpp new file mode 100644 index 00000000..8d0ac8fc --- /dev/null +++ b/engine/server/application/ChatServer/src/win32/WinMain.cpp @@ -0,0 +1,42 @@ +#include "FirstChatServer.h" +#include "ConfigChatServer.h" +#include "ChatServer.h" +#include "sharedCompression/SetupSharedCompression.h" +#include "sharedDebug/SetupSharedDebug.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" +#include "sharedThread/SetupSharedThread.h" + +#include +#include + +int main( int argc, char ** argv ) +{ + SetupSharedThread::install(); + SetupSharedDebug::install(1024); + + //-- setup foundation + SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game); + + //setupFoundationData.hInstance = hInstance; + setupFoundationData.argc = argc; + setupFoundationData.argv = argv; + setupFoundationData.createWindow = false; + setupFoundationData.clockUsesSleep = true; + + SetupSharedFoundation::install (setupFoundationData); + + SetupSharedCompression::install(); + + SetupSharedNetworkMessages::install(); + + //-- setup game server + ConfigChatServer::install (); + + //-- run game + SetupSharedFoundation::callbackWithExceptionHandling(ChatServer::run); + + SetupSharedFoundation::remove(); + + return 0; +} diff --git a/external/3rd/library/CMakeLists.txt b/external/3rd/library/CMakeLists.txt index a70aa712..9d0041c3 100644 --- a/external/3rd/library/CMakeLists.txt +++ b/external/3rd/library/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(platform) +add_subdirectory(soePlatform) add_subdirectory(udplibrary) diff --git a/external/3rd/library/soePlatform/CMakeLists.txt b/external/3rd/library/soePlatform/CMakeLists.txt new file mode 100644 index 00000000..05bc1665 --- /dev/null +++ b/external/3rd/library/soePlatform/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(ChatAPI) diff --git a/external/3rd/library/soePlatform/ChatAPI/CMakeLists.txt b/external/3rd/library/soePlatform/ChatAPI/CMakeLists.txt new file mode 100644 index 00000000..156d67ba --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/CMakeLists.txt @@ -0,0 +1,7 @@ + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/projects + ${CMAKE_CURRENT_SOURCE_DIR}/utils +) + +add_subdirectory(projects) diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/CMakeLists.txt b/external/3rd/library/soePlatform/ChatAPI/projects/CMakeLists.txt new file mode 100644 index 00000000..b52eabe4 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(ChatMono) diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarIteratorCore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarIteratorCore.cpp new file mode 100644 index 00000000..3786718c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarIteratorCore.cpp @@ -0,0 +1,478 @@ +#include "AvatarIteratorCore.h" +#include "ChatAvatar.h" + +using namespace std; + +namespace ChatSystem +{ + +// AVATAR ITERATOR CORE + +AvatarIteratorCore::AvatarIteratorCore() +: m_map(NULL) +{ +} + +AvatarIteratorCore::AvatarIteratorCore(std::map *mapIn, std::map::iterator iter) +: m_map(mapIn), + m_mapIter(iter) +{ +} + +AvatarIteratorCore::~AvatarIteratorCore() +{ +} + +AvatarIteratorCore &AvatarIteratorCore::operator=(const AvatarIteratorCore& rhs) +{ + m_map = rhs.m_map; + m_mapIter = rhs.m_mapIter; + + return (*this); +} + +ChatAvatar *AvatarIteratorCore::getCurAvatar() +{ + ChatAvatar *returnVal = NULL; + + if (!outOfBounds()) + { + returnVal = (*m_mapIter).second; + } + + return returnVal; +} + +bool AvatarIteratorCore::increment() +{ + bool returnVal = false; + + m_mapIter++; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool AvatarIteratorCore::decrement() +{ + bool returnVal = false; + + m_mapIter--; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool AvatarIteratorCore::outOfBounds() +{ + bool returnVal = true; + + if (m_map) + { + if (m_mapIter != m_map->end()) + { + returnVal = false; + } + } + + return returnVal; +} + +// MODERATOR ITERATOR CORE + +ModeratorIteratorCore::ModeratorIteratorCore() +: m_set(NULL) +{ +} + +ModeratorIteratorCore::ModeratorIteratorCore(std::set *setIn, std::set::iterator iter) +: m_set(setIn), + m_setIter(iter) +{ +} + +ModeratorIteratorCore::~ModeratorIteratorCore() +{ +} + +ModeratorIteratorCore &ModeratorIteratorCore::operator=(const ModeratorIteratorCore& rhs) +{ + m_set = rhs.m_set; + m_setIter = rhs.m_setIter; + + return (*this); +} + +ChatAvatar *ModeratorIteratorCore::getCurAvatar() +{ + ChatAvatar *returnVal = NULL; + + if (!outOfBounds()) + { + returnVal = (*m_setIter); + } + + return returnVal; +} + +bool ModeratorIteratorCore::increment() +{ + bool returnVal = false; + + m_setIter++; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool ModeratorIteratorCore::decrement() +{ + bool returnVal = false; + + m_setIter--; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool ModeratorIteratorCore::outOfBounds() +{ + bool returnVal = true; + + if (m_set) + { + if (m_setIter != m_set->end()) + { + returnVal = false; + } + } + + return returnVal; +} + +// TEMPORARY MODERATOR ITERATOR CORE + +TemporaryModeratorIteratorCore::TemporaryModeratorIteratorCore() +: m_set(NULL) +{ +} + +TemporaryModeratorIteratorCore::TemporaryModeratorIteratorCore(std::set *setIn, std::set::iterator iter) +: m_set(setIn), + m_setIter(iter) +{ +} + +TemporaryModeratorIteratorCore::~TemporaryModeratorIteratorCore() +{ +} + +TemporaryModeratorIteratorCore &TemporaryModeratorIteratorCore::operator=(const TemporaryModeratorIteratorCore& rhs) +{ + m_set = rhs.m_set; + m_setIter = rhs.m_setIter; + + return (*this); +} + +ChatAvatar *TemporaryModeratorIteratorCore::getCurAvatar() +{ + ChatAvatar *returnVal = NULL; + + if (!outOfBounds()) + { + returnVal = (*m_setIter); + } + + return returnVal; +} + +bool TemporaryModeratorIteratorCore::increment() +{ + bool returnVal = false; + + m_setIter++; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool TemporaryModeratorIteratorCore::decrement() +{ + bool returnVal = false; + + m_setIter--; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool TemporaryModeratorIteratorCore::outOfBounds() +{ + bool returnVal = true; + + if (m_set) + { + if (m_setIter != m_set->end()) + { + returnVal = false; + } + } + + return returnVal; +} + +// VOICE ITERATOR CORE + +VoiceIteratorCore::VoiceIteratorCore() +: m_set(NULL) +{ +} + +VoiceIteratorCore::VoiceIteratorCore(std::set *setIn, std::set::iterator iter) +: m_set(setIn), + m_setIter(iter) +{ +} + +VoiceIteratorCore::~VoiceIteratorCore() +{ +} + +VoiceIteratorCore &VoiceIteratorCore::operator=(const VoiceIteratorCore& rhs) +{ + m_set = rhs.m_set; + m_setIter = rhs.m_setIter; + + return (*this); +} + +ChatAvatar *VoiceIteratorCore::getCurAvatar() +{ + ChatAvatar *returnVal = NULL; + + if (!outOfBounds()) + { + returnVal = (*m_setIter); + } + + return returnVal; +} + +bool VoiceIteratorCore::increment() +{ + bool returnVal = false; + + m_setIter++; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool VoiceIteratorCore::decrement() +{ + bool returnVal = false; + + m_setIter--; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool VoiceIteratorCore::outOfBounds() +{ + bool returnVal = true; + + if (m_set) + { + if (m_setIter != m_set->end()) + { + returnVal = false; + } + } + + return returnVal; +} + +// INVITE ITERATOR CORE + +InviteIteratorCore::InviteIteratorCore() +: m_set(NULL) +{ +} + +InviteIteratorCore::InviteIteratorCore(std::set *setIn, std::set::iterator iter) +: m_set(setIn), + m_setIter(iter) +{ +} + +InviteIteratorCore::~InviteIteratorCore() +{ +} + +InviteIteratorCore &InviteIteratorCore::operator=(const InviteIteratorCore& rhs) +{ + m_set = rhs.m_set; + m_setIter = rhs.m_setIter; + + return (*this); +} + +ChatAvatar *InviteIteratorCore::getCurAvatar() +{ + ChatAvatar *returnVal = NULL; + + if (!outOfBounds()) + { + returnVal = (*m_setIter); + } + + return returnVal; +} + +bool InviteIteratorCore::increment() +{ + bool returnVal = false; + + m_setIter++; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool InviteIteratorCore::decrement() +{ + bool returnVal = false; + + m_setIter--; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool InviteIteratorCore::outOfBounds() +{ + bool returnVal = true; + + if (m_set) + { + if (m_setIter != m_set->end()) + { + returnVal = false; + } + } + + return returnVal; +} + +// BAN ITERATOR CORE + +BanIteratorCore::BanIteratorCore() +: m_set(NULL) +{ +} + +BanIteratorCore::BanIteratorCore(std::set *setIn, std::set::iterator iter) +: m_set(setIn), + m_setIter(iter) +{ +} + +BanIteratorCore::~BanIteratorCore() +{ +} + +BanIteratorCore &BanIteratorCore::operator=(const BanIteratorCore& rhs) +{ + m_set = rhs.m_set; + m_setIter = rhs.m_setIter; + + return (*this); +} + +ChatAvatar *BanIteratorCore::getCurAvatar() +{ + ChatAvatar *returnVal = NULL; + + if (!outOfBounds()) + { + returnVal = (*m_setIter); + } + + return returnVal; +} + +bool BanIteratorCore::increment() +{ + bool returnVal = false; + + m_setIter++; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool BanIteratorCore::decrement() +{ + bool returnVal = false; + + m_setIter--; + if (!outOfBounds()) + { + returnVal = true; + } + + return returnVal; +} + +bool BanIteratorCore::outOfBounds() +{ + bool returnVal = true; + + if (m_set) + { + if (m_setIter != m_set->end()) + { + returnVal = false; + } + } + + return returnVal; +} + +}; + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarIteratorCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarIteratorCore.h new file mode 100644 index 00000000..ce69ec6c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarIteratorCore.h @@ -0,0 +1,159 @@ +#if !defined (AVATARITERATORCORE_H_) +#define AVATARITERATORCORE_H_ + +#pragma warning (disable : 4786) +#include +#include + +namespace ChatSystem +{ + + class ChatAvatar; + + class AvatarIteratorCore + { + public: + AvatarIteratorCore(); + AvatarIteratorCore(std::map *mapIn, std::map::iterator iter); + ~AvatarIteratorCore(); + + AvatarIteratorCore & operator=(const AvatarIteratorCore& rhs); + + ChatAvatar *getCurAvatar(); + + // navigation functions return true while iterator points to a map node, + // else false if reached the end. + bool increment(); + bool decrement(); + + // have we reached the end? + bool outOfBounds(); + + private: + std::map *m_map; + std::map::iterator m_mapIter; + }; + + class ModeratorIteratorCore + { + public: + ModeratorIteratorCore(); + ModeratorIteratorCore(std::set *setIn, std::set::iterator iter); + ~ModeratorIteratorCore(); + + ModeratorIteratorCore & operator=(const ModeratorIteratorCore& rhs); + + ChatAvatar *getCurAvatar(); + + // navigation functions return true while iterator points to a map node, + // else false if reached the end. + bool increment(); + bool decrement(); + + // have we reached the end? + bool outOfBounds(); + + private: + std::set *m_set; + std::set::iterator m_setIter; + }; + + class TemporaryModeratorIteratorCore + { + public: + TemporaryModeratorIteratorCore(); + TemporaryModeratorIteratorCore(std::set *setIn, std::set::iterator iter); + ~TemporaryModeratorIteratorCore(); + + TemporaryModeratorIteratorCore & operator=(const TemporaryModeratorIteratorCore& rhs); + + ChatAvatar *getCurAvatar(); + + // navigation functions return true while iterator points to a map node, + // else false if reached the end. + bool increment(); + bool decrement(); + + // have we reached the end? + bool outOfBounds(); + + private: + std::set *m_set; + std::set::iterator m_setIter; + }; + + class VoiceIteratorCore + { + public: + VoiceIteratorCore(); + VoiceIteratorCore(std::set *setIn, std::set::iterator iter); + ~VoiceIteratorCore(); + + VoiceIteratorCore & operator=(const VoiceIteratorCore& rhs); + + ChatAvatar *getCurAvatar(); + + // navigation functions return true while iterator points to a map node, + // else false if reached the end. + bool increment(); + bool decrement(); + + // have we reached the end? + bool outOfBounds(); + + private: + std::set *m_set; + std::set::iterator m_setIter; + }; + + class InviteIteratorCore + { + public: + InviteIteratorCore(); + InviteIteratorCore(std::set *setIn, std::set::iterator iter); + ~InviteIteratorCore(); + + InviteIteratorCore & operator=(const InviteIteratorCore& rhs); + + ChatAvatar *getCurAvatar(); + + // navigation functions return true while iterator points to a map node, + // else false if reached the end. + bool increment(); + bool decrement(); + + // have we reached the end? + bool outOfBounds(); + + private: + std::set *m_set; + std::set::iterator m_setIter; + }; + + class BanIteratorCore + { + public: + BanIteratorCore(); + BanIteratorCore(std::set *setIn, std::set::iterator iter); + ~BanIteratorCore(); + + BanIteratorCore & operator=(const BanIteratorCore& rhs); + + ChatAvatar *getCurAvatar(); + + // navigation functions return true while iterator points to a map node, + // else false if reached the end. + bool increment(); + bool decrement(); + + // have we reached the end? + bool outOfBounds(); + + private: + std::set *m_set; + std::set::iterator m_setIter; + }; + +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItem.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItem.h new file mode 100644 index 00000000..02a6c159 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItem.h @@ -0,0 +1,29 @@ +#if !defined (AVATARLISTITEM_H_) +#define AVATARLISTITEM_H_ + +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + class AvatarListItemCore; + + class AvatarListItem + { + public: + AvatarListItem(); + ~AvatarListItem(); + const ChatUnicodeString &getName() const { return m_name; } + const ChatUnicodeString &getAddress() const { return m_address; } + + friend class AvatarListItemCore; + private: + ChatUnicodeString m_name; + ChatUnicodeString m_address; + + AvatarListItemCore *m_core; + }; +}; + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItemCore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItemCore.cpp new file mode 100644 index 00000000..15e9af48 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItemCore.cpp @@ -0,0 +1,37 @@ +#include "AvatarListItemCore.h" +#include "AvatarListItem.h" + +namespace ChatSystem +{ + using namespace Base; + using namespace Plat_Unicode; + + AvatarListItem::AvatarListItem() + : m_core(NULL) + { + } + + AvatarListItem::~AvatarListItem() + { + } + + AvatarListItemCore::AvatarListItemCore() + : m_interface(NULL) + { + } + + AvatarListItemCore::~AvatarListItemCore() + { + } + + void AvatarListItemCore::load(Base::ByteStream::ReadIterator &iter, AvatarListItem *inf) + { + m_interface = inf; + inf->m_core = this; + get(iter, m_name); + get(iter, m_address); + + m_interface->m_name = m_name; + m_interface->m_address = m_address; + } +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItemCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItemCore.h new file mode 100644 index 00000000..463bbe72 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/AvatarListItemCore.h @@ -0,0 +1,37 @@ +#if !defined (AVATARLISTITEMCORE_H_) +#define AVATARLISTITEMCORE_H_ + +#include +#include +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + + + class AvatarListItem; + + class AvatarListItemCore + { + public: + AvatarListItemCore(); + ~AvatarListItemCore(); + + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + + void load(Base::ByteStream::ReadIterator &iter, AvatarListItem *inf); + + private: + AvatarListItem *m_interface; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + +}; + +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPI.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPI.cpp new file mode 100644 index 00000000..ee2dcdd8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPI.cpp @@ -0,0 +1,1409 @@ +#include + +#include "ChatAPICore.h" +#include "ChatAPI.h" +#include "Response.h" +#include "Request.h" +#include "ChatAvatar.h" +#include "ChatRoom.h" +#include "PersistentMessage.h" +#include "GenericAPI/GenericConnection.h" + +namespace ChatSystem +{ + +ChatAPI::ChatAPI(const char *registrar_host, short registrar_port, const char *server_host, short server_port) +: m_defaultRoomParams(NULL), + m_defaultLoginPriority(0), + m_defaultEntryType(false) +{ + GenericAPI::GenericConnection::ms_crcBytes = 2; + m_core = new ChatAPICore(registrar_host, registrar_port, server_host, server_port); + m_core->setAPI(this); +} + +ChatAPI::~ChatAPI() +{ + delete m_defaultRoomParams; + m_defaultRoomParams = NULL; + delete m_core; + m_core = NULL; +} + +ChatAPI::ChatAPI(ChatAPICore *core) +: m_defaultRoomParams(NULL) +{ + m_core = core; + m_core->setAPI(this); +} + +void ChatAPI::setRequestTimeout(unsigned requestTimeout) +{ + m_core->setRequestTimeout(requestTimeout); +} + +void ChatAPI::Process() +{ + m_core->processAPI(); + m_core->clearRequestCount(); +} + +unsigned ChatAPI::RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user) +{ + return RequestLoginAvatar(userID, avatarName, avatarAddress, m_defaultLoginLocation, m_defaultLoginPriority, 0, user); +} + +unsigned ChatAPI::RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &avatarLoginLocation, void *user) +{ + return RequestLoginAvatar(userID, avatarName, avatarAddress, avatarLoginLocation, m_defaultLoginPriority, 0, user); +} + +unsigned ChatAPI::RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &avatarLoginLocation, int avatarLoginPriority, void *user) +{ + return RequestLoginAvatar(userID, avatarName, avatarAddress, avatarLoginLocation, avatarLoginPriority, 0, user); +} + +unsigned ChatAPI::RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &avatarLoginLocation, int avatarLoginPriority, int avatarLoginAttributes, void *user) +{ + RLoginAvatar *req = new RLoginAvatar(userID, avatarName, avatarAddress, avatarLoginLocation, avatarLoginPriority, avatarLoginAttributes); + ResLoginAvatar *res = new ResLoginAvatar(user, avatarLoginPriority); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestTemporaryAvatar(unsigned userID, const ChatUnicodeString& avatarName, const ChatUnicodeString& avatarAddress, const ChatUnicodeString& avatarLoginLocation, void* user) +{ + RTemporaryAvatar* req = new RTemporaryAvatar(userID, avatarName, avatarAddress, avatarLoginLocation ); + ResTemporaryAvatar* res = new ResTemporaryAvatar(user); + return (m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestLogoutAvatar(const ChatAvatar *srcAvatar, void *user) +{ + RLogoutAvatar *req = new RLogoutAvatar(srcAvatar->getAvatarID(), srcAvatar->getAddress()); + ResLogoutAvatar *res = new ResLogoutAvatar(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestDestroyAvatar(const ChatAvatar *srcAvatar, void *user) +{ + RDestroyAvatar *req = new RDestroyAvatar(srcAvatar->getAvatarID(), srcAvatar->getAddress()); + ResDestroyAvatar *res = new ResDestroyAvatar(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSetAvatarKeywords(const ChatAvatar *srcAvatar, const ChatUnicodeString *keywordList, unsigned keywordLength, void *user) +{ + RSetAvatarKeywords *req = new RSetAvatarKeywords(srcAvatar->getAvatarID(), keywordList, keywordLength); + ResSetAvatarKeywords *res = new ResSetAvatarKeywords(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetAvatarKeywords(const ChatAvatar *srcAvatar, void *user) +{ + RGetAvatarKeywords *req = new RGetAvatarKeywords(srcAvatar->getAvatarID()); + ResGetAvatarKeywords *res = new ResGetAvatarKeywords(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSearchAvatarKeywords(const ChatUnicodeString nodeAddress, const ChatUnicodeString *keywordList, unsigned keywordLength, void *user) +{ + RSearchAvatarKeywords *req = new RSearchAvatarKeywords(nodeAddress, keywordList, keywordLength); + ResSearchAvatarKeywords *res = new ResSearchAvatarKeywords(user); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetAvatar(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user) +{ + RGetAvatar *req = new RGetAvatar(avatarName, avatarAddress); + ResGetAvatar *res = new ResGetAvatar(user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestGetAnyAvatar(const ChatUnicodeString& avatarName, const ChatUnicodeString& avatarAddress, void* user ) +{ + RGetAnyAvatar* req = new RGetAnyAvatar(avatarName, avatarAddress); + ResGetAnyAvatar* res = new ResGetAnyAvatar(user); + return (m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAvatarList(unsigned userID, void* user ) +{ + RAvatarList* req = new RAvatarList(userID); + ResAvatarList* res = new ResAvatarList(user); + return (m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSetAvatarAttributes(const ChatAvatar *srcAvatar, unsigned long avatarAttributes, void *user) +{ + RSetAvatarAttributes *req = new RSetAvatarAttributes(srcAvatar->getAvatarID(), srcAvatar->getAddress(), avatarAttributes); + ResSetAvatarAttributes *res = new ResSetAvatarAttributes(user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestSetAvatarSessionAttributes(const ChatAvatar *srcAvatar, unsigned long avatarAttributes, void *user) +{ + RSetAvatarAttributes *req = new RSetAvatarAttributes(srcAvatar->getAvatarID(), srcAvatar->getAddress(), avatarAttributes, false); + ResSetAvatarAttributes *res = new ResSetAvatarAttributes(user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestSetAvatarStatusMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString& statusMessage, void *user) +{ + RSetAvatarStatusMessage *req = new RSetAvatarStatusMessage(srcAvatar->getAvatarID(), srcAvatar->getAddress(), statusMessage); + ResSetAvatarStatusMessage* res = new ResSetAvatarStatusMessage(user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestSetAvatarForwardingEmail(const ChatAvatar *srcAvatar, const ChatUnicodeString &avatarForwardingEmail, void *user) +{ + RSetAvatarForwardingEmail *req = new RSetAvatarForwardingEmail(srcAvatar->getAvatarID(), avatarForwardingEmail); + ResSetAvatarForwardingEmail *res = new ResSetAvatarForwardingEmail(user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestSetAvatarInboxLimit(const ChatAvatar *srcAvatar, unsigned long avatarInboxLimit, void *user) +{ + RSetAvatarInboxLimit *req = new RSetAvatarInboxLimit(srcAvatar->getAvatarID(), avatarInboxLimit); + ResSetAvatarInboxLimit *res = new ResSetAvatarInboxLimit(user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestFindAvatarByUID(unsigned userID, void *user) +{ + RFindAvatarByUID *req = new RFindAvatarByUID(userID); + ResFindAvatarByUID *res = new ResFindAvatarByUID(user); + return(m_core->submitRequest(req,res)); +} + +ChatAvatar *ChatAPI::getAvatar(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress) +{ + return m_core->getAvatar(avatarName, avatarAddress); +} + +ChatAvatar *ChatAPI::getAvatar(unsigned avatarID) +{ + return m_core->getAvatar(avatarID); +} + +unsigned ChatAPI::RequestTransferAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned newUserID, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &newAvatarAddress, void *user) +{ + return RequestTransferAvatar(userID, avatarName, avatarAddress, newUserID, newAvatarName, newAvatarAddress, false, user); +} + +unsigned ChatAPI::RequestTransferAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned newUserID, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &newAvatarAddress, bool transferPersistentMessages, void *user) +{ + RTransferAvatar *req = new RTransferAvatar(userID, newUserID, avatarName, newAvatarName, avatarAddress, newAvatarAddress, transferPersistentMessages); + ResTransferAvatar *res = new ResTransferAvatar(user, userID, newUserID, avatarName, newAvatarName, avatarAddress, newAvatarAddress); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestFanClubHandle(unsigned stationID, unsigned fanClubCode, void *user) +{ + RGetFanClubHandle *req = new RGetFanClubHandle(stationID, fanClubCode); + ResGetFanClubHandle *res = new ResGetFanClubHandle(stationID, fanClubCode, user); + return(m_core->submitRequest(req,res)); +} + +unsigned ChatAPI::RequestCreateRoom(const ChatAvatar *srcAvatar, const RoomParams &roomParams, const ChatUnicodeString &parentAddress, void *user) +{ + RCreateRoom *req = new RCreateRoom(srcAvatar->getAvatarID(), srcAvatar->getAddress(), roomParams, parentAddress); + ResCreateRoom *res = new ResCreateRoom(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestDestroyRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, void *user) +{ + RDestroyRoom *req = new RDestroyRoom(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destRoomAddress); + ResDestroyRoom *res = new ResDestroyRoom(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetRoomSummaries(const ChatUnicodeString &startNodeAddress, const ChatUnicodeString &roomFilter, void *user) +{ + RGetRoomSummaries *req = new RGetRoomSummaries(startNodeAddress, roomFilter); + ResGetRoomSummaries *res = new ResGetRoomSummaries(user); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendInstantMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + RSendInstantMessage *req = new RSendInstantMessage(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, msg, oob); + ResSendInstantMessage *res = new ResSendInstantMessage(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendRoomMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + RSendRoomMessage *req = new RSendRoomMessage(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destRoomAddress, msg, oob); + ResSendRoomMessage *res = new ResSendRoomMessage(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendBroadcastMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destNodeAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + RSendBroadcastMessage *req = new RSendBroadcastMessage(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destNodeAddress, msg, oob); + ResSendBroadcastMessage *res = new ResSendBroadcastMessage(user, srcAvatar->getAvatarID(), destNodeAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestFilterMessage(const ChatUnicodeString &in_msg, void *user) +{ + RFilterMessage *req = new RFilterMessage(in_msg); + ResFilterMessage *res = new ResFilterMessage(user); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestFilterMessageEx(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &msg, void *user) +{ + RFilterMessageEx *req = new RFilterMessageEx(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, msg); + ResFilterMessage *res = new ResFilterMessage(user, RESPONSE_FILTERMESSAGE_EX); + return(m_core->submitRequest(req, res)); + +} + +unsigned ChatAPI::RequestAddFriend(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, bool confirm, void *user) +{ + return RequestAddFriend(srcAvatar, destAvatarName, destAvatarAddress, ChatUnicodeString(), confirm, user); +} + +unsigned ChatAPI::RequestAddFriendReciprocate(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, bool confirm, void *user) +{ + return RequestAddFriendReciprocate(srcAvatar, destAvatarName, destAvatarAddress, ChatUnicodeString(), confirm, user); +} + +unsigned ChatAPI::RequestAddFriend(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &friendComment, bool confirm, void *user) +{ + RAddFriend *req = new RAddFriend(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, friendComment, confirm); + ResAddFriend *res = new ResAddFriend(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress, friendComment); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAddFriendReciprocate(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &friendComment, bool confirm, void *user) +{ + RAddFriendReciprocate *req = new RAddFriendReciprocate(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, friendComment, confirm); + ResAddFriendReciprocate *res = new ResAddFriendReciprocate(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress, friendComment); + return(m_core->submitRequest(req, res)); +} +unsigned ChatAPI::RequestSetFriendComment(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &friendComment, void *user) +{ + RSetFriendComment *req = new RSetFriendComment(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, friendComment); + ResSetFriendComment *res = new ResSetFriendComment(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress, friendComment); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRemoveFriend(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) +{ + RRemoveFriend *req = new RRemoveFriend(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress); + ResRemoveFriend *res = new ResRemoveFriend(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRemoveFriendReciprocate(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) +{ + RRemoveFriendReciprocate *req = new RRemoveFriendReciprocate(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress); + ResRemoveFriendReciprocate *res = new ResRemoveFriendReciprocate(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestFriendStatus(const ChatAvatar *srcAvatar, void *user) +{ + RFriendStatus *req = new RFriendStatus(srcAvatar->getAvatarID(), srcAvatar->getAddress()); + ResFriendStatus *res = new ResFriendStatus(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAddIgnore(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) +{ + RAddIgnore *req = new RAddIgnore(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress); + ResAddIgnore *res = new ResAddIgnore(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); + +} + +unsigned ChatAPI::RequestRemoveIgnore(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) +{ + RRemoveIgnore *req = new RRemoveIgnore(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress); + ResRemoveIgnore *res = new ResRemoveIgnore(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestIgnoreStatus(const ChatAvatar *srcAvatar, void *user) +{ + RIgnoreStatus *req = new RIgnoreStatus(srcAvatar->getAvatarID(), srcAvatar->getAddress()); + ResIgnoreStatus *res = new ResIgnoreStatus(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestEnterRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, void *user) +{ + return RequestEnterRoom(srcAvatar, destRoomAddress, ChatUnicodeString(), user); +} + +unsigned ChatAPI::RequestEnterRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destRoomPassword, void *user) +{ + return RequestEnterRoom(srcAvatar, destRoomAddress, destRoomPassword, m_defaultEntryType, user); +} + +unsigned ChatAPI::RequestEnterRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destRoomPassword, bool requestEntry, void *user) +{ + REnterRoom *req = new REnterRoom(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destRoomAddress, destRoomPassword, m_defaultRoomParams, requestEntry); + ResEnterRoom *res = new ResEnterRoom(user, srcAvatar->getAvatarID(), destRoomAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAllowRoomEntry(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, bool allow, void *user) +{ + RAllowRoomEntry *req = new RAllowRoomEntry(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress, allow); + ResAllowRoomEntry *res = new ResAllowRoomEntry(user, srcAvatar->getAvatarID(), destRoomAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestLeaveRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, void *user) +{ + RLeaveRoom *req = new RLeaveRoom(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destRoomAddress); + ResLeaveRoom *res = new ResLeaveRoom(user, srcAvatar->getAvatarID(), destRoomAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetRoom(const ChatUnicodeString &roomAddress, void *user) +{ + RGetRoom *req = new RGetRoom(roomAddress); + ResGetRoom *res = new ResGetRoom(user); + return(m_core->submitRequest(req, res)); +} + +ChatRoom *ChatAPI::getRoom(const ChatUnicodeString &roomAddress) +{ + return m_core->getRoom(roomAddress); +} + +ChatRoom *ChatAPI::getRoom(unsigned roomID) +{ + return m_core->getRoom(roomID); +} + +unsigned ChatAPI::RequestAddModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RAddModerator *req = new RAddModerator(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResAddModerator *res = new ResAddModerator(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRemoveModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RRemoveModerator *req = new RRemoveModerator(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResRemoveModerator *res = new ResRemoveModerator(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAddTemporaryModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RAddTemporaryModerator *req = new RAddTemporaryModerator(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResAddTemporaryModerator *res = new ResAddTemporaryModerator(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRemoveTemporaryModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RRemoveTemporaryModerator *req = new RRemoveTemporaryModerator(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResRemoveTemporaryModerator *res = new ResRemoveTemporaryModerator(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAddBan(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RAddBan *req = new RAddBan(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResAddBan *res = new ResAddBan(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRemoveBan(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RRemoveBan *req = new RRemoveBan(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResRemoveBan *res = new ResRemoveBan(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAddInvite(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RAddInvite *req = new RAddInvite(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResAddInvite *res = new ResAddInvite(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRemoveInvite(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RRemoveInvite *req = new RRemoveInvite(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResRemoveInvite *res = new ResRemoveInvite(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGrantVoice(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RGrantVoice *req = new RGrantVoice(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResGrantVoice *res = new ResGrantVoice(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestRevokeVoice(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RRevokeVoice *req = new RRevokeVoice(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResRevokeVoice *res = new ResRevokeVoice(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestKickAvatar(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user) +{ + RKickAvatar *req = new RKickAvatar(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatarName, destAvatarAddress, destRoomAddress); + ResKickAvatar *res = new ResKickAvatar(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSetRoomParams(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const RoomParams *params, void *user) + +{ + RSetRoomParams *req = new RSetRoomParams(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destRoomAddress, params); + ResSetRoomParams *res = new ResSetRoomParams(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestChangeRoomOwner(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) + +{ + RChangeRoomOwner *req = new RChangeRoomOwner(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destRoomAddress, destAvatarName, destAvatarAddress); + ResChangeRoomOwner *res = new ResChangeRoomOwner(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatUnicodeString &src, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + return RequestSendPersistentMessage(src, destAvatarName, destAvatarAddress, subject, msg, oob, ChatUnicodeString(), true, 0, user); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatUnicodeString &src, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user) +{ + return RequestSendPersistentMessage(src, destAvatarName, destAvatarAddress, subject, msg, oob, category, true, 0, user); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatUnicodeString &src, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user) +{ + return RequestSendPersistentMessage(src, destAvatarName, destAvatarAddress, subject, msg, oob, category, enforceInboxLimit, 0, user); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatUnicodeString &src, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user) +{ + RSendPersistentMessage *req = new RSendPersistentMessage(src, destAvatarName, destAvatarAddress, subject, msg, oob, category, enforceInboxLimit, categoryLimit); + ResSendPersistentMessage *res = new ResSendPersistentMessage(user, 0); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + return RequestSendPersistentMessage(srcAvatar, destAvatarName, destAvatarAddress, subject, msg, oob, ChatUnicodeString(), true, 0, user); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user) +{ + return RequestSendPersistentMessage(srcAvatar, destAvatarName, destAvatarAddress, subject, msg, oob, category, true, 0, user); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user) +{ + return RequestSendPersistentMessage(srcAvatar, destAvatarName, destAvatarAddress, subject, msg, oob, category, enforceInboxLimit, 0, user); +} + +unsigned ChatAPI::RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user) +{ + RSendPersistentMessage *req = new RSendPersistentMessage(srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress, subject, msg, oob, category, enforceInboxLimit, categoryLimit); + ResSendPersistentMessage *res = new ResSendPersistentMessage(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user) +{ + return RequestSendMultiplePersistentMessages(srcAvatar, numDestAvatars, destAvatarNames, destAvatarAddresses, subject, msg, oob, category, true, 0, user); +} + +unsigned ChatAPI::RequestSendMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user) +{ + return RequestSendMultiplePersistentMessages(srcAvatar, numDestAvatars, destAvatarNames, destAvatarAddresses, subject, msg, oob, category, enforceInboxLimit, 0, user); +} + +unsigned ChatAPI::RequestSendMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user) +{ + RSendMultiplePersistentMessages *req = new RSendMultiplePersistentMessages(srcAvatar->getAvatarID(), numDestAvatars, destAvatarNames, destAvatarAddresses, subject, msg, oob, category, enforceInboxLimit, categoryLimit); + ResSendMultiplePersistentMessages *res = new ResSendMultiplePersistentMessages(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestSendMultiplePersistentMessages(const ChatUnicodeString &srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user) +{ + return RequestSendMultiplePersistentMessages(srcAvatar, numDestAvatars, destAvatarNames, destAvatarAddresses, subject, msg, oob, category, true, 0, user); +} + +unsigned ChatAPI::RequestSendMultiplePersistentMessages(const ChatUnicodeString &srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user) +{ + return RequestSendMultiplePersistentMessages(srcAvatar, numDestAvatars, destAvatarNames, destAvatarAddresses, subject, msg, oob, category, enforceInboxLimit, 0, user); +} + +unsigned ChatAPI::RequestSendMultiplePersistentMessages(const ChatUnicodeString &srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user) +{ + RSendMultiplePersistentMessages *req = new RSendMultiplePersistentMessages(srcAvatar, numDestAvatars, destAvatarNames, destAvatarAddresses, subject, msg, oob, category, enforceInboxLimit, categoryLimit); + ResSendMultiplePersistentMessages *res = new ResSendMultiplePersistentMessages(user, 0); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestAlterPersistentMessage(const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID, unsigned alterationAttributes, const ChatUnicodeString &newSenderName, const ChatUnicodeString &newSenderAddress, const ChatUnicodeString &newSubject, const ChatUnicodeString &newMsg, const ChatUnicodeString &newOOB, const ChatUnicodeString &newCategory, unsigned newSentTime, void *user) +{ + RAlterPersistentMessage *req = new RAlterPersistentMessage(destAvatarName, destAvatarAddress, messageID, alterationAttributes, newSenderName, newSenderAddress, newSubject, newMsg, newOOB, newCategory, newSentTime); + ResAlterPersistentMessage *res = new ResAlterPersistentMessage(destAvatarName, destAvatarAddress, messageID, user); + return (m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetPersistentHeaders(const ChatAvatar *srcAvatar, void *user) +{ + return RequestGetPersistentHeaders(srcAvatar, ChatUnicodeString(), user); +} + +unsigned ChatAPI::RequestGetPersistentHeaders(const ChatAvatar *srcAvatar, const ChatUnicodeString &category, void *user) +{ + RGetPersistentHeaders *req = new RGetPersistentHeaders(srcAvatar->getAvatarID(), category); + ResGetPersistentHeaders *res = new ResGetPersistentHeaders(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetPartialPersistentHeaders(const ChatAvatar *srcAvatar, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, void *user) +{ + return RequestGetPartialPersistentHeaders(srcAvatar, maxHeaders, inDescendingOrder, sentTimeStart, ChatUnicodeString(), user); +} + +unsigned ChatAPI::RequestGetPartialPersistentHeaders(const ChatAvatar *srcAvatar, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category, void *user) +{ + RGetPartialPersistentHeaders *req = new RGetPartialPersistentHeaders(srcAvatar->getAvatarID(), maxHeaders, inDescendingOrder, sentTimeStart, category); + ResGetPartialPersistentHeaders *res = new ResGetPartialPersistentHeaders(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestCountPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user) +{ + return RequestCountPersistentMessages(avatarName, avatarAddress, ChatUnicodeString(), user); +} + +unsigned ChatAPI::RequestCountPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category, void *user) +{ + RCountPersistentMessages *req = new RCountPersistentMessages(avatarName, avatarAddress, category); + ResCountPersistentMessages *res = new ResCountPersistentMessages(user, avatarName, avatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetPersistentMessage(const ChatAvatar *srcAvatar, unsigned messageID, void *user) +{ + RGetPersistentMessage *req = new RGetPersistentMessage(srcAvatar->getAvatarID(), messageID); + ResGetPersistentMessage *res = new ResGetPersistentMessage(user, srcAvatar->getAvatarID(), messageID); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category, void *user) +{ + RGetMultiplePersistentMessages *req = new RGetMultiplePersistentMessages(srcAvatar->getAvatarID(), maxHeaders, inDescendingOrder, sentTimeStart, category); + ResGetMultiplePersistentMessages *res = new ResGetMultiplePersistentMessages(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestUpdatePersistentMessage(const ChatAvatar *srcAvatar, unsigned messageID, PersistentStatus status, void *user) +{ + RUpdatePersistentMessage *req = new RUpdatePersistentMessage(srcAvatar->getAvatarID(), messageID, status); + ResUpdatePersistentMessage *res = new ResUpdatePersistentMessage(user, srcAvatar->getAvatarID(), messageID); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestUpdatePersistentMessages(const ChatAvatar *srcAvatar, PersistentStatus currentStatus, PersistentStatus newStatus, void *user) +{ + return RequestUpdatePersistentMessages(srcAvatar, currentStatus, newStatus, ChatUnicodeString(), user); +} + +unsigned ChatAPI::RequestUpdatePersistentMessages(const ChatAvatar *srcAvatar, PersistentStatus currentStatus, PersistentStatus newStatus, const ChatUnicodeString &category, void *user) +{ + RUpdatePersistentMessages *req = new RUpdatePersistentMessages(srcAvatar->getAvatarID(), currentStatus, newStatus, category); + ResUpdatePersistentMessages *res = new ResUpdatePersistentMessages(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestClassifyPersistentMessages(const ChatAvatar *srcAvatar, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder, void *user) +{ + RClassifyPersistentMessages *req = new RClassifyPersistentMessages(srcAvatar->getAvatarID(), numIDs, messageIDs, newFolder); + ResClassifyPersistentMessages *res = new ResClassifyPersistentMessages(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestClassifyPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder, void *user) +{ + RClassifyPersistentMessages *req = new RClassifyPersistentMessages(avatarName, avatarAddress, numIDs, messageIDs, newFolder); + ResClassifyPersistentMessages *res = new ResClassifyPersistentMessages(user, 0); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestDeleteAllPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user) +{ + return RequestDeleteAllPersistentMessages(avatarName, avatarAddress, ChatUnicodeString(), 0, user); +} + +unsigned ChatAPI::RequestDeleteAllPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category, unsigned olderThan, void *user) +{ + RDeleteAllPersistentMessages *req = new RDeleteAllPersistentMessages(avatarName, avatarAddress, category, olderThan); + ResDeleteAllPersistentMessages *res = new ResDeleteAllPersistentMessages(user, avatarName, avatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestUnregisterRoom(const ChatUnicodeString &roomAddress, void *user) +{ + RUnregisterRoom *req = new RUnregisterRoom(roomAddress); + ResUnregisterRoom *res = new ResUnregisterRoom(user); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestFriendConfirm(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, bool confirm, void *user) +{ + RFriendConfirm *req = new RFriendConfirm(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatar->getAvatarID(), confirm); + ResFriendConfirm *res = new ResFriendConfirm(srcAvatar->getAvatarID(), user); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestFriendConfirmReciprocate(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, bool confirm, void *user) +{ + RFriendConfirmReciprocate *req = new RFriendConfirmReciprocate(srcAvatar->getAvatarID(), srcAvatar->getAddress(), destAvatar->getAvatarID(), confirm); + ResFriendConfirmReciprocate *res = new ResFriendConfirmReciprocate(srcAvatar->getAvatarID(), user); + return(m_core->submitRequest(req, res)); +} + + +unsigned ChatAPI::RequestBeginSnoopingAvatar(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) +{ + RAddSnoopAvatar *req = new RAddSnoopAvatar(srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + ResAddSnoopAvatar *res = new ResAddSnoopAvatar(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestStopSnoopingAvatar(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user) +{ + RRemoveSnoopAvatar *req = new RRemoveSnoopAvatar(srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + ResRemoveSnoopAvatar *res = new ResRemoveSnoopAvatar(user, srcAvatar->getAvatarID(), destAvatarName, destAvatarAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestBeginSnoopingRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user) +{ + RAddSnoopRoom *req = new RAddSnoopRoom(srcAvatar->getAvatarID(), roomAddress); + ResAddSnoopRoom *res = new ResAddSnoopRoom(user, srcAvatar->getAvatarID(), roomAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestStopSnoopingRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user) +{ + RRemoveSnoopRoom *req = new RRemoveSnoopRoom(srcAvatar->getAvatarID(), roomAddress); + ResRemoveSnoopRoom *res = new ResRemoveSnoopRoom(user, srcAvatar->getAvatarID(), roomAddress); + return(m_core->submitRequest(req, res)); +} + +unsigned ChatAPI::RequestGetSnoopList(const ChatAvatar *srcAvatar, void *user) +{ + RGetSnoopList *req = new RGetSnoopList(srcAvatar->getAvatarID()); + ResGetSnoopList *res = new ResGetSnoopList(user, srcAvatar->getAvatarID()); + return(m_core->submitRequest(req, res)); +} + +const RoomParams *ChatAPI::getDefaultRoomParams(void) +{ + return m_defaultRoomParams; +} + +void ChatAPI::setDefaultRoomParams(RoomParams *roomParams) +{ + if (roomParams) + { + if (m_defaultRoomParams == NULL) + { + m_defaultRoomParams = new RoomParams; + } + + // set new params + (*m_defaultRoomParams) = (*roomParams); + } + else + { + delete m_defaultRoomParams; + m_defaultRoomParams = NULL; + } +} +void ChatAPI::setDefaultLoginLocation(const ChatUnicodeString &defaultLoginLocation) +{ + m_defaultLoginLocation = defaultLoginLocation; +} + +void ChatAPI::setDefaultLoginPriority(int defaultLoginPriority) +{ + m_defaultLoginPriority = defaultLoginPriority; +} + +void ChatAPI::setDefaultEntryType(bool defaultEntryType) +{ + m_defaultEntryType = defaultEntryType; +} + +bool ChatAPI::isUID(const ChatUnicodeString &uidNode) +{ + Plat_Unicode::String uid(uidNode.data(), uidNode.length()); + return ( m_core->isUID(uid) ); +} + + +void ChatAPI::OnConnect() +{ + fprintf(stderr, "[ChatAPI.cpp] default OnConnect\n"); +} + +void ChatAPI::OnDisconnect() +{ + fprintf(stderr, "[ChatAPI.cpp] default OnDisconnect\n"); +} + +void ChatAPI::OnFailoverBegin() +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFailoverBegin\n"); +} + +void ChatAPI::OnFailoverComplete() +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFailoverComplete\n"); +} + +void ChatAPI::OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnLoginAvatar\n"); +} +void ChatAPI::OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, int requiredLoginPriority, void *user) +{ + // fprintf(stderr, "[ChatAPI.cpp] default OnLoginAvatar(with loginPriority) \n"); +} + +void ChatAPI::OnTemporaryAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnTemporaryAvatar\n"); +} + +void ChatAPI::OnLogoutAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnLogoutAvatar\n"); +} + +void ChatAPI::OnDestroyAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnDestroyAvatar\n"); +} + +void ChatAPI::OnGetAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetAvatar\n"); +} + +void ChatAPI::OnGetAnyAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, bool loggedIn, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetAnyAvatar\n"); +} + +void ChatAPI::OnAvatarList(unsigned track, unsigned result, unsigned listLength, const AvatarListItem* avatarList, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAvatarList\n"); +} + +void ChatAPI::OnSetAvatarAttributes(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetAvatarAttributes\n"); +} + +void ChatAPI::OnSetAvatarStatusMessage(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetAvatarStatusMessage\n"); +} + +void ChatAPI::OnSetAvatarForwardingEmail(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetAvatarForwardingEmail\n"); +} + +void ChatAPI::OnSetAvatarInboxLimit(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetAvatarInboxLimit\n"); +} + +void ChatAPI::OnTransferAvatar(unsigned track, unsigned result, unsigned oldUserID, unsigned newUserID, const ChatUnicodeString &oldName, const ChatUnicodeString &newName, const ChatUnicodeString &oldAddress, const ChatUnicodeString &newAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnTransferAvatar\n"); +} + +void ChatAPI::OnFanClubHandle(unsigned track, unsigned result, const ChatUnicodeString &handle, unsigned stationID, unsigned fanClubCode, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFanClubHandle\n"); +} + +void ChatAPI::OnCreateRoom(unsigned track, unsigned result, const ChatRoom *newRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnCreateRoom\n"); +} + +void ChatAPI::OnDestroyRoom(unsigned track, unsigned result, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnDestroyRoom\n"); +} + +void ChatAPI::OnGetRoom(unsigned track, unsigned result, const ChatRoom *room, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetRoom\n"); +} + +void ChatAPI::OnGetRoomSummaries(unsigned track, unsigned result, unsigned numFoundRooms, RoomSummary *foundRooms, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetRoomSummaries\n"); +} + +void ChatAPI::OnSendInstantMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSendInstantMessage\n"); +} + +void ChatAPI::OnSendRoomMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSendRoomMessage\n"); +} + +void ChatAPI::OnSendBroadcastMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &address, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSendBroadcastMessage\n"); +} + +void ChatAPI::OnFilterMessage(unsigned track, unsigned result, const ChatUnicodeString &filteredMsg, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFilterMessage\n"); +} + +void ChatAPI::OnFilterMessageEx(unsigned track, unsigned result, const ChatUnicodeString &filteredMsg, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFilterMessageEx\n"); +} + +void ChatAPI::OnAddFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddFriend\n"); +} + +void ChatAPI::OnAddFriendReciprocate(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddFriendReciprocate\n"); +} + + +void ChatAPI::OnSetFriendComment(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetFriendComment\n"); +} + +void ChatAPI::OnRemoveFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveFriend\n"); +} + +void ChatAPI::OnRemoveFriendReciprocate(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveFriendReciprocate\n"); +} + +void ChatAPI::OnFriendStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatFriendStatus *friendList, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFriendStatus\n"); +} + +void ChatAPI::OnAddIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddIgnore\n"); +} + +void ChatAPI::OnRemoveIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveIgnore\n"); +} + +void ChatAPI::OnIgnoreStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatIgnoreStatus *ignoreList, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnIgnoreStatus\n"); +} + +void ChatAPI::OnEnterRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnEnterRoom\n"); +} + +void ChatAPI::OnAllowRoomEntry(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAllowRoomEntry\n"); +} + +void ChatAPI::OnLeaveRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnLeaveRoom\n"); +} + +void ChatAPI::OnReceiveDestroyRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveDestroyRoom\n"); +} + +void ChatAPI::OnAddModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddModerator\n"); +} + +void ChatAPI::OnRemoveModerator(unsigned track,unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveModerator\n"); +} + +void ChatAPI::OnAddTemporaryModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddTemporaryModerator\n"); +} + +void ChatAPI::OnRemoveTemporaryModerator(unsigned track,unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveTemporaryModerator\n"); +} + +void ChatAPI::OnAddBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddBan\n"); +} + +void ChatAPI::OnRemoveBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveBan\n"); +} + +void ChatAPI::OnAddInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAddInvite\n"); +} + +void ChatAPI::OnRemoveInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRemoveInvite\n"); +} + +void ChatAPI::OnGrantVoice(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGrantVoice\n"); +} + +void ChatAPI::OnRevokeVoice(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnRevokeVoice\n"); +} + +void ChatAPI::OnKickAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnKickAvatar\n"); +} + +void ChatAPI::OnSetRoomParams(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetRoomParams\n"); +} + +void ChatAPI::OnChangeRoomOwner(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnChangeRoomOwner\n"); +} + +void ChatAPI::OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSendPersistentMessage\n"); +} + +void ChatAPI::OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned messageID, void *user) +{ + // fprintf(stderr, "[ChatAPI.cpp] default OnSendPersistentMessage (with message ID) \n"); +} + +void ChatAPI::OnSendMultiplePersistentMessages(unsigned track, unsigned result, unsigned numSubResults, const unsigned *subResults, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSendMultiplePersistentMessages\n"); +} + +void ChatAPI::OnSendMultiplePersistentMessages(unsigned track, unsigned result, unsigned numSubResults, const unsigned *subResults, const unsigned *messageIDs, const ChatAvatar *srcAvatar, void *user) +{ + // fprintf(stderr, "[ChatAPI.cpp] default OnSendMultiplePersistentMessages (with message IDs)\n"); +} + +void ChatAPI::OnAlterPersistentMessage(unsigned track, unsigned result, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnAlterPersistentMessage\n"); +} + +void ChatAPI::OnGetPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetPersistentHeaders\n"); +} + +void ChatAPI::OnGetPartialPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetPartialPersistentHeaders\n"); +} + +void ChatAPI::OnCountPersistentMessages(unsigned track, unsigned result, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numberOfMessages, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnCountPersistentMessages\n"); +} + +void ChatAPI::OnGetPersistentMessage(unsigned track, unsigned result, ChatAvatar *destAvatar, const PersistentHeader *header, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetPersistentMessage\n"); +} + +void ChatAPI::OnGetMultiplePersistentMessages(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, PersistentMessage ** const list, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetMultiplePersistentMessages\n"); +} + +void ChatAPI::OnUpdatePersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnUpdatePersistentMessage\n"); +} + +void ChatAPI::OnUpdatePersistentMessages(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnUpdatePersistentMessages\n"); +} + +void ChatAPI::OnClassifyPersistentMessages(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnClassifyPersistentMessages\n"); +} + +void ChatAPI::OnDeleteAllPersistentMessages(unsigned track, unsigned result, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numberDeleted, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnDeleteAllPersistentMessages\n"); +} + +void ChatAPI::OnUnregisterRoom(unsigned track, unsigned result, const ChatRoom *destRoom, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnUnregisterRoom\n"); +} + +void ChatAPI::OnSetAvatarKeywords(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSetAvatarKeywords\n"); +} + +void ChatAPI::OnGetAvatarKeywords(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString *keywordList, unsigned listLength, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetAvatarKeywords\n"); +} + +void ChatAPI::OnSearchAvatarKeywords(unsigned track, unsigned result, ChatAvatar **avatarMatches, unsigned numMatches, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnSearchAvatarKeywords\n"); +} + +void ChatAPI::OnFriendConfirm(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFriendConfirm\n"); +} + +void ChatAPI::OnFriendConfirmReciprocate(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFriendConfirmReciprocate\n"); +} + + +void ChatAPI::OnFindAvatarByUID(unsigned track, unsigned result, unsigned numFoundAvatarsOnline, ChatAvatar **foundAvatars, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnFindAvatarByUID\n"); +} + +void ChatAPI::OnBeginSnoopingAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnBeginSnoopingAvatar\n"); +} + +void ChatAPI::OnStopSnoopingAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnStopSnoopingAvatar\n"); +} + +void ChatAPI::OnBeginSnoopingRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnBeginSnoopingRoom\n"); +} + +void ChatAPI::OnStopSnoopingRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnStopSnoopingRoom\n"); +} + +void ChatAPI::OnGetSnoopList(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned avatarSnoopListLength, AvatarSnoopPair **avatarSnoops, unsigned roomSnoopListLength, ChatUnicodeString **roomSnoops, void *user) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnGetSnoopList\n"); +} + +ChatUnicodeString ChatAPI::getErrorString(unsigned resultCode) +{ + return ChatAPICore::getErrorString(resultCode); +} + +void ChatAPI::OnReceiveInstantMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveInstantMessage\n"); +} + +void ChatAPI::OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRoomMessage\n"); +} + +void ChatAPI::OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob, unsigned messageID) +{ + // fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRoomMessage (with message ID)\n"); +} + +void ChatAPI::OnReceiveBroadcastMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveBroadcastMessage\n"); +} + +void ChatAPI::OnReceiveFilterMessage(const ChatUnicodeString &msg) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFilterMessage\n"); +} + +void ChatAPI::OnReceiveFriendLogin(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendLogin\n"); +} + +void ChatAPI::OnReceiveFriendLogout(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendLogout\n"); +} + +void ChatAPI::OnReceiveFriendStatusChange(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendStatusChange\n"); +} + +void ChatAPI::OnReceiveKickRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveKickRoom\n"); +} + +void ChatAPI::OnReceiveKickAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveKickAvatar\n"); +} + +void ChatAPI::OnReceiveRoomEntryRequest(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &destRoomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRoomEntryRequest\n"); +} + +void ChatAPI::OnReceiveDelayedRoomEntry(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveDelayedRoomEntry\n"); +} + +void ChatAPI::OnReceiveDeniedRoomEntry(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveDeniedRoomEntry\n"); +} + +void ChatAPI::OnReceiveEnterRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveEnterRoom\n"); +} + +void ChatAPI::OnReceiveLeaveRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveLeaveRoom\n"); +} + +void ChatAPI::OnReceiveAddModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddModeratorRoom\n"); +} + +void ChatAPI::OnReceiveAddModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddModeratorAvatar\n"); +} + +void ChatAPI::OnReceiveRemoveModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveModeratorRoom\n"); +} + +void ChatAPI::OnReceiveRemoveModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveModeratorAvatar\n"); +} + +void ChatAPI::OnReceiveAddTemporaryModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddTemporaryModeratorRoom\n"); +} + +void ChatAPI::OnReceiveAddTemporaryModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddTemporaryModeratorAvatar\n"); +} + +void ChatAPI::OnReceiveRemoveTemporaryModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveTemporaryModeratorRoom\n"); +} + +void ChatAPI::OnReceiveRemoveTemporaryModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveTemporaryModeratorAvatar\n"); +} + +void ChatAPI::OnReceiveAddBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddBanRoom\n"); +} + +void ChatAPI::OnReceiveAddBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddBanAvatar\n"); +} + +void ChatAPI::OnReceiveRemoveBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveBanRoom\n"); +} + +void ChatAPI::OnReceiveRemoveBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveBanAvatar\n"); +} + +void ChatAPI::OnReceiveAddInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddInviteRoom\n"); +} + +void ChatAPI::OnReceiveAddInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveAddInviteAvatar\n"); +} + +void ChatAPI::OnReceiveRemoveInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveInviteRoom\n"); +} + +void ChatAPI::OnReceiveRemoveInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRemoveInviteAvatar\n"); +} + +void ChatAPI::OnReceiveGrantVoiceRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveGrantVoiceRoom\n"); +} + +void ChatAPI::OnReceiveGrantVoiceAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveGrantVoiceAvatar\n"); +} + +void ChatAPI::OnReceiveRevokeVoiceRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRevokeVoiceRoom\n"); +} + +void ChatAPI::OnReceiveRevokeVoiceAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRevokeVoiceAvatar\n"); +} + +void ChatAPI::OnReceiveRoomParams(const ChatAvatar *srcAvatar, const ChatRoom *destRoom, const RoomParams *params, const RoomParams *oldParams) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRoomParams\n"); +} + +void ChatAPI::OnReceivePersistentMessage(const ChatAvatar *destAvatar, const PersistentHeader *header) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceivePersistentMessage\n"); +} + +void ChatAPI::OnReceiveForcedLogout(const ChatAvatar *oldAvatar) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveForcedLogout\n"); +} + +void ChatAPI::OnReceiveUnregisterRoomReady(const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveUnregisterRoomReady\n"); +} + +void ChatAPI::OnReceiveFriendConfirmRequest(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendConfirmRequest\n"); +} + +void ChatAPI::OnReceiveFriendConfirmResponse(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar ,bool confirmed) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendConfirmResponse\n"); +} + +void ChatAPI::OnReceiveFriendConfirmReciprocateRequest(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendConfirmReciprocateRequest\n"); +} + +void ChatAPI::OnReceiveFriendConfirmReciprocateResponse(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar ,bool confirmed) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveFriendConfirmReciprocateResponse\n"); +} + +void ChatAPI::OnReceiveRoomOwnerChange(const ChatRoom *destRoom) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveRoomOwnerChange\n"); +} + +void ChatAPI::OnReceiveSnoopMessage(unsigned snoopType, + const ChatUnicodeString &snooperName, + const ChatUnicodeString &snooperAddress, + const ChatUnicodeString &srcName, // msg sender + const ChatUnicodeString &srcAddress, // msg sender + const ChatUnicodeString &destName, // dest avatar, invalid if room is destination + const ChatUnicodeString &destAddress, // dest avatar or room address + const ChatUnicodeString &message) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveSnoopMessage\n"); +} + +void ChatAPI::OnReceiveNotifyFriendIsRemoved(ChatAvatar * avatar, const ChatUnicodeString &friendName, const ChatUnicodeString &friendAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveNotifyFriendIsRemoved\n"); +} + +void ChatAPI::OnReceiveNotifyFriendsListChange(ChatAvatar * avatar, + const ChatUnicodeString &originalName, + const ChatUnicodeString &originalAddress, + const ChatUnicodeString &newName, + const ChatUnicodeString &newAddress) +{ + fprintf(stderr, "[ChatAPI.cpp] default OnReceiveNotifyFriendsListChange\n"); +} + + +}; + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPI.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPI.h new file mode 100644 index 00000000..e6110d5c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPI.h @@ -0,0 +1,1094 @@ +#if !defined (CHATAPI_H_) +#define CHATAPI_H_ + +#define CHAT_API_VERSION "080107" +// update this on each code drop, or even better, on each ChatAPI.h modification + +#include "ChatEnum.h" + +namespace ChatSystem +{ + class ChatAPICore; + class ChatAvatar; + class ChatRoom; + class ChatFriendStatus; + class ChatIgnoreStatus; + class AvatarListItem; + class RoomParams; + class RoomSummary; + class RoomParams; + class PersistentHeader; + class PersistentMessage; + class AvatarSnoopPair; + +// class ChatAPI +// +// Description: +// This class is the interface to the ChatSystem. It must be derived by +// another class so that its callback functions may be overridden. +// +// Key features include: +// - Single-threaded API. +// - Rooms. Rooms support moderators, moderation (non-moderators muted), +// kick, ban, invite (private rooms), room messaging, changing of +// room parameters. +// - Messaging. Instant, Room, Broadcast, and Persistent messaging. +// - Friends/Ignores. Friend on/offline notification and avatar ignore. +// - Searching. Room objects returned through callbacks offer iterators +// for their avatar, moderator, ban and invite lists. API calls +// include requests for a chat avatar, a chat room, or a list of +// summarized chat rooms. +// - Tracking. Each request is associated with a void *user, which +// is returned in the callback. +// +// Usage: +// Derive the ChatAPI and pass the constructor the hostname and port of the +// ChatSystem you wish to connect the API to. +// +// Implement the callback functions in your derived class, so that you can +// receive room and avatar specific information, as well as status of the +// completion of your Request function calls. +// +// Continuously call the Process() method to guarantee prompt sending and +// receipt of messages to and from the ChatServer. This can be done in +// a simple worker process whose job is just to call Process(). +// +// ChatAvatar objects returned from callbacks are returned as follows: +// 1) Request callbacks, On___(), always return the locally cached +// avatar's pointer, the same one returned from request callback +// OnLoginAvatar(). This pointer is valid until avatar logs out. +// 2) Message callbacks, OnReceive___(), will return ChatAvatar +// pointers that cannot be guaranteed after the callback returns. +// Typically, the avatar information from the callback is not +// needed beyond the life of the callback anyway, but the equal- +// operator can be used to copy a ChatAvatar object to another. +// +// ChatRoom objects returned from callbacks are returned as follows: +// 1) Any callback that returns a ChatRoom pointer, except for +// OnReceiveDestroyRoom() and OnUnregisterRoom(), returns a +// pointer to the locally cached room and that pointer will +// be valid until either of the preceding two callbacks are +// called and return. +// 2) ChatRoom objects do not have the equal-operator overloaded, +// therefore they cannot be copied, but all the data is +// accessible from the pointer returned by the callback. +// +// See the comments for each Request function and callback method for +// specific information about each. +// +// ChatSystem Details: +// The ChatSystem is an arbitrary hierarchy of nodes allowing for deployment +// of chat systems in remote data centersr that can be linked to the central +// chat tree. Messages only do a long distance hop when they get routed out +// of a given data center. Node organization from the gamecode name down +// is entirely up to the game team, and can be reorganized to allow for further +// chat segmentation should subtrees become overloaded with traffic +// ->Guild Channel #1 (room) +// ->Guild Channels ->Guild Channel #2 (room) +// ->EQ ->EQ WestCoast #1 ->Zone Channels ->Zone channel #1 (room) +// -> West Coast Datacenter ->SWG ->SWG WestCoast #1 +// SOE (root) ->SWG WestCoast #2 +// -> East Coast Dataceneter ->EQ ->EQ EastCoast #1 +// ->SWG ->SWG EastCoast #1 +// ->SWG EastCoast #2 -> Chat Channels -> SWG Chat #1 (room) +// +// Chat addresses are built from the names of the nodes using a '+' character for a delimiter. so Guild Channel #1 above would be +// SOE+West Coast Datacenter+EQ+EQ WestCoast #1+GuildChannels+Guild Channel #1 + + class ChatAPI + { + public: + // ---- CONSTRUCTOR methods ---- + + // ChatAPI + // Constructs a ChatAPI from a hostname and port of the ChatServer it + // will be connected to, as well as the hostname and port of the Registrar + // ChatServer (which will automatically reroute the ChatAPI connection to + // a hotspare ChatServer if the provided choice is unavailable). + // NULL pointers are NOT valid input. + ChatAPI(const char *registrar_host, short registrar_port, const char *server_host, short server_port); + virtual ~ChatAPI(); + + // setRequestTimeout + // This overrides the default request timeout of 180 seconds for outstanding + // client requests. It will be used for all new requests, but will not change + // the timeout of previously submitted requests. + void setRequestTimeout(unsigned requestTimeout); + + // ---- AVATAR creation/destruction/find methods ---- + + // RequestLoginAvatar + // Logs in an avatar from station ID, avatar name, and avatar address. + // If the avatar's first login, the ChatSystem implicitly creates the + // Chat avatar. Returns a trackID. + unsigned RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user); + + // RequestLoginAvatar + // Logs in avatar as above, but sends login location, which will be set on avatar object, + // in order to provide tracking information to game teams. + unsigned RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &avatarLoginLocation, void *user); + + // RequestLoginAvatar + // Logs in avatar as above, but sends login priority as well, which will be set on avatar object. + // Login priority must be <= login priority of logged-in avatar in order to force logout. For use with external vs. in-game chat. + unsigned RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &avatarLoginLocation, int avatarLoginPriority, void *user); + + // RequestLoginAvatar + // Logs in avatar as above, but also sends avatar attributes to be applied at login. + unsigned RequestLoginAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &avatarLoginLocation, int avatarLoginPriority, int avatarLoginAttributes, void *user); + + // RequestTemporaryAvatar + // Logs in a temporary avatar. A temporary avatar has no friends and is never recorded + // in the database. There is no login priority (the first one must be logged out before another can be logged in). + // This method is intended primarily for providing universal friends a way to 'hook' into the message routing scheme. + unsigned RequestTemporaryAvatar(unsigned userID, const ChatUnicodeString& avatarName, const ChatUnicodeString& avatarAddress, const ChatUnicodeString& avatarLoginLocation, void* user ); + + // RequestLogoutAvatar + // Logs out an avatar, given the avatar's information. Returns a + // trackID. + unsigned RequestLogoutAvatar(const ChatAvatar *srcAvatar, void *user); + + // RequestDestroyAvatar + // Logs out an avatar if logged in and destroys all ChatSystem records + // of the avatar. Returns a trackID. + unsigned RequestDestroyAvatar(const ChatAvatar *srcAvatar, void *user); + + // RequestGetAvatar + // Requests a ChatAvatar object for the avatar with the given name and + // address. Returns a trackID. + unsigned RequestGetAvatar(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user); + + // RequestGetAnyAvatar + // As above, but also returns an avatar which may be offline. Useful + // for checking if an avatar exists. Returns a trackID. + unsigned RequestGetAnyAvatar(const ChatUnicodeString& avatarName, const ChatUnicodeString& avatarAddress, void* user); + + // RequestAvatarList + // Returns all avatars owned by the given userID, regardless if + // the avatar is online or not. Note that this does not work across + // servers, i.e., only avatars created on this ChatAPI's server will + // be returned. This is a somewhat expensive call and is not intended + // to be used frequently. + unsigned RequestAvatarList(unsigned userID, void* user); + + // + // RequestSetAvatarAttributes + // Sets the attributes (e.g. invisibility) for a given avatar. + // Returns a trackID. + unsigned RequestSetAvatarAttributes(const ChatAvatar *srcAvatar, unsigned long avatarAttributes, void *user); + + // RequestSetAvatarSessionAttributes + // Sets the attributes (e.g. invisibility) for a given avatar, as above. + // However, these attributes are not persistent and last only for the duration of the avatar's session. + unsigned RequestSetAvatarSessionAttributes(const ChatAvatar *srcAvatar, unsigned long avatarAttributes, void *user); + + // RequestSetAvatarStatusMessage + // Sets a 'status' message for the given avatar. This is similar to, but much more flexible than the + // 'attributes' methods. The status message can be any string and is scoped to the avatar's session. + // This method takes the 'Universal' out of 'Universal Chat' because it does not define or require a common + // set of strings to be used - that's sort of the point really. + unsigned RequestSetAvatarStatusMessage(const ChatAvatar* srcAvatar, const ChatUnicodeString& statusMessage, void* user); + + // RequestSetAvatarForwardingEmail + // Sets the forwading email address for an avatar. A string with length < 2 indicates no forwarding. + // However, the actual address used will always be the Station email account, for security reasons. + // Returns a trackID. + unsigned RequestSetAvatarForwardingEmail(const ChatAvatar *srcAvatar, const ChatUnicodeString &avatarForwardingEmail, void *user); + + // RequestSetAvatarInboxLimit + // Sets the inbox limit (max. number of persistent messages) for a given avatar. + // Returns a trackID. + unsigned RequestSetAvatarInboxLimit(const ChatAvatar *srcAvatar, unsigned long avatarInboxLimit, void *user); + + // RequestFindAvatarByUID + // Requests a list of ChatAvatar logins by user (station) ID. Returns + // a trackID (note that this only returns avatrs which are online). + unsigned RequestFindAvatarByUID(unsigned userID, void *user); + + // + // getAvatar + // Requests immediate return of a ChatAvatar object that this API + // has cached due to a RequestLoginAvatar. Request does not go + // to ChatServer. Returns NULL if API does not have object locally. + ChatAvatar *getAvatar(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress); + ChatAvatar *getAvatar(unsigned avatarID); + + // isUID + // Requests if the string is a valid game/namespace Chat node in the ChatSystem + // example: isUID("SOE+SWG") is good form, isUID("SWG") will fail + bool isUID(const ChatUnicodeString &uidNode); + + // setDefaultLoginLocation + // Sets a default value to be used as the login location when the + // version of RequestLoginAvatar is called that does not include that argument. + void setDefaultLoginLocation(const ChatUnicodeString &defaultLoginLocation); + + // setDefaultLoginPriority + // Sets a default value to be used as the login priority when the + // version of RequestLoginAvatar is called that does not include that argument. + void setDefaultLoginPriority(int defaultLoginPriority); + + // ---- AVATAR transfer methods ---- + + // RequestTransferAvatar + // Transfers an avatar, which optionally changes name, address and + // userID (stationID). Do not call this individually for each change, + // instead for all required changes at once. The avatar must be + // logged out of Chat. The game is required to first guarantee that + // the destination avatar is valid/unused, as Chat will overwrite any + // existing destination data. Persistent messages are not transferred by default, + // but the version that includes the transferPersistentMessages argument allows it. + // Returns a trackID. + unsigned RequestTransferAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned newUserID, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &newAvatarAddress, void *user); + unsigned RequestTransferAvatar(unsigned userID, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned newUserID, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &newAvatarAddress, bool transferPersistentMessages, void *user); + + // ---- AVATAR keyword manipulation methods ---- + + // RequestSetAvatarKeywords + // Sets the keywords on the specified avatar allowing them to be searched on within the chat system + unsigned RequestSetAvatarKeywords(const ChatAvatar *srcAvatar, const ChatUnicodeString *keywordList, unsigned keywordLength, void *user); + + // RequestGetAvatarKeywords + // Gets the keywords previously set on the specified avatar + unsigned RequestGetAvatarKeywords(const ChatAvatar *srcAvatar, void *user); + + // RequestSearchAvatarKeywords + // Searches the keywords on within the chat system and returns a list of avatars that match + unsigned RequestSearchAvatarKeywords(const ChatUnicodeString nodeAddress, const ChatUnicodeString *keywordList, unsigned keywordLength, void *user); + + // ---- FANCLUB handle lookup method ---- + + // RequestFanClubHandle + // Obtains a fan club handle and relevant information given the + // user's station ID and fan club code. + unsigned RequestFanClubHandle(unsigned stationID, unsigned fanClubCode, void *user); + + // ---- ROOM creation/destruction/params methods ---- + + // RequestCreateRoom + // Creates a room for user srcAvatar, from the room parameters (includes + // room name) and the parent node's address. The new room's address + // will be "parentAddress+roomName". Returns a trackID. + unsigned RequestCreateRoom(const ChatAvatar *srcAvatar, const RoomParams &roomParams, const ChatUnicodeString &parentAddress, void *user); + + // RequestDestroyRoom + // Destroys a room for user srcAvatar, using roomAddress. + // The avatar must have created the room to destroy it. Returns a + // trackID. + unsigned RequestDestroyRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestGetRoom + // Requests a ChatRoom object for the room with the given address. + // Returns a trackID. + unsigned RequestGetRoom(const ChatUnicodeString &roomAddress, void *user); + + // getRoom + // Requests immediate return of a ChatRoom object that this API + // has cached due to a RequestGetRoom, RequestCreateRoom, or + // RequestEnterRoom. Request does not go to ChatServer. Returns + // NULL if API does not have object locally. + ChatRoom *getRoom(const ChatUnicodeString &roomAddress); + ChatRoom *getRoom(unsigned roomID); + + // RequestGetRoomSummaries + // Requests a list of RoomSummary objects for the rooms matching the + // given room name filter and at or below the node startNodeAddress. + // Returns a trackID. + unsigned RequestGetRoomSummaries(const ChatUnicodeString &startNodeAddress, const ChatUnicodeString &roomFilter, void *user); + + // getDefaultRoomParams + // Requests the ChatAPI's current default RoomParams object. Used for + // the EnterRoom call. If NULL, EnterRoom will not do passive room + // creation if the room to enter does not yet exist. Initial value + // is NULL (no RoomParams object defined). + const RoomParams *getDefaultRoomParams(void); + + // setDefaultRoomParams + // Sets the ChatAPI's current default RoomParams object. Passing a NULL + // pointer will cause the default params not to be used by EnterRoom. + void setDefaultRoomParams(RoomParams *roomParams); + + // ---- MESSAGING methods ---- + + // RequestSendInstantMessage + // Sends an instant message from srcAvatar to the avatar of the given + // name and address. Supports out-of-band data which the ChatSystem + // does not use but delivers to provide additional content transfer. + // Returns a trackID. + unsigned RequestSendInstantMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + + // RequestSendRoomMessage + // Sends a room message from srcAvatar to the room of given + // room address. Also supports out-of-band data. Returns a trackID. + unsigned RequestSendRoomMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + + // RequestSendBroadcastMessage + // Sends a broadcast message from srcAvatar to the nodes at and below + // the node located at destAddress. Also supports out-of-band data. + // Returns a trackID. + unsigned RequestSendBroadcastMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destNodeAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + + // RequestFilterMessage + // Filters the message + // Returns a trackID. + unsigned RequestFilterMessage(const ChatUnicodeString &in_msg, void *user); + + // RequestFilterMessageEx + // Filters the message + // Returns a trackID. + unsigned RequestFilterMessageEx(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &in_msg, void *user); + + // ---- FRIEND methods ---- + + // RequestAddFriend + // Adds a friend for srcAvatar for the avatar described by destName and + // destAddress. If parameter "confirm" is set to true, then the destAvatar + // is given opportunity to accept/decline the request. When that avatar's + // online status changes, notification is sent to srcAvatar's connected API. + // Returns a trackID. + unsigned RequestAddFriend(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, bool confirm, void *user); + unsigned RequestAddFriendReciprocate(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, bool confirm, void *user); + + // RequestAddFriend + // Adds a friend as above, and also set the "friend comment" field, requested by SWG. + unsigned RequestAddFriend(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &friendComment, bool confirm, void *user); + unsigned RequestAddFriendReciprocate(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &friendComment, bool confirm, void *user); + + // RequestSetFriendComment + // Sets the "friend comment" field, requested by SWG, for the avatar. + // The friend must already exist. + unsigned RequestSetFriendComment(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &friendComment, void *user); + + // RequestRemoveFriend + // Removes a friend for srcAvatar for the avatar described by destName + // and destAddress. Online status change notifications for the + // described avatar will cease being delivered to srcAvatar. Returns a + // trackID. + unsigned RequestRemoveFriend(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + unsigned RequestRemoveFriendReciprocate(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + + // RequestFriendStatus + // Requests the friend list for avatar srcAvatar. Returns a trackID. + unsigned RequestFriendStatus(const ChatAvatar *srcAvatar, void *user); + + // RequestFriendConfirm + // Acknowledges a RequestAddFriend call from another avatar. Call after + // receipt of OnReceiveFriendConfirmRequest callback. Submitting a + // value of "true" for parameter "confirm" will cause friend association + // to be made. srcAvatar is the avatar on this API that was requested + // friendship from destAvatar. This means the srcAvatar in above callback + // is the destAvatar in this request. Remember that the validity of + // srcAvatar in the callback ends when the callback ends, thus should be + // copied first or this should be called within that callback to assure + // passing a valid ChatAvatar as destAvatar. + unsigned RequestFriendConfirm(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, bool confirm, void *user); + unsigned RequestFriendConfirmReciprocate(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, bool confirm, void *user); + + // ---- IGNORE methods ---- + + // RequestAddIgnore + // Adds an ignore for srcAvatar for any messages originating from the + // avatar described by destName and destAddress. Returns a trackID. + unsigned RequestAddIgnore(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + + // RequestRemoveIgnore + // Removes an ignore for srcAvatar for any messages originating from + // the avatar described by destName and destAddress. Returns a trackID. + unsigned RequestRemoveIgnore(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + + // RequestIgnoreStatus + // Requests the ignore list for the avatar srcAvatar. Returns a trackID. + unsigned RequestIgnoreStatus(const ChatAvatar *srcAvatar, void *user); + + // ---- ROOM enter/leave methods ---- + + // RequestEnterRoom + // Enters srcAvatar into the room defined by destRoomAddress. If the + // room does not yet exist and the default RoomParams object is defined + // by setDefaultRoomParams(), then the ChatSystem will attempt to + // passively create the room. Returns a trackID. + unsigned RequestEnterRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestEnterRoom + // Enters room, as above, but provides a password, + // to be used if room is private and has a password. + unsigned RequestEnterRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destRoomPassword, void *user); + + // RequestEnterRoom + // Enters room, as above, but provides a Boolean value stating whether delayed entry may occur + // if the room is private and the owner chooses to allow the avatar to enter. + unsigned RequestEnterRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destRoomPassword, bool requestEntry, void *user); + + // RequestAllowRoomEntry + // Allows an avatar that has previously attempted to enter a room with requestEntry set to true + // to enter the specified room, or deny such entry to the avatar if desired. + unsigned RequestAllowRoomEntry(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, bool allow, void *user); + + // RequestLeaveRoom + // Removes srcAvatar from the room defined by destRoomAddress. Returns + // a trackID. + unsigned RequestLeaveRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, void *user); + + // setDefaultEntryType + // Sets a default value to be used as the requestEntry value when the + // version of RequestEnterRoom is called that does not include that argument. + void setDefaultEntryType(bool defaultEntryType); + + // ---- ROOM admin/moderator methods ---- + + // RequestAddModerator + // Adds destAvatar as a moderator to room described by + // destRoomAddress. The srcAvatar must be the creator or a GM. Returns a + // trackID. + unsigned RequestAddModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestRemoveModerator + // Removes destAvatar as a moderator to room described by + // destRoomAddress. The srcAvatar must be the creator or a GM. Returns a + // trackID. + unsigned RequestRemoveModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestAddTemporaryModerator + // Adds destAvatar as a temporary moderator to room described by + // destRoomAddress. This status will be lost when the affected avatar leaves the room. + // The srcAvatar must be the creator or a GM. Returns a trackID. + unsigned RequestAddTemporaryModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestRemoveTemporaryModerator + // Removes destAvatar as a temporary moderator to room described by + // destRoomAddress. The srcAvatar must be the creator or a GM. Returns a + // trackID. + unsigned RequestRemoveTemporaryModerator(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestAddBan + // Bans and kicks destAvatar from the room described by + // destRoomAddress. The srcAvatar must be the creator. Returns a + // trackID. + unsigned RequestAddBan(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestRemoveBan + // Unbans destAvatar from the room described by + // destRoomAddress. The srcAvatar must be the creator. Returns a + // trackID. + unsigned RequestRemoveBan(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestAddInvite + // Adds an invitation for destAvatar for the room described by + // destRoomAddress. The srcAvatar must be the creator + // or a moderator. This only applies to private rooms. Returns a + // trackID. + unsigned RequestAddInvite(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestRemoveInvite + // Removes an invitation for destAvatar for the room described by + // destRoomAddress. The srcAvatar must be the creator + // or a moderator. This only applies to private rooms. Removing + // invitation indicates that destAvatar will not succeed on any + // further EnterRoom requests, but does not kick destAvatar if in-room. + // Returns a trackID. + unsigned RequestRemoveInvite(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestGrantVoice + // Grants the destAvatar the right to speak in the room described by + // destRoomAddress. The srcAvatar must be the creator, a moderator, or a GM. + // This only applies to moderated rooms. Returns a trackID. + unsigned RequestGrantVoice(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestRevokeVoice + // Revokes the right of destAvatar to speak in the room described by + // destRoomAddress. The srcAvatar must be the creator, a GM, + // or a moderator. This only applies to moderated rooms. Revoking + // voice indicates that destAvatar will not succeed on any + // further SendRoomMessage requests. + // Returns a trackID. + unsigned RequestRevokeVoice(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestKickAvatar + // Kicks destAvatar from the room described by + // destRoomAddress. The srcAvatar must be the creator or a moderator. + // Returns a trackID. + unsigned RequestKickAvatar(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, void *user); + + // RequestSetRoomParams + // Sets new room parameters for the room described by + // destRoomAddress. The name parameter cannot be changed and is + // ignored from the RoomParams object. Returns a trackID. + unsigned RequestSetRoomParams(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const RoomParams *params, void *user); + + // RequestChangeRoomOwner + // Changes the owner of a room to the specified avatar, + // if the avatar exists. srcAvatar must be current owner or GM. + // Returns a trackID. + unsigned RequestChangeRoomOwner(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + + // ---- PERSISTENT MESSAGE methods ---- + + // RequestSendPersistentMessage + // Sends a persistent message from srcAvatar to a destination name and address + // "category" is an optional argument, stored with the message for classification purposes + // The "enforceInboxLimit" specifies whether this message should be subject to inbox size limits; it defaults to "true" in the calls that don't include that parameter. + unsigned RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + unsigned RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user); + unsigned RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user); + unsigned RequestSendPersistentMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user); + + // RequestSendPersistentMessage + // Sends a persistent message from an arbitrary source (such as an in game NPC) to a destination avatar + // NOTE that this message cannot be replyed to + // "category" is an optional argument, stored with the message for classification purposes + // The "enforceInboxLimit" specifies whether this message should be subject to inbox size limits; it defaults to "true" in the calls that don't include that parameter. + unsigned RequestSendPersistentMessage(const ChatUnicodeString &srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + unsigned RequestSendPersistentMessage(const ChatUnicodeString &srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user); + unsigned RequestSendPersistentMessage(const ChatUnicodeString &srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user); + unsigned RequestSendPersistentMessage(const ChatUnicodeString &srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user); + + // RequestSendMultiplePersistentMessages + // Sends the same persistent message from srcAvatar to the destination names and addresses + // The "enforceInboxLimit" specifies whether this message should be subject to inbox size limits; it defaults to "true" in the calls that don't include that parameter. + unsigned RequestSendMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user); + unsigned RequestSendMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user); + unsigned RequestSendMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user); + + // RequestSendMultiplePersistentMessages + // Sends the same persistent message from an arbitrary source (such as an in game NPC) to the destination avatars + // NOTE that this message cannot be replyed to + // The "enforceInboxLimit" specifies whether this message should be subject to inbox size limits; it defaults to "true" in the calls that don't include that parameter. + unsigned RequestSendMultiplePersistentMessages(const ChatUnicodeString &srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, void *user); + unsigned RequestSendMultiplePersistentMessages(const ChatUnicodeString &srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, void *user); + unsigned RequestSendMultiplePersistentMessages(const ChatUnicodeString &srcAvatar, unsigned numDestAvatars, const ChatUnicodeString *destAvatarNames, const ChatUnicodeString *destAvatarAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit, void *user); + + // RequestAlterPersistentMessage + // Alters various fields in a persistent message, based on the specified attributes from PersistentAlterationTypes. + unsigned RequestAlterPersistentMessage(const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID, unsigned alterationAttributes, const ChatUnicodeString &newSenderName, const ChatUnicodeString &newSenderAddress, const ChatUnicodeString &newSubject, const ChatUnicodeString &newMsg, const ChatUnicodeString &newOOB, const ChatUnicodeString &newCategory, unsigned newSentTime, void *user); + + // RequestGetPersistentHeaders + // Retrieves persistent message headers for the given avatar. + // "category" field is optional; no category or empty category matches all messages + unsigned RequestGetPersistentHeaders(const ChatAvatar *srcAvatar, void *user); + unsigned RequestGetPersistentHeaders(const ChatAvatar *srcAvatar, const ChatUnicodeString &category, void *user); + + // RequestGetPartialPersistentHeaders + // Retrieves up to maxHeaders (or all header is this value is zero) + // persistent message headers for the given avatar, + // either up to sentTimeStart or after sentTimeStart, depending on the value of + // inDescendingOrder. Setting sentTimeStart to zero will retrieve either the + // most recent or oldest messages, depending on the value of inDescendingOrder. + // "category" field is optional; no category or empty category matches all messages + unsigned RequestGetPartialPersistentHeaders(const ChatAvatar *srcAvatar, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, void *user); + unsigned RequestGetPartialPersistentHeaders(const ChatAvatar *srcAvatar, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category, void *user); + + // RequestCountPersistentMessages + // Retrieves the number persistent messages for the given avatar. + // "category" field is optional; no category or empty category matches all messages + unsigned RequestCountPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user); + unsigned RequestCountPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category, void *user); + + // RequestGetPersistentMessage + // Retrieves the message body and out of band data for a given message header + unsigned RequestGetPersistentMessage(const ChatAvatar *srcAvatar, unsigned messageID, void *user); + + // RequestGetMultiplePersistentMessages + // Retrieves ALL message bodies for messages matching the given criteria, + // which are the same as for RequestGetPartialPersistentHeaders + unsigned RequestGetMultiplePersistentMessages(const ChatAvatar *srcAvatar, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category, void *user); + + // RequestUpdatePersistentMessage + // Updates a persistent message's status. Note that all statuses are applied + // except for PERSISTENT_DELETED, which causes immediate and permanent removal + // of the message. + unsigned RequestUpdatePersistentMessage(const ChatAvatar *srcAvatar, unsigned messageID, PersistentStatus newStatus, void *user); + + // RequestUpdatePersistentMessages + // Changes status of all persistent messages received by srcAvatar that are + // set at currentStatus and updates their status to newStatus. If newStatus + // is PERSISTENT_DELETED, those messages are immediately and permanently + // removed. This is particularly useful for emptying the PERSISTENT_TRASH + // messages, but can be used for any statuses except from PERSISTENT_DELETED. + // "category" field is optional; no category or empty category matches all messages + unsigned RequestUpdatePersistentMessages(const ChatAvatar *srcAvatar, PersistentStatus currentStatus, PersistentStatus newStatus, void *user); + unsigned RequestUpdatePersistentMessages(const ChatAvatar *srcAvatar, PersistentStatus currentStatus, PersistentStatus newStatus, const ChatUnicodeString &category, void *user); + + // RequestClassifyPersistentMessages + // Updates the folder for a set of persistent messages. Can be called with a ChatAvater pointer or a name and address, + // but the avatar must be local to the server that the API is connected to (i.e. not a different game/world) + unsigned RequestClassifyPersistentMessages(const ChatAvatar *srcAvatar, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder, void *user); + unsigned RequestClassifyPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder, void *user); + + // RequestDeleteAllPersistentMessages + // Deletes all persistent messages received by srcAvatar. + // "category" and "olderThan" fields are optional; not supplying these matches all messages. + // Supplying olderThan field deletes only messages older than the given date-time. + unsigned RequestDeleteAllPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, void *user); + unsigned RequestDeleteAllPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category, unsigned olderThan, void *user); + + // ---- ROOM CACHING methods ---- + + // RequestUnregisterRoom + // To be called after receiving the callback OnReadyToUnregisterRoom(), + // which indicated no more avatars from this API are logged in to a + // given room. When there is no further reason to keep the ChatRoom* + // valid and to receive room updates from that room, then this should + // be called to unregister the room, stopping room updates. + unsigned RequestUnregisterRoom(const ChatUnicodeString &roomAddress, void *user); + + // ---- SNOOPING methods ---- + + // RequestBeginSnoopingAvatar + // Begins snooping the destAvatar by srcAvatar. The srcAvatar must have the + // rights to do so, as determined by avatar attrbiutes: the GM attribute allows + // snooping within the same game/project namespace (i.e. SOE+SWG), and the + // superSnoop attribute allows snooping outside of one's game/project namespace. + // Returns a trackID. + unsigned RequestBeginSnoopingAvatar(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + + // RequestStopSnoopingAvatar + // Stops snooping the destAvatar by srcAvatar. If destAvatar has already logged + // out, then this call is not necessary and you will receive an OnReceiveSnoopMessage + // with snoopType SNOOP_END which indicates the snooping has automatically stopped. + // Returns a trackID. + unsigned RequestStopSnoopingAvatar(const ChatAvatar *srcAvatar, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, void *user); + + // RequestBeginSnoopingRoom + // Begins snooping the room by srcAvatar. The srcAvatar must have the + // rights to do so, as determined by avatar attrbiutes: the GM attribute allows + // snooping within the same game/project namespace (i.e. SOE+SWG), and the + // superSnoop attribute allows snooping outside of one's game/project namespace. + // Returns a trackID. + unsigned RequestBeginSnoopingRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user); + + // RequestStopSnoopingRoom + // Stops snooping the room by srcAvatar. If the room has already destructed, + // then this call is not necessary and you will receive an OnReceiveSnoopMessage + // with snoopType SNOOP_END which indicates the snooping has automatically stopped. + // Returns a trackID. + unsigned RequestStopSnoopingRoom(const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user); + + // RequestGetSnoopList + // Requests the snooping list for the avatar srcAvatar. Returns a trackID. + unsigned RequestGetSnoopList(const ChatAvatar *srcAvatar, void *user); + + + // ---- PROCESS method ---- + + // Process + // Must be called to process incoming and outgoing messages between the + // API and the ChatServer. + void Process(); + + // ---- CHATAPI connect/disconnect/failover callback methods ---- + + // OnConnect + // Called when the ChatAPI has established connection to the ChatServer + // and is ready to accept requests. + virtual void OnConnect(); + + // OnDisconnect + // Called when the ChatAPI has lost connection to the ChatServer. + // This may be followed by an OnFailoverBegin command if connection + // is re-established and failover mode is initiated. + virtual void OnDisconnect(); + + // OnFailoverBegin + // Called when the ChatAPI has restored connection to the ChatServer and + // is attempting failover to restore validity of its state. It is + // retaining its queued requests for server submission upon + // OnFailoverComplete. OnConnect is not called during failover attempt. + virtual void OnFailoverBegin(); + + // OnFailoverComplete + // Called when the ChatAPI has restored its connection to the + // ChatServer and restored its state. It is submitting the queued + // requests and ready to accept new requests. + virtual void OnFailoverComplete(); + + // ---- REQUEST CALLBACK methods ---- + // All callbacks are results of their related Request__ methods. + // Check parameter "result" for value 0 (success) before using any + // returned data. + + virtual void OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, void *user); + virtual void OnLoginAvatar(unsigned track, unsigned result, const ChatAvatar *newAvatar, int requiredLoginPriority, void *user); + virtual void OnTemporaryAvatar(unsigned track, unsigned result, const ChatAvatar* newAvatar, void* user ); + virtual void OnLogoutAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user); + virtual void OnDestroyAvatar(unsigned track, unsigned result, const ChatAvatar *oldAvatar, void *user); + virtual void OnGetAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, void *user); + virtual void OnGetAnyAvatar(unsigned track, unsigned result, const ChatAvatar *foundAvatar, bool loggedIn, void *user); + virtual void OnAvatarList(unsigned track, unsigned result, unsigned listLength, const AvatarListItem* avatarList, void* user); + virtual void OnSetAvatarAttributes(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user); + virtual void OnSetAvatarStatusMessage(unsigned track, unsigned result, const ChatAvatar* changedAvatar, void* user ); + virtual void OnSetAvatarForwardingEmail(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user); + virtual void OnSetAvatarInboxLimit(unsigned track, unsigned result, const ChatAvatar *changedAvatar, void *user); + virtual void OnFindAvatarByUID(unsigned track, unsigned result, unsigned numFoundAvatarsOnline, ChatAvatar **foundAvatars, void *user); + + virtual void OnTransferAvatar(unsigned track, unsigned result, unsigned oldUserID, unsigned newUserID, const ChatUnicodeString &oldName, const ChatUnicodeString &newName, const ChatUnicodeString &oldAddress, const ChatUnicodeString &newAddress, void *user); + + virtual void OnFanClubHandle(unsigned track, unsigned result, const ChatUnicodeString &handle, unsigned stationID, unsigned fanClubCode, void *user); + + virtual void OnCreateRoom(unsigned track,unsigned result, const ChatRoom *newRoom, void *user); + virtual void OnDestroyRoom(unsigned track, unsigned result, void *user); + virtual void OnEnterRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnAllowRoomEntry(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user); + virtual void OnLeaveRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + + virtual void OnGetRoom(unsigned track, unsigned result, const ChatRoom *room, void *user); + virtual void OnGetRoomSummaries(unsigned track, unsigned result, unsigned numFoundRooms, RoomSummary *foundRooms, void *user); + + virtual void OnSendInstantMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnSendRoomMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnSendBroadcastMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &address, void *user); + virtual void OnFilterMessage(unsigned track, unsigned result, const ChatUnicodeString &filteredMsg, void *user); + virtual void OnFilterMessageEx(unsigned track, unsigned result, const ChatUnicodeString &filteredMsg, void *user); + + virtual void OnAddFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnAddFriendReciprocate(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnSetFriendComment(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment, void *user); + virtual void OnRemoveFriend(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnRemoveFriendReciprocate(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnFriendStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatFriendStatus *friendList, void *user); + virtual void OnFriendConfirm(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnFriendConfirmReciprocate(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + + virtual void OnAddIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnRemoveIgnore(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnIgnoreStatus(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned listLength, const ChatIgnoreStatus *ignoreList, void *user); + + virtual void OnAddModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnRemoveModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnAddTemporaryModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnRemoveTemporaryModerator(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnAddBan(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnRemoveBan(unsigned track,unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnAddInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnRemoveInvite(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnGrantVoice(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnRevokeVoice(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnKickAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnSetRoomParams(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + virtual void OnChangeRoomOwner(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatRoom *destRoom, void *user); + + virtual void OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnSendPersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned messageID, void *user); + virtual void OnSendMultiplePersistentMessages(unsigned track, unsigned result, unsigned numSubResults, const unsigned *subResults, const ChatAvatar *srcAvatar, void *user); + virtual void OnSendMultiplePersistentMessages(unsigned track, unsigned result, unsigned numSubResults, const unsigned *subResults, const unsigned *messageIDs, const ChatAvatar *srcAvatar, void *user); + virtual void OnAlterPersistentMessage(unsigned track, unsigned result, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID); + virtual void OnGetPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user); + virtual void OnGetPartialPersistentHeaders(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, const PersistentHeader *list, void *user); + virtual void OnCountPersistentMessages(unsigned track, unsigned result, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numberOfMessages, void *user); + virtual void OnGetPersistentMessage(unsigned track, unsigned result, ChatAvatar *destAvatar, const PersistentHeader *header, const ChatUnicodeString &msg, const ChatUnicodeString &oob, void *user); + virtual void OnGetMultiplePersistentMessages(unsigned track, unsigned result, ChatAvatar *destAvatar, unsigned listLength, PersistentMessage ** const list, void *user); + virtual void OnUpdatePersistentMessage(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnUpdatePersistentMessages(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnClassifyPersistentMessages(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnDeleteAllPersistentMessages(unsigned track, unsigned result, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numberDeleted, void *user); + + virtual void OnUnregisterRoom(unsigned track, unsigned result, const ChatRoom *destRoom, void *user); + + virtual void OnSetAvatarKeywords(unsigned track, unsigned result, const ChatAvatar *srcAvatar, void *user); + virtual void OnGetAvatarKeywords(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString *keywordList, unsigned listLength, void *user); + virtual void OnSearchAvatarKeywords(unsigned track, unsigned result, ChatAvatar **avatarMatches, unsigned numAvatarMatches, void *user); + + virtual void OnBeginSnoopingAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnStopSnoopingAvatar(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, void *user); + virtual void OnBeginSnoopingRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user); + virtual void OnStopSnoopingRoom(unsigned track, unsigned result, const ChatAvatar *srcAvatar, const ChatUnicodeString &roomAddress, void *user); + virtual void OnGetSnoopList(unsigned track, unsigned result, const ChatAvatar *srcAvatar, unsigned avatarSnoopListLength, AvatarSnoopPair **avatarSnoops, unsigned roomSnoopListLength, ChatUnicodeString **roomSnoops, void *user); + + // getErrorString + // This is a helper function that returns a brief description of the result code + // returned by the server. + static ChatUnicodeString getErrorString(unsigned resultCode); + + // ---- RECEIVE CALLBACK methods ---- + // All callbacks are results of messages from the ChatServer, such as a + // room update, a message receipt, or an avatar kick. See each's comments + // for information about when it is generated. + // Do not use returned data pointers after callback completes. Instead, + // copy the data inside the callback to local structures. + + // OnReceiveUnregisterRoomReady + // No more avatars connected to this API are participating in the + // given room, thus it should be unregistered to prevent further + // room updates by calling RequestUnregisterRoom(), unless the API + // needs to keep the ChatRoom* for this room valid and to continue + // receiving room updates. + virtual void OnReceiveUnregisterRoomReady(const ChatRoom *destRoom); + + // OnReceiveInstantMessage + // Called when destAvatar, connected to this API, receives an instant + // message from srcAvatar. + virtual void OnReceiveInstantMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + + // OnReceiveRoomMessage + // Called when srcAvatar sends a room message to destRoom. This is + // called for each destAvatar on this API that should receive this + // message. Both versions will be called; handle only ONE with server logic. + virtual void OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + virtual void OnReceiveRoomMessage(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom, const ChatUnicodeString &msg, const ChatUnicodeString &oob, unsigned messageID); + + // OnReceiveBroadcastMessage + // Called when srcAvatar sends a broadcast message to node srcAddress + // and its nodes below. This is called for each destAvatar on this API + // that should receive this message. + virtual void OnReceiveBroadcastMessage(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + + // OnReceiveFilterMessage + virtual void OnReceiveFilterMessage(const ChatUnicodeString &msg); + + // OnReceiveFriendLogin + // Called when srcAvatar has logged in. The destAvatar is on this API + // and has requested to receive notifications about srcAvatar. The + // srcAddress is the AvatarID node sending the notification. + virtual void OnReceiveFriendLogin(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar); + + // OnReceiveFriendLogout + // Called when srcAvatar has logged out. The destAvatar is on this API + // and has requested to receive notifications about srcAvatar. The + // srcAddress is the AvatarID node sending the notification. + virtual void OnReceiveFriendLogout(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar); + + // OnReceiveFriendStatusChange + // Called when a friend of destAvatar has changed their status message. + // The destAvatar is on this API and has requestd to receive notifications + // about srcAvatar. + virtual void OnReceiveFriendStatusChange(const ChatAvatar *srcAvatar, const ChatUnicodeString &srcAddress, const ChatAvatar *destAvatar); + + // OnReceiveFriendConfirmRequest + // Called when srcAvatar is asking destAvatar for confirmation to be added to srcAvatar's friend list + virtual void OnReceiveFriendConfirmRequest(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar); + + // OnReceiveFriendConfirmResponse + // Called when srcAvatar responds to destAvatar's request for friend confirmation. Contains whether or not the attempt to add + // the friend was successful or not + virtual void OnReceiveFriendConfirmResponse(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, bool confirmed); + + // OnReceiveFriendConfirmRequest + // Called when srcAvatar is asking destAvatar for confirmation to be added to srcAvatar's friend list + virtual void OnReceiveFriendConfirmReciprocateRequest(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar); + + // OnReceiveFriendConfirmResponse + // Called when srcAvatar responds to destAvatar's request for friend confirmation. Contains whether or not the attempt to add + // the friend was successful or not + virtual void OnReceiveFriendConfirmReciprocateResponse(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, bool confirmed); + + // OnReceiveKickRoom + // Called when destAvatar has been kicked by srcAvatar from destRoom + // and this API has avatars that are in destRoom. + virtual void OnReceiveKickRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveKickAvatar + // Called when destAvatar has been kicked by srcAvatar from the room + // described by roomName and roomAddress, and destAvatar is on + // this API. + virtual void OnReceiveKickAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRoomEntryRequest + // Called when srcAvatar has attempted to enter the room at destRoomAddress with + // m_requestingEntry set to true and has been denied entry because the room is private. + // The API through which the room's owner (destAvatar) is logged in will receive this callback. + virtual void OnReceiveRoomEntryRequest(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &destRoomAddress); + + // OnReceiveDelayedRoomEntry + // Called when srcAvatar has attempted to enter the room at destRoomAddress with + // m_requestingEntry set to true, was initiallly denied entry because the room is private, + // but has been allowed into the room by the owner. This is essentially a delayed OnEnterRoom callback, + // and it will be followed by an OnReceiveEnterRoom notification. + virtual void OnReceiveDelayedRoomEntry(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + // OnReceiveDeniedRoomEntry + // Called when srcAvatar has attempted to enter the room at destRoomAddress with + // m_requestingEntry set to true, was initiallly denied entry because the room is private, + // and has been denied again room by the owner. The avatar will not be in the room. + virtual void OnReceiveDeniedRoomEntry(const ChatAvatar *srcAvatar, const ChatUnicodeString &destRoomAddress); + + // OnReceiveEnterRoom + // Called when srcAvatar has entered destRoom and this API has avatars + // that are in destRoom. If srcAvatar is on this API and no others from + // this API are in the room, this is not called. + virtual void OnReceiveEnterRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + // OnReceiveLeaveRoom + // Called when srcAvatar has left destRoom and this API has avatars + // that are in destRoom. + virtual void OnReceiveLeaveRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + // OnReceiveDestroyRoom + // Called when srcAvatar has destroyed destRoom and this API has avatars + // that were in destRoom. + virtual void OnReceiveDestroyRoom(const ChatAvatar *srcAvatar, const ChatRoom *destRoom); + + // OnReceiveAddModeratorRoom + // Called when srcAvatar has granted destAvatar moderator privileges in + // destRoom and this API has avatars that are in destRoom. + virtual void OnReceiveAddModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveAddModeratorAvatar + // Called when srcAvatar has granted destAvatar moderator privileges in + // the room described by roomName and roomAddress, and destAvatar + // is on this API. + virtual void OnReceiveAddModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRemoveModeratorRoom + // Called when srcAvatar has removed destAvatar moderator privileges in + // destRoom and this API has avatars that are in destRoom. + virtual void OnReceiveRemoveModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveRemoveModeratorAvatar + // Called when srcAvatar has removed destAvatar moderator privileges from + // the room described by roomName and roomAddress, and destAvatar is on + // this API. + virtual void OnReceiveRemoveModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveAddTemporaryModeratorRoom + // Called when srcAvatar has granted destAvatar temporary moderator privileges in + // destRoom and this API has avatars that are in destRoom. + virtual void OnReceiveAddTemporaryModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveAddTemporaryModeratorAvatar + // Called when srcAvatar has granted destAvatar temporary moderator privileges in + // the room described by roomName and roomAddress, and destAvatar + // is on this API. + virtual void OnReceiveAddTemporaryModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRemoveTemporaryModeratorRoom + // Called when srcAvatar has removed destAvatar temporary moderator privileges in + // destRoom and this API has avatars that are in destRoom. + virtual void OnReceiveRemoveTemporaryModeratorRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveRemoveTemporaryModeratorAvatar + // Called when srcAvatar has removed destAvatar temporary moderator privileges from + // the room described by roomName and roomAddress, and destAvatar is on + // this API. + virtual void OnReceiveRemoveTemporaryModeratorAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveAddBanRoom + // Called when srcAvatar has banned destAvatar from destRoom and this + // API has avatars that are in destRoom. + virtual void OnReceiveAddBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveAddBanAvatar + // Called when srcAvatar has banned destAvatar from the room described by + // roomName and roomAddress, and destAvatar is on this API. + virtual void OnReceiveAddBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRemoveBanRoom + // Called when srcAvatar has removed the ban on destAvatar from + // destRoom and this API has avatars that are in destRoom. + virtual void OnReceiveRemoveBanRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveRemoveBanAvatar + // Called when srcAvatar has removed the ban on destAvatar from + // the room described by roomName and roomAddress, and destAvatar is on + // this API. + virtual void OnReceiveRemoveBanAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveAddInviteRoom + // Called when srcAvatar has invited destAvatar to destRoom and this + // API has avatars that are in this room. + virtual void OnReceiveAddInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveAddInviteAvatar + // Called when srcAvatar has invited destAvatar to the room described + // by roomName and roomAddress, and destAvatar is on this API. + virtual void OnReceiveAddInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRemoveInviteRoom + // Called when srcAvatar has uninvited destAvatar from destRoom and + // this API has avatars that are in this room. + virtual void OnReceiveRemoveInviteRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveRemoveInviteAvatar + // Called when srcAvatar has uninvited destAvatar from the room + // described by roomName and roomAddress, and destAvatar is on + // this API. + virtual void OnReceiveRemoveInviteAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveGrantVoiceRoom + // Called when srcAvatar has granted voice to destAvatar in destRoom and this + // API has avatars that are in the room. + virtual void OnReceiveGrantVoiceRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveGrantVoiceAvatar + // Called when srcAvatar has granter voice to destAvatar in the room described + // by roomName and roomAddress, and destAvatar is on this API. + virtual void OnReceiveGrantVoiceAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRevokeVoiceRoom + // Called when srcAvatar has revoked the voice privilege for destAvatar in destRoom and + // this API has avatars that are in this room. + virtual void OnReceiveRevokeVoiceRoom(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatRoom *destRoom); + + // OnReceiveRevokeVoiceAvatar + // Called when srcAvatar has revoked voice for destAvatar in the room + // described by roomName and roomAddress, and destAvatar is on + // this API. + virtual void OnReceiveRevokeVoiceAvatar(const ChatAvatar *srcAvatar, const ChatAvatar *destAvatar, const ChatUnicodeString &roomName, const ChatUnicodeString &roomAddress); + + // OnReceiveRoomParams + // Called when the room parameters have been changed for destRoom by + // srcAvatar and this API has avatars that are in this room. + virtual void OnReceiveRoomParams(const ChatAvatar *srcAvatar, const ChatRoom *destRoom, const RoomParams *params, const RoomParams *oldParams); + + // OnReceivePersistentMessage + // Called when a persistent message is sent to an avatar who is logged in + // at the time it's received + virtual void OnReceivePersistentMessage(const ChatAvatar *destAvatar, const PersistentHeader *header); + + // OnReceiveForcedLogout + // Called when an avatar is logged in from a different API. + // The first instance of the avatar will be logged out + virtual void OnReceiveForcedLogout(const ChatAvatar *oldAvatar); + + // OnReceiveRoomOwnerChange + // Called when the owner of a room has been changed. + virtual void OnReceiveRoomOwnerChange(const ChatRoom *destRoom); + + // OnReceiveSnoopMessage + // Called when a message is sniffed during transmission to/from + // an avatar or room that is currently being snooped by an avatar + // logged in through this API. + // NOTE: types are defined in ChatEnum.h and SNOOP_END should be + // caught to detect snoop stream end due to destAvatar logout or + // destRoom destruction + virtual void OnReceiveSnoopMessage(unsigned snoopType, + const ChatUnicodeString &snooperName, + const ChatUnicodeString &snooperAddress, + const ChatUnicodeString &srcName, // msg sender + const ChatUnicodeString &srcAddress, // msg sender + const ChatUnicodeString &destName, // dest avatar, invalid if room is destination + const ChatUnicodeString &destAddress, // dest avatar or room address + const ChatUnicodeString &message); + + // OnReceiveNotifyFriendIsRemoved + // Called when destAvatar has been removed by srcAvatar from the friend list + // described by destAvatarID, destName and destAddress is on this API. + virtual void OnReceiveNotifyFriendIsRemoved(ChatAvatar * avatar, const ChatUnicodeString &friendName, const ChatUnicodeString &friendAddress); + + // OnReceiveNotifyFriendsListChange + // Called After an AvatarTransfer. If the avatar had any friends this will be + // called for each friend. + // avatar - the friend that should be updated + // originalName - the name before the transfer + // originalAddress - the address before the transfer + // newName - the name after the transfer + // newAddress - the address after the transfer + virtual void OnReceiveNotifyFriendsListChange(ChatAvatar * avatar, + const ChatUnicodeString &originalName, + const ChatUnicodeString &originalAddress, + const ChatUnicodeString &newName, + const ChatUnicodeString &newAddress); + + protected: + // Do not use this constructor + ChatAPI(ChatAPICore *core); + + private: + ChatAPICore *m_core; + RoomParams *m_defaultRoomParams; + ChatUnicodeString m_defaultLoginLocation; + int m_defaultLoginPriority; + bool m_defaultEntryType; + }; +}; + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPICore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPICore.cpp new file mode 100644 index 00000000..e1d79635 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPICore.cpp @@ -0,0 +1,3354 @@ +#include "ChatAPICore.h" +#include "ChatAPI.h" +#include "Response.h" +#include "Request.h" +#include "Message.h" +#include "ChatAvatar.h" +#include "ChatAvatarCore.h" +#include "ChatRoomCore.h" +#include "ChatEnum.h" +#include "PersistentMessage.h" + +#include + +const unsigned long kChatApiVersion = 2; + +namespace ChatSystem +{ + +using namespace std; +using namespace Base; +using namespace Plat_Unicode; +using namespace GenericAPI; + +const char * const ChatAPICore::ms_errorStringsEnglish[] = +{ + "Succeeded", // 0 + "Timed Out", + "Duplicate login", + "Source avatar does not exist", + "Destination avatar does not exist", + "Address does not exist", // 5 + "Address is not a room", + "Address is not an AID node", + "Friend not found", + "Unknown failure", + "Source avatar not in room", // 10 + "Destination avatar not in room", + "Avatar is banned from room", + "Room is private", + "Room is moderated", + "Not in room", // 15 + "Insufficient room privileges", + "Database error", + "Cannot get avatar ID", + "Cannot get node ID", + "Cannot get persistent message ID", // 20 + "Persistent message not found", + "Maximum number of avatars already in room", + "Destination avatar is ignoring source avatar", + "Room already exists", + "Nothing to confirm", // 25 + "Duplicate friend", + "Ignore not found", + "Duplicate ignore", + "Database error", + "Destination avatar is not a moderator", // 30 + "Destination avatar is not a invited", + "Destination avatar has not been banned", + "Duplicate ban", + "Duplicate moderator", + "Duplicate invite", // 35 + "Already in room", + "Parent room is not persistent", + "Parent node is of wrong type", + "No fan club handle", + "AID node already exists", // 40 + "UID node already exists", + "Wrong chat server for request", + "Succeeded, but local data is invalid", + "Login with null name", + "No server assigned to this identity", // 45 + "Another server already assumed this identity", + "Remote server is down", + "Node ID conflict", + "Invalid node name", + "Insufficient message privileges", // 50 + "Snoop already added", + "Not snooping", + "Destination avatar is not a temporary moderator", + "Destination avatar does not have voice", + "Duplicate temporary moderator", // 55 + "Duplicate voice", + "Chat avatar must first be logged out", + "No work to do", + "Cannot perform rename to NULL avatar name", + "Cannot perform station acct transfer to stationID = 0", // 60 + "Cannot perform avatar move to NULL avatar address", + "Failed to obtain an ID for a new room or avatar", + "Room is local to namespace/world; cannot enter from other worlds", + "Room is local to game; cannot enter from other game namespaces", + "Destination avatar has not submitted entry request for room", // 65 + "Insufficient login priority to force logout of current avatar", + "Avatar must wait to be allowed into specified room.", + "Persistent message would exceed inbox limit for this avatar", + "Duplicate destination specified for multiple persistent send", + "Persistent message would exceed given category limit", // 70 + "Add friend request is pending due to destination avatar is offline", +}; + +unsigned ChatAPICore::ms_numErrorStrings = sizeof(ChatAPICore::ms_errorStringsEnglish) / sizeof(const char *); + +ChatAPICore::ChatAPICore(const char *registrar_host, short registrar_port, const char *server_host, short server_port) +: GenericAPICore(registrar_host, + registrar_port, + 180 /*request timeout*/, + 10 /* reconnect timeout */, + 60 /*nodata timeout*/, + 60 /*noack timeout*/, + 2048 /*in buffer in KB*/, + 2048 /*out buffer in KB*/, + 15 /*keepalives in secs*/), + m_connected(false), + m_sentVersion(false), + m_inFailoverMode(false), + m_failoverAvatarResRemain(0), + m_failoverRoomResRemain(0), + m_requestCount(0), + m_setToRegistrar(true), + m_registrarHost(registrar_host), + m_defaultServerHost(server_host), + m_assignedServerHost(server_host), + m_registrarPort(registrar_port), + m_defaultServerPort(server_port), + m_assignedServerPort(server_port), + m_timeSinceLastDisconnect(time(NULL)), + m_rcvdRegistrarResponse(false), + m_shouldSendVersion(true) +{ + // prevent user requests from going through + suspendProcessing(); +} + +ChatAPICore::~ChatAPICore() +{ + m_api = NULL; + + std::map::iterator iter = m_avatarCoreCache.begin(); + for (; iter != m_avatarCoreCache.end(); iter++) + { + delete (*iter).second; + } + + std::map::iterator iter2 = m_avatarCache.begin(); + for (; iter2 != m_avatarCache.end(); iter2++) + { + delete (*iter2).second; + } + + std::map::iterator iter3 = m_roomCoreCache.begin(); + for (; iter3 != m_roomCoreCache.end(); iter3++) + { + delete (*iter3).second; + } + + std::map::iterator iter4 = m_roomCache.begin(); + for (; iter4 != m_roomCache.end(); iter4++) + { + delete (*iter4).second; + } +} + +ChatUnicodeString ChatAPICore::getErrorString(unsigned resultCode) +{ + ChatUnicodeString errorString; + + if (resultCode < ms_numErrorStrings) + { + errorString = ms_errorStringsEnglish[resultCode]; + } + + return errorString; +} + +void ChatAPICore::cacheAvatar(ChatAvatarCore *avatarCore) +{ + if(avatarCore) + { + pair < map::iterator, bool > result; + + result = m_avatarCoreCache.insert(pair(avatarCore->getAvatarID(), avatarCore)); + + if (result.second == true) + { + // create m_avatarCache entry as well + ChatAvatar *newAvatar = new ChatAvatar(avatarCore->getAvatarID(), + avatarCore->getUserID(), + ChatUnicodeString(avatarCore->getName().data(), avatarCore->getName().size()), + ChatUnicodeString(avatarCore->getAddress().data(), avatarCore->getAddress().size()), + ChatUnicodeString(avatarCore->getGateway().data(), avatarCore->getGateway().size()), + ChatUnicodeString(avatarCore->getServer().data(), avatarCore->getServer().size()), + avatarCore->getGatewayID(), + avatarCore->getServerID(), + ChatUnicodeString(avatarCore->getLoginLocation().data(), avatarCore->getLoginLocation().size()), + avatarCore->getAttributes()); + + newAvatar->setLoginPriority(avatarCore->getLoginPriority()); + newAvatar->setForwardingEmail(avatarCore->getEmail()); + newAvatar->setInboxLimit(avatarCore->getInboxLimit()); + + m_avatarCache.insert(pair(newAvatar->getAvatarID(), newAvatar)); + } + else + { + // insert failed; we have to clean up the ChatAvatarCore + delete avatarCore; + } + } +} + +ChatAvatarCore *ChatAPICore::getAvatarCore(unsigned avatarID) +{ + ChatAvatarCore *returnAvatar = NULL; + + std::map::iterator iter = m_avatarCoreCache.find(avatarID); + if(iter != m_avatarCoreCache.end()) + { + returnAvatar = (*iter).second; + } + return(returnAvatar); +} + +ChatAvatar *ChatAPICore::getAvatar(unsigned avatarID) +{ + ChatAvatar *returnAvatar = NULL; + + std::map::iterator iter = m_avatarCache.find(avatarID); + if(iter != m_avatarCache.end()) + { + returnAvatar = (*iter).second; + } + return(returnAvatar); +} + +ChatAvatarCore *ChatAPICore::decacheAvatar(unsigned avatarID) +{ + ChatAvatarCore *returnAvatar = NULL; + std::map::iterator iterCore = m_avatarCoreCache.find(avatarID); + if(iterCore != m_avatarCoreCache.end()) + { + returnAvatar = (*iterCore).second; + m_avatarCoreCache.erase(iterCore); + + // erase and delete from m_avatarCache as well + std::map::iterator iter = m_avatarCache.find(avatarID); + delete (*iter).second; + m_avatarCache.erase(iter); + } + return(returnAvatar); +} + +void ChatAPICore::cacheRoom(ChatRoomCore *roomCore) +{ + if(roomCore) + { + pair < map::iterator, bool > result; + result = m_roomCoreCache.insert(pair(roomCore->getRoomID(), roomCore)); + + if (result.second == true) + { + // create m_avatarCache entry as well + ChatRoom *newRoom = new ChatRoom(roomCore); + + m_roomCache.insert(pair(roomCore->getRoomID(), newRoom)); + } + } +} + +ChatRoomCore *ChatAPICore::getRoomCore(unsigned roomID) +{ + ChatRoomCore *returnRoom = NULL; + std::map::iterator iter = m_roomCoreCache.find(roomID); + if(iter != m_roomCoreCache.end()) + { + returnRoom = (*iter).second; + } + + return(returnRoom); +} + +ChatRoom *ChatAPICore::getRoom(unsigned roomID) +{ + ChatRoom *returnRoom = NULL; + std::map::iterator iter = m_roomCache.find(roomID); + if(iter != m_roomCache.end()) + { + returnRoom = (*iter).second; + } + + return(returnRoom); +} + +ChatRoomCore *ChatAPICore::decacheRoom(unsigned roomID) +{ + ChatRoomCore *returnRoom = NULL; + + std::map::iterator iterCore = m_roomCoreCache.find(roomID); + if(iterCore != m_roomCoreCache.end()) + { + returnRoom = (*iterCore).second; + m_roomCoreCache.erase(iterCore); + + // erase and delete from m_roomCache as well + std::map::iterator iter = m_roomCache.find(roomID); + delete (*iter).second; + m_roomCache.erase(iter); + } + + return(returnRoom); +} + +void ChatAPICore::responseCallback(GenericResponse *res) +{ + switch(res->getType()) + { + case RESPONSE_LOGINAVATAR: + { + ResLoginAvatar *R = static_cast(res); + ChatAvatar *avatar = NULL; + + if(R->getAvatar()) + { + cacheAvatar(R->getAvatar()); + avatar = getAvatar(R->getAvatar()->getAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_LOGINAVATAR: avatar=%p\n", avatar); + } + if (avatar) + { + avatar->setLoginPriority(R->getSubmittedLoginPriority()); + } + m_api->OnLoginAvatar(R->getTrack(), R->getResult(), avatar, R->getUser()); + m_api->OnLoginAvatar(R->getTrack(), R->getResult(), avatar, R->getRequiredLoginPriority(), R->getUser()); + } + break; + case RESPONSE_TEMPORARYAVATAR: + { + ResTemporaryAvatar* R = static_cast(res); + ChatAvatar* avatar = NULL; + + if ( R->getAvatar() ) + { + cacheAvatar(R->getAvatar()); + avatar = getAvatar(R->getAvatar()->getAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_TEMPORARYAVATAR: avatar=%p\n", avatar); + } + + m_api->OnTemporaryAvatar(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_LOGOUTAVATAR: + { + ResLogoutAvatar *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_LOGOUTAVATAR: avatar=%p\n", avatar); + } + m_api->OnLogoutAvatar(R->getTrack(), R->getResult(), avatar, R->getUser()); + if (R->getResult() == 0) + { + ChatAvatarCore *avatarCore = decacheAvatar(R->getAvatarID()); + delete avatarCore; + } + } + break; + case RESPONSE_DESTROYAVATAR: + { + ResDestroyAvatar *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_DESTROYAVATAR: avatar=%p\n", avatar); + } + m_api->OnDestroyAvatar(R->getTrack(), R->getResult(), avatar, R->getUser()); + ChatAvatarCore *avatarCore = decacheAvatar(R->getAvatarID()); + delete avatarCore; + } + break; + case RESPONSE_GETFANCLUBHANDLE: + { + ResGetFanClubHandle *R = static_cast(res); + m_api->OnFanClubHandle(R->getTrack(), R->getResult(), ChatUnicodeString(R->getHandle().data(), R->getHandle().size()), R->getStationID(), R->getFanClubCode(), R->getUser()); + } + break; + case RESPONSE_GETAVATAR: + { + ResGetAvatar *R = static_cast(res); + ChatAvatar *cachedAvatar = NULL; + ChatAvatar *avatar = NULL; + ChatAvatarCore *avatarCore = R->getAvatar(); + + if (R->getResult() == 0 && avatarCore) // if success + { + // attempt to return locally cached avatar, if available + cachedAvatar = getAvatar(avatarCore->getAvatarID()); + + if (cachedAvatar != NULL) + { + // update cached information with returned data + cachedAvatar->setAttributes(avatarCore->getAttributes()); + cachedAvatar->setForwardingEmail(avatarCore->getEmail()); + cachedAvatar->setInboxLimit(avatarCore->getInboxLimit()); + + avatar = cachedAvatar; + } + else + { + // don't cache uncached avatars + avatar = avatarCore->getNewChatAvatar(); + } + } + + if ((!avatar||!avatarCore) && (R->getResult() == CHATRESULT_SUCCESS)) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETAVATAR: avatarCore=%p, avatar=%p\n", avatarCore, avatar); + } + + m_api->OnGetAvatar(R->getTrack(), R->getResult(), avatar, R->getUser()); + + if (cachedAvatar == NULL) + { + delete avatar; + } + + delete avatarCore; + } + break; + case RESPONSE_GETANYAVATAR: + { + ResGetAnyAvatar *R = static_cast(res); + ChatAvatar *cachedAvatar = NULL; + ChatAvatar *avatar = NULL; + ChatAvatarCore *avatarCore = R->getAvatar(); + + if (R->getResult() == 0 && avatarCore) // if success + { + // attempt to return locally cached avatar, if available + cachedAvatar = getAvatar(avatarCore->getAvatarID()); + + if (cachedAvatar != NULL) + { + // update cached information with returned data + cachedAvatar->setAttributes(avatarCore->getAttributes()); + cachedAvatar->setForwardingEmail(avatarCore->getEmail()); + cachedAvatar->setInboxLimit(avatarCore->getInboxLimit()); + + avatar = cachedAvatar; + } + else + { + // don't cache uncached avatars + avatar = avatarCore->getNewChatAvatar(); + } + } + + if ((!avatar||!avatarCore) && (R->getResult() == CHATRESULT_SUCCESS)) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETANYAVATAR: avatarCore=%p, avatar=%p\n", avatarCore, avatar); + } + + m_api->OnGetAnyAvatar(R->getTrack(), R->getResult(), avatar, R->isLoggedIn(), R->getUser()); + + if (cachedAvatar == NULL) + { + delete avatar; + } + + delete avatarCore; + } + break; + case RESPONSE_AVATARLIST: + { + ResAvatarList *R = static_cast(res); + + m_api->OnAvatarList(R->getTrack(), R->getResult(), R->getListLength(), R->getAvatarList(), R->getUser()); + + break; + } + case RESPONSE_SETAVATARATTRIBUTES: + { + ResSetAvatarAttributes *R = static_cast(res); + ChatAvatar *cachedAvatar = NULL; + ChatAvatar *avatar = NULL; + ChatAvatarCore *avatarCore = R->getAvatar(); + + if (R->getResult() == 0 && avatarCore) // if success + { + avatar = avatarCore->getNewChatAvatar(); + if (avatar) + { + // attempt to return locally cached avatar, if available + cachedAvatar = getAvatar(avatar->getAvatarID()); + + if (cachedAvatar != NULL) + { + cachedAvatar->setAttributes(avatar->getAttributes()); + } + } + } + + if (cachedAvatar != NULL) + { + cachedAvatar = avatar; + m_api->OnSetAvatarAttributes(R->getTrack(), R->getResult(), cachedAvatar, R->getUser()); + } + else + { + if ((!avatar||!avatarCore) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SETAVATARATTRIBUTES: avatarCore=%p, avatar=%p\n", avatarCore, avatar); + } + m_api->OnSetAvatarAttributes(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + + delete avatar; + delete avatarCore; + } + break; + case RESPONSE_SETSTATUSMESSAGE: + { + ResSetAvatarStatusMessage *R = static_cast(res); + ChatAvatar *cachedAvatar = NULL; + ChatAvatar *avatar = NULL; + ChatAvatarCore *avatarCore = R->getAvatar(); + + if (R->getResult() == 0 && avatarCore) // if success + { + avatar = avatarCore->getNewChatAvatar(); + if (avatar) + { + // attempt to return locally cached avatar, if available + cachedAvatar = getAvatar(avatar->getAvatarID()); + + if (cachedAvatar != NULL) + { + cachedAvatar->setStatusMessage(avatar->getStatusMessage()); + } + } + } + + if (cachedAvatar != NULL) + { + cachedAvatar = avatar; + m_api->OnSetAvatarStatusMessage(R->getTrack(), R->getResult(), cachedAvatar, R->getUser()); + } + else + { + if ((!avatar||!avatarCore) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SETAVATARATTRIBUTES: avatarCore=%p, avatar=%p\n", avatarCore, avatar); + } + m_api->OnSetAvatarAttributes(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + + delete avatar; + delete avatarCore; + } + break; + case RESPONSE_SETAVATAREMAIL: + { + ResSetAvatarForwardingEmail*R = static_cast(res); + ChatAvatar *cachedAvatar = NULL; + ChatAvatar *avatar = NULL; + ChatAvatarCore *avatarCore = R->getAvatar(); + + if (R->getResult() == 0 && avatarCore) // if success + { + avatar = avatarCore->getNewChatAvatar(); + if (avatar) + { + // attempt to return locally cached avatar, if available + cachedAvatar = getAvatar(avatar->getAvatarID()); + + if (cachedAvatar != NULL) + { + cachedAvatar->setForwardingEmail(avatar->getForwardingEmail()); + } + } + } + + if (cachedAvatar != NULL) + { + cachedAvatar = avatar; + m_api->OnSetAvatarForwardingEmail(R->getTrack(), R->getResult(), cachedAvatar, R->getUser()); + } + else + { + if ((!avatar||!avatarCore) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SETAVATAREMAIL: avatarCore=%p, avatar=%p\n", avatarCore, avatar); + } + m_api->OnSetAvatarForwardingEmail(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + + delete avatar; + delete avatarCore; + } + break; + case RESPONSE_SETAVATARINBOXLIMIT: + { + ResSetAvatarInboxLimit *R = static_cast(res); + ChatAvatar *cachedAvatar = NULL; + ChatAvatar *avatar = NULL; + ChatAvatarCore *avatarCore = R->getAvatar(); + + if (R->getResult() == 0 && avatarCore) // if success + { + avatar = avatarCore->getNewChatAvatar(); + if (avatar) + { + // attempt to return locally cached avatar, if available + cachedAvatar = getAvatar(avatar->getAvatarID()); + + if (cachedAvatar != NULL) + { + cachedAvatar->setInboxLimit(avatar->getInboxLimit()); + } + } + } + + if (cachedAvatar != NULL) + { + cachedAvatar = avatar; + m_api->OnSetAvatarInboxLimit(R->getTrack(), R->getResult(), cachedAvatar, R->getUser()); + } + else + { + if ((!avatar||!avatarCore) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SETAVATARINBOXLIMIT: avatarCore=%p, avatar=%p\n", avatarCore, avatar); + } + m_api->OnSetAvatarInboxLimit(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + + delete avatar; + delete avatarCore; + } + break; + case RESPONSE_GETROOM: + { + ResGetRoom *R = static_cast(res); + ChatRoom *room = NULL; + ChatRoomCore *roomCore = R->getRoom(); + + if (R->getResult() == 0 && roomCore) // if success + { + unsigned roomid = roomCore->getRoomID(); + if (getRoomCore(roomid) == NULL) + { + // we need to cache this room first + cacheRoom(roomCore); + + // are there any parent rooms to the one we + // created that we need to cache as well? + const set &extraRooms = R->getExtraRooms(); + set::const_iterator iter = extraRooms.begin(); + for (; iter != extraRooms.end(); iter++) + { + cacheRoom(*iter); + } + } + else + { + // room was already cached, so we must + // recache it + ChatRoomCore *oldCore = decacheRoom(roomid); + + delete oldCore; + cacheRoom(roomCore); + + // if we were sent parent rooms, we need to delete + // the ChatRoomCore objects because we shouldn't need them + const set &extraRooms = R->getExtraRooms(); + set::const_iterator iter = extraRooms.begin(); + for (; iter != extraRooms.end(); iter++) + { + delete (*iter); + } + } + + room = getRoom(roomid); + } + + if ((!room||!roomCore) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETROOM: roomCore=%p, room=%p\n", roomCore, room); + } + m_api->OnGetRoom(R->getTrack(), R->getResult(), room, R->getUser()); + } + break; + case RESPONSE_CREATEROOM: + { + ResCreateRoom *R = static_cast(res); + + ChatRoom *room = NULL; + ChatRoomCore* roomCore = NULL; + + if (R->getResult() == 0) // if success + { + roomCore = R->getRoom(); + + if (roomCore) + { + // cache this room + cacheRoom(roomCore); + room = getRoom(roomCore->getRoomID()); + + if (room) + { + // are there any parent rooms to the one we + // created that we need to cache as well? + const set &extraRooms = R->getExtraRooms(); + set::const_iterator iter = extraRooms.begin(); + for (; iter != extraRooms.end(); iter++) + { + cacheRoom(*iter); + } + } + } + } + + if ((!room||!roomCore) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_CREATEROOM: roomCore=%p, room=%p\n", roomCore, room); + } + m_api->OnCreateRoom(R->getTrack(), R->getResult(), room, R->getUser()); + } + break; + case RESPONSE_DESTROYROOM: + { + ResDestroyRoom *R = static_cast(res); + m_api->OnDestroyRoom(R->getTrack(), R->getResult(), R->getUser()); + // decache occurs on MESSAGE_DESTROYROOM + } + break; + case RESPONSE_SENDINSTANTMESSAGE: + { + ResSendInstantMessage *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SENDINSTANTMESSAGE: avatar=%p\n", avatar); + } + m_api->OnSendInstantMessage(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_SENDROOMMESSAGE: + { + ResSendRoomMessage *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + ChatRoom *room = getRoom(R->getRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SENDROOMMESSAGE: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnSendRoomMessage(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + } + break; + case RESPONSE_SENDBROADCASTMESSAGE: + { + ResSendBroadcastMessage *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SENDBROADCASTMESSAGE: avatar=%p\n", avatar); + } + m_api->OnSendBroadcastMessage(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + case RESPONSE_FILTERMESSAGE: + { + ResFilterMessage *R = static_cast(res); + m_api->OnFilterMessage(R->getTrack(), R->getResult(), ChatUnicodeString(R->getMsg().data(),R->getMsg().size()), R->getUser()); + } + break; + case RESPONSE_FILTERMESSAGE_EX: + { + ResFilterMessage *R = static_cast(res); + m_api->OnFilterMessageEx(R->getTrack(), R->getResult(), ChatUnicodeString(R->getMsg().data(),R->getMsg().size()), R->getUser()); + } + break; + case RESPONSE_ADDFRIEND: + { + ResAddFriend *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDFRIEND: avatar=%p\n", avatar); + } + m_api->OnAddFriend(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + case RESPONSE_ADDFRIEND_RECIPROCATE: + { + ResAddFriendReciprocate *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDFRIEND_RECIPROCATE: avatar=%p\n", avatar); + } + m_api->OnAddFriendReciprocate(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + case RESPONSE_SETFRIENDCOMMENT: + { + ResSetFriendComment *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDFRIEND: avatar=%p\n", avatar); + } + m_api->OnSetFriendComment(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), ChatUnicodeString(R->getComment().data(), R->getComment().size()) ,R->getUser()); + } + break; + case RESPONSE_REMOVEFRIEND: + { + ResRemoveFriend *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVEFRIEND: avatar=%p\n", avatar); + } + m_api->OnRemoveFriend(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + + case RESPONSE_REMOVEFRIEND_RECIPROCATE: + { + ResRemoveFriendReciprocate *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVEFRIEND_RECIPROCATE: avatar=%p\n", avatar); + } + m_api->OnRemoveFriendReciprocate(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + case RESPONSE_FRIENDSTATUS: + { + ResFriendStatus *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_FRIENDSTATUS: avatar=%p\n", avatar); + } + m_api->OnFriendStatus(R->getTrack(), R->getResult(), avatar, R->getListLength(), R->getFriendList(), R->getUser()); + } + break; + case RESPONSE_ADDIGNORE: + { + ResAddIgnore *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDIGNORE: avatar=%p\n", avatar); + } + m_api->OnAddIgnore(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + case RESPONSE_REMOVEIGNORE: + { + ResRemoveIgnore *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVEIGNORE: avatar=%p\n", avatar); + } + m_api->OnRemoveIgnore(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getName().data(), R->getName().size()), ChatUnicodeString(R->getAddress().data(), R->getAddress().size()), R->getUser()); + } + break; + case RESPONSE_ENTERROOM: + { + ResEnterRoom *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + ChatRoomCore *roomCore = R->getRoom(); + ChatRoom *room = getRoom(R->getRoomID()); + + if (R->getResult() == 0) + { + if (!room && roomCore) + { + // we didn't have this room cached already + cacheRoom(roomCore); + room = getRoom(roomCore->getRoomID()); + + // are there any parent rooms to the one we + // created that we need to cache as well? + const set &extraRooms = R->getExtraRooms(); + set::const_iterator iter = extraRooms.begin(); + for (; iter != extraRooms.end(); iter++) + { + cacheRoom(*iter); + } + } + else if (room && roomCore) + { + // We already had room (and parents) cached, and our + // ResEnterRoom object has created a new ChatRoomCore, + // so we delete it because we don't need to cache it. + delete roomCore; + + // if we were sent parent rooms, we need to delete + // the ChatRoomCore objects because we shouldn't need them + const set &extraRooms = R->getExtraRooms(); + set::const_iterator iter = extraRooms.begin(); + for (; iter != extraRooms.end(); iter++) + { + delete (*iter); + } + } + else if (!room && !roomCore) + { + // we didn't have room cached, and we didn't get one to cache, + // thus we'll have trouble giving a callback with a NULL pointer. + _chatdebug_("ChatAPI:BadData: RESPONSE_ENTERROOM: avatar=%p, room=%p , roomCore=%p\n", avatar, room, roomCore); + } + } + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ENTERROOM: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnEnterRoom(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + } + break; + case RESPONSE_ALLOWROOMENTRY: + { + ResAllowRoomEntry *R = static_cast(res); + ChatAvatar *srcAvatar = getAvatar(R->getSrcAvatarID()); + + if (!srcAvatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ALLOWROOMENTRY: srcAvatar=%p\n", srcAvatar); + } + + m_api->OnAllowRoomEntry(R->getTrack(), R->getResult(), srcAvatar, R->getDestRoomAddress(), R->getUser()); + } + break; + case RESPONSE_LEAVEROOM: + { + ResLeaveRoom *R = static_cast(res); + ChatRoom *room = getRoom(R->getRoomID()); + + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_LEAVEROOM: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnLeaveRoom(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + } + break; + case RESPONSE_ADDMODERATOR: + { + ResAddModerator *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDMODERATOR: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnAddModerator(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_ADDMODERATOR + } + break; + case RESPONSE_REMOVEMODERATOR: + { + ResRemoveModerator *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVEMODERATOR: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnRemoveModerator(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_REMOVEMODERATOR + } + break; + case RESPONSE_ADDTEMPORARYMODERATOR: + { + ResAddTemporaryModerator *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDTEMPORARYMODERATOR: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnAddTemporaryModerator(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_ADDMTEMPORARYODERATOR + } + break; + case RESPONSE_REMOVETEMPORARYMODERATOR: + { + ResRemoveTemporaryModerator *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVETEMPORARYMODERATOR: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnRemoveTemporaryModerator(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_REMOVETEMPORARYMODERATOR + } + break; + case RESPONSE_ADDBAN: + { + ResAddBan *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDBAN: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnAddBan(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_ADDBAN + } + break; + case RESPONSE_REMOVEBAN: + { + ResRemoveBan *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVEBAN: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnRemoveBan(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_REMOVEBAN + } + break; + case RESPONSE_ADDINVITE: + { + ResAddInvite *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDINVITE: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnAddInvite(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_ADDINVITE + } + break; + case RESPONSE_REMOVEINVITE: + { + ResRemoveInvite *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVEINVITE: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnRemoveInvite(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_REMOVEINVITE + } + break; + case RESPONSE_GRANTVOICE: + { + ResGrantVoice *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GRANTVOICE: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnGrantVoice(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_GRANTVOICE + } + break; + case RESPONSE_REVOKEVOICE: + { + ResRevokeVoice *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REVOKEVOICE: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnRevokeVoice(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_REVOKEVOICE + } + break; + case RESPONSE_KICKAVATAR: + { + ResKickAvatar *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_KICKAVATAR: avatar=%p, room=%p\n", avatar, room); + } + m_api->OnKickAvatar(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_KICK + } + break; + case RESPONSE_SETROOMPARAMS: + { + ResSetRoomParams *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SETROOMPARAMS: avatar=%p, room=%p\n", avatar, room); + } + + m_api->OnSetRoomParams(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_SETROOMPARAMS + } + break; + case RESPONSE_CHANGEROOMOWNER: + { + ResChangeRoomOwner *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatRoom *room = getRoom(R->getDestRoomID()); + if ((!avatar||!room) && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_CHANGEROOMOWNER: avatar=%p, room=%p\n", avatar, room); + } + + m_api->OnChangeRoomOwner(R->getTrack(), R->getResult(), avatar, room, R->getUser()); + // cached room gets updated by MESSAGE_CHANGEROOMOWNER + } + break; + case RESPONSE_GETROOMSUMMARIES: + { + ResGetRoomSummaries *R = static_cast(res); + unsigned numRooms = R->getNumRooms(); + RoomSummary *foundRooms = R->getRoomSummaries(); + + m_api->OnGetRoomSummaries(R->getTrack(), R->getResult(), numRooms, foundRooms, R->getUser()); + } + break; + case RESPONSE_FINDAVATARBYUID: + { + ResFindAvatarByUID *R = static_cast(res); + ChatAvatar **avatarMatches = NULL; + ChatAvatarCore **avatarCoreMatches = NULL; + + unsigned numAvatarsOnline = R->getNumAvatarsOnline(); + + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatarCoreMatches = R->getAvatarsCore(); + avatarMatches = new ChatAvatar*[numAvatarsOnline]; + for (unsigned i(0); i < numAvatarsOnline; i++) + { + avatarMatches[i] = avatarCoreMatches[i]->getNewChatAvatar(); + } + } + + m_api->OnFindAvatarByUID(R->getTrack(), R->getResult(), numAvatarsOnline, avatarMatches, R->getUser()); + + delete [] avatarMatches; + } + break; + case RESPONSE_SENDPERSISTENTMESSAGE: + { + ResSendPersistentMessage *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SENDPERSISTENTMESSAGE: avatar=%p\n", avatar); + } + m_api->OnSendPersistentMessage(R->getTrack(), R->getResult(), avatar, R->getUser()); + m_api->OnSendPersistentMessage(R->getTrack(), R->getResult(), avatar, R->getMessageID(), R->getUser()); + } + break; + case RESPONSE_SENDMULTIPLEPERSISTENTMESSAGES: + { + ResSendMultiplePersistentMessages *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SENDMULTIPLEPERSISTENTMESSAGES: avatar=%p\n", avatar); + } + m_api->OnSendMultiplePersistentMessages(R->getTrack(), R->getResult(), R->getNumResults(), &R->getResultVector()[0], avatar, R->getUser()); + m_api->OnSendMultiplePersistentMessages(R->getTrack(), R->getResult(), R->getNumResults(), &R->getResultVector()[0], &R->getMessageIDvector()[0], avatar, R->getUser()); + } + break; + case RESPONSE_ALTERPERSISTENTMESSAGE: + { + ResAlterPersistentMessage *R = static_cast(res); + ChatUnicodeString destAvatarName(R->getDestAvatarName().data(), R->getDestAvatarName().length()); + ChatUnicodeString destAvatarAddress(R->getDestAvatarAddress().data(), R->getDestAvatarAddress().length()); + + m_api->OnAlterPersistentMessage(R->getTrack(), R->getResult(), destAvatarName, destAvatarAddress, R->getMessageID()); + } + break; + case RESPONSE_GETPERSISTENTMESSAGE: + { + ResGetPersistentMessage *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + ChatUnicodeString message(R->getMsg().data(), R->getMsg().size()); + ChatUnicodeString oobdata(R->getOOB().data(), R->getOOB().size()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETPERSISTENTMESSAGE: avatar=%p\n", avatar); + } + m_api->OnGetPersistentMessage(R->getTrack(), R->getResult(), avatar, R->getHeader(), message, oobdata, R->getUser()); + } + break; + case RESPONSE_GETMULTIPLEPERSISTENTMESSAGES: + { + ResGetMultiplePersistentMessages *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETMULTIPLEPERSISTENTMESSAGES: avatar=%p\n", avatar); + } + m_api->OnGetMultiplePersistentMessages(R->getTrack(), R->getResult(), avatar, R->getListLength(), R->getList(), R->getUser()); + } + break; + case RESPONSE_UPDATEPERSISTENTMESSAGE: + { + ResUpdatePersistentMessage *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_UPDATEPERSISTENTMESSAGE: avatar=%p\n", avatar); + } + m_api->OnUpdatePersistentMessage(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_UPDATEPERSISTENTMESSAGES: + { + ResUpdatePersistentMessages *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_UPDATEPERSISTENTMESSAGES: avatar=%p\n", avatar); + } + m_api->OnUpdatePersistentMessages(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_CHANGEPERSISTENTFOLDER: + { + ResClassifyPersistentMessages *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_CHANGEPERSISTENTFOLDER: avatar=%p\n", avatar); + } + m_api->OnClassifyPersistentMessages(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_PURGEPERSISTENTMESSAGES: + { + ResDeleteAllPersistentMessages *R = static_cast(res); + + m_api->OnDeleteAllPersistentMessages(R->getTrack(), R->getResult(), R->getAvatarName(), R->getAvatarAddress(), R->getNumberDeleted(), R->getUser()); + } + break; + case RESPONSE_GETPERSISTENTHEADERS: + { + ResGetPersistentHeaders *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETPERSISTENTHEADERS: avatar=%p\n", avatar); + } + m_api->OnGetPersistentHeaders(R->getTrack(), R->getResult(), avatar, R->getListLength(), R->getList(), R->getUser()); + } + break; + case RESPONSE_PARTIALPERSISTENTHEADERS: + { + ResGetPartialPersistentHeaders *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getSrcAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETPARTIALPERSISTENTHEADERS: avatar=%p\n", avatar); + } + m_api->OnGetPartialPersistentHeaders(R->getTrack(), R->getResult(), avatar, R->getListLength(), R->getList(), R->getUser()); + } + break; + case RESPONSE_COUNTPERSISTENTMESSAGES: + { + ResCountPersistentMessages *R = static_cast(res); + + m_api->OnCountPersistentMessages(R->getTrack(), R->getResult(), R->getAvatarName(), R->getAvatarAddress(), R->getNumberOfMessages(), R->getUser()); + } + break; + case RESPONSE_UNREGISTERROOM: + { + ResUnregisterRoom *R = static_cast(res); + ChatRoom *room = getRoom(R->getDestRoomID()); + if (!room && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_UNREGISTERROOM: room=%p\n", room); + } + m_api->OnUnregisterRoom(R->getTrack(), R->getResult(), room, R->getUser()); + + if (R->getResult() == 0 && room) + { + ChatRoomCore *roomCore = decacheRoom(R->getDestRoomID()); + delete roomCore; + } + } + break; + case RESPONSE_IGNORESTATUS: + { + ResIgnoreStatus *R = static_cast(res); + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_IGNORESTATUS: avatar=%p\n", avatar); + } + m_api->OnIgnoreStatus(R->getTrack(), R->getResult(), avatar, R->getListLength(), R->getIgnoreList(), R->getUser()); + } + break; + case RESPONSE_FAILOVER_RELOGINAVATAR: + { + ResFailoverReloginAvatar *R = static_cast(res); + + unsigned result = R->getResult(); + if (result != 0 && result != CHATRESULT_DUPLICATELOGIN) + { + ChatAvatar *avatar = getAvatar(R->getAvatarID()); + if (avatar) + { + // if we can't relogin the avatar for reason other than + // duplicate login from this API, then effectively + // our API must consider him logged out because he's now + // no longer logged in to his AID controller. + m_api->OnLogoutAvatar(0, 0, avatar, NULL); + } + } + + m_failoverAvatarResRemain--; + + if (!m_failoverAvatarResRemain) + { + failoverRecreateRooms(); + } + } + break; + case RESPONSE_FAILOVER_RECREATEROOM: + { + ResFailoverRecreateRoom *R = static_cast(res); + + if (R->getResult() == 0) + { + ChatRoomCore *rcvdRoom = R->getRoom(); + + if (rcvdRoom) + { + ChatRoomCore *roomCore = getRoomCore(R->getRoomID()); + + if (!roomCore) + { + // probably shouldn't ever get to this point, but protection + cacheRoom(rcvdRoom); + } + else + { + + // MAKE APPROPRIATE CHANGES to the cached roomCore object + + // creator values should NEVER change + + // CHECK room values (attribs, topic, maxsize, id) + // (name, address, createtime should NEVER change) + if (roomCore->getRoomID() != rcvdRoom->getRoomID()) + { + roomCore->setID(rcvdRoom->getRoomID()); + } + if (roomCore->getRoomAttributes() != rcvdRoom->getRoomAttributes()) + { + roomCore->setAttributes(rcvdRoom->getRoomAttributes()); + } + if (roomCore->getRoomTopic() != rcvdRoom->getRoomTopic()) + { + roomCore->setTopic(rcvdRoom->getRoomTopic()); + } + if (roomCore->getMaxRoomSize() != rcvdRoom->getMaxRoomSize()) + { + roomCore->setMaxRoomSize(rcvdRoom->getMaxRoomSize()); + } + } + } + } + else + { + // destroy room from cache and send OnDestroyRoom() callback + ChatRoomCore *destRoomCore = getRoomCore(R->getRoomID()); + + if (destRoomCore) + { + Plat_Unicode::String pus1(narrowToWide("ChatSystem")); + Plat_Unicode::String pus2(narrowToWide("")); + ChatUnicodeString cus1(pus1.data(), pus1.size()); + ChatUnicodeString cus2(pus2.data(), pus2.size()); + + ChatAvatar dummySrcAvatar(0, 0, cus1, cus1, cus2, cus2, 0, 0); + + ChatRoom *destRoom = getRoom(R->getRoomID()); + + if (!destRoom && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_FAILOVER_RECREATEROOM: destRoom=%p\n", destRoom); + } + m_api->OnReceiveDestroyRoom(&dummySrcAvatar, destRoom); + + destRoomCore = decacheRoom(R->getRoomID()); + delete destRoomCore; + } + } + + if (R->wasFailoverForcedByServer() == false) + { + m_failoverRoomResRemain--; + + if (!m_failoverRoomResRemain) + { + // resume processing and indicate it's ok to send new requests. + m_inFailoverMode = false; + m_api->OnFailoverComplete(); + resumeProcessing(); + } + } + } + break; + case RESPONSE_GETAVATARKEYWORDS: + { + ResGetAvatarKeywords *R = static_cast(res); + ChatAvatar *avatar = NULL; + + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_GETAVATARKEYWORDS: avatar=%p\n", avatar); + } + m_api->OnGetAvatarKeywords(R->getTrack(), R->getResult(), avatar, R->getList(), R->getListLength(), R->getUser()); + } + break; + + case RESPONSE_SETAVATARKEYWORDS: + { + ResSetAvatarKeywords *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_SETAVATARKEYWORDS: avatar=%p\n", avatar); + } + m_api->OnSetAvatarKeywords(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_SEARCHAVATARKEYWORDS: + { + ResSearchAvatarKeywords *R = static_cast(res); + ChatAvatar **avatarMatches = NULL; + ChatAvatarCore **avatarCoreMatches = NULL; + + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatarCoreMatches = R->getMatches(); + avatarMatches = new ChatAvatar*[R->getNumMatches()]; + for (unsigned i(0); i < R->getNumMatches(); i++) + { + avatarMatches[i] = avatarCoreMatches[i]->getNewChatAvatar(); + } + } + m_api->OnSearchAvatarKeywords(R->getTrack(), R->getResult(), avatarMatches, R->getNumMatches(), R->getUser()); + + delete [] avatarMatches; + } + break; + case RESPONSE_CONFIRMFRIEND: + { + ResFriendConfirm *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_CONFIRMFRIEND: avatar=%p\n", avatar); + } + m_api->OnFriendConfirm(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_CONFIRMFRIEND_RECIPROCATE: + { + ResFriendConfirmReciprocate *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_CONFIRMFRIEND_RECIPROCATE: avatar=%p\n", avatar); + } + m_api->OnFriendConfirmReciprocate(R->getTrack(), R->getResult(), avatar, R->getUser()); + } + break; + case RESPONSE_REGISTRAR_GETCHATSERVER: + { + ResRegistrarGetChatServer *R = static_cast(res); + + m_rcvdRegistrarResponse = true; + + if (R->getResult() == CHATRESULT_SUCCESS) + { + m_assignedServerHost = wideToNarrow(R->getHostname()).c_str(); + m_assignedServerPort = (short) R->getPort(); + } + } + break; + case RESPONSE_SETAPIVERSION: + { + ResSendApiVersion *R = static_cast(res); + + if (R->getResult() == CHATRESULT_SUCCESS) + { + m_sentVersion = true; + + if (m_inFailoverMode) + { + // reconnect to server succeeded, proceed with failover procedures. + // The failover procs will make the resumeProcessing() call. + m_api->OnFailoverBegin(); + failoverReloginAvatars(); + } + else + { + // first time connecting, allow user requests to go through + resumeProcessing(); + m_api->OnConnect(); + } + } + else if (R->getResult() == CHATRESULT_TIMEOUT) + { + // force resubmit request + if (m_connected) + { + OnConnect(m_assignedServerHost.c_str(), m_assignedServerPort); + } + } + else + { + // server is wrong version, so we can't work with it. + if (R->getResult() == CHATRESULT_WRONGCHATSERVERFORREQUEST) + { + fprintf(stderr, "The client API is a higher version than the server version.\n"); + assert(true); + } + } + } + break; + case RESPONSE_ADDSNOOPAVATAR: + { + ResAddSnoopAvatar *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getSrcAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDSNOOPAVATAR: avatar=%p\n", avatar); + } + m_api->OnBeginSnoopingAvatar(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getDestAvatarName()), ChatUnicodeString(R->getDestAvatarAddress()), R->getUser()); + } + break; + case RESPONSE_REMOVESNOOPAVATAR: + { + ResRemoveSnoopAvatar *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getSrcAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVESNOOPAVATAR: avatar=%p\n", avatar); + } + m_api->OnStopSnoopingAvatar(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getDestAvatarName()), ChatUnicodeString(R->getDestAvatarAddress()), R->getUser()); + } + break; + case RESPONSE_ADDSNOOPROOM: + { + ResAddSnoopRoom *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getSrcAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_ADDSNOOPROOM: avatar=%p\n", avatar); + } + m_api->OnBeginSnoopingRoom(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getRoomAddress()), R->getUser()); + } + break; + case RESPONSE_REMOVESNOOPROOM: + { + ResRemoveSnoopRoom *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getSrcAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVESNOOPROOM: avatar=%p\n", avatar); + } + m_api->OnStopSnoopingRoom(R->getTrack(), R->getResult(), avatar, ChatUnicodeString(R->getRoomAddress()), R->getUser()); + } + break; + case RESPONSE_GETSNOOPLIST: + { + ResGetSnoopList *R = static_cast(res); + ChatAvatar *avatar = NULL; + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatar = getAvatar(R->getSrcAvatarID()); + } + if (!avatar && R->getResult()==CHATRESULT_SUCCESS) + { + R->setResult(CHATRESULT_SUCCESSBADDATA); + _chatdebug_("ChatAPI:BadData: RESPONSE_REMOVESNOOPROOM: avatar=%p\n", avatar); + } + + AvatarSnoopPair **avatarList = NULL; + ChatUnicodeString **roomList = NULL; + + unsigned numAvatars = R->getAvatarSnoopListLength(); + unsigned numRooms = R->getRoomSnoopListLength(); + + if(R->getResult() == CHATRESULT_SUCCESS) + { + avatarList = R->getAvatarSnoopList(); + roomList = R->getRoomSnoopList(); + } + + m_api->OnGetSnoopList(R->getTrack(), R->getResult(), avatar, numAvatars, avatarList, numRooms, roomList, R->getUser()); + } + break; + case RESPONSE_TRANSFERAVATAR: + { + ResTransferAvatar *R = static_cast(res); + + m_api->OnTransferAvatar(R->getTrack(), R->getResult(), R->getUserID(), R->getNewUserID(), R->getAvatarName(), R->getNewAvatarName(), R->getAvatarAddress(), R->getNewAvatarAddress(), R->getUser()); + } + break; + + default: + fprintf(stderr, "[ChatAPICore.cpp] default (response) responseCallback(GenericResponse *), type = %u\n", res->getType()); + } +} + +void ChatAPICore::responseCallback(short type, ByteStream::ReadIterator &iter) +{ + switch(type) + { + case MESSAGE_INSTANTMESSAGE: + { + MInstantMessage M(iter); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_INSTANTMESSAGE: M.getSrcAvatar()=%p\n", M.getSrcAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + if (!destAvatar || !srcAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_INSTANTMESSAGE: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + break; + } + m_api->OnReceiveInstantMessage(srcAvatar, destAvatar, ChatUnicodeString(M.getMsg().data(), M.getMsg().size()), ChatUnicodeString(M.getOOB().data(), M.getOOB().size())); + delete srcAvatar; + } + break; + case MESSAGE_ROOMMESSAGE: + { + MRoomMessage M(iter); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!M.getSrcAvatar() || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ROOMMESSAGE: M.getSrcAvatar()=%p, destRoom=%p\n", M.getSrcAvatar(), destRoom); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + if (!srcAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ROOMMESSAGE: srcAvatar=%p\n", srcAvatar); + break; + } + for(unsigned i = 0; i < M.getListLength(); i++) + { + ChatAvatar *destAvatar = getAvatar(M.getDestList()[i]); + if (!destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ROOMMESSAGE: destAvatar[%i]=NULL\n", i); + continue; + } + m_api->OnReceiveRoomMessage(srcAvatar, destAvatar, destRoom, ChatUnicodeString(M.getMsg().data(), M.getMsg().size()), ChatUnicodeString(M.getOOB().data(), M.getOOB().size())); + m_api->OnReceiveRoomMessage(srcAvatar, destAvatar, destRoom, ChatUnicodeString(M.getMsg().data(), M.getMsg().size()), ChatUnicodeString(M.getOOB().data(), M.getOOB().size()), M.getMessageID()); + } + + if (destRoom && (M.getMessageID() > 0)) + { + destRoom->setRoomMessageID(M.getMessageID()); + } + + delete srcAvatar; + } + break; + case MESSAGE_BROADCASTMESSAGE: + { + MBroadcastMessage M(iter); + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_BROADCASTMESSAGE: M.getSrcAvatar()=%p\n", M.getSrcAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + if (!srcAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_BROADCASTMESSAGE: srcAvatar=%p\n", srcAvatar); + break; + } + for(unsigned i = 0; i < M.getListLength(); i++) + { + ChatAvatar *destAvatar = getAvatar(M.getDestList()[i]); + if (!destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_BROADCASTMESSAGE: destAvatar[%i]=NULL\n", i); + continue; + } + m_api->OnReceiveBroadcastMessage(srcAvatar, ChatUnicodeString(M.getSrcAddress().data(), M.getSrcAddress().size()), destAvatar, ChatUnicodeString(M.getMsg().data(), M.getMsg().size()), ChatUnicodeString(M.getOOB().data(), M.getOOB().size())); + } + delete srcAvatar; + } + break; + case MESSAGE_FILTERMESSAGE: + { + MFilterMessage M(iter); + m_api->OnReceiveFilterMessage(ChatUnicodeString(M.getMsg().data(), M.getMsg().size())); + } + break; + case MESSAGE_FRIENDLOGIN: + { + MFriendLogin M(iter); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + if (!M.getFriendAvatar() || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDLOGIN: M.getFriendAvatar()=%p, destAvatar=%p\n", M.getFriendAvatar(), destAvatar); + break; + } + ChatAvatar *friendAvatar = M.getFriendAvatar()->getNewChatAvatar(); + if (!friendAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDLOGIN: friendAvatar=%p\n", friendAvatar); + break; + } + + friendAvatar->setStatusMessage( M.getFriendStatusMessage() ); + m_api->OnReceiveFriendLogin(friendAvatar, ChatUnicodeString(M.getFriendAddress().data(), M.getFriendAddress().size()), destAvatar); + delete friendAvatar; + } + break; + case MESSAGE_FRIENDLOGOUT: + { + MFriendLogout M(iter); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + if (!M.getFriendAvatar() || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDLOGOUT: M.getFriendAvatar()=%p, destAvatar=%p\n", M.getFriendAvatar(), destAvatar); + break; + } + ChatAvatar *friendAvatar = M.getFriendAvatar()->getNewChatAvatar(); + if (!friendAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDLOGOUT: friendAvatar=%p\n", friendAvatar); + break; + } + m_api->OnReceiveFriendLogout(friendAvatar, ChatUnicodeString(M.getFriendAddress().data(), M.getFriendAddress().size()), destAvatar); + delete friendAvatar; + } + break; + case MESSAGE_FRIENDSTATUS: + { + MFriendStatus M(iter); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + if (!M.getFriendAvatar() || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDSTATUS: M.getFriendAvatar()=%p, destAvatar=%p\n", M.getFriendAvatar(), destAvatar); + break; + } + ChatAvatar *friendAvatar = M.getFriendAvatar()->getNewChatAvatar(); + if (!friendAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDSTATUS: friendAvatar=%p\n", friendAvatar); + break; + } + friendAvatar->setStatusMessage( M.getFriendStatusMessage() ); + m_api->OnReceiveFriendStatusChange(friendAvatar, ChatUnicodeString(M.getFriendAddress().data(), M.getFriendAddress().size()), destAvatar); + delete friendAvatar; + } + break; + case MESSAGE_KICKROOM: + { + MKickRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_KICKROOM: M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatarCore *kickedAvatar = destRoomCore ? destRoomCore->removeAvatar(destAvatar->getAvatarID()) : NULL; + + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!srcAvatar || !destAvatar || !kickedAvatar || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_KICKROOM: srcAvatar=%p, destAvatar=%p, kickedAvatar=%p, destRoom=%p\n", srcAvatar, destAvatar, kickedAvatar, destRoom); + delete srcAvatar; + delete destAvatar; + delete kickedAvatar; + break; + } + + m_api->OnReceiveKickRoom(srcAvatar, destAvatar, destRoom); + delete kickedAvatar; + delete destAvatar; + delete srcAvatar; + } + break; + case MESSAGE_ADDMODERATORROOM: + { + MAddModeratorRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDMODERATORROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + delete M.getDestAvatar(); + break; + } + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + ChatAvatarCore *destAvatarCore = M.getDestAvatar(); + if (!srcAvatar || !destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDMODERATORROOM: srcAvatar=%p, destAvatarCore=%p\n", srcAvatar, destAvatarCore); + delete M.getDestAvatar(); + break; + } + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + + if (!destRoomCore->addModerator(destAvatarCore)) + { + delete M.getDestAvatar(); + } + + if (!destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDMODERATORROOM: destAvatar=%p\n", destAvatar); + break; + } + m_api->OnReceiveAddModeratorRoom(srcAvatar, destAvatar, destRoom); + delete destAvatar; + } + break; + case MESSAGE_REMOVEMODERATORROOM: + { + MRemoveModeratorRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEMODERATORROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + break; + } + + ChatAvatarCore *destAvatarCore = destRoomCore->removeModerator(M.getDestAvatarName(), M.getDestAvatarAddress()); + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + if (!destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEMODERATORROOM: destAvatarCore=%p\n", destAvatarCore); + delete destAvatarCore; + break; + } + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEMODERATORROOM: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete destAvatar; + break; + } + m_api->OnReceiveRemoveModeratorRoom(srcAvatar, destAvatar, destRoom); + + delete destAvatarCore; + delete destAvatar; + } + break; + case MESSAGE_REMOVEMODERATORAVATAR: + { + MRemoveModeratorAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEMODERATORAVATAR: M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEMODERATORAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveRemoveModeratorAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDTEMPORARYMODERATORROOM: + { + MAddTemporaryModeratorRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDTEMPORARYMODERATORROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + delete M.getDestAvatar(); + break; + } + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + ChatAvatarCore *destAvatarCore = M.getDestAvatar(); + if (!srcAvatar || !destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDTEMPORARYMODERATORROOM: srcAvatar=%p, destAvatarCore=%p\n", srcAvatar, destAvatarCore); + delete M.getDestAvatar(); + break; + } + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + + if (!destRoomCore->addTempModerator(destAvatarCore)) + { + delete M.getDestAvatar(); + } + + if (!destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDTEMPORARYMODERATORROOM: destAvatar=%p\n", destAvatar); + break; + } + m_api->OnReceiveAddTemporaryModeratorRoom(srcAvatar, destAvatar, destRoom); + delete destAvatar; + } + break; + case MESSAGE_REMOVETEMPORARYMODERATORROOM: + { + MRemoveTemporaryModeratorRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVETEMPORARYMODERATORROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + break; + } + + ChatAvatarCore *destAvatarCore = destRoomCore->removeTempModerator(M.getDestAvatarName(), M.getDestAvatarAddress()); + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + if (!destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVETEMPORARYMODERATORROOM: destAvatarCore=%p\n", destAvatarCore); + delete destAvatarCore; + break; + } + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVETEMPORARYMODERATORROOM: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete destAvatar; + break; + } + m_api->OnReceiveRemoveTemporaryModeratorRoom(srcAvatar, destAvatar, destRoom); + + delete destAvatarCore; + delete destAvatar; + } + break; + case MESSAGE_REMOVETEMPORARYMODERATORAVATAR: + { + MRemoveTemporaryModeratorAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVETEMPORARYMODERATORAVATAR: M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVETEMPORARYMODERATORAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveRemoveTemporaryModeratorAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDBANROOM: + { + MAddBanRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDBANAVATAR: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + break; + } + + if (!M.getDestAvatar() || !M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDBANAVATAR: M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + delete M.getSrcAvatar(); + break; + } + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + + if (!destRoomCore->addBan(M.getDestAvatar())) + { + delete M.getSrcAvatar(); + } + + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDBANAVATAR: destRoom=%p, destRoomCore=%p\n", destRoom, destRoomCore); + delete srcAvatar; + delete destAvatar; + break; + } + + ChatAvatarCore *removedAvatar = destRoomCore->removeAvatar(destAvatar->getAvatarID()); + if (removedAvatar) delete removedAvatar; + + m_api->OnReceiveAddBanRoom(srcAvatar, destAvatar, destRoom); + + delete destAvatar; + delete srcAvatar; + } + break; + case MESSAGE_REMOVEBANROOM: + { + MRemoveBanRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + + if (!destRoom || !destRoomCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEBANROOM: destRoom=%p, destRoomCore=%p\n", destRoom, destRoomCore); + break; + } + ChatAvatarCore *destAvatarCore = destRoomCore->removeBan(M.getDestAvatarName(), M.getDestAvatarAddress()); + if (!destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEBANROOM: destAvatarCore=%p\n", destAvatarCore); + break; + } + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEBANROOM: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete destAvatar; + break; + } + + m_api->OnReceiveRemoveBanRoom(srcAvatar, destAvatar, destRoom); + + delete destAvatarCore; + delete destAvatar; + } + break; + case MESSAGE_REMOVEBANAVATAR: + { + MRemoveBanAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEBANAVATAR: M.getSrcAvatar=()%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEBANAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveRemoveBanAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDINVITEROOM: + { + MAddInviteRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + + if (!destRoomCore || !M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDINVITEROOM: destRoomCore=%p, M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", destRoomCore, M.getSrcAvatar(), M.getDestAvatar()); + delete M.getDestAvatar(); + break; + } + + if (!destRoomCore->addInvite(M.getDestAvatar())) + { + delete M.getDestAvatar(); + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + ChatRoom *destRoom = getRoom(M.getRoomID()); + + if (!srcAvatar || !destAvatar || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDINVITEROOM: srcAvatar=%p, destAvatar=%p, destRoom=%p\n", srcAvatar, destAvatar, destRoom); + delete srcAvatar; + delete destAvatar; + break; + } + + m_api->OnReceiveAddInviteRoom(srcAvatar, destAvatar, destRoom); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDINVITEAVATAR: + { + MAddInviteAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDINVITEAVATAR: M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDINVITEAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveAddInviteAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_REMOVEINVITEROOM: + { + MRemoveInviteRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEINVITEROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + break; + } + + ChatAvatarCore *destAvatarCore = destRoomCore->removeInvite(M.getDestAvatarName(), M.getDestAvatarAddress()); + if (!destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEINVITEROOM: destAvatarCore=%p\n", destAvatarCore); + break; + } + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEINVITEROOM: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete destAvatarCore; + delete destAvatar; + break; + } + m_api->OnReceiveRemoveInviteRoom(srcAvatar, destAvatar, destRoom); + + delete destAvatarCore; + delete destAvatar; + } + break; + case MESSAGE_REMOVEINVITEAVATAR: + { + MRemoveInviteAvatar M(iter); + + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEINVITEAVATAR: M.getSrcAvatar=%p, M.getDestAvatar=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REMOVEINVITEAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveRemoveInviteAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_GRANTVOICEROOM: + { + MGrantVoiceRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + + if (!destRoomCore || !M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_GRANTVOICEROOM: destRoomCore=%p, M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", destRoomCore, M.getSrcAvatar(), M.getDestAvatar()); + delete M.getDestAvatar(); + break; + } + + if (!destRoomCore->addVoice(M.getDestAvatar())) + { + delete M.getDestAvatar(); + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + ChatRoom *destRoom = getRoom(M.getRoomID()); + + if (!srcAvatar || !destAvatar || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_GRANTVOICEROOM: srcAvatar=%p, destAvatar=%p, destRoom=%p\n", srcAvatar, destAvatar, destRoom); + delete srcAvatar; + delete destAvatar; + break; + } + + m_api->OnReceiveGrantVoiceRoom(srcAvatar, destAvatar, destRoom); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_GRANTVOICEAVATAR: + { + MGrantVoiceAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_GRANTVOICEAVATAR: M.getSrcAvatar()=%p, M.getDestAvatar()=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_GRANTVOICEAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveGrantVoiceAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_REVOKEVOICEROOM: + { + MRevokeVoiceRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REVOKEVOICEROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + break; + } + + ChatAvatarCore *destAvatarCore = destRoomCore->removeVoice(M.getDestAvatarName(), M.getDestAvatarAddress()); + if (!destAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REVOKEVOICEROOM: destAvatarCore=%p\n", destAvatarCore); + break; + } + + const ChatAvatar *srcAvatar = destRoomCore->getAvatar(M.getSrcAvatarID()); + ChatAvatar *destAvatar = destAvatarCore->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REVOKEVOICEROOM: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete destAvatarCore; + delete destAvatar; + break; + } + m_api->OnReceiveRevokeVoiceRoom(srcAvatar, destAvatar, destRoom); + + delete destAvatarCore; + delete destAvatar; + } + break; + case MESSAGE_REVOKEVOICEAVATAR: + { + MRevokeVoiceAvatar M(iter); + + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REVOKEVOICEAVATAR: M.getSrcAvatar=%p, M.getDestAvatar=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REVOKEVOICEAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveRevokeVoiceAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ENTERROOM: + { + MEnterRoom M(iter); + + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom || !M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ENTERROOM: destRoomCore=%p, destRoom=%p, M.getSrcAvatar=%p\n", destRoomCore, destRoom, M.getSrcAvatar()); + delete M.getSrcAvatar(); + break; + } + + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + if (!srcAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ENTERROOM: srcAvatar=NULL\n"); + delete M.getSrcAvatar(); + break; + } + + bool isLocalAvatar = (getAvatar(srcAvatar->getAvatarID()) != NULL); + if(!destRoomCore->addAvatar(M.getSrcAvatar(),isLocalAvatar)) + { + delete M.getSrcAvatar(); + } + + m_api->OnReceiveEnterRoom(srcAvatar, destRoom); + delete srcAvatar; + } + break; + case MESSAGE_LEAVEROOM: + { + MLeaveRoom M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatRoom *destRoom = getRoom(M.getRoomID()); + if (!destRoomCore || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_LEAVEROOM: destRoomCore=%p, destRoom=%p\n", destRoomCore, destRoom); + break; + } + + ChatAvatarCore *srcAvatarCore = destRoomCore->removeAvatar(M.getAvatarID()); + if (!srcAvatarCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_LEAVEROOM: srcAvatarCore=%p\n", srcAvatarCore); + break; + } + ChatAvatar *srcAvatar = srcAvatarCore->getNewChatAvatar(); + if (!srcAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_LEAVEROOM: srcAvatar=%p\n", srcAvatar); + break; + } + + m_api->OnReceiveLeaveRoom(srcAvatar, destRoom); + delete srcAvatarCore; + delete srcAvatar; + } + break; + case MESSAGE_DESTROYROOM: + { + MDestroyRoom M(iter); + + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + + if (destRoomCore) + { + ChatRoom *destRoom = getRoom(M.getRoomID()); + ChatAvatar *srcAvatar = NULL; + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_DESTROYROOM: M.getSrcAvatar=NULL\n"); + } + else + { + srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + } + + if (destRoom) + { + m_api->OnReceiveDestroyRoom(srcAvatar, destRoom); + } + else + { + _chatdebug_("ChatAPI:BadData: MESSAGE_DESTROYROOM: srcAvatar=%p, destRoom=%p\n", srcAvatar, destRoom); + } + delete srcAvatar; + + ChatRoomCore *destRoomCore = decacheRoom(M.getRoomID()); + delete destRoomCore; + } + else + { + _chatdebug_("ChatAPI:BadData: MESSAGE_DESTROYROOM: destRoomCore=%p\n", destRoomCore); + } + } + break; + case MESSAGE_SETROOMPARAMS: + { + MSetRoomParams M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + if (!destRoomCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_SETROOMPARAMS: destRoomCore=NULL\n"); + break; + } + + // build RoomParams object for OnReceiveRoomParams call + RoomParams oldParams(ChatUnicodeString(destRoomCore->getRoomName().data(), destRoomCore->getRoomName().size()), ChatUnicodeString(destRoomCore->getRoomTopic().data(), destRoomCore->getRoomTopic().size()), ChatUnicodeString(destRoomCore->getRoomPassword().data(), destRoomCore->getRoomPassword().size()), destRoomCore->getRoomAttributes(), destRoomCore->getMaxRoomSize()); + RoomParams params(ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomTopic().data(), M.getRoomTopic().size()), ChatUnicodeString(M.getRoomPassword().data(), M.getRoomPassword().size()), M.getRoomAttributes(), M.getRoomSize()); + + // update cached room + destRoomCore->setAttributes(M.getRoomAttributes()); + destRoomCore->setMaxRoomSize(M.getRoomSize()); + destRoomCore->setName(M.getRoomName()); + destRoomCore->setTopic(M.getRoomTopic()); + destRoomCore->setPassword(M.getRoomPassword()); + + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_SETROOMPARAMS: M.getSrcAvatar=NULL\n"); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatRoom *destRoom = getRoom(M.getRoomID()); + + if (!srcAvatar || !destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_SETROOMPARAMS: srcAvatar=%p, destRoom=%p\n", srcAvatar, destRoom); + delete srcAvatar; + break; + } + m_api->OnReceiveRoomParams(srcAvatar, destRoom, ¶ms, &oldParams); + delete srcAvatar; + } + break; + case MESSAGE_PERSISTENTMESSAGE: + { + MPersistentMessage M(iter); + ChatAvatar *avatar = getAvatar(M.getDestAvatarID()); + if (avatar) + m_api->OnReceivePersistentMessage(avatar, M.getHeader()); + } + break; + case MESSAGE_FORCEDLOGOUT: + { + MForcedLogout M(iter); + ChatAvatar *avatar = getAvatar(M.getAvatarID()); + if (avatar) + m_api->OnReceiveForcedLogout(avatar); + ChatAvatarCore *core = decacheAvatar(M.getAvatarID()); + delete core; + } + break; + case MESSAGE_UNREGISTERROOMREADY: + { + MUnregisterRoomReady M(iter); + + ChatRoom *room = getRoom(M.getRoomID()); + + if (room) + { + m_api->OnReceiveUnregisterRoomReady(room); + } + } + break; + case MESSAGE_KICKAVATAR: + { + MKickAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_KICKAVATAR: M.getSrcAvatar=%p, M.getDestAvatar=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_KICKAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveKickAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDMODERATORAVATAR: + { + MAddModeratorAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDMODERATORAVATAR: M.getSrcAvatar=%p, M.getDestAvatar=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDMODERATORAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveAddModeratorAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDTEMPORARYMODERATORAVATAR: + { + MAddTemporaryModeratorAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDTEMPORARYMODERATORAVATAR: M.getSrcAvatar=%p, M.getDestAvatar=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDTEMPORARYMODERATORAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveAddTemporaryModeratorAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDBANAVATAR: + { + MAddBanAvatar M(iter); + if (!M.getSrcAvatar() || !M.getDestAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDBANAVATAR: M.getSrcAvatar=%p, M.getDestAvatar=%p\n", M.getSrcAvatar(), M.getDestAvatar()); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = M.getDestAvatar()->getNewChatAvatar(); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_ADDBANAVATAR: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + delete destAvatar; + break; + } + m_api->OnReceiveAddBanAvatar(srcAvatar, destAvatar, ChatUnicodeString(M.getRoomName().data(), M.getRoomName().size()), ChatUnicodeString(M.getRoomAddress().data(), M.getRoomAddress().size())); + delete srcAvatar; + delete destAvatar; + } + break; + case MESSAGE_ADDADMIN: + { + MAddAdmin M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + if (destRoomCore && (destRoomCore->addAdministrator(M.getAvatar()) == NULL)) + { + delete (M.getAvatar()); + } + } + break; + case MESSAGE_REMOVEADMIN: + { + MRemoveAdmin M(iter); + ChatRoomCore *destRoomCore = getRoomCore(M.getRoomID()); + ChatAvatarCore *admin = NULL; + if (destRoomCore) + admin = destRoomCore->removeAdministrator(M.getAvatarID()); + delete admin; + } + break; + case MESSAGE_FRIENDCONFIRMREQUEST: + { + MFriendConfirmRequest M(iter); + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMREQUEST: M.getSrcAvatar=NULL\n"); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMREQUEST: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + break; + } + m_api->OnReceiveFriendConfirmRequest(srcAvatar, destAvatar); + + delete srcAvatar; + } + break; + case MESSAGE_FRIENDCONFIRMRESPONSE: + { + MFriendConfirmResponse M(iter); + + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMRESPONSE: M.getSrcAvatar=NULL\n"); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMRESPONSE: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + break; + } + m_api->OnReceiveFriendConfirmResponse(srcAvatar, destAvatar, M.getConfirm()); + + delete srcAvatar; + } + break; + case MESSAGE_FRIENDCONFIRMRECIPROCATE_REQUEST: + { + MFriendConfirmReciprocateRequest M(iter); + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMRECIPROCATE_REQUEST: M.getSrcAvatar=NULL\n"); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMRECIPROCATE_REQUEST: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + break; + } + m_api->OnReceiveFriendConfirmReciprocateRequest(srcAvatar, destAvatar); + + delete srcAvatar; + } + break; + case MESSAGE_FRIENDCONFIRMRECIPROCATE_RESPONSE: + { + MFriendConfirmReciprocateResponse M(iter); + + if (!M.getSrcAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMRECIPROCATE_RESPONSE: M.getSrcAvatar=NULL\n"); + break; + } + ChatAvatar *srcAvatar = M.getSrcAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = getAvatar(M.getDestAvatarID()); + + if (!srcAvatar || !destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_FRIENDCONFIRMRECIPROCATE_RESPONSE: srcAvatar=%p, destAvatar=%p\n", srcAvatar, destAvatar); + delete srcAvatar; + break; + } + m_api->OnReceiveFriendConfirmReciprocateResponse(srcAvatar, destAvatar, M.getConfirm()); + + delete srcAvatar; + } + break; + case MESSAGE_CHANGEROOMOWNER: + { + MChangeRoomOwner M(iter); + + ChatRoomCore *destRoomCore = getRoomCore(M.getDestRoomID()); + if (!destRoomCore) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_CHANGEROOMOWNER: destRoomCore=NULL\n"); + break; + } + + // update cached room + destRoomCore->setCreator(M.getNewRoomOwnerID(), M.getNewRoomOwnerName(), M.getNewRoomOwnerAddress()); + ChatRoom *destRoom = getRoom(M.getDestRoomID()); + + if (!destRoom) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_CHANGEROOMOWNER: destRoom=%p\n", destRoom); + break; + } + + m_api->OnReceiveRoomOwnerChange(destRoom); + } + break; + case MESSAGE_REQUESTROOMENTRY: + { + MRoomEntryRequest M(iter); + + if (!M.getRequestorAvatar()) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REQUESTROOMENTRY: M.getRequestorAvatar=NULL\n"); + break; + } + ChatAvatar *srcAvatar = M.getRequestorAvatar()->getNewChatAvatar(); + ChatAvatar *destAvatar = getAvatar(M.getRoomOwnerID()); + + if (!destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_REQUESTROOMENTRY: destAvatar=%p\n", destAvatar); + delete srcAvatar; + break; + } + + m_api->OnReceiveRoomEntryRequest(srcAvatar, destAvatar, M.getRequestedRoomAddress()); + + delete srcAvatar; + } + break; + case MESSAGE_DELAYEDROOMENTRY: + { + MDelayedRoomEntry M(iter); + + ChatAvatar *avatar = getAvatar(M.getAvatarID()); + ChatRoom *room = getRoom(M.getRoomID()); + + const set &extraRooms = M.getExtraRooms(); + set::const_iterator iter = extraRooms.begin(); + for (; iter != extraRooms.end(); iter++) + { + if (room) + { + // we don't need to cache the rooms, so delete them + delete (*iter); + } + else + { + cacheRoom(*iter); + } + } + + room = getRoom(M.getRoomID()); + + if (!avatar || !room) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_DELAYEDROOMENTRY: avatar=%p, room=%p\n", avatar, room); + break; + } + + m_api->OnReceiveDelayedRoomEntry(avatar, room); + } + break; + case MESSAGE_DENIEDROOMENTRY: + { + MDeniedRoomEntry M(iter); + + ChatAvatar *destAvatar = getAvatar(M.getRequestorID()); + + if (!destAvatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_DENIEDROOMENTRY: destAvatar=%p\n", destAvatar); + break; + } + + m_api->OnReceiveDeniedRoomEntry(destAvatar, M.getRequestedRoomAddress()); + } + break; + case MESSAGE_FORCEROOMFAILOVER: + { + MForceRoomFailover M(iter); + + // get list of AIDs for which we need to send room failover requests + const list &aidList = M.getAIDList(); + if (aidList.size() > 0) + { + // iterate through rooms, checking if we must fail them over + map::const_iterator roomIter = m_roomCoreCache.begin(); + for (; roomIter != m_roomCoreCache.end(); roomIter++) + { + ChatRoomCore *room = (*roomIter).second; + const String &roomAddress = room->getAddress(); + + // compare room address against aid string, it is a match + // if aid string is found at index 0 (start of roomAddr string) + String::size_type index; + list::const_iterator aidIter = aidList.begin(); + for (; aidIter != aidList.end(); aidIter++) + { + index = roomAddress.find(*aidIter); + if (index == 0) + { + // we need to failover this room + RFailoverRecreateRoom *req = new RFailoverRecreateRoom(room); + ResFailoverRecreateRoom *res = new ResFailoverRecreateRoom(room->getRoomID(), true); + submitRequest(req, res); + break; + } + } + } + } + } + break; + case MESSAGE_FAILOVER_AVATAR_LIST: + { + unsigned numWorlds = 0; + + get(iter, numWorlds); + + std::vector worldVec; + unsigned i = 0; + for (i = 0; i < numWorlds; ++i) + { + Plat_Unicode::String world; + get(iter, world); + worldVec.push_back(world); + } + + map::iterator avatarIter; + + if (m_avatarCoreCache.size() > 0) + { + for (avatarIter = m_avatarCoreCache.begin(); avatarIter != m_avatarCoreCache.end(); ++avatarIter) + { + for(i = 0; i < worldVec.size(); ++i) + { + if (caseInsensitiveCompare((*avatarIter).second->getAddress(),worldVec[i])) + { + failoverReloginOneAvatar((*avatarIter).second); + break; // break out of world loop into avatar loop + } + } + } + } + } + break; + case MESSAGE_SNOOP: + { + MSnoop M(iter); + + m_api->OnReceiveSnoopMessage(M.getSnoopType(), + ChatUnicodeString(M.getSnooperName()), + ChatUnicodeString(M.getSnooperAddr()), + ChatUnicodeString(M.getSrcName()), + ChatUnicodeString(M.getSrcAddr()), + ChatUnicodeString(M.getDestName()), + ChatUnicodeString(M.getDestAddr()), + ChatUnicodeString(M.getMessage())); + } + break; + case MESSAGE_UIDLIST: + { + MUIDList M(iter); + + m_uidSet = M.getUIDList(); + } + break; + case MESSAGE_NOTIFY_FRIEND_IS_REMOVED: + { + MNotifyFriendIsRemoved M(iter); + + ChatAvatar *avatar = getAvatar(M.getAvatarID()); + + if (!avatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_NOTIFY_FRIEND_IS_REMOVED: avatar=%p avatarID(%d)\n", avatar, M.getAvatarID()); + break; + } + + m_api->OnReceiveNotifyFriendIsRemoved(avatar, M.getDestName(), M.getDestAddress()); + } + break; + case MESSAGE_NOTIFY_FRIENDS_LIST_CHANGE: + { + MNotifyFriendsListChange M(iter); + ChatAvatar *avatar = getAvatar(M.getAvatarID()); + + if (!avatar) + { + _chatdebug_("ChatAPI:BadData: MESSAGE_NOTIFY_FRIENDS_LIST_CHANGE: avatar=%p avatarID(%d)\n", avatar, M.getAvatarID()); + break; + } + + m_api->OnReceiveNotifyFriendsListChange(avatar,M.getOriginalName(), M.getOriginalAddress(), M.getNewName(), M.getNewAddress()); + } + break; + default: + fprintf(stderr, "[ChatAPICore.cpp] default (message) responseCallback(ByteStream::ReadIterator &), type = %u\n", type); + } +} + +void ChatAPICore::processAPI() +{ + // if we are connected to the registrar and we got the + // ResRegistrarGetChatServer callback, then we disconnect + // and connect to the assigned ChatServer + if (m_connected && + m_setToRegistrar && + m_rcvdRegistrarResponse) + { + // disconnect from the Registrar + m_serverConnections[0]->disconnect(); + } + // if we've been disconnected for at least a minute... + else if (!m_connected && + time(NULL) - m_timeSinceLastDisconnect >= 60) + { + if (m_setToRegistrar) + { + // ...and we can't connect to the registrar, then + // connect to lastAssigned Chat Server host and port + // (which on the first attempt would be the same as default) + changeHostPort(0, m_assignedServerHost.c_str(), m_assignedServerPort); + m_setToRegistrar = false; + } + else + { + // ...and we can't connect to the Chat Server, then + // connect to the registrar and ask again for direction + changeHostPort(0, m_registrarHost.c_str(), m_registrarPort); + m_setToRegistrar = true; + } + + m_timeSinceLastDisconnect = time(NULL); + } + + + // call GenericAPICore::process() + process(); +} + +void ChatAPICore::OnConnect(const char *host, short port) +{ + m_connected = true; + + // act on connection depending on if we are connected to + // registrar or chatserver + if (m_setToRegistrar) + { + // negotiate chat server host/port with the Registrar + Base::ByteStream msg; + RRegistrarGetChatServer *req = new RRegistrarGetChatServer(m_defaultServerHost, m_defaultServerPort); + ResRegistrarGetChatServer *res = new ResRegistrarGetChatServer(); + + if(m_currTrack == 0) + { + m_currTrack++; + } + req->setTrack(m_currTrack); + res->setTrack(m_currTrack); + m_currTrack++; + + time_t timeout = time(NULL) + m_requestTimeout; + req->setTimeout(timeout); + res->setTimeout(timeout); + + m_pending.insert(pair(res->getTrack(), res)); + m_pendingCount++; + + // submit request directly (the exception, not using submitRequest()) + req->pack(msg); + m_serverConnections[0]->Send(msg); + delete req; + + m_rcvdRegistrarResponse = false; + m_serverConnections[0]->process(); + } + else if (!m_sentVersion && + m_shouldSendVersion) // always true, except ChatAdminAPICore can override + { + // send the version to the chat server + Base::ByteStream msg; + RSendApiVersion *req = new RSendApiVersion(kChatApiVersion); + ResSendApiVersion *res = new ResSendApiVersion(); + + if(m_currTrack == 0) + { + m_currTrack++; + } + req->setTrack(m_currTrack); + res->setTrack(m_currTrack); + m_currTrack++; + + time_t timeout = time(NULL) + m_requestTimeout; + req->setTimeout(timeout); + res->setTimeout(timeout); + + m_pending.insert(pair(res->getTrack(), res)); + m_pendingCount++; + + // submit request directly (the exception, not using submitRequest()) + req->pack(msg); + m_serverConnections[0]->Send(msg); + delete req; + + m_serverConnections[0]->process(); + } + else if (m_shouldSendVersion == false) + { + if (m_inFailoverMode) + { + // reconnect to server succeeded, proceed with failover procedures. + // The failover procs will make the resumeProcessing() call. + m_api->OnFailoverBegin(); + failoverReloginAvatars(); + } + else + { + // first time connecting, allow user requests to go through + resumeProcessing(); + m_api->OnConnect(); + } + } +} + +void ChatAPICore::OnDisconnect(const char *host, short port) +{ + // we may get OnDisconnect even when we're already disconnected, + // so protect against unnecessary OnDisconnects by checking m_connected + if (m_connected) + { + m_connected = false; + m_sentVersion = false; + + // stop processing immediately + suspendProcessing(); + + m_timeSinceLastDisconnect = time(NULL); + + // determine who we disconnected from and take appropriate action + if (strcmp(host, m_registrarHost.c_str()) == 0 && + port == m_registrarPort) + { + // we finished communication to the registrar + // change connection to the assigned host and port + changeHostPort(0, m_assignedServerHost.c_str(), m_assignedServerPort); + m_setToRegistrar = false; + } + else + { + // we disconnected from a Chat Server + // consider ourselves in failover mode, meaning next connection to + // a Chat Server will induce API failure procedure. First we will + // attempt to connect to Registrar again. + m_inFailoverMode = true; + m_failoverAvatarResRemain = 0; + m_failoverRoomResRemain = 0; + + changeHostPort(0, m_registrarHost.c_str(), m_registrarPort); + m_setToRegistrar = true; + + // indicate disconnect state + m_api->OnDisconnect(); + } + } +} + +void ChatAPICore::failoverReloginAvatars() +{ + map::iterator avatarIter; + + if (m_avatarCoreCache.size() > 0) + { + for (avatarIter = m_avatarCoreCache.begin(); avatarIter != m_avatarCoreCache.end(); avatarIter++) + { + // build failover-login request for avatar + failoverReloginOneAvatar(avatarIter->second); + } + } + else + { + // no avatars to relogin, so directly proceed to failover rooms + failoverRecreateRooms(); + } +} + + +void ChatAPICore::failoverReloginOneAvatar(ChatAvatarCore * avatarCore) +{ + if (avatarCore) + { + // build failover-login request for avatar + Base::ByteStream msg; + RFailoverReloginAvatar *req = new RFailoverReloginAvatar(avatarCore); + ResFailoverReloginAvatar *res = new ResFailoverReloginAvatar(avatarCore->getAvatarID()); + + if(m_currTrack == 0) + { + m_currTrack++; + } + req->setTrack(m_currTrack); + res->setTrack(m_currTrack); + m_currTrack++; + + time_t timeout = time(NULL) + m_requestTimeout; + req->setTimeout(timeout); + res->setTimeout(timeout); + + m_pending.insert(pair(res->getTrack(), res)); + m_pendingCount++; + + // submit request directly (the exception, not using submitRequest()) + req->pack(msg); + m_serverConnections[0]->Send(msg); + delete req; + + m_failoverAvatarResRemain++; + m_serverConnections[0]->process(false); + } +} + + +void ChatAPICore::failoverRecreateRooms() +{ + map::iterator roomIter; + multimap::iterator roomMultiIter; + + if (m_roomCoreCache.size() > 0) + { + // first build multimap of rooms keyed by their node level (ascending order is default). + multimap levelMap; + ChatRoomCore *roomCore = NULL; + for (roomIter = m_roomCoreCache.begin(); roomIter != m_roomCoreCache.end(); roomIter++) + { + roomCore = (*roomIter).second; + if (roomCore->getNodeLevel() != 0) + { + levelMap.insert(pair(roomCore->getNodeLevel(), roomCore)); + } + } + + for (roomMultiIter = levelMap.begin(); roomMultiIter != levelMap.end(); roomMultiIter++) + { + roomCore = (*roomMultiIter).second; + + // build failover-room-create request for room + Base::ByteStream msg; + RFailoverRecreateRoom *req = new RFailoverRecreateRoom(roomCore); + ResFailoverRecreateRoom *res = new ResFailoverRecreateRoom(roomCore->getRoomID()); + + if(m_currTrack == 0) + { + m_currTrack++; + } + req->setTrack(m_currTrack); + res->setTrack(m_currTrack); + m_currTrack++; + + time_t timeout = time(NULL) + m_requestTimeout; + req->setTimeout(timeout); + res->setTimeout(timeout); + + m_pending.insert(pair(res->getTrack(), res)); + m_pendingCount++; + + // submit request directly (the exception, not using submitRequest()) + req->pack(msg); + m_serverConnections[0]->Send(msg); + delete req; + + m_failoverRoomResRemain++; + m_serverConnections[0]->process(false); + } + } + else + { + // no rooms to recreate, so resume processing and + // indicate it's ok to send new requests. + m_inFailoverMode = false; + m_api->OnFailoverComplete(); + resumeProcessing(); + } +} + +ChatAvatar *ChatAPICore::getAvatar(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress) +{ + ChatAvatar *returnVal = NULL; + + map::iterator iter = m_avatarCache.begin(); + + for (; iter != m_avatarCache.end(); iter++) + { + ChatAvatar *avatar = (*iter).second; + + if (areEqualChatStrings(avatarName, avatar->getName()) && + areEqualChatStrings(avatarAddress, avatar->getAddress())) + { + returnVal = avatar; + break; + } + } + + return returnVal; +} + +ChatRoom *ChatAPICore::getRoom(const ChatUnicodeString &roomAddress) +{ + ChatRoom *returnVal = NULL; + + map::iterator iter = m_roomCache.begin(); + + for (; iter != m_roomCache.end(); iter++) + { + ChatRoom *room = (*iter).second; + + if (areEqualChatStrings(roomAddress, room->getAddress())) + { + returnVal = room; + break; + } + } + + return returnVal; +} + +bool ChatAPICore::areEqualChatStrings(const ChatUnicodeString &str1, const ChatUnicodeString &str2) +{ + bool returnVal = true; + + if (str1.string_length != str2.string_length) + { + returnVal = false; + } + else + { + for (unsigned i = 0; i != str1.string_length; i++) + { + if (trueLower(str1.string_data[i]) != trueLower(str2.string_data[i])) + { + returnVal = false; + break; + } + } + } + + return returnVal; +} + +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPICore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPICore.h new file mode 100644 index 00000000..583850d2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAPICore.h @@ -0,0 +1,106 @@ +#if !defined (CHATAPICORE_H_) +#define CHATAPICORE_H_ + +#pragma warning (disable : 4786) +#include +#include +#include +#include + +#include + +namespace ChatSystem +{ + + class ChatAvatar; + class ChatAvatarCore; + class ChatRoomCore; + class ChatRoom; + class ChatAPI; + class ChatUnicodeString; + + class ChatAPICore : public GenericAPI::GenericAPICore + { + public: + ChatAPICore(const char *registrar_host, short registrar_port, const char *server_host, short server_port); + virtual ~ChatAPICore(); + + void setRequestTimeout(unsigned requestTimeout) { m_requestTimeout = requestTimeout; } + + unsigned RequestCreateAvatar(const char *name); + unsigned RequestDestroyAvatar(ChatAvatar *avatar); + + virtual void responseCallback(GenericAPI::GenericResponse *res); + virtual void responseCallback(short type, Base::ByteStream::ReadIterator &iter); + void clearRequestCount() { m_requestCount = 0; } + + virtual void OnConnect(const char *host, short port); + virtual void OnDisconnect(const char *host, short port); + + void setAPI(ChatAPI *api) { m_api = api; } + ChatAvatar *getAvatar(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress); + ChatAvatar *getAvatar(unsigned avatarID); + ChatRoom *getRoom(const ChatUnicodeString &roomAddress); + ChatRoom *getRoom(unsigned roomID); + + static ChatUnicodeString getErrorString(unsigned resultCode); + + bool isUID(Plat_Unicode::String &uid) { return (m_uidSet.find(Plat_Unicode::toUpper(uid)) != m_uidSet.end()); } + + // calls GenericAPICore::processAPI() after doing any necessary work + void processAPI(); + + private: + void cacheRoom(ChatRoomCore *roomCore); + ChatRoomCore *decacheRoom(unsigned roomID); + + ChatRoomCore *getRoomCore(unsigned roomID); + + void cacheAvatar(ChatAvatarCore *avatarCore); + ChatAvatarCore *decacheAvatar(unsigned avatarID); + + ChatAvatarCore *getAvatarCore(unsigned avatarID); + + bool areEqualChatStrings(const ChatUnicodeString &str1, const ChatUnicodeString &str2); + + void failoverReloginAvatars(); + void failoverReloginOneAvatar(ChatAvatarCore * avatarCore); + + void failoverRecreateRooms(); + + std::map m_avatarCoreCache; + std::map m_avatarCache; + std::map m_roomCoreCache; + std::map m_roomCache; + + std::set m_uidSet; + + bool m_connected; + bool m_sentVersion; + bool m_inFailoverMode; + unsigned m_failoverAvatarResRemain; + unsigned m_failoverRoomResRemain; + unsigned m_requestCount; + + bool m_setToRegistrar; + std::string m_registrarHost; + std::string m_defaultServerHost; + std::string m_assignedServerHost; + short m_registrarPort; + short m_defaultServerPort; + short m_assignedServerPort; + + time_t m_timeSinceLastDisconnect; + bool m_rcvdRegistrarResponse; + + static const char * const ms_errorStringsEnglish[]; + static unsigned ms_numErrorStrings; + + ChatAPI *m_api; + + protected: + bool m_shouldSendVersion; + }; +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatar.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatar.cpp new file mode 100644 index 00000000..8ec60bc8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatar.cpp @@ -0,0 +1,213 @@ +#include "ChatAvatar.h" +#include "ChatAvatarCore.h" +#include "Base/MD5.h" +#include "Unicode/utf8.h" +#include +#include +#include + +const unsigned MOD_NUMBER = 256; + +namespace ChatSystem +{ + +ChatAvatar::ChatAvatar() +: m_core(new ChatAvatarCore()) +{ +} + + +ChatAvatar::ChatAvatar(unsigned avatarID, unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &gateway, const ChatUnicodeString &server, unsigned gatewayID, unsigned serverID) +: m_core(new ChatAvatarCore(avatarID, userID, name, address, gateway, server, gatewayID, serverID, ChatUnicodeString(), 0)), + m_cServer(m_core->getServer().data(), m_core->getServer().size()), + m_cGateway(m_core->getGateway().data(), m_core->getGateway().size()), + m_cName(m_core->getName().data(), m_core->getName().size()), + m_cAddress(m_core->getAddress().data(), m_core->getAddress().size()), + m_cLoginLocation(m_core->getLoginLocation().data(), m_core->getLoginLocation().size()) +{ +} + +ChatAvatar::ChatAvatar(unsigned avatarID, unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &gateway, const ChatUnicodeString &server, unsigned gatewayID, unsigned serverID, const ChatUnicodeString &loginLocation, unsigned attributes) +: m_core(new ChatAvatarCore(avatarID, userID, name, address, gateway, server, gatewayID, serverID, loginLocation, attributes)), + m_cServer(m_core->getServer().data(), m_core->getServer().size()), + m_cGateway(m_core->getGateway().data(), m_core->getGateway().size()), + m_cName(m_core->getName().data(), m_core->getName().size()), + m_cAddress(m_core->getAddress().data(), m_core->getAddress().size()), + m_cLoginLocation(m_core->getLoginLocation().data(), m_core->getLoginLocation().size()) +{ +} + +ChatAvatar::ChatAvatar(const ChatAvatar &rhs) +: m_core(new ChatAvatarCore(*(rhs.m_core))) +{ +} + +ChatAvatar::~ChatAvatar() +{ + delete m_core; +} + +ChatAvatar &ChatAvatar::operator=(const ChatAvatar &rhs) +{ + delete m_core; + m_core = new ChatAvatarCore(rhs.m_core->getAvatarID(), + rhs.m_core->getUserID(), + rhs.m_core->getName(), + rhs.m_core->getAddress(), + rhs.m_core->getGateway(), + rhs.m_core->getServer(), + rhs.m_core->getGatewayID(), + rhs.m_core->getServerID(), + rhs.m_core->getLoginLocation(), + rhs.getAttributes()); + + m_cServer = m_core->getServer(); + m_cGateway= m_core->getGateway(); + m_cName = m_core->getName(); + m_cAddress = m_core->getAddress(); + + return(*this); +} + +const ChatUnicodeString &ChatAvatar::getName() const +{ + m_cName = m_core->getName(); + return m_cName; +} + +const ChatUnicodeString &ChatAvatar::getAddress() const +{ + m_cAddress = m_core->getAddress(); + return m_cAddress; +} + +unsigned ChatAvatar::getUserID() const +{ + return m_core->getUserID(); +} + +unsigned ChatAvatar::getAvatarID() const +{ + return m_core->getAvatarID(); +} + +const ChatUnicodeString &ChatAvatar::getLoginLocation() const +{ + m_cLoginLocation = m_core->getLoginLocation(); + + return m_cLoginLocation; +} + +int ChatAvatar::getLoginPriority() const +{ + return m_core->getLoginPriority(); +} + +unsigned ChatAvatar::getInboxLimit() const +{ + return m_core->getInboxLimit(); +} + +const ChatUnicodeString &ChatAvatar::getForwardingEmail() const +{ + m_cForwardingEmail = m_core->getEmail(); + + return m_cForwardingEmail; +} + +unsigned ChatAvatar::getAttributes() const +{ + return m_core->getAttributes(); +} + +const ChatUnicodeString &ChatAvatar::getServer() const +{ + m_cServer = m_core->getServer(); + return m_cServer; +} + +const ChatUnicodeString &ChatAvatar::getGateway() const +{ + m_cGateway = m_core->getGateway(); + return m_cGateway; +} + +unsigned ChatAvatar::getServerID() const +{ + return m_core->getServerID(); +} + +unsigned ChatAvatar::getGatewayID() const +{ + return m_core->getGatewayID(); +} + +const ChatUnicodeString& ChatAvatar::getStatusMessage() const +{ + m_cStatusMessage = m_core->getStatusMessage(); + return m_cStatusMessage; +} + +void ChatAvatar::setAttributes(unsigned long attributes) +{ + m_core->setAttributes(attributes); +} + +void ChatAvatar::setLoginPriority(int loginPriority) +{ + m_core->setLoginPriority(loginPriority); +} + +void ChatAvatar::setInboxLimit(unsigned inboxLimit) +{ + m_core->setInboxLimit(inboxLimit); +} + +void ChatAvatar::setForwardingEmail(const ChatUnicodeString &forwardingEmail) +{ + m_core->setEmail(forwardingEmail.data()); +} + +void ChatAvatar::setStatusMessage(const ChatUnicodeString& statusMessage) +{ + m_core->setStatusMessage( statusMessage.data() ); +} + + +ChatUnicodeString ChatAvatar::CreateAddressFromName(const ChatUnicodeString & name, const std::string & gameCode) +{ + // convert to utf8 + char utf8Buff[256]; + memset(utf8Buff, 0, 256); + Plat_Unicode::UTF16_convertToUTF8( (Plat_Unicode::UTF16 *)name.data(), utf8Buff, 256); + + std::string utf8String(utf8Buff); + + std::transform(utf8String.begin(), utf8String.end(), utf8String.begin(), tolower); + + // hash the username + Base::MD5 md5r(utf8String); + std::string hexName = md5r.asHex(); + + // get the sum of each character + unsigned sum = std::accumulate(hexName.begin(), hexName.end(), 0); + + // mod to a world ID. + unsigned short worldID = (sum % MOD_NUMBER); + + char buff[256]; + memset(buff, 0, 256); + unsigned len = 0; + + if (gameCode.length() < 230) + { + len = sprintf (buff, "SOE+%s+World%03d", gameCode.c_str(), worldID); + } + + return ChatUnicodeString(buff, len); +} + + +}; // end ChatSystem namespace + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatar.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatar.h new file mode 100644 index 00000000..998738da --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatar.h @@ -0,0 +1,85 @@ +#if !defined (CHATAVATAR_H_) +#define CHATAVATAR_H_ + +#pragma warning (disable : 4786) + +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + + enum AvatarAttributes + { + AVATARATTR_INVISIBLE = 1 << 0, + AVATARATTR_GM = 1 << 1, + AVATARATTR_SUPERGM = 1 << 2, + AVATARATTR_SUPERSNOOP = 1 << 3, + AVATARATTR_EXTENDED = 1 << 4 + }; + + class ChatAvatarCore; + + // class ChatAvatar + // + // Description: + // This class stores the information about an avatar in the ChatSystem that + // is relevant to the API. + // + // Usage: + // Typically a ChatAvatar will originate from an API callback method. + // The ChatAvatar object can be copied for local storage and the data + // members can be retrieved from the available get__ methods below. + class ChatAvatar + { + public: + ChatAvatar(); + ChatAvatar(unsigned avatarID, unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &gateway, const ChatUnicodeString &server, unsigned gatewayID, unsigned serverID); + ChatAvatar(unsigned avatarID, unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &gateway, const ChatUnicodeString &server, unsigned gatewayID, unsigned serverID, const ChatUnicodeString &loginLocation, unsigned attributes); + ChatAvatar(const ChatAvatar &rhs); + ~ChatAvatar(); + + ChatAvatar &operator=(const ChatAvatar &rhs); + + const ChatUnicodeString &getName() const; + const ChatUnicodeString &getAddress() const; + + unsigned getUserID() const; + unsigned getAvatarID() const; + + const ChatUnicodeString &getServer() const; + const ChatUnicodeString &getGateway() const; + + unsigned getServerID() const; + unsigned getGatewayID() const; + + const ChatUnicodeString &getLoginLocation() const; + int getLoginPriority() const; + unsigned getAttributes() const; + unsigned getInboxLimit() const; + const ChatUnicodeString &getForwardingEmail() const; + const ChatUnicodeString& getStatusMessage() const; + + void setAttributes(unsigned long attributes); + void setLoginPriority(int loginPriority); + void setInboxLimit(unsigned inboxLimit); + void setForwardingEmail(const ChatUnicodeString &forwardingEmail); + void setStatusMessage(const ChatUnicodeString& statusMessage); + + static ChatUnicodeString CreateAddressFromName(const ChatUnicodeString & name, const std::string & gameCode); + + private: + ChatAvatarCore *m_core; + mutable ChatUnicodeString m_cServer; + mutable ChatUnicodeString m_cGateway; + mutable ChatUnicodeString m_cName; + mutable ChatUnicodeString m_cAddress; + mutable ChatUnicodeString m_cLoginLocation; + mutable ChatUnicodeString m_cForwardingEmail; + mutable ChatUnicodeString m_cStatusMessage; + }; +}; + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatarCore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatarCore.cpp new file mode 100644 index 00000000..7eb0c47d --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatarCore.cpp @@ -0,0 +1,186 @@ +#include "ChatAvatarCore.h" +#include "ChatAvatar.h" + +namespace ChatSystem +{ + +using namespace Plat_Unicode; +using namespace Base; + +ChatAvatarCore::ChatAvatarCore() +: m_inboxLimit(0), + m_loginPriority(0), + m_userID(0), + m_avatarID(0), + m_serverID(0), + m_gatewayID(0) +{ +} + +ChatAvatarCore::ChatAvatarCore(unsigned avatarID, unsigned userID, const unsigned short *name, const unsigned short *address, const unsigned short *gateway, const unsigned short *server, unsigned gatewayID, unsigned serverID, const unsigned short *loginLocation, unsigned attributes) +: m_name(name), + m_address(address), + m_server(server), + m_gateway(gateway), + m_loginLocation(loginLocation), + m_attributes(attributes), + m_inboxLimit(0), + m_loginPriority(0), + m_userID(userID), + m_avatarID(avatarID), + m_serverID(serverID), + m_gatewayID(gatewayID) +{ +} + +ChatAvatarCore::ChatAvatarCore(unsigned avatarID, unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &gateway, const ChatUnicodeString &server, unsigned gatewayID, unsigned serverID, const ChatUnicodeString &loginLocation, unsigned attributes) +: m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length), + m_server(server.string_data, server.string_length), + m_gateway(gateway.string_data, gateway.string_length), + m_loginLocation(loginLocation.string_data, loginLocation.string_length), + m_attributes(attributes), + m_inboxLimit(0), + m_loginPriority(0), + m_userID(userID), + m_avatarID(avatarID), + m_serverID(serverID), + m_gatewayID(gatewayID) +{ +} + +ChatAvatarCore::ChatAvatarCore(unsigned avatarID, unsigned userID, const String &name, const String &address, const String &gateway, const String &server, unsigned gatewayID, unsigned serverID, const Plat_Unicode::String &loginLocation, unsigned attributes) +: m_name(name), + m_address(address), + m_server(server), + m_gateway(gateway), + m_loginLocation(loginLocation), + m_attributes(attributes), + m_inboxLimit(0), + m_loginPriority(0), + m_userID(userID), + m_avatarID(avatarID), + m_serverID(serverID), + m_gatewayID(gatewayID) +{ +} + + +ChatAvatarCore::ChatAvatarCore(ByteStream::ReadIterator &iter) +{ + get(iter, m_avatarID); + get(iter, m_userID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_name)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_address)); + get(iter, (uint32 &)m_attributes); + ASSERT_VALID_STRING_LENGTH(get(iter, m_loginLocation)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_server)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_gateway)); + get(iter, m_serverID); + get(iter, m_gatewayID); + + m_loginPriority = 0; + m_inboxLimit = 0; +} + +ChatAvatarCore::ChatAvatarCore(const ChatAvatarCore &rhs) +: m_name(rhs.m_name), + m_address(rhs.m_address), + m_server(rhs.m_server), + m_gateway(rhs.m_gateway), + m_loginLocation(rhs.m_loginLocation), + m_email(rhs.m_email), + m_statusMessage(rhs.m_statusMessage), + m_attributes(rhs.m_attributes), + m_inboxLimit(rhs.m_inboxLimit), + m_loginPriority(rhs.m_loginPriority), + m_userID(rhs.m_userID), + m_avatarID(rhs.m_avatarID), + m_serverID(rhs.m_serverID), + m_gatewayID(rhs.m_gatewayID) +{ +} + +ChatAvatarCore &ChatAvatarCore::operator=(const ChatAvatarCore &rhs) +{ + m_name = rhs.m_name; + m_address = rhs.m_address; + m_userID = rhs.m_userID; + m_avatarID = rhs.m_avatarID; + m_server = rhs.m_server; + m_gateway = rhs.m_gateway; + m_serverID = rhs.m_serverID; + m_gatewayID = rhs.m_gatewayID; + m_attributes = rhs.m_attributes; + m_inboxLimit = rhs.m_inboxLimit; + m_loginPriority = rhs.m_loginPriority; + m_loginLocation = rhs.m_loginLocation; + m_email = rhs.m_email; + m_inboxLimit = rhs.m_inboxLimit; + m_statusMessage = rhs.m_statusMessage; + + return(*this); +} + +ChatAvatar *ChatAvatarCore::getNewChatAvatar() const +{ + ChatUnicodeString addr(m_address.data(), m_address.size()); + ChatUnicodeString name(m_name.data(), m_name.size()); + ChatUnicodeString gateway(m_gateway.data(), m_gateway.size()); + ChatUnicodeString server(m_server.data(), m_server.size()); + + ChatAvatar *newChatAvatar = new ChatAvatar(m_avatarID, + m_userID, + name, + addr, + gateway, + server, + m_gatewayID, + m_serverID, + m_loginLocation, + m_attributes); + + newChatAvatar->setLoginPriority(m_loginPriority); + newChatAvatar->setInboxLimit(m_inboxLimit); + newChatAvatar->setForwardingEmail(m_email); + newChatAvatar->setStatusMessage(m_statusMessage); + + return (newChatAvatar); +} + +void ChatAvatarCore::serialize(Base::ByteStream &msg) +{ + put(msg, m_avatarID); + put(msg, m_userID); + put(msg, m_name); + put(msg, m_address); + put(msg, (uint32)m_attributes); + put(msg, m_loginLocation); +} + +void ChatAvatarCore::setAttributes(unsigned long attributes) +{ + m_attributes = attributes; +} + +void ChatAvatarCore::setLoginPriority(int loginPriority) +{ + m_loginPriority = loginPriority; +} + +void ChatAvatarCore::setEmail(const Plat_Unicode::String email) +{ + m_email = email; +} + +void ChatAvatarCore::setInboxLimit(unsigned inboxLimit) +{ + m_inboxLimit = inboxLimit; +} + +void ChatAvatarCore::setStatusMessage(const Plat_Unicode::String statusMessage) +{ + m_statusMessage = statusMessage; +} + +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatarCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatarCore.h new file mode 100644 index 00000000..b2e1aaae --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatAvatarCore.h @@ -0,0 +1,79 @@ +#if !defined (CHATAVATARCORE_H_) +#define CHATAVATARCORE_H_ + +#pragma warning (disable : 4786) + +#include +#include +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + + + class ChatAvatar; + + class ChatAvatarCore + { + public: + ChatAvatarCore(); + ChatAvatarCore(Base::ByteStream::ReadIterator &iter); + ChatAvatarCore(unsigned avatarID, unsigned userID, const unsigned short *name, const unsigned short *address, const unsigned short *gateway, const unsigned short *server, unsigned gatewayID, unsigned serverID, const unsigned short *loginLocation, unsigned attributes); + ChatAvatarCore(unsigned avatarID, unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &gateway, const ChatUnicodeString &server, unsigned gatewayID, unsigned serverID, const ChatUnicodeString &loginLocation, unsigned attributes); + ChatAvatarCore(unsigned avatarID, unsigned userID, const Plat_Unicode::String &name, const Plat_Unicode::String &address, const Plat_Unicode::String &gateway, const Plat_Unicode::String &server, unsigned gatewayID, unsigned serverID, const Plat_Unicode::String &loginLocation, unsigned attributes); + + + ChatAvatarCore(const ChatAvatarCore &rhs); + ~ChatAvatarCore() {}; + + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + unsigned getUserID() const { return m_userID; } + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getLoginLocation() const { return m_loginLocation; } + int getLoginPriority() const { return m_loginPriority; } + unsigned getAttributes() const { return m_attributes; } + const Plat_Unicode::String &getEmail() const { return m_email; } + unsigned getInboxLimit() const { return m_inboxLimit; } + const Plat_Unicode::String &getServer() const { return m_server; } + const Plat_Unicode::String &getGateway() const { return m_gateway; } + unsigned getServerID() const { return m_serverID; } + unsigned getGatewayID() const { return m_gatewayID; } + const Plat_Unicode::String& getStatusMessage() { return m_statusMessage; } + + ChatAvatar *getNewChatAvatar() const; + + void setAttributes(unsigned long attributes); + void setLoginPriority(int loginPriority); + void setEmail(const Plat_Unicode::String email); + void setInboxLimit(unsigned inboxLimit); + void setStatusMessage(const Plat_Unicode::String statusMessage); + + ChatAvatarCore &operator=(const ChatAvatarCore &rhs); + + void serialize(Base::ByteStream &msg); + private: + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_server; + Plat_Unicode::String m_gateway; + Plat_Unicode::String m_loginLocation; + Plat_Unicode::String m_email; + Plat_Unicode::String m_statusMessage; + + unsigned long m_attributes; + unsigned long m_inboxLimit; + int m_loginPriority; + + unsigned m_userID; + unsigned m_avatarID; + unsigned m_serverID; + unsigned m_gatewayID; + }; + +}; + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatEnum.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatEnum.cpp new file mode 100644 index 00000000..fba1bc17 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatEnum.cpp @@ -0,0 +1,129 @@ +#include "ChatEnum.h" +#include + +namespace ChatSystem { + +using namespace std; +using namespace Plat_Unicode; + +Plat_Unicode::String ChatUnicodeString::getEmptyString() +{ + return narrowToWide(""); +} + +ChatUnicodeString::ChatUnicodeString() +{ + m_wideString = getEmptyString(); + m_cString = wideToNarrow(m_wideString); +} + +ChatUnicodeString::ChatUnicodeString(const unsigned short *data, unsigned length) +{ + m_wideString.assign(data, length); + m_cString = wideToNarrow(m_wideString); +} + +ChatUnicodeString::ChatUnicodeString(const char *nData, unsigned length) +{ + m_cString.assign(nData, length); + m_wideString = narrowToWide(m_cString); +} + +ChatUnicodeString::ChatUnicodeString(const Plat_Unicode::String& src) +{ + m_wideString = src; + m_cString = wideToNarrow(m_wideString); +} + +ChatUnicodeString::ChatUnicodeString(const std::string& nSrc) +{ + m_cString = nSrc; + m_wideString = narrowToWide(m_cString); +} + +ChatUnicodeString::ChatUnicodeString(const char *nStrSrc) +{ + if (nStrSrc==NULL) + { + m_wideString = getEmptyString(); + m_cString = wideToNarrow(m_wideString); + } + else + { + m_cString.assign(nStrSrc); + m_wideString = narrowToWide(m_cString); + } +} + +ChatUnicodeString::ChatUnicodeString(const ChatUnicodeString& src) +{ + m_wideString = src.m_wideString; + m_cString = wideToNarrow(m_wideString); +} + +// = operator +ChatUnicodeString& ChatUnicodeString::operator=(const Plat_Unicode::String& src) +{ + m_wideString = src; + m_cString = wideToNarrow(m_wideString); + + return *this; +} + +ChatUnicodeString& ChatUnicodeString::operator=(const std::string& nSrc) +{ + m_cString = nSrc; + m_wideString = narrowToWide(m_cString); + + return *this; +} + +ChatUnicodeString& ChatUnicodeString::operator=(const char * nStrSrc) +{ + m_cString = nStrSrc; + m_wideString = narrowToWide(m_cString); + + return *this; +} + +ChatUnicodeString& ChatUnicodeString::operator=(const ChatUnicodeString& src) +{ + if (this != &src) { + m_wideString = src.m_wideString; + m_cString = wideToNarrow(m_wideString); + } + + return *this; +} + +// += operator +ChatUnicodeString& ChatUnicodeString::operator+=(const ChatUnicodeString& src) +{ + m_wideString += src.m_wideString; + m_cString = wideToNarrow(m_wideString); + + return *this; +} + +// + operator +ChatUnicodeString ChatUnicodeString::operator+(const ChatUnicodeString& src) +{ + ChatUnicodeString tmp; + + tmp.m_wideString = m_wideString + src.m_wideString; + m_cString = wideToNarrow(m_wideString); + + return tmp; +} + +const char *ChatUnicodeString::c_str() const { + return m_cString.c_str(); +} + +AvatarSnoopPair::AvatarSnoopPair(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +: m_name(name), + m_address(address) +{ +} + +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatEnum.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatEnum.h new file mode 100644 index 00000000..b17ab132 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatEnum.h @@ -0,0 +1,214 @@ +#if !defined (CHATENUM_H_) +#define CHATENUM_H_ + +#include +#include + +#pragma warning ( disable : 4786 ) + +// Defining _chatdebug_ +#ifdef _DEBUG +#ifdef WIN32 +#define _chatdebug_ ::printf +#else +#define _chatdebug_ ::printf +#endif +#endif + +#ifndef _DEBUG +#ifdef WIN32 +#define _chatdebug_ +#else +#define _chatdebug_ +#endif +#endif +// END: "Defining _chatdebug_" + + +// Use AVATAR_PRIORITY_NOFORCELOGOUT on RequestAvatarLogin if you want to override the +// "last login wins" rule, switching that given avatar's session to use "first login wins" +#define AVATAR_PRIORITY_NOFORCELOGOUT ((int) 0x80000000) /*-2147483648*/ + +#define ASSERT_VALID_STRING_LENGTH(X) if (X ==0) return; + +namespace ChatSystem +{ + + enum eResultCodes + { + CHATRESULT_SUCCESS, + + CHATRESULT_TIMEOUT = 1, + CHATRESULT_DUPLICATELOGIN, + CHATRESULT_SRCAVATARDOESNTEXIST, + CHATRESULT_DESTAVATARDOESNTEXIST, + CHATRESULT_ADDRESSDOESNTEXIST, // 5 + CHATRESULT_ADDRESSNOTROOM, + CHATRESULT_ADDRESSNOTAID, + CHATRESULT_FRIENDNOTFOUND, + CHATRESULT_ROOM_UNKNOWNFAILURE, + CHATRESULT_ROOM_SRCNOTINROOM, // 10 + CHATRESULT_ROOM_DESTNOTINROOM, + CHATRESULT_ROOM_BANNEDAVATAR, + CHATRESULT_ROOM_PRIVATEROOM, + CHATRESULT_ROOM_MODERATEDROOM, + CHATRESULT_ROOM_NOTINROOM, // 15 + CHATRESULT_ROOM_NOPRIVILEGES, + CHATRESULT_DATABASE, + CHATRESULT_CANNOTGETAVATARID, + CHATRESULT_CANNOTGETNODEID, + CHATRESULT_CANNOTGETPMSGID, // 20 + CHATRESULT_PMSGNOTFOUND, + CHATRESULT_ROOMMAXAVATARSREACHED, + CHATRESULT_IGNORING, + CHATRESULT_ROOM_ALREADYEXISTS, + CHATRESULT_NOTHINGTOCONFIRM, // 25 + CHATRESULT_DUPLICATEFRIEND, + CHATRESULT_IGNORENOTFOUND, + CHATRESULT_DUPLICATEIGNORE, + CHATRESULT_DBFAIL, + CHATRESULT_ROOM_DESTAVATARNOTMODERATOR, // 30 + CHATRESULT_ROOM_DESTAVATARNOTINVITED, + CHATRESULT_ROOM_DESTAVATARNOTBANNED, + CHATRESULT_ROOM_DUPLICATEBAN, + CHATRESULT_ROOM_DUPLICATEMODERATOR, + CHATRESULT_ROOM_DUPLICATEINVITE, // 35 + CHATRESULT_ROOM_ALREADYINROOM, + CHATRESULT_ROOM_PARENTNONPERSISTENT, + CHATRESULT_ROOM_PARENTBADNODETYPE, + CHATRESULT_NOFANCLUBHANDLE, + CHATRESULT_AIDALREADYEXISTS, // 40 + CHATRESULT_UIDALREADYEXISTS, + CHATRESULT_WRONGCHATSERVERFORREQUEST, + CHATRESULT_SUCCESSBADDATA, + CHATRESULT_NULLNAMELOGIN, + CHATRESULT_SERVER_IDENTITY_EMPTY, // 45 + CHATRESULT_SERVER_IDENTITY_TAKEN, + CHATRESULT_REMOTESERVERDOWN, + CHATRESULT_NODEIDCONFLICT, + CHATRESULT_INVALIDNODENAME, + CHATRESULT_INSUFFICIENTGMPRIVS, // 50 + CHATRESULT_SNOOPALREADYADDED, + CHATRESULT_NOTSNOOPING, + CHATRESULT_ROOM_DESTAVATARNOTTEMPORARYMODERATOR, + CHATRESULT_ROOM_DESTAVATARNOTVOICE, + CHATRESULT_ROOM_DUPLICATETEMPORARYMODERATOR, // 55 + CHATRESULT_ROOM_DUPLICATEVOICE, + CHATRESULT_AVATARMUSTBELOGGEDOUT, + CHATRESULT_NOTHINGTODO, + CHATRESULT_TRANSFERNAMENULL, + CHATRESULT_TRANSFERUSERIDZERO, // 60 + CHATRESULT_TRANSFERADDRESSNULL, + CHATRESULT_OUTOFIDS, + CHATRESULT_ROOM_LOCALROOM, + CHATRESULT_ROOM_GAMEROOM, + CHATRESULT_ROOM_DESTAVATARNOTENTERING, // 65 + CHATRESULT_INSUFFICIENTPRIORITY, + CHATRESULT_ROOM_WAITINGFORENTRY, + CHATRESULT_INBOXLIMITEXCEEDED, + CHATRESULT_DUPLICATEDESTINATION, + CHATRESULT_CATEGORYLIMITEXCEEDED, // 70 + CHATRESULT_MESSAGE_FILTER_FAILURE, + CHATRESULT_INVALID_INPUT, + + }; + + // Status for PersistentHeader objects as found in PersistentMessage.h + enum PersistentStatus + { + PERSISTENT_NEW = 1, + PERSISTENT_UNREAD, + PERSISTENT_READ, + PERSISTENT_TRASH, + PERSISTENT_DELETED + }; + + // Bit flags for persistent message alterations. These are used in RequestAlterPersistentMessage + enum PersistentAlterationTypes + { + ALTER_SENDER = 1, + ALTER_SUBJECT = 2, + ALTER_MSG = 4, + ALTER_OOB = 8, + ALTER_SENT_TIME = 16, + ALTER_CATEGORY = 32 + }; + + // Types of Snoop messages for OnReceiveSnoopMessage() callback in ChatAPI.h + enum SnoopTypes + { + SNOOP_INSTANTMESSAGE, + SNOOP_ROOMMESSAGE, + SNOOP_PERSISTENTMESSAGE, + SNOOP_END + }; + +#define CHATUNICODESTRING_COMP_OPER_DECL(__oper__) \ + inline bool operator __oper__(const ChatUnicodeString &src) const \ + { \ + return (m_wideString __oper__ src.m_wideString); \ + } + +#define string_data data() +#define string_length length() + + class ChatUnicodeString { + + private: + Plat_Unicode::String m_wideString; + Plat_Unicode::String getEmptyString(); + + std::string m_cString; + + // const unsigned short *string_data; + // unsigned string_length; + + public: + + ChatUnicodeString(); + ChatUnicodeString(const unsigned short *data, unsigned length); + ChatUnicodeString(const char *nData, unsigned length); + ChatUnicodeString(const Plat_Unicode::String& src); + ChatUnicodeString(const std::string& nSrc); + ChatUnicodeString(const char *nStrSrc); + ChatUnicodeString(const ChatUnicodeString& src); + + ChatUnicodeString& operator=(const std::string& nSrc); + ChatUnicodeString& operator=(const Plat_Unicode::String& src); + ChatUnicodeString& operator=(const char *nStrSrc); + ChatUnicodeString& operator=(const ChatUnicodeString& src); + + ChatUnicodeString& operator+=(const ChatUnicodeString& src); + ChatUnicodeString operator+(const ChatUnicodeString& src); + CHATUNICODESTRING_COMP_OPER_DECL(<) + CHATUNICODESTRING_COMP_OPER_DECL(<=) + CHATUNICODESTRING_COMP_OPER_DECL(==) + CHATUNICODESTRING_COMP_OPER_DECL(!=) + CHATUNICODESTRING_COMP_OPER_DECL(>=) + CHATUNICODESTRING_COMP_OPER_DECL(>) + inline unsigned length() const { return (unsigned)m_wideString.length(); } + inline const unsigned short * data() const { return m_wideString.data(); } + const char * c_str() const; + + }; + + + // class for OnGetSnoopList() callback to summarize a name/address pair + class AvatarSnoopPair + { + public: + AvatarSnoopPair(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ~AvatarSnoopPair() {} + + const ChatUnicodeString &getAvatarName() const { return m_name; } + const ChatUnicodeString &getAvatarAddress() const { return m_address; } + + private: + ChatUnicodeString m_name; + ChatUnicodeString m_address; + }; + +}; + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatus.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatus.h new file mode 100644 index 00000000..069d2705 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatus.h @@ -0,0 +1,34 @@ +#if !defined (CHATFRIENDSTATUS_H_) +#define CHATFRIENDSTATUS_H_ + +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + class ChatFriendStatusCore; + + class ChatFriendStatus + { + public: + ChatFriendStatus(); + ~ChatFriendStatus(); + const ChatUnicodeString &getName() const; + const ChatUnicodeString &getAddress() const; + const ChatUnicodeString &getComment() const; + short getStatus() const; // 0 = offline, else = online + + friend class ChatFriendStatusCore; + private: + ChatUnicodeString m_name; + ChatUnicodeString m_address; + ChatUnicodeString m_comment; + + ChatFriendStatusCore *m_core; + }; +}; + +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatusCore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatusCore.cpp new file mode 100644 index 00000000..c6eea945 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatusCore.cpp @@ -0,0 +1,63 @@ +#include "ChatFriendStatusCore.h" +#include "ChatFriendStatus.h" + +namespace ChatSystem +{ + +using namespace Base; +using namespace Plat_Unicode; +ChatFriendStatusCore::ChatFriendStatusCore() +: m_interface(NULL), + m_status(0) +{ +} + +void ChatFriendStatusCore::load(ByteStream::ReadIterator &iter, ChatFriendStatus *inf) +{ + m_interface = inf; + inf->m_core = this; + ASSERT_VALID_STRING_LENGTH(get(iter, m_name)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_address)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_comment)); + get(iter, m_status); + + m_interface->m_name = m_name; + m_interface->m_address = m_address; + m_interface->m_comment = m_comment; +} + +ChatFriendStatusCore::~ChatFriendStatusCore() +{ +} + +ChatFriendStatus::ChatFriendStatus() +: m_core(NULL) +{ +} + +ChatFriendStatus::~ChatFriendStatus() +{ +} + +const ChatUnicodeString &ChatFriendStatus::getName() const +{ + return m_name; +} + +const ChatUnicodeString &ChatFriendStatus::getAddress() const +{ + return m_address; +} + +const ChatUnicodeString &ChatFriendStatus::getComment() const +{ + return m_comment; +} + +short ChatFriendStatus::getStatus() const +{ + return m_core->getStatus(); +} + +}; + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatusCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatusCore.h new file mode 100644 index 00000000..841f80d0 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatFriendStatusCore.h @@ -0,0 +1,41 @@ +#if !defined (CHATFRIENDSTATUSCORE_H_) +#define CHATFRIENDSTATUSCORE_H_ + +#include +#include +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + + + class ChatFriendStatus; + + class ChatFriendStatusCore + { + public: + ChatFriendStatusCore(); + ~ChatFriendStatusCore(); + + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + short getStatus() const { return m_status; } + + void load(Base::ByteStream::ReadIterator &iter, ChatFriendStatus *inf); + + private: + ChatFriendStatus *m_interface; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_comment; + + short m_status; + }; + +}; + +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatus.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatus.h new file mode 100644 index 00000000..533319ed --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatus.h @@ -0,0 +1,29 @@ +#if !defined (CHATIGNORESTATUS_H_) +#define CHATIGNORESTATUS_H_ + +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + class ChatIgnoreStatusCore; + + class ChatIgnoreStatus + { + public: + ChatIgnoreStatus(); + ~ChatIgnoreStatus(); + const ChatUnicodeString &getName() const { return m_name; } + const ChatUnicodeString &getAddress() const { return m_address; } + + friend class ChatIgnoreStatusCore; + private: + ChatUnicodeString m_name; + ChatUnicodeString m_address; + + ChatIgnoreStatusCore *m_core; + }; +}; + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatusCore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatusCore.cpp new file mode 100644 index 00000000..06717992 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatusCore.cpp @@ -0,0 +1,37 @@ +#include "ChatIgnoreStatusCore.h" +#include "ChatIgnoreStatus.h" + +namespace ChatSystem +{ + using namespace Base; + using namespace Plat_Unicode; + + ChatIgnoreStatus::ChatIgnoreStatus() + : m_core(NULL) + { + } + + ChatIgnoreStatus::~ChatIgnoreStatus() + { + } + + ChatIgnoreStatusCore::ChatIgnoreStatusCore() + : m_interface(NULL) + { + } + + ChatIgnoreStatusCore::~ChatIgnoreStatusCore() + { + } + + void ChatIgnoreStatusCore::load(Base::ByteStream::ReadIterator &iter, ChatIgnoreStatus *inf) + { + m_interface = inf; + inf->m_core = this; + ASSERT_VALID_STRING_LENGTH(get(iter, m_name)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_address)); + + m_interface->m_name = m_name; + m_interface->m_address = m_address; + } +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatusCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatusCore.h new file mode 100644 index 00000000..2a41e39b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatIgnoreStatusCore.h @@ -0,0 +1,37 @@ +#if !defined (CHATIGNORESTATUSCORE_H_) +#define CHATIGNORESTATUSCORE_H_ + +#include +#include +#include + +#include "ChatEnum.h" + +namespace ChatSystem +{ + + + class ChatIgnoreStatus; + + class ChatIgnoreStatusCore + { + public: + ChatIgnoreStatusCore(); + ~ChatIgnoreStatusCore(); + + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + + void load(Base::ByteStream::ReadIterator &iter, ChatIgnoreStatus *inf); + + private: + ChatIgnoreStatus *m_interface; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + +}; + +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoom.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoom.cpp new file mode 100644 index 00000000..d022aafa --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoom.cpp @@ -0,0 +1,777 @@ +#include "ChatRoom.h" + +#include + +#include "AvatarIteratorCore.h" +#include "ChatRoomCore.h" +#include "ChatAvatar.h" +#include "ChatAvatarCore.h" +#include "RoomParamsCore.h" +#include "RoomSummaryCore.h" + +namespace ChatSystem +{ +using namespace Plat_Unicode; +using namespace std; + + +// AVATAR ITERATOR + +AvatarIterator::AvatarIterator() +{ + m_core = new AvatarIteratorCore(); +} + +AvatarIterator::AvatarIterator(const AvatarIteratorCore &core) +{ + m_core = new AvatarIteratorCore(); + + (*m_core) = core; +} + +AvatarIterator::~AvatarIterator() +{ + delete m_core; +} + +AvatarIterator &AvatarIterator::operator=(const AvatarIterator &rhs) +{ + (*m_core) = *(rhs.m_core); + + return (*this); +} + +void AvatarIterator::operator++() +{ + m_core->increment(); +} + +void AvatarIterator::operator++(int dummyForPostfix) +{ + m_core->increment(); +} + +void AvatarIterator::operator--() +{ + m_core->decrement(); +} + +void AvatarIterator::operator--(int dummyForPostfix) +{ + m_core->decrement(); +} + +ChatAvatar *AvatarIterator::operator*() +{ + return (m_core->getCurAvatar()); +} + +bool AvatarIterator::outOfBounds() +{ + return (m_core->outOfBounds()); +} + +// MODERATOR ITERATOR + +ModeratorIterator::ModeratorIterator() +{ + m_core = new ModeratorIteratorCore(); +} + +ModeratorIterator::ModeratorIterator(const ModeratorIteratorCore &core) +{ + m_core = new ModeratorIteratorCore(); + + (*m_core) = core; +} + +ModeratorIterator::~ModeratorIterator() +{ + delete m_core; +} + +ModeratorIterator &ModeratorIterator::operator=(const ModeratorIterator &rhs) +{ + (*m_core) = *(rhs.m_core); + + return (*this); +} + +void ModeratorIterator::operator++() +{ + m_core->increment(); +} + +void ModeratorIterator::operator++(int dummyForPostfix) +{ + m_core->increment(); +} + +void ModeratorIterator::operator--() +{ + m_core->decrement(); +} + +void ModeratorIterator::operator--(int dummyForPostfix) +{ + m_core->decrement(); +} +ChatAvatar *ModeratorIterator::operator*() +{ + return (m_core->getCurAvatar()); +} + +bool ModeratorIterator::outOfBounds() +{ + return (m_core->outOfBounds()); +} + +// TEMPORARY MODERATOR ITERATOR + +TemporaryModeratorIterator::TemporaryModeratorIterator() +{ + m_core = new TemporaryModeratorIteratorCore(); +} + +TemporaryModeratorIterator::TemporaryModeratorIterator(const TemporaryModeratorIteratorCore &core) +{ + m_core = new TemporaryModeratorIteratorCore(); + + (*m_core) = core; +} + +TemporaryModeratorIterator::~TemporaryModeratorIterator() +{ + delete m_core; +} + +TemporaryModeratorIterator &TemporaryModeratorIterator::operator=(const TemporaryModeratorIterator &rhs) +{ + (*m_core) = *(rhs.m_core); + + return (*this); +} + +void TemporaryModeratorIterator::operator++() +{ + m_core->increment(); +} + +void TemporaryModeratorIterator::operator++(int dummyForPostfix) +{ + m_core->increment(); +} + +void TemporaryModeratorIterator::operator--() +{ + m_core->decrement(); +} + +void TemporaryModeratorIterator::operator--(int dummyForPostfix) +{ + m_core->decrement(); +} +ChatAvatar *TemporaryModeratorIterator::operator*() +{ + return (m_core->getCurAvatar()); +} + +bool TemporaryModeratorIterator::outOfBounds() +{ + return (m_core->outOfBounds()); +} + +// VOICE ITERATOR + +VoiceIterator::VoiceIterator() +{ + m_core = new VoiceIteratorCore(); +} + +VoiceIterator::VoiceIterator(const VoiceIteratorCore &core) +{ + m_core = new VoiceIteratorCore(); + + (*m_core) = core; +} + +VoiceIterator::~VoiceIterator() +{ + delete m_core; +} + +VoiceIterator &VoiceIterator::operator=(const VoiceIterator &rhs) +{ + (*m_core) = *(rhs.m_core); + + return (*this); +} + +void VoiceIterator::operator++() +{ + m_core->increment(); +} + +void VoiceIterator::operator++(int dummyForPostfix) +{ + m_core->increment(); +} + +void VoiceIterator::operator--() +{ + m_core->decrement(); +} + +void VoiceIterator::operator--(int dummyForPostfix) +{ + m_core->decrement(); +} + +ChatAvatar *VoiceIterator::operator*() +{ + return (m_core->getCurAvatar()); +} + +bool VoiceIterator::outOfBounds() +{ + return (m_core->outOfBounds()); +} + +// INVITE ITERATOR + +InviteIterator::InviteIterator() +{ + m_core = new InviteIteratorCore(); +} + +InviteIterator::InviteIterator(const InviteIteratorCore &core) +{ + m_core = new InviteIteratorCore(); + + (*m_core) = core; +} + +InviteIterator::~InviteIterator() +{ + delete m_core; +} + +InviteIterator &InviteIterator::operator=(const InviteIterator &rhs) +{ + (*m_core) = *(rhs.m_core); + + return (*this); +} + +void InviteIterator::operator++() +{ + m_core->increment(); +} + +void InviteIterator::operator++(int dummyForPostfix) +{ + m_core->increment(); +} + +void InviteIterator::operator--() +{ + m_core->decrement(); +} + +void InviteIterator::operator--(int dummyForPostfix) +{ + m_core->decrement(); +} + +ChatAvatar *InviteIterator::operator*() +{ + return (m_core->getCurAvatar()); +} + +bool InviteIterator::outOfBounds() +{ + return (m_core->outOfBounds()); +} + +// BAN ITERATOR + +BanIterator::BanIterator() +{ + m_core = new BanIteratorCore(); +} + +BanIterator::BanIterator(const BanIteratorCore &core) +{ + m_core = new BanIteratorCore(); + + (*m_core) = core; +} + +BanIterator::~BanIterator() +{ + delete m_core; +} + +BanIterator &BanIterator::operator=(const BanIterator &rhs) +{ + (*m_core) = *(rhs.m_core); + + return (*this); +} + +void BanIterator::operator++() +{ + m_core->increment(); +} + +void BanIterator::operator++(int dummyForPostfix) +{ + m_core->increment(); +} + +void BanIterator::operator--() +{ + m_core->decrement(); +} + +void BanIterator::operator--(int dummyForPostfix) +{ + m_core->decrement(); +} + +ChatAvatar *BanIterator::operator*() +{ + return (m_core->getCurAvatar()); +} + +bool BanIterator::outOfBounds() +{ + return (m_core->outOfBounds()); +} + + +// ROOM PARAMS + +RoomParams::RoomParams() +{ + m_core = new struct RoomParamsCore; + m_core->m_attributes = 0; + m_core->m_size = 0; +} + + +RoomParams::RoomParams(const ChatUnicodeString &name, const ChatUnicodeString &topic, unsigned attributes, unsigned maxSize) +{ + m_core = new struct RoomParamsCore; + + m_core->m_name.assign(name.string_data, name.string_length); + m_cName = m_core->m_name; + + m_core->m_topic.assign(topic.string_data, topic.string_length); + m_cTopic = m_core->m_topic; + + m_cPassword = m_core->m_password; + + m_core->m_attributes = attributes; + m_core->m_size = maxSize; +} + +RoomParams::RoomParams(const ChatUnicodeString &name, const ChatUnicodeString &topic, const ChatUnicodeString &password, unsigned attributes, unsigned maxSize) +{ + m_core = new struct RoomParamsCore; + + m_core->m_name.assign(name.string_data, name.string_length); + m_cName = m_core->m_name; + + m_core->m_topic.assign(topic.string_data, topic.string_length); + m_cTopic = m_core->m_topic; + + m_core->m_password.assign(password.string_data, password.string_length); + m_cPassword = m_core->m_password; + + m_core->m_attributes = attributes; + m_core->m_size = maxSize; +} + +RoomParams::RoomParams(const RoomParams &orig) : m_core(new struct RoomParamsCore) +{ + this->setRoomName(orig.getRoomName()); + this->setRoomTopic(orig.getRoomTopic()); + this->setRoomPassword(orig.getRoomPassword()); + this->setRoomAttributes(orig.getRoomAttributes()); + this->setRoomMaxSize(orig.getRoomMaxSize()); +} + +RoomParams::~RoomParams() +{ + delete m_core; +} + +RoomParams &RoomParams::operator=(const RoomParams &rhs) +{ + this->setRoomName(rhs.getRoomName()); + this->setRoomTopic(rhs.getRoomTopic()); + this->setRoomPassword(rhs.getRoomPassword()); + this->setRoomAttributes(rhs.getRoomAttributes()); + this->setRoomMaxSize(rhs.getRoomMaxSize()); + + return (*this); +} + +void RoomParams::setRoomName(const ChatUnicodeString &name) +{ + m_core->m_name.assign(name.string_data, name.string_length); + m_cName = m_core->m_name; +} + +void RoomParams::setRoomTopic(const ChatUnicodeString &topic) +{ + m_core->m_topic.assign(topic.string_data, topic.string_length); + m_cTopic = m_core->m_topic; +} + +void RoomParams::setRoomPassword(const ChatUnicodeString &password) +{ + m_core->m_password.assign(password.string_data, password.string_length); + m_cPassword = m_core->m_password; +} + +void RoomParams::setRoomAttributes(unsigned attributes) +{ + m_core->m_attributes = attributes; +} + +void RoomParams::setRoomMaxSize(unsigned size) +{ + m_core->m_size = size; +} + +const ChatUnicodeString &RoomParams::getRoomName() const +{ + m_cName = m_core->m_name; + return (m_cName); +} + +const ChatUnicodeString &RoomParams::getRoomTopic() const +{ + m_cTopic = m_core->m_topic; + return (m_cTopic); +} + +const ChatUnicodeString &RoomParams::getRoomPassword() const +{ + m_cPassword = m_core->m_password; + return (m_cPassword); +} + +unsigned RoomParams::getRoomAttributes() const +{ + return (m_core->m_attributes); +} + +unsigned RoomParams::getRoomMaxSize() const +{ + return (m_core->m_size); +} + +// ROOM SUMMARY + +RoomSummary::RoomSummary() +{ + m_core = new struct RoomSummaryCore; + m_core->m_attributes = 0; + m_core->m_curSize = 0; + m_core->m_maxSize = 0; +} + +RoomSummary::RoomSummary(const ChatUnicodeString &address, const ChatUnicodeString &topic, unsigned attributes, unsigned curSize, unsigned maxSize) +{ + m_core = new struct RoomSummaryCore; + + m_core->m_address.assign(address.string_data, address.string_length); + m_cAddress = m_core->m_address; + + m_core->m_topic.assign(address.string_data, address.string_length); + m_cTopic = m_core->m_address; + + m_core->m_attributes = attributes; + m_core->m_curSize = curSize; + m_core->m_maxSize = maxSize; +} + +RoomSummary::~RoomSummary() +{ + delete m_core; +} + +RoomSummary &RoomSummary::operator=(const RoomSummary &rhs) +{ + this->setRoomAddress(rhs.getRoomAddress()); + m_cAddress= m_core->m_address; + + this->setRoomTopic(rhs.getRoomTopic()); + m_cTopic = m_core->m_address; + + this->setRoomAttributes(rhs.getRoomAttributes()); + this->setRoomCurSize(rhs.getRoomCurSize()); + this->setRoomMaxSize(rhs.getRoomMaxSize()); + + return (*this); +} + +void RoomSummary::setRoomAddress(const ChatUnicodeString &address) +{ + m_core->m_address.assign(address.string_data, address.string_length); + m_cAddress = m_core->m_address; + +} + +void RoomSummary::setRoomTopic(const ChatUnicodeString &topic) +{ + m_core->m_topic.assign(topic.string_data, topic.string_length); + m_cTopic = m_core->m_address; +} + +void RoomSummary::setRoomAttributes(unsigned attributes) +{ + m_core->m_attributes = attributes; +} + +void RoomSummary::setRoomCurSize(unsigned curSize) +{ + m_core->m_curSize = curSize; +} + +void RoomSummary::setRoomMaxSize(unsigned maxSize) +{ + m_core->m_maxSize = maxSize; +} + +const ChatUnicodeString &RoomSummary::getRoomAddress() const +{ + m_cAddress = m_core->m_address; + + return (m_cAddress); +} + +const ChatUnicodeString &RoomSummary::getRoomTopic() const +{ + m_cTopic = m_core->m_topic; + + return (m_cTopic); +} + +unsigned RoomSummary::getRoomAttributes() const +{ + return (m_core->m_attributes); +} + +unsigned RoomSummary::getRoomCurSize() const +{ + return (m_core->m_curSize); +} + +unsigned RoomSummary::getRoomMaxSize() const +{ + return (m_core->m_maxSize); +} + + +// CHAT ROOM + +ChatRoom::ChatRoom() +{ + m_core = NULL; +} + +ChatRoom::ChatRoom(ChatRoomCore *core) +: m_core(core) +{ +} + +ChatRoom::~ChatRoom() +{ +} + +const ChatUnicodeString &ChatRoom::getCreatorName() const +{ + m_cCreatorName = m_core->getCreatorName(); + + return (m_cCreatorName); +} + +const ChatUnicodeString &ChatRoom::getCreatorAddress() const +{ + m_cCreatorAddress = m_core->getCreatorAddress(); + + return (m_cCreatorAddress); +} + +unsigned ChatRoom::getCreatorID() const +{ + return (m_core->getCreatorID()); +} + +unsigned ChatRoom::getRoomID() const +{ + return (m_core->getRoomID()); +} + +const ChatUnicodeString &ChatRoom::getRoomName() const +{ + m_cRoomName = m_core->getRoomName(); + + return(m_cRoomName); +} + +const ChatUnicodeString &ChatRoom::getRoomTopic() const +{ + m_cRoomTopic = m_core->getRoomTopic(); + + return(m_cRoomTopic); +} + +const ChatUnicodeString &ChatRoom::getRoomPassword() const +{ + m_cRoomPassword = m_core->getRoomPassword(); + + return(m_cRoomPassword); +} + +unsigned ChatRoom::getRoomAttributes() const +{ + return (m_core->getRoomAttributes()); +} + +unsigned ChatRoom::getMaxRoomSize() const +{ + return (m_core->getMaxRoomSize()); +} + +const ChatUnicodeString &ChatRoom::getAddress() const +{ + m_cRoomAddress = m_core->getAddress(); + + return (m_cRoomAddress); +} + +unsigned ChatRoom::getAvatarCount() const +{ + return (m_core->getAvatarCount()); +} + +unsigned ChatRoom::getBanCount() const +{ + return (m_core->getBanCount()); +} + +unsigned ChatRoom::getInviteCount() const +{ + return (m_core->getInviteCount()); +} + +unsigned ChatRoom::getModeratorCount() const +{ + return (m_core->getModeratorCount()); +} + +unsigned ChatRoom::getTemporaryModeratorCount() const +{ + return (m_core->getTemporaryModeratorCount()); +} + +unsigned ChatRoom::getVoiceCount() const +{ + return (m_core->getVoiceCount()); +} + +AvatarIterator ChatRoom::getFirstAvatar() const +{ + return (AvatarIterator(m_core->getFirstAvatar())); +} + +AvatarIterator ChatRoom::findAvatar(unsigned avatarID) const +{ + return (AvatarIterator(m_core->findAvatar(avatarID))); +} + +AvatarIterator ChatRoom::findAvatar(const ChatUnicodeString &name, const ChatUnicodeString &address) const +{ + String uni_name(name.string_data, name.string_length); + String uni_addr(address.string_data, address.string_length); + + return (AvatarIterator(m_core->findAvatar(uni_name, uni_addr))); +} + +ModeratorIterator ChatRoom::getFirstModerator() const +{ + return (ModeratorIterator(m_core->getFirstModerator())); +} + +ModeratorIterator ChatRoom::findModerator(const ChatUnicodeString &name, const ChatUnicodeString &address) const +{ + String uni_name(name.string_data, name.string_length); + String uni_addr(address.string_data, address.string_length); + + return (ModeratorIterator(m_core->findModerator(uni_name, uni_addr))); +} + +TemporaryModeratorIterator ChatRoom::getFirstTemporaryModerator() const +{ + return (TemporaryModeratorIterator(m_core->getFirstTemporaryModerator())); +} + +TemporaryModeratorIterator ChatRoom::findTemporaryModerator(const ChatUnicodeString &name, const ChatUnicodeString &address) const +{ + String uni_name(name.string_data, name.string_length); + String uni_addr(address.string_data, address.string_length); + + return (TemporaryModeratorIterator(m_core->findTemporaryModerator(uni_name, uni_addr))); +} + +BanIterator ChatRoom::getFirstBanned() const +{ + return (BanIterator(m_core->getFirstBanned())); +} + +BanIterator ChatRoom::findBanned(const ChatUnicodeString &name, const ChatUnicodeString &address) const +{ + String uni_name(name.string_data, name.string_length); + String uni_addr(address.string_data, address.string_length); + + return (BanIterator(m_core->findBanned(uni_name, uni_addr))); +} + +InviteIterator ChatRoom::getFirstInvited() const +{ + return (InviteIterator(m_core->getFirstInvited())); +} + +InviteIterator ChatRoom::findInvited(const ChatUnicodeString &name, const ChatUnicodeString &address) const +{ + String uni_name(name.string_data, name.string_length); + String uni_addr(address.string_data, address.string_length); + + return (InviteIterator(m_core->findInvited(uni_name, uni_addr))); +} + +VoiceIterator ChatRoom::getFirstVoice() const +{ + return (VoiceIterator(m_core->getFirstVoice())); +} + +VoiceIterator ChatRoom::findVoice(const ChatUnicodeString &name, const ChatUnicodeString &address) const +{ + String uni_name(name.string_data, name.string_length); + String uni_addr(address.string_data, address.string_length); + + return (VoiceIterator(m_core->findVoice(uni_name, uni_addr))); +} + +void ChatRoom::setRoomMessageID(unsigned roomMessageID) +{ + m_core->setRoomMessageID(roomMessageID); +} + +}; + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoom.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoom.h new file mode 100644 index 00000000..c1c6de1b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoom.h @@ -0,0 +1,422 @@ +#if !defined (CHATROOM_H_) +#define CHATROOM_H_ + +#pragma warning (disable : 4786) +#pragma warning (disable : 4620) + +#include "ChatEnum.h" + +namespace ChatSystem +{ + + + class ChatAvatar; + class ChatRoomCore; + class AvatarIteratorCore; + class ModeratorIteratorCore; + class TemporaryModeratorIteratorCore; + class VoiceIteratorCore; + class InviteIteratorCore; + class BanIteratorCore; + struct RoomParamsCore; + struct RoomSummaryCore; + + + // Room attribute test macros + // example: IS_SET(myRoomAttributes, ROOMATTR_PERSISTENT) + inline unsigned IS_SET(unsigned var, unsigned bit) + { + return (var & bit); + } + + inline unsigned SET_BIT(unsigned &var, unsigned bit) + { + var |= bit; + return(var); + } + + inline unsigned REMOVE_BIT(unsigned &var, unsigned bit) + { + var &= ~bit; + return(var); + } + + enum RoomAttributes + { + ROOMATTR_PRIVATE = 1<<0, + ROOMATTR_MODERATED = 1<<1, + ROOMATTR_PERSISTENT = 1<<2, + ROOMATTR_LOCAL_WORLD = 1<<4, + ROOMATTR_LOCAL_GAME = 1<<5 + }; + + + // class RoomParams + // + // Description: + // This class stores the basic room parameters for creating a room. + // + // Usage: + // A RoomParams object is required for creating a room. + // It can be copied and there are get__ and set__ methods for retrieving + // and storing values. + // + class RoomParams + { + public: + RoomParams(); + RoomParams(const ChatUnicodeString &name, const ChatUnicodeString &topic, unsigned attributes, unsigned maxSize); + RoomParams(const ChatUnicodeString &name, const ChatUnicodeString &topic, const ChatUnicodeString &password, unsigned attributes, unsigned maxSize); + RoomParams(const RoomParams &orig); + ~RoomParams(); + + RoomParams & operator=(const RoomParams &rhs); + + void setRoomName(const ChatUnicodeString &name); + void setRoomTopic(const ChatUnicodeString &topic); + void setRoomPassword(const ChatUnicodeString &name); + void setRoomAttributes(unsigned attributes); + void setRoomMaxSize(unsigned size); + + const ChatUnicodeString &getRoomName() const; + const ChatUnicodeString &getRoomTopic() const; + const ChatUnicodeString &getRoomPassword() const; + unsigned getRoomAttributes() const; + unsigned getRoomMaxSize() const; + + private: + RoomParamsCore *m_core; + mutable ChatUnicodeString m_cName; + mutable ChatUnicodeString m_cTopic; + mutable ChatUnicodeString m_cPassword; + }; + + + // class RoomSummary + // + // Description: + // This class stores the basic room parameters to describe a room. + // It is useful for describing a room with less byte resources than + // a full ChatRoom. + // + // Usage: + // A RoomSummary object is passed through OnGetRoomSummaries(). + // It can be copied and there are get__ and set__ methods for retrieving + // and storing values. + // + class RoomSummary + { + public: + RoomSummary(); + RoomSummary(const ChatUnicodeString &name, const ChatUnicodeString &topic, unsigned attributes, unsigned curSize, unsigned maxSize); + ~RoomSummary(); + + RoomSummary & operator=(const RoomSummary &rhs); + + void setRoomAddress(const ChatUnicodeString &address); + void setRoomTopic(const ChatUnicodeString &topic); + void setRoomAttributes(unsigned attributes); + void setRoomCurSize(unsigned curSize); + void setRoomMaxSize(unsigned maxSize); + + const ChatUnicodeString &getRoomAddress() const; + const ChatUnicodeString &getRoomTopic() const; + unsigned getRoomAttributes() const; + unsigned getRoomCurSize() const; + unsigned getRoomMaxSize() const; + + private: + RoomSummaryCore *m_core; + mutable ChatUnicodeString m_cAddress; + mutable ChatUnicodeString m_cTopic; + + }; + + + // class AvatarIterator + // + // Description: + // This class implements an iterator for the ChatRoom avatar container. + // + // Usage: + // An AvatarIterator will originate from getFirstAvatar() or findAvatar(). + // It can be copied, incremented, decremented, and dereferenced to get the + // ChatAvatar* it points to. To check the validity of the iterator while + // iterating to know whether the end of the container has been reached, + // use outOfBounds() method. + // example: + // AvatarIterator iter; + // for (iter = room->getFirstAvatar(); iter.outOfBounds() == false; iter++) + // { + // ChatAvatar *avatar = (*iter); + // // do stuff with avatar info + // } + // + class AvatarIterator + { + public: + AvatarIterator(); + AvatarIterator(const AvatarIteratorCore &core); + ~AvatarIterator(); + + AvatarIterator & operator=(const AvatarIterator &rhs); + + // Bi-directional container navigation + void operator++(); + void operator++(int dummyForPostfix); + void operator--(); + void operator--(int dummyForPostfix); + + // Dereference to ChatAvatar* value + ChatAvatar * operator*(); + + // Test movement past beginning or end of container + bool outOfBounds(); + + private: + AvatarIteratorCore *m_core; + }; + + // class ModeratorIterator + // + // Description: + // This class implements an iterator for the ChatRoom moderator container. + // + // Usage: + // A ModeratorIterator will originate from getFirstModerator() or findModerator(). + // Same as AvatarIterator usage. + // + class ModeratorIterator + { + public: + ModeratorIterator(); + ModeratorIterator(const ModeratorIteratorCore &core); + ~ModeratorIterator(); + + ModeratorIterator & operator=(const ModeratorIterator &rhs); + + // Bi-directional container navigation + void operator++(); + void operator++(int dummyForPostfix); + void operator--(); + void operator--(int dummyForPostfix); + + // Dereference to ChatAvatar* value + ChatAvatar * operator*(); + + // Test movement past beginning or end of container + bool outOfBounds(); + + private: + ModeratorIteratorCore *m_core; + }; + + // class TemporaryModeratorIterator + // + // Description: + // This class implements an iterator for the ChatRoom temporary moderator container. + // + // Usage: + // A TemporaryModeratorIterator will originate from getFirstModerator() or findModerator(). + // Same as AvatarIterator usage. + // + class TemporaryModeratorIterator + { + public: + TemporaryModeratorIterator(); + TemporaryModeratorIterator(const TemporaryModeratorIteratorCore &core); + ~TemporaryModeratorIterator(); + + TemporaryModeratorIterator & operator=(const TemporaryModeratorIterator &rhs); + + // Bi-directional container navigation + void operator++(); + void operator++(int dummyForPostfix); + void operator--(); + void operator--(int dummyForPostfix); + + // Dereference to ChatAvatar* value + ChatAvatar * operator*(); + + // Test movement past beginning or end of container + bool outOfBounds(); + + private: + TemporaryModeratorIteratorCore *m_core; + }; + + // class VoiceIterator + // + // Description: + // This class implements an iterator for the ChatRoom Voice container. + // + // Usage: + // An VoiceIterator will originate from getFirstVoice() or findVoice(). + // Same as AvatarIterator usage. + // + class VoiceIterator + { + public: + VoiceIterator(); + VoiceIterator(const VoiceIteratorCore &core); + ~VoiceIterator(); + + VoiceIterator & operator=(const VoiceIterator &rhs); + + // Bi-directional container navigation + void operator++(); + void operator++(int dummyForPostfix); + void operator--(); + void operator--(int dummyForPostfix); + + // Dereference to ChatAvatar* value + ChatAvatar * operator*(); + + // Test movement past beginning or end of container + bool outOfBounds(); + + private: + VoiceIteratorCore *m_core; + }; + + // class InviteIterator + // + // Description: + // This class implements an iterator for the ChatRoom invite container. + // + // Usage: + // An InviteIterator will originate from getFirstInvite() or findInvite(). + // Same as AvatarIterator usage. + // + class InviteIterator + { + public: + InviteIterator(); + InviteIterator(const InviteIteratorCore &core); + ~InviteIterator(); + + InviteIterator & operator=(const InviteIterator &rhs); + + // Bi-directional container navigation + void operator++(); + void operator++(int dummyForPostfix); + void operator--(); + void operator--(int dummyForPostfix); + + // Dereference to ChatAvatar* value + ChatAvatar * operator*(); + + // Test movement past beginning or end of container + bool outOfBounds(); + + private: + InviteIteratorCore *m_core; + }; + + // class BanIterator + // + // Description: + // This class implements an iterator for the ChatRoom ban container. + // + // Usage: + // A BanIterator will originate from getFirstBan() or findBan(). + // Same as AvatarIterator usage. + // + class BanIterator + { + public: + BanIterator(); + BanIterator(const BanIteratorCore &core); + ~BanIterator(); + + BanIterator & operator=(const BanIterator &rhs); + + // Bi-directional container navigation + void operator++(); + void operator++(int dummyForPostfix); + void operator--(); + void operator--(int dummyForPostfix); + + // Dereference to ChatAvatar* value + ChatAvatar * operator*(); + + // Test movement past beginning or end of container + bool outOfBounds(); + + private: + BanIteratorCore *m_core; + }; + + // class ChatRoom + // + // Description: + // This class stores the information about a room in the ChatSystem that + // is relevant to the API. + // + // Usage: + // A ChatRoom will originate from an API callback method. + // The ChatRoom object cannot be copied however all of its member data can + // be retrived either by get__ methods or iterator methods (see comments + // for AvatarIterator class). + // + class ChatRoom + { + public: + ChatRoom(); + ChatRoom(ChatRoomCore *core); + ~ChatRoom(); + + const ChatUnicodeString &getCreatorName() const; + const ChatUnicodeString &getCreatorAddress() const; + unsigned getCreatorID() const; + + unsigned getRoomID() const; + const ChatUnicodeString &getRoomName() const; + const ChatUnicodeString &getRoomTopic() const; + const ChatUnicodeString &getRoomPassword() const; + unsigned getRoomAttributes() const; + unsigned getMaxRoomSize() const; + const ChatUnicodeString &getAddress() const; + + unsigned getAvatarCount() const; + unsigned getBanCount() const; + unsigned getInviteCount() const; + unsigned getModeratorCount() const; + unsigned getTemporaryModeratorCount() const; + unsigned getVoiceCount() const; + + AvatarIterator getFirstAvatar() const; + AvatarIterator findAvatar(unsigned avatarID) const; + AvatarIterator findAvatar(const ChatUnicodeString &name, const ChatUnicodeString &address) const; + + ModeratorIterator getFirstModerator() const; + ModeratorIterator findModerator(const ChatUnicodeString &name, const ChatUnicodeString &address) const; + + TemporaryModeratorIterator getFirstTemporaryModerator() const; + TemporaryModeratorIterator findTemporaryModerator(const ChatUnicodeString &name, const ChatUnicodeString &address) const; + + BanIterator getFirstBanned() const; + BanIterator findBanned(const ChatUnicodeString &name, const ChatUnicodeString &address) const; + + InviteIterator getFirstInvited() const; + InviteIterator findInvited(const ChatUnicodeString &name, const ChatUnicodeString &address) const; + + VoiceIterator getFirstVoice() const; + VoiceIterator findVoice(const ChatUnicodeString &name, const ChatUnicodeString &address) const; + + void setRoomMessageID(unsigned roomMessageID); + + private: + ChatRoomCore *m_core; + mutable ChatUnicodeString m_cCreatorAddress; + mutable ChatUnicodeString m_cCreatorName; + mutable ChatUnicodeString m_cRoomName; + mutable ChatUnicodeString m_cRoomTopic; + mutable ChatUnicodeString m_cRoomPassword; + mutable ChatUnicodeString m_cRoomAddress; + }; + +}; + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoomCore.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoomCore.cpp new file mode 100644 index 00000000..e4f32283 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoomCore.cpp @@ -0,0 +1,1143 @@ +#include "ChatRoomCore.h" +#include "ChatAvatar.h" +#include "ChatAvatarCore.h" +#include "AvatarIteratorCore.h" + +namespace ChatSystem +{ + +using namespace std; +using namespace Base; +using namespace Plat_Unicode; + +ChatRoomCore::ChatRoomCore() +: m_creatorID(0), + m_roomAttributes(0), + m_maxRoomSize(0), + m_roomID(0), + m_createTime(0), + m_nodeLevel(0) +{ +} + +ChatRoomCore::ChatRoomCore(ByteStream::ReadIterator &iter) +{ + unsigned avatarCount; + unsigned administratorCount; + unsigned moderatorCount; + unsigned tempModeratorCount; + unsigned bannedCount; + unsigned invitedCount; + unsigned voiceCount; + ChatAvatarCore *avatar; + unsigned i; + + ASSERT_VALID_STRING_LENGTH(get(iter, m_creatorName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_creatorAddress)); + get(iter, m_creatorID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomTopic)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomPrefix)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomPassword)); + get(iter, m_roomAttributes); + get(iter, m_maxRoomSize); + get(iter, m_roomID); + get(iter, m_createTime); + get(iter, m_nodeLevel); + + get(iter, avatarCount); + for (i = 0; i != avatarCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addAvatar(avatar, false); + } + + get(iter, administratorCount); + for (i = 0; i != administratorCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addAdministrator(avatar); + } + + get(iter, moderatorCount); + for (i = 0; i != moderatorCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addModerator(avatar); + } + + get(iter, tempModeratorCount); + for (i = 0; i != tempModeratorCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addTempModerator(avatar); + } + + get(iter, bannedCount); + for (i = 0; i != bannedCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addBan(avatar); + } + + get(iter, invitedCount); + for (i = 0; i != invitedCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addInvite(avatar); + } + + get(iter, voiceCount); + for (i = 0; i != voiceCount; i++) + { + avatar = new ChatAvatarCore(iter); + this->addVoice(avatar); + } +} + +ChatRoomCore::ChatRoomCore(const String &name, const String &address, const String &topic, const unsigned attributes, const unsigned maxSize) +: m_roomName(name), + m_roomTopic(topic), + m_roomAddress(address), + m_creatorID(0), + m_roomAttributes(attributes), + m_maxRoomSize(maxSize), + m_roomID(0) +{ +} + +ChatRoomCore::~ChatRoomCore() +{ + map::iterator iterCore; + map::iterator iter; + + set::iterator setIterCore; + set::iterator setIter; + + for (iterCore = m_inroomAvatarsCore.begin(); iterCore != m_inroomAvatarsCore.end(); iterCore++) + { + delete (iterCore->second); + } + + for (iter = m_inroomAvatars.begin(); iter != m_inroomAvatars.end(); iter++) + { + delete (iter->second); + } + + for (iterCore = m_adminAvatarsCore.begin(); iterCore != m_adminAvatarsCore.end(); iterCore++) + { + delete (iterCore->second); + } + + for (iter = m_adminAvatars.begin(); iter != m_adminAvatars.end(); iter++) + { + delete (iter->second); + } + + for (setIterCore = m_moderatorAvatarsCore.begin(); setIterCore != m_moderatorAvatarsCore.end(); setIterCore++) + { + delete (*setIterCore); + } + + for (setIter = m_moderatorAvatars.begin(); setIter != m_moderatorAvatars.end(); setIter++) + { + delete (*setIter); + } + + for (setIterCore = m_tempModeratorAvatarsCore.begin(); setIterCore != m_tempModeratorAvatarsCore.end(); setIterCore++) + { + delete (*setIterCore); + } + + for (setIter = m_tempModeratorAvatars.begin(); setIter != m_tempModeratorAvatars.end(); setIter++) + { + delete (*setIter); + } + + for (setIterCore = m_banAvatarsCore.begin(); setIterCore != m_banAvatarsCore.end(); setIterCore++) + { + delete (*setIterCore); + } + + for (setIter = m_banAvatars.begin(); setIter != m_banAvatars.end(); setIter++) + { + delete (*setIter); + } + + for (setIterCore = m_inviteAvatarsCore.begin(); setIterCore != m_inviteAvatarsCore.end(); setIterCore++) + { + delete (*setIterCore); + } + + for (setIter = m_inviteAvatars.begin(); setIter != m_inviteAvatars.end(); setIter++) + { + delete (*setIter); + } + + for (setIterCore = m_voiceAvatarsCore.begin(); setIterCore != m_voiceAvatarsCore.end(); setIterCore++) + { + delete (*setIterCore); + } + + for (setIter = m_voiceAvatars.begin(); setIter != m_voiceAvatars.end(); setIter++) + { + delete (*setIter); + } + +} + +ChatAvatarCore *ChatRoomCore::getAvatarCore(unsigned avatarID) +{ + ChatAvatarCore *returnAvatar = NULL; + + map::iterator iterCore = m_inroomAvatarsCore.find(avatarID); + + if(iterCore != m_inroomAvatarsCore.end()) + { + returnAvatar = (*iterCore).second; + } + return(returnAvatar); +} + +ChatAvatar *ChatRoomCore::getAvatar(unsigned avatarID) +{ + ChatAvatar *returnAvatar = NULL; + + map::iterator iter = m_inroomAvatars.find(avatarID); + + if(iter != m_inroomAvatars.end()) + { + returnAvatar = (*iter).second; + } + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::getModeratorCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_moderatorAvatarsCore.begin(); + + for(; iterCore != m_moderatorAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_moderatorAvatarsCore.end()) + { + returnAvatar = (*iterCore); + } + return(returnAvatar); +} + +ChatAvatar *ChatRoomCore::getModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatar *returnAvatar = NULL; + + set::iterator iter = m_moderatorAvatars.begin(); + + for(; iter != m_moderatorAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_moderatorAvatars.end()) + { + returnAvatar = (*iter); + } + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::getBannedCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_banAvatarsCore.begin(); + + for(; iterCore != m_banAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_banAvatarsCore.end()) + { + returnAvatar = (*iterCore); + } + return(returnAvatar); +} + +ChatAvatar *ChatRoomCore::getBanned(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatar *returnAvatar = NULL; + + set::iterator iter = m_banAvatars.begin(); + + for(; iter != m_banAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_banAvatars.end()) + { + returnAvatar = (*iter); + } + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::getInvitedCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_inviteAvatarsCore.begin(); + + for(; iterCore != m_inviteAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_inviteAvatarsCore.end()) + { + returnAvatar = (*iterCore); + } + return(returnAvatar); +} + +ChatAvatar *ChatRoomCore::getInvited(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatar *returnAvatar = NULL; + + set::iterator iter = m_inviteAvatars.begin(); + + for(; iter != m_inviteAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_inviteAvatars.end()) + { + returnAvatar = (*iter); + } + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addAvatar(ChatAvatarCore *newAvatar, bool local) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< map::iterator, bool > result; + + result = m_inroomAvatarsCore.insert(pair(newAvatar->getAvatarID(), newAvatar)); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_inroomAvatars.insert(pair(avatar->getAvatarID(), avatar)); + + // keep track of avatars connected to this API that are in room + if (local) + { + m_inroomAvatarsLocal.insert(newAvatar->getAvatarID()); + } + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +void ChatRoomCore::addLocalAvatar(unsigned avatarID) +{ + m_inroomAvatarsLocal.insert(avatarID); +} + +ChatAvatarCore *ChatRoomCore::removeAvatar(unsigned avatarID) +{ + ChatAvatarCore *returnAvatar = NULL; + + map::iterator iterCore = m_inroomAvatarsCore.find(avatarID); + + if(iterCore != m_inroomAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore).second; + + m_inroomAvatarsCore.erase(iterCore); + + // because the addAvatar() made the ChatAvatar, removeAvatar() deletes it. + map::iterator iter = m_inroomAvatars.find(avatarID); + delete (*iter).second; + m_inroomAvatars.erase(avatarID); + + // remove from cache of local API avatars logged into this room, if nec. + std::set::iterator localIter = m_inroomAvatarsLocal.find(avatarID); + if (localIter != m_inroomAvatarsLocal.end()) + m_inroomAvatarsLocal.erase(localIter); + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addBan(ChatAvatarCore *newAvatar) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< set::iterator, bool > result; + + result = m_banAvatarsCore.insert(newAvatar); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_banAvatars.insert(avatar); + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +ChatAvatarCore *ChatRoomCore::removeBan(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_banAvatarsCore.begin(); + + for(; iterCore != m_banAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_banAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore); + m_banAvatarsCore.erase(iterCore); + + // because the addBan() made the ChatAvatar, removeBan() deletes it. + set::iterator iter = m_banAvatars.begin(); + + for(; iter != m_banAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_banAvatars.end()) + { + delete (*iter); + m_banAvatars.erase(iter); + } + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addAdministrator(ChatAvatarCore *newAvatar) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< map::iterator, bool > result; + + result = this->m_adminAvatarsCore.insert(pair(newAvatar->getAvatarID(), newAvatar)); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_adminAvatars.insert(pair(avatar->getAvatarID(), avatar)); + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +ChatAvatarCore *ChatRoomCore::removeAdministrator(unsigned avatarID) +{ + ChatAvatarCore *returnAvatar = NULL; + + map::iterator iterCore = m_adminAvatarsCore.find(avatarID); + + if(iterCore != m_adminAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore).second; + + m_adminAvatarsCore.erase(iterCore); + + // because the addAvatar() made the ChatAvatar, removeAvatar() deletes it. + map::iterator iter = m_adminAvatars.find(avatarID); + delete (*iter).second; + m_adminAvatars.erase(avatarID); + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addModerator(ChatAvatarCore *newAvatar) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< set::iterator, bool > result; + + result = this->m_moderatorAvatarsCore.insert(newAvatar); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_moderatorAvatars.insert(avatar); + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +ChatAvatarCore *ChatRoomCore::removeModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_moderatorAvatarsCore.begin(); + + for(; iterCore != m_moderatorAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_moderatorAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore); + m_moderatorAvatarsCore.erase(iterCore); + + // because the addBan() made the ChatAvatar, removeBan() deletes it. + set::iterator iter = m_moderatorAvatars.begin(); + + for(; iter != m_moderatorAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_moderatorAvatars.end()) + { + delete (*iter); + m_moderatorAvatars.erase(iter); + } + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addTempModerator(ChatAvatarCore *newAvatar) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< set::iterator, bool > result; + + result = this->m_tempModeratorAvatarsCore.insert(newAvatar); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_tempModeratorAvatars.insert(avatar); + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +ChatAvatarCore *ChatRoomCore::removeTempModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_tempModeratorAvatarsCore.begin(); + + for(; iterCore != m_tempModeratorAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_tempModeratorAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore); + m_tempModeratorAvatarsCore.erase(iterCore); + + // because the addBan() made the ChatAvatar, removeBan() deletes it. + set::iterator iter = m_tempModeratorAvatars.begin(); + + for(; iter != m_tempModeratorAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_tempModeratorAvatars.end()) + { + delete (*iter); + m_tempModeratorAvatars.erase(iter); + } + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addInvite(ChatAvatarCore* newAvatar) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< set::iterator, bool > result; + + result = m_inviteAvatarsCore.insert(newAvatar); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_inviteAvatars.insert(avatar); + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +ChatAvatarCore *ChatRoomCore::removeInvite(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_inviteAvatarsCore.begin(); + + for(; iterCore != m_inviteAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_inviteAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore); + m_inviteAvatarsCore.erase(iterCore); + + // because the addBan() made the ChatAvatar, removeBan() deletes it. + set::iterator iter = m_inviteAvatars.begin(); + + for(; iter != m_inviteAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_inviteAvatars.end()) + { + delete (*iter); + m_inviteAvatars.erase(iter); + } + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +ChatAvatarCore *ChatRoomCore::addVoice(ChatAvatarCore* newAvatar) +{ + ChatAvatarCore *returnAvatar = NULL; + + if(newAvatar) + { + pair< set::iterator, bool > result; + + result = m_voiceAvatarsCore.insert(newAvatar); + + // if add of ChatAvatarCore works, add a new ChatAvatar also. + if (result.second == true) + { + ChatAvatar *avatar = newAvatar->getNewChatAvatar(); + + m_voiceAvatars.insert(avatar); + + returnAvatar = newAvatar; + } + } + + return returnAvatar; +} + +ChatAvatarCore *ChatRoomCore::removeVoice(const Plat_Unicode::String &name, const Plat_Unicode::String &address) +{ + ChatAvatarCore *returnAvatar = NULL; + + set::iterator iterCore = m_voiceAvatarsCore.begin(); + + for(; iterCore != m_voiceAvatarsCore.end(); iterCore++) + { + ChatAvatarCore *avatarCore = (*iterCore); + if (caseInsensitiveCompare(name, avatarCore->getName()) && + caseInsensitiveCompare(address, avatarCore->getAddress(), true)) + { + break; + } + } + + if(iterCore != m_voiceAvatarsCore.end()) + { + // remove ChatAvatarCore and ChatAvatar objects. + returnAvatar = (*iterCore); + m_voiceAvatarsCore.erase(iterCore); + + // because the addBan() made the ChatAvatar, removeBan() deletes it. + set::iterator iter = m_voiceAvatars.begin(); + + for(; iter != m_voiceAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + if(iter != m_voiceAvatars.end()) + { + delete (*iter); + m_voiceAvatars.erase(iter); + } + } + + // pass back the ChatAvatarCore and let caller delete it (b/c he created it). + return(returnAvatar); +} + +// ------- ChatRoom class support functions + + +unsigned ChatRoomCore::getAvatarCount() const +{ + return m_inroomAvatarsCore.size(); +} + +unsigned ChatRoomCore::getBanCount() const +{ + return m_banAvatarsCore.size(); +} + +unsigned ChatRoomCore::getInviteCount() const +{ + return m_inviteAvatarsCore.size(); +} + +unsigned ChatRoomCore::getModeratorCount() const +{ + return m_moderatorAvatarsCore.size(); +} + +unsigned ChatRoomCore::getTemporaryModeratorCount() const +{ + return m_tempModeratorAvatarsCore.size(); +} + +unsigned ChatRoomCore::getVoiceCount() const +{ + return m_voiceAvatarsCore.size(); +} + +AvatarIteratorCore ChatRoomCore::getFirstAvatar() +{ + return (AvatarIteratorCore(&m_inroomAvatars, m_inroomAvatars.begin())); +} + +AvatarIteratorCore ChatRoomCore::findAvatar(unsigned avatarID) +{ + return (AvatarIteratorCore(&m_inroomAvatars, m_inroomAvatars.find(avatarID))); +} + +AvatarIteratorCore ChatRoomCore::findAvatar(const String &name, const String &address) +{ + map::iterator iter; + + for (iter = m_inroomAvatars.begin(); iter != m_inroomAvatars.end(); iter++) + { + if(String((*iter).second->getName().string_data, (*iter).second->getName().string_length) == name && + String((*iter).second->getAddress().string_data, (*iter).second->getAddress().string_length) == address) + { + break; + } + } + + return (AvatarIteratorCore(&m_inroomAvatars, iter)); +} + +ModeratorIteratorCore ChatRoomCore::getFirstModerator() +{ + return (ModeratorIteratorCore(&m_moderatorAvatars, m_moderatorAvatars.begin())); +} + +ModeratorIteratorCore ChatRoomCore::findModerator(const String &name, const String &address) +{ + set::iterator iter; + + for (iter = m_moderatorAvatars.begin(); iter != m_moderatorAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + return (ModeratorIteratorCore(&m_moderatorAvatars, iter)); +} + +TemporaryModeratorIteratorCore ChatRoomCore::getFirstTemporaryModerator() +{ + return (TemporaryModeratorIteratorCore(&m_tempModeratorAvatars, m_tempModeratorAvatars.begin())); +} + +TemporaryModeratorIteratorCore ChatRoomCore::findTemporaryModerator(const String &name, const String &address) +{ + set::iterator iter; + + for (iter = m_tempModeratorAvatars.begin(); iter != m_tempModeratorAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + return (TemporaryModeratorIteratorCore(&m_tempModeratorAvatars, iter)); +} + +BanIteratorCore ChatRoomCore::getFirstBanned() +{ + return (BanIteratorCore(&m_banAvatars, m_banAvatars.begin())); +} + +BanIteratorCore ChatRoomCore::findBanned(const String &name, const String &address) +{ + set::iterator iter; + + for (iter = m_banAvatars.begin(); iter != m_banAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + return (BanIteratorCore(&m_banAvatars, iter)); +} + +InviteIteratorCore ChatRoomCore::getFirstInvited() +{ + return (InviteIteratorCore(&m_inviteAvatars, m_inviteAvatars.begin())); +} + +InviteIteratorCore ChatRoomCore::findInvited(const String &name, const String &address) +{ + set::iterator iter; + + for (iter = m_inviteAvatars.begin(); iter != m_inviteAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + return (InviteIteratorCore(&m_inviteAvatars, iter)); +} + +VoiceIteratorCore ChatRoomCore::getFirstVoice() +{ + return (VoiceIteratorCore(&m_voiceAvatars, m_voiceAvatars.begin())); +} + +VoiceIteratorCore ChatRoomCore::findVoice(const String &name, const String &address) +{ + set::iterator iter; + + for (iter = m_voiceAvatars.begin(); iter != m_voiceAvatars.end(); iter++) + { + ChatAvatar *avatar = (*iter); + Plat_Unicode::String avatarName(avatar->getName().string_data, avatar->getName().string_length); + Plat_Unicode::String avatarAddress(avatar->getAddress().string_data, avatar->getAddress().string_length); + if (caseInsensitiveCompare(name, avatarName) && + caseInsensitiveCompare(address, avatarAddress, true)) + { + break; + } + } + + return (VoiceIteratorCore(&m_voiceAvatars, iter)); +} + +void ChatRoomCore::serializeWithLocalAvatarsOnly(Base::ByteStream &msg) +{ + // put creator name + put(msg, m_creatorName); + + // put creator address + put(msg, m_creatorAddress); + + // put creator ID + put(msg, m_creatorID); + + // put room name + put(msg, m_roomName); + + // put room topic + put(msg, m_roomTopic); + + // put room password + put(msg, m_roomPassword); + + // put room prefix + put(msg, m_roomPrefix); + + // put room address + put(msg, m_roomAddress); + + // put room attributes + put(msg, m_roomAttributes); + + // put room max size + put(msg, m_maxRoomSize); + + // put room ID + put(msg, m_roomID); + + // put room creation time + put(msg, m_createTime); + + // put in-room avatars + unsigned avatarCount = m_inroomAvatarsCore.size(); + + std::map::iterator avatarIter; + std::set avatarsToSend; + + for (avatarIter = m_inroomAvatarsCore.begin(); avatarIter != m_inroomAvatarsCore.end(); avatarIter++) + { + // include only the avatars that are on this API + if ( this->getAvatar((*avatarIter).second->getAvatarID()) != NULL ) + { + avatarsToSend.insert((*avatarIter).second); + } + } + + // actually send avatars from this API *after* they have been counted + avatarCount = avatarsToSend.size(); + put(msg, avatarCount); + + std::set::iterator sendIter; + for (sendIter = avatarsToSend.begin(); sendIter != avatarsToSend.end(); sendIter++) + { + (*sendIter)->serialize(msg); + } + + // put administrator avatars + unsigned administratorCount = m_adminAvatarsCore.size(); + put(msg, administratorCount); + + std::map::iterator adminIter; + for (adminIter = m_adminAvatarsCore.begin(); adminIter != m_adminAvatarsCore.end(); adminIter++) + { + (*adminIter).second->serialize(msg); + } + + // put moderator avatars + unsigned moderatorCount = m_moderatorAvatarsCore.size(); + put(msg, moderatorCount); + + std::set::iterator moderatorIter; + for (moderatorIter = m_moderatorAvatarsCore.begin(); moderatorIter != m_moderatorAvatarsCore.end(); moderatorIter++) + { + (*moderatorIter)->serialize(msg); + } + + // put temporary moderator avatars + unsigned tempModeratorCount = m_tempModeratorAvatarsCore.size(); + put(msg, tempModeratorCount); + + std::set::iterator tempModeratorIter; + for (tempModeratorIter = m_tempModeratorAvatarsCore.begin(); tempModeratorIter != m_tempModeratorAvatarsCore.end(); tempModeratorIter++) + { + (*tempModeratorIter)->serialize(msg); + } + + // put banned avatars + unsigned bannedCount = m_banAvatarsCore.size(); + put(msg, bannedCount); + + std::set::iterator bannedIter; + for (bannedIter = m_banAvatarsCore.begin(); bannedIter != m_banAvatarsCore.end(); bannedIter++) + { + (*bannedIter)->serialize(msg); + } + + // put invited avatars + unsigned invitedCount = m_inviteAvatarsCore.size(); + put(msg, invitedCount); + + std::set::iterator invitesIter; + for (invitesIter = m_inviteAvatarsCore.begin(); invitesIter != m_inviteAvatarsCore.end(); invitesIter++) + { + (*invitesIter)->serialize(msg); + } + + // put voice avatars + unsigned voiceCount = m_voiceAvatarsCore.size(); + put(msg, voiceCount); + + std::set::iterator voicesIter; + for (voicesIter = m_voiceAvatarsCore.begin(); voicesIter != m_voiceAvatarsCore.end(); voicesIter++) + { + (*voicesIter)->serialize(msg); + } + + put(msg, m_roomMessageID); +} + +void ChatRoomCore::setCreator(unsigned creatorID, const Plat_Unicode::String &creatorName, const Plat_Unicode::String &creatorAddress) +{ + m_creatorID = creatorID; + m_creatorName = creatorName; + m_creatorAddress = creatorAddress; +} + +}; + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoomCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoomCore.h new file mode 100644 index 00000000..6bc193ad --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/ChatRoomCore.h @@ -0,0 +1,159 @@ +#if !defined (CHATROOMCORE_H_) +#define CHATROOMCORE_H_ + +#pragma warning (disable : 4786) + +#include +#include + +#include +#include +#include + +#include "ChatRoom.h" + +namespace ChatSystem +{ + class ChatAvatar; + class ChatAvatarCore; + class AvatarIteratorCore; + class ModeratorIteratorCore; + class TemporaryModeratorIteratorCore; + class VoiceIteratorCore; + class InviteIteratorCore; + class BanIteratorCore; + class RoomParams; + + + class ChatRoomCore + { + public: + ChatRoomCore(); + ChatRoomCore(Base::ByteStream::ReadIterator &iter); + ChatRoomCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address, const Plat_Unicode::String &topic, const unsigned attributes, const unsigned maxSize); + + ~ChatRoomCore(); + + const Plat_Unicode::String &getCreatorName() const { return m_creatorName; } + const Plat_Unicode::String &getCreatorAddress() const { return m_creatorAddress; } + unsigned getCreatorID() const { return m_creatorID; } + + unsigned getRoomID() const { return m_roomID; } + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomTopic() const { return m_roomTopic; } + const Plat_Unicode::String &getRoomPassword() const { return m_roomPassword; } + unsigned getRoomAttributes() const { return m_roomAttributes; } + unsigned getMaxRoomSize() const { return m_maxRoomSize; } + const Plat_Unicode::String &getAddress() const { return m_roomAddress; } + unsigned getNodeLevel() const { return m_nodeLevel; } + + unsigned getAvatarCount() const; + unsigned getBanCount() const; + unsigned getInviteCount() const; + unsigned getModeratorCount() const; + unsigned getTemporaryModeratorCount() const; + unsigned getVoiceCount() const; + + + void setName(const Plat_Unicode::String &name) { m_roomName = name; } + void setTopic(const Plat_Unicode::String &topic) { m_roomTopic = topic; } + void setPassword(const Plat_Unicode::String &password) { m_roomPassword = password; } + void setAttributes(unsigned attributes) { m_roomAttributes = attributes; } + void setMaxRoomSize(unsigned size) { m_maxRoomSize = size; } + void setID(unsigned id) { m_roomID = id; } + void setCreator(unsigned creatorID, const Plat_Unicode::String &creatorName, const Plat_Unicode::String &creatorAddress); + + void setRoomMessageID(unsigned roomMessageID) { m_roomMessageID = roomMessageID; } + + ChatAvatarCore *getAvatarCore(unsigned avatarID); + ChatAvatar *getAvatar(unsigned avatarID); + ChatAvatarCore *getModeratorCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatar *getModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatarCore *getTemporaryModeratorCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatar *getTemporaryModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatarCore *getBannedCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatar *getBanned(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatarCore *getInvitedCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatar *getInvited(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatarCore *getVoiceCore(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + ChatAvatar *getVoice(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + ChatAvatarCore *addAvatar(ChatAvatarCore *newAvatar, bool local); + void addLocalAvatar(unsigned avatarID); + ChatAvatarCore *removeAvatar(unsigned avatarID); + + ChatAvatarCore *addAdministrator(ChatAvatarCore *newAvatar); + ChatAvatarCore *removeAdministrator(unsigned avatarID); + + ChatAvatarCore *addModerator(ChatAvatarCore *newAvatar); + ChatAvatarCore *removeModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + ChatAvatarCore *addTempModerator(ChatAvatarCore *newAvatar); + ChatAvatarCore *removeTempModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + ChatAvatarCore *addBan(ChatAvatarCore *newAvatar); + ChatAvatarCore *removeBan(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + ChatAvatarCore *addInvite(ChatAvatarCore *newAvatar); + ChatAvatarCore *removeInvite(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + ChatAvatarCore *addVoice(ChatAvatarCore *newAvatar); + ChatAvatarCore *removeVoice(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + AvatarIteratorCore getFirstAvatar(); + AvatarIteratorCore findAvatar(unsigned avatarID); + AvatarIteratorCore findAvatar(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + ModeratorIteratorCore getFirstModerator(); + ModeratorIteratorCore findModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + TemporaryModeratorIteratorCore getFirstTemporaryModerator(); + TemporaryModeratorIteratorCore findTemporaryModerator(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + BanIteratorCore getFirstBanned(); + BanIteratorCore findBanned(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + InviteIteratorCore getFirstInvited(); + InviteIteratorCore findInvited(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + VoiceIteratorCore getFirstVoice(); + VoiceIteratorCore findVoice(const Plat_Unicode::String &name, const Plat_Unicode::String &address); + + void serializeWithLocalAvatarsOnly(Base::ByteStream &msg); + + private: + Plat_Unicode::String m_creatorName; + Plat_Unicode::String m_creatorAddress; + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomTopic; + Plat_Unicode::String m_roomPassword; + Plat_Unicode::String m_roomPrefix; + Plat_Unicode::String m_roomAddress; + + unsigned m_creatorID; + unsigned m_roomAttributes; + unsigned m_maxRoomSize; + unsigned m_roomID; + unsigned m_createTime; + unsigned m_nodeLevel; + unsigned m_roomMessageID; + + std::map m_inroomAvatarsCore; + std::map m_inroomAvatars; + std::set m_inroomAvatarsLocal; + std::map m_adminAvatarsCore; + std::map m_adminAvatars; + std::set m_moderatorAvatarsCore; + std::set m_tempModeratorAvatarsCore; + std::set m_moderatorAvatars; + std::set m_tempModeratorAvatars; + std::set m_banAvatarsCore; + std::set m_banAvatars; + std::set m_inviteAvatarsCore; + std::set m_inviteAvatars; + std::set m_voiceAvatarsCore; + std::set m_voiceAvatars; + }; +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Message.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Message.cpp new file mode 100644 index 00000000..d38defbc --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Message.cpp @@ -0,0 +1,515 @@ +#include "Message.h" +#include "PersistentMessage.h" +#include "PersistentMessageCore.h" + + +unsigned numRead; +namespace ChatSystem +{ + using namespace std; + using namespace Base; + using namespace Plat_Unicode; + + MInstantMessage::MInstantMessage(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_INSTANTMESSAGE), + m_srcAvatar(iter) + { + get(iter, m_destAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_msg)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_oob)); + } + + MRoomMessage::MRoomMessage(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ROOMMESSAGE), + m_destList(NULL), + m_srcAvatar(iter), + m_messageID(0) + { + get(iter, m_roomID); + get(iter, m_listLength); + + m_destList = new unsigned[m_listLength]; + for(unsigned i = 0; i < m_listLength; i++) + { + get(iter, m_destList[i]); + } + ASSERT_VALID_STRING_LENGTH(get(iter, m_msg)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_oob)); + + if (iter.getSize() >= sizeof(unsigned)) + { + get(iter, m_messageID); + } + } + + MRoomMessage::~MRoomMessage() + { + delete[] m_destList; + m_destList = NULL; + } + + MBroadcastMessage::MBroadcastMessage(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_BROADCASTMESSAGE), + m_srcAvatar(iter), + m_destList(NULL) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_srcAddress)); + get(iter, m_listLength); + + m_destList = new unsigned[m_listLength]; + for(unsigned i = 0; i < m_listLength; i++) + { + get(iter, m_destList[i]); + } + ASSERT_VALID_STRING_LENGTH(get(iter, m_msg)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_oob)); + } + + MBroadcastMessage::~MBroadcastMessage() + { + delete[] m_destList; + m_destList = NULL; + } + + MFilterMessage::MFilterMessage(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FILTERMESSAGE) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_inmsg)); + } + + MFriendLogin::MFriendLogin(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDLOGIN), + m_friendAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_friendAddress)); + get(iter, m_destAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_friendStatus)); + } + + MFriendLogout::MFriendLogout(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDLOGOUT), + m_friendAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_friendAddress)); + get(iter, m_destAvatarID); + } + + MFriendStatus::MFriendStatus(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDSTATUS), + m_friendAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_friendAddress)); + get(iter, m_destAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_friendStatus)); + } + + MKickRoom::MKickRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_KICKROOM), + m_srcAvatar(iter), + m_destAvatar(iter) + { + get(iter, m_roomID); + } + + MKickAvatar::MKickAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_KICKAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MAddModeratorRoom::MAddModeratorRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDMODERATORROOM) + { + get(iter, m_srcAvatarID); + m_destAvatar = new ChatAvatarCore(iter); + get(iter, m_roomID); + } + + MAddModeratorAvatar::MAddModeratorAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDMODERATORAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MRemoveModeratorRoom::MRemoveModeratorRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEMODERATORROOM) + { + get(iter, m_srcAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarAddress)); + get(iter, m_roomID); + } + + MRemoveModeratorAvatar::MRemoveModeratorAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEMODERATORAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MAddTemporaryModeratorRoom::MAddTemporaryModeratorRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDMODERATORROOM) + { + get(iter, m_srcAvatarID); + m_destAvatar = new ChatAvatarCore(iter); + get(iter, m_roomID); + } + + MAddTemporaryModeratorAvatar::MAddTemporaryModeratorAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDMODERATORAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MRemoveTemporaryModeratorRoom::MRemoveTemporaryModeratorRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEMODERATORROOM) + { + get(iter, m_srcAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarAddress)); + get(iter, m_roomID); + } + + MRemoveTemporaryModeratorAvatar::MRemoveTemporaryModeratorAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEMODERATORAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MAddBanRoom::MAddBanRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDBANROOM), + m_srcAvatar(iter) + { + m_destAvatar = new ChatAvatarCore(iter); + get(iter, m_roomID); + } + + MAddBanAvatar::MAddBanAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDBANAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MRemoveBanRoom::MRemoveBanRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEBANROOM) + { + get(iter, m_srcAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarAddress)); + get(iter, m_roomID); + } + + MRemoveBanAvatar::MRemoveBanAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEBANAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MAddInviteRoom::MAddInviteRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDINVITEROOM), + m_srcAvatar(iter) + { + m_destAvatar = new ChatAvatarCore(iter); + get(iter, m_roomID); + } + + MAddInviteAvatar::MAddInviteAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDINVITEAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MRemoveInviteRoom::MRemoveInviteRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEINVITEROOM) + { + get(iter, m_srcAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarAddress)); + get(iter, m_roomID); + } + + MRemoveInviteAvatar::MRemoveInviteAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEINVITEAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MGrantVoiceRoom::MGrantVoiceRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDINVITEROOM), + m_srcAvatar(iter) + { + m_destAvatar = new ChatAvatarCore(iter); + get(iter, m_roomID); + } + + MGrantVoiceAvatar::MGrantVoiceAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDINVITEAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MRevokeVoiceRoom::MRevokeVoiceRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEINVITEROOM) + { + get(iter, m_srcAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAvatarAddress)); + get(iter, m_roomID); + } + + MRevokeVoiceAvatar::MRevokeVoiceAvatar(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEINVITEAVATAR), + m_srcAvatar(iter), + m_destAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomAddress)); + } + + MEnterRoom::MEnterRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ENTERROOM), + m_srcAvatar(new ChatAvatarCore(iter)) + { + get(iter, m_roomID); + } + + MLeaveRoom::MLeaveRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_LEAVEROOM) + { + get(iter, m_avatarID); + get(iter, m_roomID); + } + + MDestroyRoom::MDestroyRoom(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_DESTROYROOM), + m_srcAvatar(iter) + { + get(iter, m_roomID); + } + + MSetRoomParams::MSetRoomParams(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_SETROOMPARAMS), + m_srcAvatar(iter) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomTopic)); + get(iter, m_roomAttributes); + get(iter, m_maxRoomSize); + get(iter, m_roomID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_roomPassword)); + } + + MPersistentMessage::MPersistentMessage(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_PERSISTENTMESSAGE) + { + m_core = new PersistentHeaderCore(); + m_header = new PersistentHeader(); + get(iter, m_destAvatarID); + + // unpack messageID, + // destAvatarID, + // fromName, + // fromAddress, + // subject, + // sentTime, and + // status into PersistentHeaderCore object + m_core->load(iter, m_header); + + if (iter.getSize() > 0) + { + m_core->setCategory(iter); + } + } + + MPersistentMessage::~MPersistentMessage() + { + delete m_core; + delete m_header; + } + + MForcedLogout::MForcedLogout(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FORCEDLOGOUT) + { + get(iter, m_avatarID); + } + + MUnregisterRoomReady::MUnregisterRoomReady(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_UNREGISTERROOMREADY) + { + get(iter, m_roomID); + } + + MAddAdmin::MAddAdmin(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_ADDADMIN), + m_avatar(new ChatAvatarCore(iter)) + { + get(iter, m_roomID); + } + + MRemoveAdmin::MRemoveAdmin(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REMOVEADMIN) + { + get(iter, m_avatarID); + get(iter, m_roomID); + } + + MFriendConfirmRequest::MFriendConfirmRequest(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDCONFIRMREQUEST), + m_srcAvatar(iter) + { + get(iter, m_destAvatarID); + } + + MFriendConfirmResponse::MFriendConfirmResponse(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDCONFIRMRESPONSE), + m_srcAvatar(iter) + { + get(iter, m_destAvatarID); + get(iter, m_confirm); + } + + MFriendConfirmReciprocateRequest::MFriendConfirmReciprocateRequest(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDCONFIRMRECIPROCATE_REQUEST), + m_srcAvatar(iter) + { + get(iter, m_destAvatarID); + } + + MFriendConfirmReciprocateResponse::MFriendConfirmReciprocateResponse(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FRIENDCONFIRMRECIPROCATE_RESPONSE), + m_srcAvatar(iter) + { + get(iter, m_destAvatarID); + get(iter, m_confirm); + } + + MChangeRoomOwner::MChangeRoomOwner(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_CHANGEROOMOWNER) + { + get(iter, m_destRoomID); + get(iter, m_newRoomOwnerID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_newRoomOwnerName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_newRoomOwnerAddress)); + } + + MRoomEntryRequest::MRoomEntryRequest(Base::ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_REQUESTROOMENTRY), + m_requestorAvatar(iter) + { + get(iter, m_roomOwnerID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_requestedRoomAddress)); + } + + MDelayedRoomEntry::MDelayedRoomEntry(Base::ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_DELAYEDROOMENTRY) + { + int numExtraRooms = 0; + + get(iter, m_avatarID); + get(iter, m_roomID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_enteredAddress)); + get(iter, numExtraRooms); + + while (numExtraRooms > 0) + { + m_setExtraRooms.insert(new ChatRoomCore(iter)); + numExtraRooms--; + } + } + + MDeniedRoomEntry::MDeniedRoomEntry(Base::ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_DENIEDROOMENTRY) + { + get(iter, m_requestorAvatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_requestedRoomAddress)); + } + + MForceRoomFailover::MForceRoomFailover(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_FORCEROOMFAILOVER) + { + unsigned numAIDs(0); + get(iter, numAIDs); + + String aid; + for (unsigned i = 0; i < numAIDs; i++) + { + ASSERT_VALID_STRING_LENGTH(get(iter, aid)); + m_aidList.push_back(aid); + } + } + + MSnoop::MSnoop(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_SNOOP) + { + get(iter, m_snoopType); + ASSERT_VALID_STRING_LENGTH(get(iter, m_snooperName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_snooperAddr)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_srcName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_srcAddr)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAddr)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_message)); + } + + MUIDList::MUIDList(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_UIDLIST) + { + unsigned numUIDs; + get(iter, numUIDs); + for (unsigned i = 0; i < numUIDs; i++) + { + Plat_Unicode::String uid; + ASSERT_VALID_STRING_LENGTH(get(iter, uid)); + m_uidList.insert(toUpper(uid)); + } + } + + MNotifyFriendIsRemoved::MNotifyFriendIsRemoved(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_NOTIFY_FRIEND_IS_REMOVED) + { + get(iter, m_avatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_destAddress)); + + } + + MNotifyFriendsListChange::MNotifyFriendsListChange(ByteStream::ReadIterator &iter) + : GenericMessage(MESSAGE_NOTIFY_FRIENDS_LIST_CHANGE) + { + get(iter, m_avatarID); + ASSERT_VALID_STRING_LENGTH(get(iter, m_originalName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_originalAddress)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_newName)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_newAddress)); + } + +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Message.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Message.h new file mode 100644 index 00000000..2f8bcd8b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Message.h @@ -0,0 +1,929 @@ +#if !defined (MESSAGE_H_) +#define MESSAGE_H_ +#pragma warning (disable : 4786) + +#include +#include + +#include "ChatRoomCore.h" +#include "ChatAvatarCore.h" + +#include +#include +#include + +namespace ChatSystem +{ + + class PersistentHeader; + class PersistentHeaderCore; + + enum eMessageType + { + // ChatAvatar message types + MESSAGE_INSTANTMESSAGE, // 0 + MESSAGE_ROOMMESSAGE, + MESSAGE_BROADCASTMESSAGE, + MESSAGE_FRIENDLOGIN, + MESSAGE_FRIENDLOGOUT, + MESSAGE_KICKROOM, // 5 + + // ChatRoom message types + MESSAGE_ADDMODERATORROOM, + MESSAGE_REMOVEMODERATORROOM, + MESSAGE_REMOVEMODERATORAVATAR, + MESSAGE_ADDBANROOM, + MESSAGE_REMOVEBANROOM, // 10 + MESSAGE_REMOVEBANAVATAR, + MESSAGE_ADDINVITEROOM, + MESSAGE_ADDINVITEAVATAR, + MESSAGE_REMOVEINVITEROOM, + MESSAGE_REMOVEINVITEAVATAR, // 15 + MESSAGE_ENTERROOM, + MESSAGE_LEAVEROOM, + MESSAGE_DESTROYROOM, + MESSAGE_SETROOMPARAMS, + MESSAGE_PERSISTENTMESSAGE, // 20 + MESSAGE_FORCEDLOGOUT, + MESSAGE_UNREGISTERROOMREADY, + MESSAGE_KICKAVATAR, + MESSAGE_ADDMODERATORAVATAR, + MESSAGE_ADDBANAVATAR, // 25 + MESSAGE_ADDADMIN, + MESSAGE_REMOVEADMIN, + MESSAGE_FRIENDCONFIRMREQUEST, + MESSAGE_FRIENDCONFIRMRESPONSE, + MESSAGE_CHANGEROOMOWNER, // 30 + MESSAGE_FORCEROOMFAILOVER, + MESSAGE_ADDTEMPORARYMODERATORROOM, + MESSAGE_ADDTEMPORARYMODERATORAVATAR, + MESSAGE_REMOVETEMPORARYMODERATORROOM, + MESSAGE_REMOVETEMPORARYMODERATORAVATAR, // 35 + MESSAGE_GRANTVOICEROOM, + MESSAGE_GRANTVOICEAVATAR, + MESSAGE_REVOKEVOICEROOM, + MESSAGE_REVOKEVOICEAVATAR, + MESSAGE_SNOOP, // 40 + MESSAGE_UIDLIST, + MESSAGE_REQUESTROOMENTRY, + MESSAGE_DELAYEDROOMENTRY, + MESSAGE_DENIEDROOMENTRY, + MESSAGE_FRIENDSTATUS, // 45 + MESSAGE_FRIENDCONFIRMRECIPROCATE_REQUEST, + MESSAGE_FRIENDCONFIRMRECIPROCATE_RESPONSE, + MESSAGE_FILTERMESSAGE, + MESSAGE_FAILOVER_AVATAR_LIST, + MESSAGE_NOTIFY_FRIENDS_LIST_CHANGE, // 50 + MESSAGE_NOTIFY_FRIEND_IS_REMOVED + + }; + + class MInstantMessage : public GenericAPI::GenericMessage + { + public: + MInstantMessage(Base::ByteStream::ReadIterator &iter); + virtual ~MInstantMessage() {}; + + unsigned getDestAvatarID() const { return m_destAvatarID; } + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const Plat_Unicode::String &getMsg() const { return m_msg; } + const Plat_Unicode::String &getOOB() const { return m_oob; } + + private: + ChatAvatarCore m_srcAvatar; + unsigned m_destAvatarID; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + }; + + class MRoomMessage : public GenericAPI::GenericMessage + { + public: + MRoomMessage(Base::ByteStream::ReadIterator &iter); + virtual ~MRoomMessage(); + + unsigned getListLength() const { return m_listLength; } + const unsigned *getDestList() const { return m_destList; } + ChatAvatarCore *getSrcAvatar() { return &m_srcAvatar; } + unsigned getRoomID() const { return m_roomID; } + const Plat_Unicode::String &getMsg() const { return m_msg; } + const Plat_Unicode::String &getOOB() const { return m_oob; } + unsigned getMessageID() const { return m_messageID; } + + private: + unsigned m_listLength; + unsigned *m_destList; + ChatAvatarCore m_srcAvatar; + unsigned m_roomID; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + unsigned m_messageID; + }; + + class MBroadcastMessage : public GenericAPI::GenericMessage + { + public: + MBroadcastMessage(Base::ByteStream::ReadIterator &iter); + virtual ~MBroadcastMessage(); + + unsigned getListLength() const { return m_listLength; } + const unsigned *getDestList() const { return m_destList; } + ChatAvatarCore *getSrcAvatar() { return &m_srcAvatar; } + const Plat_Unicode::String &getSrcAddress() const { return m_srcAddress; } + const Plat_Unicode::String &getMsg() const { return m_msg; } + const Plat_Unicode::String &getOOB() const { return m_oob; } + + private: + ChatAvatarCore m_srcAvatar; + unsigned m_listLength; + unsigned *m_destList; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + }; + + class MFilterMessage : public GenericAPI::GenericMessage + { + public: + MFilterMessage(Base::ByteStream::ReadIterator &iter); + virtual ~MFilterMessage() {}; + + const Plat_Unicode::String &getMsg() const { return m_inmsg; } + + private: + Plat_Unicode::String m_inmsg; + }; + + class MFriendLogin : public GenericAPI::GenericMessage + { + public: + MFriendLogin(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendLogin() {}; + + const ChatAvatarCore *getFriendAvatar() const { return &m_friendAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + const Plat_Unicode::String &getFriendAddress() const { return m_friendAddress; } + const Plat_Unicode::String &getFriendStatusMessage() const { return m_friendStatus; } + + private: + ChatAvatarCore m_friendAvatar; + unsigned m_destAvatarID; + Plat_Unicode::String m_friendAddress; + Plat_Unicode::String m_friendStatus; + }; + + class MFriendLogout : public GenericAPI::GenericMessage + { + public: + MFriendLogout(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendLogout() {}; + + const ChatAvatarCore *getFriendAvatar() const { return &m_friendAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + const Plat_Unicode::String &getFriendAddress() const { return m_friendAddress; } + + private: + ChatAvatarCore m_friendAvatar; + unsigned m_destAvatarID; + Plat_Unicode::String m_friendAddress; + }; + + class MFriendStatus : public GenericAPI::GenericMessage + { + public: + MFriendStatus(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendStatus() {}; + + const ChatAvatarCore *getFriendAvatar() const { return &m_friendAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + const Plat_Unicode::String &getFriendAddress() const { return m_friendAddress; } + const Plat_Unicode::String &getFriendStatusMessage() const { return m_friendStatus; } + + private: + ChatAvatarCore m_friendAvatar; + unsigned m_destAvatarID; + Plat_Unicode::String m_friendAddress; + Plat_Unicode::String m_friendStatus; + }; + + class MKickRoom : public GenericAPI::GenericMessage + { + public: + MKickRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MKickRoom() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + unsigned m_roomID; + }; + + class MKickAvatar : public GenericAPI::GenericMessage + { + public: + MKickAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MKickAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MAddModeratorRoom : public GenericAPI::GenericMessage + { + public: + MAddModeratorRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MAddModeratorRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + ChatAvatarCore *getDestAvatar() const { return m_destAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + ChatAvatarCore *m_destAvatar; + unsigned m_roomID; + }; + + class MAddModeratorAvatar : public GenericAPI::GenericMessage + { + public: + MAddModeratorAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MAddModeratorAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MRemoveModeratorRoom : public GenericAPI::GenericMessage + { + public: + MRemoveModeratorRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveModeratorRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_roomID; + }; + + class MRemoveModeratorAvatar : public GenericAPI::GenericMessage + { + public: + MRemoveModeratorAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveModeratorAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MAddTemporaryModeratorRoom : public GenericAPI::GenericMessage + { + public: + MAddTemporaryModeratorRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MAddTemporaryModeratorRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + ChatAvatarCore *getDestAvatar() const { return m_destAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + ChatAvatarCore *m_destAvatar; + unsigned m_roomID; + }; + + class MAddTemporaryModeratorAvatar : public GenericAPI::GenericMessage + { + public: + MAddTemporaryModeratorAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MAddTemporaryModeratorAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MRemoveTemporaryModeratorRoom : public GenericAPI::GenericMessage + { + public: + MRemoveTemporaryModeratorRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveTemporaryModeratorRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_roomID; + }; + + class MRemoveTemporaryModeratorAvatar : public GenericAPI::GenericMessage + { + public: + MRemoveTemporaryModeratorAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveTemporaryModeratorAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MAddBanRoom : public GenericAPI::GenericMessage + { + public: + MAddBanRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MAddBanRoom() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + ChatAvatarCore *getDestAvatar() const { return m_destAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore *m_destAvatar; + unsigned m_roomID; + }; + + class MAddBanAvatar : public GenericAPI::GenericMessage + { + public: + MAddBanAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MAddBanAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MRemoveBanRoom : public GenericAPI::GenericMessage + { + public: + MRemoveBanRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveBanRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_roomID; + }; + + class MRemoveBanAvatar : public GenericAPI::GenericMessage + { + public: + MRemoveBanAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveBanAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MAddInviteRoom : public GenericAPI::GenericMessage + { + public: + MAddInviteRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MAddInviteRoom() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + ChatAvatarCore *getDestAvatar() const { return m_destAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore *m_destAvatar; + unsigned m_roomID; + }; + + class MAddInviteAvatar : public GenericAPI::GenericMessage + { + public: + MAddInviteAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MAddInviteAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MRemoveInviteRoom : public GenericAPI::GenericMessage + { + public: + MRemoveInviteRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveInviteRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_roomID; + }; + + class MRemoveInviteAvatar : public GenericAPI::GenericMessage + { + public: + MRemoveInviteAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveInviteAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MGrantVoiceRoom : public GenericAPI::GenericMessage + { + public: + MGrantVoiceRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MGrantVoiceRoom() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + ChatAvatarCore *getDestAvatar() const { return m_destAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore *m_destAvatar; + unsigned m_roomID; + }; + + class MGrantVoiceAvatar : public GenericAPI::GenericMessage + { + public: + MGrantVoiceAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MGrantVoiceAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MRevokeVoiceRoom : public GenericAPI::GenericMessage + { + public: + MRevokeVoiceRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MRevokeVoiceRoom() {}; + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_roomID; + }; + + class MRevokeVoiceAvatar : public GenericAPI::GenericMessage + { + public: + MRevokeVoiceAvatar(Base::ByteStream::ReadIterator &iter); + virtual ~MRevokeVoiceAvatar() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const ChatAvatarCore *getDestAvatar() const { return &m_destAvatar; } + + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + ChatAvatarCore m_srcAvatar; + ChatAvatarCore m_destAvatar; + + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomAddress; + }; + + class MEnterRoom : public GenericAPI::GenericMessage + { + public: + MEnterRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MEnterRoom() {}; + + ChatAvatarCore *getSrcAvatar() const { return m_srcAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore *m_srcAvatar; + unsigned m_roomID; + }; + + class MLeaveRoom : public GenericAPI::GenericMessage + { + public: + MLeaveRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MLeaveRoom() {}; + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_avatarID; + unsigned m_roomID; + }; + + class MDestroyRoom : public GenericAPI::GenericMessage + { + public: + MDestroyRoom(Base::ByteStream::ReadIterator &iter); + virtual ~MDestroyRoom() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore m_srcAvatar; + unsigned m_roomID; + }; + + class MSetRoomParams : public GenericAPI::GenericMessage + { + public: + MSetRoomParams(Base::ByteStream::ReadIterator &iter); + virtual ~MSetRoomParams() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + const Plat_Unicode::String &getRoomName() const { return m_roomName; } + const Plat_Unicode::String &getRoomTopic() const { return m_roomTopic; } + const Plat_Unicode::String &getRoomPassword() const { return m_roomPassword; } + unsigned getRoomAttributes() const { return m_roomAttributes; } + unsigned getRoomSize() const { return m_maxRoomSize; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore m_srcAvatar; + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomTopic; + Plat_Unicode::String m_roomPassword; + unsigned m_roomAttributes; + unsigned m_maxRoomSize; + unsigned m_roomID; + }; + + class MPersistentMessage : public GenericAPI::GenericMessage + { + public: + MPersistentMessage(Base::ByteStream::ReadIterator &iter); + virtual ~MPersistentMessage(); + + unsigned getDestAvatarID() const { return m_destAvatarID; } + const PersistentHeader *getHeader() const { return m_header; } + + private: + unsigned m_destAvatarID; + PersistentHeaderCore *m_core; + PersistentHeader *m_header; + }; + + class MForcedLogout : public GenericAPI::GenericMessage + { + public: + MForcedLogout(Base::ByteStream::ReadIterator &iter); + virtual ~MForcedLogout() {}; + + unsigned getAvatarID() const { return m_avatarID; } + + private: + unsigned m_avatarID; + }; + + class MUnregisterRoomReady : public GenericAPI::GenericMessage + { + public: + MUnregisterRoomReady(Base::ByteStream::ReadIterator &iter); + virtual ~MUnregisterRoomReady() {}; + + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_roomID; + }; + + class MAddAdmin : public GenericAPI::GenericMessage + { + public: + MAddAdmin(Base::ByteStream::ReadIterator &iter); + virtual ~MAddAdmin() {}; + + ChatAvatarCore *getAvatar() const { return m_avatar; } + unsigned getRoomID() const { return m_roomID; } + private: + ChatAvatarCore *m_avatar; + unsigned m_roomID; + }; + + class MRemoveAdmin : public GenericAPI::GenericMessage + { + public: + MRemoveAdmin(Base::ByteStream::ReadIterator &iter); + virtual ~MRemoveAdmin() {}; + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_avatarID; + unsigned m_roomID; + }; + + class MFriendConfirmRequest : GenericAPI::GenericMessage + { + public: + MFriendConfirmRequest(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendConfirmRequest() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + private: + ChatAvatarCore m_srcAvatar; + unsigned m_destAvatarID; + }; + + class MFriendConfirmResponse : GenericAPI::GenericMessage + { + public: + MFriendConfirmResponse(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendConfirmResponse() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + bool getConfirm() const { return m_confirm != 0; } + private: + ChatAvatarCore m_srcAvatar; + unsigned m_destAvatarID; + short m_confirm; + }; + + class MFriendConfirmReciprocateRequest : GenericAPI::GenericMessage + { + public: + MFriendConfirmReciprocateRequest(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendConfirmReciprocateRequest() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + private: + ChatAvatarCore m_srcAvatar; + unsigned m_destAvatarID; + }; + + class MFriendConfirmReciprocateResponse : GenericAPI::GenericMessage + { + public: + MFriendConfirmReciprocateResponse(Base::ByteStream::ReadIterator &iter); + virtual ~MFriendConfirmReciprocateResponse() {}; + + const ChatAvatarCore *getSrcAvatar() const { return &m_srcAvatar; } + unsigned getDestAvatarID() const { return m_destAvatarID; } + bool getConfirm() const { return m_confirm != 0; } + private: + ChatAvatarCore m_srcAvatar; + unsigned m_destAvatarID; + short m_confirm; + }; + + class MChangeRoomOwner: GenericAPI::GenericMessage + { + public: + MChangeRoomOwner(Base::ByteStream::ReadIterator &iter); + virtual ~MChangeRoomOwner() {}; + + unsigned getDestRoomID() const { return m_destRoomID; } + unsigned getNewRoomOwnerID() const { return m_newRoomOwnerID; } + const Plat_Unicode::String &getNewRoomOwnerName() const { return m_newRoomOwnerName; } + const Plat_Unicode::String &getNewRoomOwnerAddress() const { return m_newRoomOwnerAddress; } + + private: + unsigned m_destRoomID; + unsigned m_newRoomOwnerID; + Plat_Unicode::String m_newRoomOwnerName; + Plat_Unicode::String m_newRoomOwnerAddress; + }; + + class MRoomEntryRequest : public GenericAPI::GenericMessage + { + public: + MRoomEntryRequest(Base::ByteStream::ReadIterator &iter); + virtual ~MRoomEntryRequest() {}; + + unsigned getRoomOwnerID() const { return m_roomOwnerID; } + const ChatAvatarCore *getRequestorAvatar() const { return &m_requestorAvatar; } + const Plat_Unicode::String &getRequestedRoomAddress() const { return m_requestedRoomAddress; } + + private: + unsigned m_roomOwnerID; + ChatAvatarCore m_requestorAvatar; + Plat_Unicode::String m_requestedRoomAddress; + }; + + class MDelayedRoomEntry : public GenericAPI::GenericMessage + { + public: + MDelayedRoomEntry(Base::ByteStream::ReadIterator &iter); + virtual ~MDelayedRoomEntry() {}; + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + const Plat_Unicode::String &getEnteredAddress() { return m_enteredAddress; } + ChatRoomCore *getRoom() const { return m_room; } + const std::set &getExtraRooms() { return m_setExtraRooms; } + + private: + unsigned m_avatarID; + unsigned m_roomID; + Plat_Unicode::String m_enteredAddress; + ChatRoomCore* m_room; + std::set m_setExtraRooms; + }; + + class MDeniedRoomEntry : public GenericAPI::GenericMessage + { + public: + MDeniedRoomEntry(Base::ByteStream::ReadIterator &iter); + virtual ~MDeniedRoomEntry() {}; + + unsigned getRequestorID() const { return m_requestorAvatarID; } + const Plat_Unicode::String &getRequestedRoomAddress() const { return m_requestedRoomAddress; } + + private: + unsigned m_requestorAvatarID; + Plat_Unicode::String m_requestedRoomAddress; + }; + + class MForceRoomFailover : GenericAPI::GenericMessage + { + public: + MForceRoomFailover(Base::ByteStream::ReadIterator &iter); + virtual ~MForceRoomFailover() {}; + + const std::list &getAIDList() const { return m_aidList; } + private: + std::list m_aidList; + }; + + class MSnoop : GenericAPI::GenericMessage + { + public: + MSnoop(Base::ByteStream::ReadIterator &iter); + virtual ~MSnoop() {}; + + unsigned getSnoopType() const { return m_snoopType; } + const Plat_Unicode::String &getSnooperName() const { return m_snooperName; } + const Plat_Unicode::String &getSnooperAddr() const { return m_snooperAddr; } + const Plat_Unicode::String &getSrcName() const { return m_srcName; } + const Plat_Unicode::String &getSrcAddr() const { return m_srcAddr; } + const Plat_Unicode::String &getDestName() const { return m_destName; } + const Plat_Unicode::String &getDestAddr() const { return m_destAddr; } + const Plat_Unicode::String &getMessage() const { return m_message; } + private: + unsigned m_snoopType; + Plat_Unicode::String m_snooperName; + Plat_Unicode::String m_snooperAddr; + Plat_Unicode::String m_srcName; + Plat_Unicode::String m_srcAddr; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddr; + Plat_Unicode::String m_message; + }; + + class MUIDList : public GenericAPI::GenericMessage + { + public: + MUIDList(Base::ByteStream::ReadIterator &iter); + virtual ~MUIDList() {}; + + const std::set &getUIDList() const { return m_uidList; } + private: + std::set m_uidList; + }; + + class MNotifyFriendIsRemoved : public GenericAPI::GenericMessage + { + public: + MNotifyFriendIsRemoved(Base::ByteStream::ReadIterator &iter); + virtual ~MNotifyFriendIsRemoved() {}; + + const unsigned &getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getDestName() const { return m_destName; } + const Plat_Unicode::String &getDestAddress() const { return m_destAddress; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; + }; + + class MNotifyFriendsListChange : public GenericAPI::GenericMessage + { + public: + MNotifyFriendsListChange(Base::ByteStream::ReadIterator &iter); + virtual ~MNotifyFriendsListChange() {}; + + const unsigned &getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getOriginalName() const { return m_originalName; } + const Plat_Unicode::String &getOriginalAddress() const { return m_originalAddress; } + const Plat_Unicode::String &getNewName() const { return m_newName; } + const Plat_Unicode::String &getNewAddress() const { return m_newAddress; } + private: + + unsigned m_avatarID; + Plat_Unicode::String m_originalName; + Plat_Unicode::String m_originalAddress; + Plat_Unicode::String m_newName; + Plat_Unicode::String m_newAddress; + }; + + +}; + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessage.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessage.cpp new file mode 100644 index 00000000..ca4b509e --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessage.cpp @@ -0,0 +1,156 @@ +#include "PersistentMessage.h" +#include "PersistentMessageCore.h" + +namespace ChatSystem +{ + +using namespace Base; +using namespace Plat_Unicode; + +PersistentHeader::PersistentHeader() +: m_core(NULL) +{ +} + +PersistentHeader::~PersistentHeader() +{ +} + +unsigned PersistentHeader::getMessageID() const +{ + return m_core->getMessageID(); +} + +unsigned PersistentHeader::getAvatarID() const +{ + return m_core->getAvatarID(); +} + +const ChatUnicodeString &PersistentHeader::getFromName() const +{ + return m_fromName; +} + +const ChatUnicodeString &PersistentHeader::getFromAddress() const +{ + return m_fromAddress; +} + +const ChatUnicodeString &PersistentHeader::getSubject() const +{ + return m_subject; +} + +const ChatUnicodeString &PersistentHeader::getFolder() const +{ + return m_folder; +} + +const ChatUnicodeString &PersistentHeader::getCategory() const +{ + return m_category; +} + +unsigned PersistentHeader::getSentTime() const +{ + return m_core->getSentTime(); +} + +unsigned PersistentHeader::getStatus() const +{ + return m_core->getStatus(); +} + +PersistentHeaderCore::PersistentHeaderCore() +: m_messageID(0), + m_avatarID(0), + m_sentTime(0), + m_status(0), + m_interface(NULL) +{ +} + +PersistentHeaderCore::~PersistentHeaderCore() +{ +} + +void PersistentHeaderCore::load(ByteStream::ReadIterator &iter, PersistentHeader *inf) +{ + m_interface = inf; + inf->m_core = this; + get(iter, m_messageID); + get(iter, m_avatarID); + get(iter, m_fromName); + get(iter, m_fromAddress); + get(iter, m_subject); + get(iter, m_sentTime); + get(iter, m_status); + + m_interface->m_fromName = m_fromName; + m_interface->m_fromAddress = m_fromAddress; + m_interface->m_subject = m_subject; +} + +void PersistentHeaderCore::setFolder(Base::ByteStream::ReadIterator &iter) +{ + get(iter, m_folder); + + m_interface->m_folder = m_folder; +} + + +void PersistentHeaderCore::setCategory(Base::ByteStream::ReadIterator &iter) +{ + get(iter, m_category); + + m_interface->m_category = m_category; +} + +PersistentMessageCore::PersistentMessageCore() +: m_messageID(0), + m_avatarID(0), + m_sentTime(0), + m_status(0), + m_fetchResult(0) +{ +} + +PersistentMessageCore::~PersistentMessageCore() +{ +} + +void PersistentMessageCore::load(Base::ByteStream::ReadIterator &iter) +{ + Plat_Unicode::String wideString; + + get(iter, m_messageID); + get(iter, m_avatarID); + + get(iter, wideString); + m_fromName = wideString; + + get(iter, wideString); + m_fromAddress = wideString; + + get(iter, wideString); + m_subject = wideString; + + get(iter, m_sentTime); + get(iter, m_status); + + get(iter, wideString); + m_folder = wideString; + + get(iter, wideString); + m_category = wideString; + + get(iter, m_fetchResult); + + get(iter, wideString); + m_msg = wideString; + + get(iter, wideString); + m_oob = wideString; +} + +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessage.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessage.h new file mode 100644 index 00000000..6f71dcc0 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessage.h @@ -0,0 +1,59 @@ +#if !defined (PERSISTENTMESSAGE_H_) +#define PERSISTENTMESSAGE_H_ + +#include "ChatEnum.h" + +namespace ChatSystem +{ + class PersistentHeaderCore; + + class PersistentHeader + { + public: + PersistentHeader(); + ~PersistentHeader(); + + unsigned getMessageID() const; + unsigned getAvatarID() const; + const ChatUnicodeString &getFromName() const; + const ChatUnicodeString &getFromAddress() const; + const ChatUnicodeString &getSubject() const; + const ChatUnicodeString &getFolder() const; + const ChatUnicodeString &getCategory() const; + + unsigned getSentTime() const; + unsigned getStatus() const; + + friend class PersistentHeaderCore; + private: + ChatUnicodeString m_fromName; + ChatUnicodeString m_fromAddress; + ChatUnicodeString m_subject; + ChatUnicodeString m_folder; + ChatUnicodeString m_category; + + PersistentHeaderCore *m_core; + }; + + class PersistentMessage + { + public: + virtual unsigned getMessageID() const = 0; + virtual unsigned getAvatarID() const = 0; + virtual const ChatUnicodeString &getFromName() const = 0; + virtual const ChatUnicodeString &getFromAddress() const = 0; + virtual const ChatUnicodeString &getSubject() const = 0; + virtual const ChatUnicodeString &getFolder() const = 0; + virtual const ChatUnicodeString &getCategory() const = 0; + + virtual unsigned getSentTime() const = 0; + virtual unsigned getStatus() const = 0; + + virtual const ChatUnicodeString &getMsg() const = 0; + virtual const ChatUnicodeString &getOOB() const = 0; + }; + +}; +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessageCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessageCore.h new file mode 100644 index 00000000..0d228e6b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/PersistentMessageCore.h @@ -0,0 +1,86 @@ +#if !defined (PERSISTENTHEADERCORE_H_) +#define PERSISTENTHEADERCORE_H_ + +#include +#include +#include + +namespace ChatSystem +{ + + class PersistentHeader; + + class PersistentHeaderCore + { + public: + PersistentHeaderCore(); + ~PersistentHeaderCore(); + + unsigned getMessageID() const { return m_messageID; } + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getFromName() const { return m_fromName; } + const Plat_Unicode::String &getFromAddress() const { return m_fromAddress; } + const Plat_Unicode::String &getSubject() const { return m_subject; } + const Plat_Unicode::String &getFolder() const { return m_folder; } + + unsigned getSentTime() const { return m_sentTime; } + unsigned getStatus() const { return m_status; } + void load(Base::ByteStream::ReadIterator &iter, PersistentHeader *inf); + void setFolder(Base::ByteStream::ReadIterator &iter); + void setCategory(Base::ByteStream::ReadIterator &iter); + private: + unsigned m_messageID; + unsigned m_avatarID; + unsigned m_sentTime; + unsigned m_status; + Plat_Unicode::String m_fromName; + Plat_Unicode::String m_fromAddress; + Plat_Unicode::String m_subject; + Plat_Unicode::String m_folder; + Plat_Unicode::String m_category; + + PersistentHeader *m_interface; + }; + + class PersistentMessageCore : public PersistentMessage + { + public: + PersistentMessageCore(); + virtual ~PersistentMessageCore(); + + // PersistentMessage implementations + virtual unsigned getMessageID() const { return m_messageID; } + virtual unsigned getAvatarID() const { return m_avatarID; } + virtual const ChatUnicodeString &getFromName() const { return m_fromName; } + virtual const ChatUnicodeString &getFromAddress() const { return m_fromAddress; } + virtual const ChatUnicodeString &getSubject() const { return m_subject; } + virtual const ChatUnicodeString &getFolder() const { return m_folder; } + virtual const ChatUnicodeString &getCategory() const { return m_category; } + + virtual unsigned getSentTime() const { return m_sentTime; } + virtual unsigned getStatus() const { return m_status; } + + virtual const ChatUnicodeString &getMsg() const { return m_msg; } + virtual const ChatUnicodeString &getOOB() const { return m_oob; } + + void load(Base::ByteStream::ReadIterator &iter); + + private: + unsigned m_messageID; + unsigned m_avatarID; + unsigned m_sentTime; + unsigned m_status; + unsigned m_fetchResult; + ChatUnicodeString m_fromName; + ChatUnicodeString m_fromAddress; + ChatUnicodeString m_subject; + ChatUnicodeString m_folder; + ChatUnicodeString m_category; + ChatUnicodeString m_msg; + ChatUnicodeString m_oob; + }; + +}; +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Request.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Request.cpp new file mode 100644 index 00000000..e58b011c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Request.cpp @@ -0,0 +1,1575 @@ +#include "Request.h" +#include "ChatRoom.h" +#include "ChatAvatarCore.h" +#include "ChatRoomCore.h" +#include "PersistentMessage.h" + +namespace ChatSystem +{ + +using namespace Base; +using namespace Plat_Unicode; + +RLoginAvatar::RLoginAvatar(unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &avatarLoginLocation, int avatarLoginPriority, int avatarLoginAttributes) +: GenericRequest(REQUEST_LOGINAVATAR), + m_userID(userID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length), + m_loginLocation(avatarLoginLocation.string_data, avatarLoginLocation.string_length), + m_loginPriority(avatarLoginPriority), + m_loginAttributes(avatarLoginAttributes) +{ +} + +void RLoginAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_userID); + put(msg, m_name); + put(msg, m_address); + put(msg, m_loginLocation); + put(msg, m_loginPriority); + put(msg, m_loginAttributes); +} + +RTemporaryAvatar::RTemporaryAvatar(unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &avatarLoginLocation ) +: GenericRequest(REQUEST_TEMPORARYAVATAR), +m_userID(userID), +m_name(name.string_data, name.string_length), +m_address(address.string_data, address.string_length), +m_loginLocation(avatarLoginLocation.string_data, avatarLoginLocation.string_length) +{ +} + +void RTemporaryAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_userID); + put(msg, m_name); + put(msg, m_address); + put(msg, m_loginLocation); +} + +RLogoutAvatar::RLogoutAvatar(unsigned avatarID, const ChatUnicodeString & address) +: GenericRequest(REQUEST_LOGOUTAVATAR) +, m_avatarID(avatarID) +, m_address(address.string_data, address.string_length) +{ +} + +void RLogoutAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, m_address); +} + +RDestroyAvatar::RDestroyAvatar(unsigned avatarID, const ChatUnicodeString & address) +: GenericRequest(REQUEST_DESTROYAVATAR) +, m_avatarID(avatarID) +, m_address(address.string_data, address.string_length) +{ +} + +void RDestroyAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, m_address); +} + +RSetAvatarKeywords::RSetAvatarKeywords(unsigned srcAvatarID, const ChatUnicodeString *keywordsList, unsigned keywordsLength) +: GenericRequest(REQUEST_SETAVATARKEYWORDS), + m_srcAvatarID(srcAvatarID), + m_keywordsLength(keywordsLength) +{ + m_keywordsList = new String[keywordsLength]; + for(unsigned i = 0; i < keywordsLength; i++) + { + m_keywordsList[i].assign(keywordsList[i].string_data, keywordsList[i].string_length); + } +} + +RSetAvatarKeywords::~RSetAvatarKeywords() +{ + delete[] m_keywordsList; +} + +void RSetAvatarKeywords::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_keywordsLength); + for(unsigned i = 0; i < m_keywordsLength; i++) + { + put(msg, m_keywordsList[i]); + } +} + +RGetAvatarKeywords::RGetAvatarKeywords(unsigned srcAvatarID) +: GenericRequest(REQUEST_GETAVATARKEYWORDS), + m_srcAvatarID(srcAvatarID) +{ +} + +void RGetAvatarKeywords::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); +} + +RSearchAvatarKeywords::RSearchAvatarKeywords(const ChatUnicodeString nodeAddress, const ChatUnicodeString *keywordsList, unsigned keywordsLength) +: GenericRequest(REQUEST_SEARCHAVATARKEYWORDS), + m_keywordsLength(keywordsLength), + m_keywordsList(NULL) +{ + m_nodeAddress.assign(nodeAddress.string_data); + m_keywordsList = new String[keywordsLength]; + for(unsigned i = 0; i < keywordsLength; i++) + { + m_keywordsList[i].assign(keywordsList[i].string_data, keywordsList[i].string_length); + } +} + +RSearchAvatarKeywords::~RSearchAvatarKeywords() +{ + delete[] m_keywordsList; +} + +void RSearchAvatarKeywords::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_nodeAddress); + put(msg, m_keywordsLength); + for(unsigned i = 0; i < m_keywordsLength; i++) + { + put(msg, m_keywordsList[i]); + } +} + +RGetAvatar::RGetAvatar(const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_GETAVATAR), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RGetAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_destName); + put(msg, m_destAddress); +} + +RGetAnyAvatar::RGetAnyAvatar(const ChatUnicodeString& destName, const ChatUnicodeString& destAddress) + : GenericRequest(REQUEST_GETANYAVATAR) + , m_destName(destName.string_data, destName.string_length) + , m_destAddress(destAddress.string_data, destAddress.string_length ) +{ +} + +void RGetAnyAvatar::pack(Base::ByteStream& msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_destName); + put(msg, m_destAddress); +} + +RAvatarList::RAvatarList(unsigned userID) + : GenericRequest(REQUEST_AVATARLIST) + , m_userID( userID ) +{ +} + +void RAvatarList::pack(Base::ByteStream& msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_userID); +} + +RSetAvatarAttributes::RSetAvatarAttributes(unsigned avatarID, const ChatUnicodeString &srcAddress, unsigned long avatarAttributes, bool persistent) +: GenericRequest(REQUEST_SETAVATARATTRIBUTES), + m_avatarID(avatarID), + m_avatarAttributes(avatarAttributes), + m_persistent(persistent), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RSetAvatarAttributes::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, (uint32)m_avatarAttributes); + put(msg, m_persistent); + put(msg, m_srcAddress); +} + +RSetAvatarStatusMessage::RSetAvatarStatusMessage(unsigned avatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString& statusMessage) +: GenericRequest(REQUEST_SETAVATARSTATUSMESSAGE), +m_avatarID(avatarID), +m_statusMessage(statusMessage.data(),statusMessage.length()), +m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RSetAvatarStatusMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, m_statusMessage); + put(msg, m_srcAddress); +} + +RSetAvatarForwardingEmail::RSetAvatarForwardingEmail(unsigned avatarID, const ChatUnicodeString &avatarForwardingEmail) +: GenericRequest(REQUEST_SETAVATAREMAIL), + m_avatarID(avatarID), + m_avatarForwardingEmail(avatarForwardingEmail.data(), avatarForwardingEmail.length()) +{ +} + +void RSetAvatarForwardingEmail::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, m_avatarForwardingEmail); +} + +RSetAvatarInboxLimit::RSetAvatarInboxLimit(unsigned avatarID, unsigned long avatarInboxLimit) +: GenericRequest(REQUEST_SETAVATARINBOXLIMIT), + m_avatarID(avatarID), + m_avatarInboxLimit(avatarInboxLimit) +{ +} + +void RSetAvatarInboxLimit::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, (uint32)m_avatarInboxLimit); +} + +RGetRoom::RGetRoom(const ChatUnicodeString &roomAddress) +: GenericRequest(REQUEST_GETROOM), + m_roomAddress(roomAddress.string_data, roomAddress.string_length) +{ +} + +void RGetRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_roomAddress); +} + +RCreateRoom::RCreateRoom(unsigned avatarID, const ChatUnicodeString & srcAddress, const RoomParams ¶ms, const ChatUnicodeString &roomAddress) +: GenericRequest(REQUEST_CREATEROOM), + m_avatarID(avatarID), + m_roomName(params.getRoomName().string_data, params.getRoomName().string_length), + m_roomTopic(params.getRoomTopic().string_data, params.getRoomTopic().string_length), + m_roomPassword(params.getRoomPassword().string_data, params.getRoomPassword().string_length), + m_roomAttributes(params.getRoomAttributes()), + m_maxRoomSize(params.getRoomMaxSize()), + m_roomAddress(roomAddress.string_data, roomAddress.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RCreateRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, m_roomName); + put(msg, m_roomTopic); + put(msg, m_roomPassword); + put(msg, m_roomAttributes); + put(msg, m_maxRoomSize); + put(msg, m_roomAddress); + put(msg, m_srcAddress); +} + +RDestroyRoom::RDestroyRoom(unsigned avatarID, const ChatUnicodeString & srcAddress, const ChatUnicodeString &roomAddress) +: GenericRequest(REQUEST_DESTROYROOM), + m_avatarID(avatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RDestroyRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarID); + put(msg, m_roomAddress); + put(msg, m_srcAddress); +} + +RSendInstantMessage::RSendInstantMessage(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +: GenericRequest(REQUEST_SENDINSTANTMESSAGE), + m_srcAvatarID(srcAvatarID), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RSendInstantMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_msg); + put(msg, m_oob); + put(msg, m_srcAddress); +} + +RSendRoomMessage::RSendRoomMessage(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +: GenericRequest(REQUEST_SENDROOMMESSAGE), + m_srcAvatarID(srcAvatarID), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RSendRoomMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destRoomAddress); + put(msg, m_msg); + put(msg, m_oob); + put(msg, m_srcAddress); +} + +RSendBroadcastMessage::RSendBroadcastMessage(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob) +: GenericRequest(REQUEST_SENDBROADCASTMESSAGE), + m_srcAvatarID(srcAvatarID), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RSendBroadcastMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAddress); + put(msg, m_msg); + put(msg, m_oob); + put(msg, m_srcAddress); +} + +RFilterMessage::RFilterMessage(const ChatUnicodeString &msg) +: GenericRequest(REQUEST_FILTERMESSAGE), + m_msg(msg.string_data, msg.string_length) +{ +} + +void RFilterMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_msg); +} + +RFilterMessageEx::RFilterMessageEx(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &msg) +: GenericRequest(REQUEST_FILTERMESSAGE_EX), + m_srcAvatarID(srcAvatarID), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_msg(msg.string_data, msg.string_length) +{ +} + +void RFilterMessageEx::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_msg); +} + +RAddFriend::RAddFriend(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment, bool confirm) +: GenericRequest(REQUEST_ADDFRIEND), + m_srcAvatarID(srcAvatarID), + m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_friendComment(friendComment.string_data, friendComment.string_length), + m_confirm(confirm) +{ +} + +void RAddFriend::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_friendComment); + put(msg, m_confirm); + put(msg, m_srcAddress); +} + +RAddFriendReciprocate::RAddFriendReciprocate(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment, bool confirm) +: GenericRequest(REQUEST_ADDFRIEND_RECIPROCATE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), +m_destName(destName.string_data, destName.string_length), +m_destAddress(destAddress.string_data, destAddress.string_length), +m_friendComment(friendComment.string_data, friendComment.string_length), +m_confirm(confirm) +{ +} + +void RAddFriendReciprocate::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_friendComment); + put(msg, m_confirm); + put(msg, m_srcAddress); +} + +RSetFriendComment::RSetFriendComment(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment) +: GenericRequest(REQUEST_SETFRIENDCOMMENT), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_friendComment(friendComment.string_data, friendComment.string_length) +{ +} + +void RSetFriendComment::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_friendComment); + put(msg, m_srcAddress); +} + +RRemoveFriend::RRemoveFriend(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_REMOVEFRIEND), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RRemoveFriend::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_srcAddress); +} +RRemoveFriendReciprocate::RRemoveFriendReciprocate(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_REMOVEFRIEND_RECIPROCATE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), +m_destName(destName.string_data, destName.string_length), +m_destAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RRemoveFriendReciprocate::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_srcAddress); +} +RFriendStatus::RFriendStatus(unsigned srcAvatarID, const ChatUnicodeString &srcAddress) +: GenericRequest(REQUEST_FRIENDSTATUS), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RFriendStatus::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_srcAddress); +} + +RAddIgnore::RAddIgnore(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_ADDIGNORE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RAddIgnore::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_srcAddress); +} + +RRemoveIgnore::RRemoveIgnore(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_REMOVEIGNORE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destName(destName.string_data, destName.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RRemoveIgnore::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destName); + put(msg, m_destAddress); + put(msg, m_srcAddress); +} + + +REnterRoom::REnterRoom(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &roomAddress, const ChatUnicodeString &roomPassword, const RoomParams *roomParams, bool requestingEntry) +: GenericRequest(REQUEST_ENTERROOM), + m_srcAvatarID(srcAvatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length), + m_roomPassword(roomPassword.string_data, roomPassword.string_length), + m_requestingEntry(requestingEntry), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ + if (roomParams) + { + // passive room creation if room address does not exist IS enabled + m_passiveCreate = true; + m_paramRoomTopic.assign(roomParams->getRoomTopic().string_data, roomParams->getRoomTopic().string_length); + m_paramRoomAttributes = roomParams->getRoomAttributes(); + m_paramRoomMaxSize = roomParams->getRoomMaxSize(); + } + else + { + // passive room creation disabled + m_passiveCreate = false; + } +} + +void REnterRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_roomAddress); + put(msg, m_roomPassword); + put(msg, m_passiveCreate); + + if (m_passiveCreate) + { + put(msg, m_paramRoomTopic); + put(msg, m_paramRoomAttributes); + put(msg, m_paramRoomMaxSize); + } + + put(msg, m_requestingEntry); + put(msg, m_srcAddress); + +} + +RAllowRoomEntry::RAllowRoomEntry(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, bool allow) +: GenericRequest(REQUEST_ALLOWROOMENTRY), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length), + m_allow(allow) +{ +} + +void RAllowRoomEntry::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_allow); + put(msg, m_srcAddress); +} + +RLeaveRoom::RLeaveRoom(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &roomAddress) +: GenericRequest(REQUEST_LEAVEROOM), + m_srcAvatarID(srcAvatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RLeaveRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_roomAddress); + put(msg, m_srcAddress); +} + +RAddModerator::RAddModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_ADDMODERATOR), + m_srcAvatarID(srcAvatarID), + m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RAddModerator::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RRemoveModerator::RRemoveModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_REMOVEMODERATOR), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RRemoveModerator::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RAddTemporaryModerator::RAddTemporaryModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_ADDTEMPORARYMODERATOR), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RAddTemporaryModerator::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RRemoveTemporaryModerator::RRemoveTemporaryModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_REMOVETEMPORARYMODERATOR), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RRemoveTemporaryModerator::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + + +RAddBan::RAddBan(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_ADDBAN), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RAddBan::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RRemoveBan::RRemoveBan(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_REMOVEBAN), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RRemoveBan::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RAddInvite::RAddInvite(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_ADDINVITE), + m_srcAvatarID(srcAvatarID), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RAddInvite::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RRemoveInvite::RRemoveInvite(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_REMOVEINVITE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RRemoveInvite::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RGrantVoice::RGrantVoice(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_GRANTVOICE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RGrantVoice::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RRevokeVoice::RRevokeVoice(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_REVOKEVOICE), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RRevokeVoice::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RKickAvatar::RKickAvatar(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_KICKAVATAR), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destAvatarName(destAvatarName.string_data, destAvatarName.string_length), + m_destAvatarAddress(destAvatarAddress.string_data, destAvatarAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RKickAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + put(msg, m_destRoomAddress); + put(msg, m_srcAddress); +} + +RSetRoomParams::RSetRoomParams(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destRoomAddress, const RoomParams *params) + +: GenericRequest(REQUEST_SETROOMPARAMS), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ + // we take in a const RoomParams, so make our own and guarantee + // null-terminated char buffers. + m_newRoomName.assign(params->getRoomName().string_data, params->getRoomName().string_length); + m_newRoomTopic.assign(params->getRoomTopic().string_data, params->getRoomTopic().string_length); + m_newRoomPassword.assign(params->getRoomPassword().string_data, params->getRoomPassword().string_length); + m_newRoomAttributes = params->getRoomAttributes(); + m_newRoomSize = params->getRoomMaxSize(); +} + +void RSetRoomParams::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destRoomAddress); + put(msg, m_newRoomName); + put(msg, m_newRoomTopic); + put(msg, m_newRoomPassword); + put(msg, m_newRoomAttributes); + put(msg, m_newRoomSize); + put(msg, m_srcAddress); +} + +RChangeRoomOwner::RChangeRoomOwner(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress) +: GenericRequest(REQUEST_CHANGEROOMOWNER), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length), + m_newRoomOwnerName(destAvatarName.data(), destAvatarName.length()), + m_newRoomOwnerAddress(destAvatarAddress.data(), destAvatarAddress.length()) +{ +} + +void RChangeRoomOwner::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destRoomAddress); + put(msg, m_newRoomOwnerName); + put(msg, m_newRoomOwnerAddress); + put(msg, m_srcAddress); +} + +RGetRoomSummaries::RGetRoomSummaries(const ChatUnicodeString &startNodeAddress, const ChatUnicodeString &roomFilter) +: GenericRequest(REQUEST_GETROOMSUMMARIES), + m_startNodeAddress(startNodeAddress.string_data, startNodeAddress.string_length), + m_roomFilter(roomFilter.string_data, roomFilter.string_length) +{ +} + +void RGetRoomSummaries::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_startNodeAddress); + put(msg, m_roomFilter); +} + +RSendPersistentMessage::RSendPersistentMessage(const ChatUnicodeString &src, const ChatUnicodeString &destAvatar, const ChatUnicodeString &destAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit) +: GenericRequest(REQUEST_SENDPERSISTENTMESSAGE), + m_avatarPresence(0), + m_srcName(src.string_data, src.string_length), + m_destAvatar(destAvatar.string_data, destAvatar.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_subject(subject.string_data, subject.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_category(category.string_data, category.string_length), + m_enforceInboxLimit(enforceInboxLimit), + m_categoryLimit(categoryLimit) +{ +} + +RSendPersistentMessage::RSendPersistentMessage(unsigned srcAvatarID, const ChatUnicodeString &destAvatar, const ChatUnicodeString &destAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit) +: GenericRequest(REQUEST_SENDPERSISTENTMESSAGE), + m_avatarPresence(1), + m_srcAvatarID(srcAvatarID), + m_destAvatar(destAvatar.string_data, destAvatar.string_length), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_subject(subject.string_data, subject.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_category(category.string_data, category.string_length), + m_enforceInboxLimit(enforceInboxLimit), + m_categoryLimit(categoryLimit) +{ +} + +void RSendPersistentMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarPresence); + if(m_avatarPresence) + { + put(msg, m_srcAvatarID); + } + else + { + put(msg, m_srcName); + } + put(msg, m_destAvatar); + put(msg, m_destAddress); + put(msg, m_subject); + put(msg, m_msg); + put(msg, m_oob); + put(msg, m_category); + put(msg, m_enforceInboxLimit); + put(msg, m_categoryLimit); +} + +RSendMultiplePersistentMessages::RSendMultiplePersistentMessages(const ChatUnicodeString &src, unsigned numDestAvatars, const ChatUnicodeString *destAvatars, const ChatUnicodeString *destAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit) +: GenericRequest(REQUEST_SENDMULTIPLEPERSISTENTMESSAGES), + m_avatarPresence(0), + m_srcName(src.string_data, src.string_length), + m_numDestAvatars(numDestAvatars), + m_subject(subject.string_data, subject.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_category(category.string_data, category.string_length), + m_enforceInboxLimit(enforceInboxLimit), + m_categoryLimit(categoryLimit) +{ + unsigned destIndex; + + m_destAvatars.resize(m_numDestAvatars); + m_destAddresses.resize(m_numDestAvatars); + + for (destIndex = 0; destIndex < m_numDestAvatars; destIndex++) + { + m_destAvatars[destIndex].assign(destAvatars[destIndex].string_data, destAvatars[destIndex].string_length); + m_destAddresses[destIndex].assign(destAddresses[destIndex].string_data, destAddresses[destIndex].string_length); + } +} + +RSendMultiplePersistentMessages::RSendMultiplePersistentMessages(unsigned srcAvatarID, unsigned numDestAvatars, const ChatUnicodeString *destAvatars, const ChatUnicodeString *destAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit) +: GenericRequest(REQUEST_SENDMULTIPLEPERSISTENTMESSAGES), + m_avatarPresence(1), + m_srcAvatarID(srcAvatarID), + m_numDestAvatars(numDestAvatars), + m_subject(subject.string_data, subject.string_length), + m_msg(msg.string_data, msg.string_length), + m_oob(oob.string_data, oob.string_length), + m_category(category.string_data, category.string_length), + m_enforceInboxLimit(enforceInboxLimit), + m_categoryLimit(categoryLimit) +{ + unsigned destIndex; + + m_destAvatars.resize(m_numDestAvatars); + m_destAddresses.resize(m_numDestAvatars); + + for (destIndex = 0; destIndex < m_numDestAvatars; destIndex++) + { + m_destAvatars[destIndex].assign(destAvatars[destIndex].string_data, destAvatars[destIndex].string_length); + m_destAddresses[destIndex].assign(destAddresses[destIndex].string_data, destAddresses[destIndex].string_length); + } +} + +void RSendMultiplePersistentMessages::pack(ByteStream &msg) +{ + unsigned destIndex; + + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarPresence); + if(m_avatarPresence) + { + put(msg, m_srcAvatarID); + } + else + { + put(msg, m_srcName); + } + put(msg, m_numDestAvatars); + for (destIndex = 0; destIndex < m_numDestAvatars; destIndex++) + { + put(msg, m_destAvatars[destIndex]); + put(msg, m_destAddresses[destIndex]); + } + put(msg, m_subject); + put(msg, m_msg); + put(msg, m_oob); + put(msg, m_category); + put(msg, m_enforceInboxLimit); + put(msg, m_categoryLimit); +} + +RAlterPersistentMessage::RAlterPersistentMessage(const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID, unsigned alterationAttributes, const ChatUnicodeString &newSenderName, const ChatUnicodeString &newSenderAddress, const ChatUnicodeString &newSubject, const ChatUnicodeString &newMsg, const ChatUnicodeString &newOOB, const ChatUnicodeString &newCategory, unsigned newSentTime) +: GenericRequest(REQUEST_ALTERPERISTENTMESSAGE), + m_destAvatarName(destAvatarName.data(), destAvatarName.length()), + m_destAvatarAddress(destAvatarAddress.data(), destAvatarAddress.length()), + m_messageID(messageID), + m_alterationAttributes(alterationAttributes), + m_newSenderName(newSenderName.data(), newSenderName.length()), + m_newSenderAddress(newSenderAddress.data(), newSenderAddress.length()), + m_newSubject(newSubject.data(), newSubject.length()), + m_newMsg(newMsg.data(), newMsg.length()), + m_newOOB(newOOB.data(), newOOB.length()), + m_newCategory(newCategory.data(), newCategory.length()), + m_newSentTime(newSentTime) +{ +} + +RAlterPersistentMessage::~RAlterPersistentMessage() +{ +} + +void RAlterPersistentMessage::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); + + put(msg, m_messageID); + put(msg, m_alterationAttributes); + put(msg, m_newSenderName); + put(msg, m_newSenderAddress); + put(msg, m_newSubject); + put(msg, m_newMsg); + put(msg, m_newOOB); + put(msg, m_newCategory); + put(msg, m_newSentTime); +} + +RGetPersistentHeaders::RGetPersistentHeaders(unsigned srcAvatarID, const ChatUnicodeString &category) +: GenericRequest(REQUEST_GETPERSISTENTHEADERS), + m_srcAvatarID(srcAvatarID), + m_category(category.string_data, category.string_length) +{ +} + +void RGetPersistentHeaders::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_category); +} + +RGetPartialPersistentHeaders::RGetPartialPersistentHeaders(unsigned srcAvatarID, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category) +: GenericRequest(REQUEST_PARTIALPERSISTENTHEADERS), + m_srcAvatarID(srcAvatarID), + m_maxHeaders(maxHeaders), + m_inDescendingOrder(inDescendingOrder), + m_sentTimeStart(sentTimeStart), + m_category(category.string_data, category.string_length) +{ +} + +void RGetPartialPersistentHeaders::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_maxHeaders); + put(msg, m_inDescendingOrder); + put(msg, m_sentTimeStart); + put(msg, m_category); +} + +RCountPersistentMessages::RCountPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category) +: GenericRequest(REQUEST_COUNTPERSISTENTMESSAGES), + m_avatarName(avatarName.string_data, avatarName.string_length), + m_avatarAddress(avatarAddress.string_data, avatarAddress.string_length), + m_category(category.string_data, category.string_length) +{ +} + +void RCountPersistentMessages::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarName); + put(msg, m_avatarAddress); + put(msg, m_category); +} + +RGetPersistentMessage::RGetPersistentMessage(unsigned srcAvatarID, unsigned messageID) +: GenericRequest(REQUEST_GETPERSISTENTMESSAGE), + m_srcAvatarID(srcAvatarID), + m_messageID(messageID) +{ +} + +void RGetPersistentMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_messageID); +} + +RGetMultiplePersistentMessages::RGetMultiplePersistentMessages(unsigned srcAvatarID, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category) +: GenericRequest(REQUEST_GETMULTIPLEPERSISTENTMESSAGES), + m_srcAvatarID(srcAvatarID), + m_maxHeaders(maxHeaders), + m_inDescendingOrder(inDescendingOrder), + m_sentTimeStart(sentTimeStart), + m_category(category.string_data, category.string_length) +{ +} + +void RGetMultiplePersistentMessages::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_maxHeaders); + put(msg, m_inDescendingOrder); + put(msg, m_sentTimeStart); + put(msg, m_category); +} + +RUpdatePersistentMessage::RUpdatePersistentMessage(unsigned srcAvatarID, unsigned messageID, PersistentStatus status) +: GenericRequest(REQUEST_UPDATEPERSISTENTMESSAGE), + m_srcAvatarID(srcAvatarID), + m_messageID(messageID), + m_status(status) +{ +} + +void RUpdatePersistentMessage::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_messageID); + put(msg, m_status); +} + +RUpdatePersistentMessages::RUpdatePersistentMessages(unsigned srcAvatarID, PersistentStatus currentStatus, PersistentStatus newStatus, const ChatUnicodeString &category) +: GenericRequest(REQUEST_UPDATEPERSISTENTMESSAGES), + m_srcAvatarID(srcAvatarID), + m_currentStatus(currentStatus), + m_newStatus(newStatus), + m_category(category.string_data, category.string_length) +{ +} + +void RUpdatePersistentMessages::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_currentStatus); + put(msg, m_newStatus); + put(msg, m_category); +} + +RClassifyPersistentMessages::RClassifyPersistentMessages(unsigned srcAvatarID, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder) +: GenericRequest(REQUEST_CHANGEPERSISTENTFOLDER), + m_srcAvatarID(srcAvatarID), + m_newFolder(newFolder.data(), newFolder.length()) +{ + for (; numIDs > 0; numIDs--) + { + m_messageIDs.insert(messageIDs[numIDs - 1]); + } +} + +RClassifyPersistentMessages::RClassifyPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder) +: GenericRequest(REQUEST_CHANGEPERSISTENTFOLDER), + m_srcAvatarID(0), + m_avatarName(avatarName.data(), avatarName.length()), + m_avatarAddress(avatarAddress.data(), avatarAddress.length()), + m_newFolder(newFolder.data(), newFolder.length()) +{ + for (; numIDs > 0; numIDs--) + { + m_messageIDs.insert(messageIDs[numIDs - 1]); + } +} + +void RClassifyPersistentMessages::pack(ByteStream &msg) +{ + std::set::iterator idIter; + + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_messageIDs.size()); + for (idIter = m_messageIDs.begin(); idIter != m_messageIDs.end(); idIter++) + { + put(msg, *idIter); + } + put(msg, m_newFolder); + put(msg, m_avatarName); + put(msg, m_avatarAddress); +} + +RDeleteAllPersistentMessages::RDeleteAllPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category, unsigned olderThan) +: GenericRequest(REQUEST_PURGEPERSISTENTMESSAGES), + m_avatarName(avatarName.string_data, avatarName.string_length), + m_avatarAddress(avatarAddress.string_data, avatarAddress.string_length), + m_category(category.string_data, category.string_length), + m_olderThan(olderThan) +{ +} + +void RDeleteAllPersistentMessages::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatarName); + put(msg, m_avatarAddress); + put(msg, m_category); + put(msg, m_olderThan); +} + +RUnregisterRoom::RUnregisterRoom(const ChatUnicodeString &destRoomAddress) +: GenericRequest(REQUEST_UNREGISTERROOM), +m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void RUnregisterRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_destRoomAddress); +} + +RIgnoreStatus::RIgnoreStatus(unsigned srcAvatarID, const ChatUnicodeString &srcAddress) +: GenericRequest(REQUEST_IGNORESTATUS), +m_srcAvatarID(srcAvatarID), +m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RIgnoreStatus::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_srcAddress); +} + +RFailoverReloginAvatar::RFailoverReloginAvatar(ChatAvatarCore *avatar) +: GenericRequest(REQUEST_FAILOVER_RELOGINAVATAR), + m_avatar(avatar) +{ +} + +void RFailoverReloginAvatar::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_avatar->getAvatarID()); + put(msg, m_avatar->getUserID()); + put(msg, m_avatar->getName()); + put(msg, m_avatar->getAddress()); + put(msg, m_avatar->getLoginLocation()); + put(msg, m_avatar->getLoginPriority()); + put(msg, m_avatar->getAttributes()); +} + +RFailoverRecreateRoom::RFailoverRecreateRoom(ChatRoomCore *room) +: GenericRequest(REQUEST_FAILOVER_RECREATEROOM), + m_room(room) +{ +} + +void RFailoverRecreateRoom::pack(ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + + // send full room object, except that the avatars sent only + // includes those on the API--"each API for itself" method reduces + // the amount of wasted iterations on the server. + m_room->serializeWithLocalAvatarsOnly(msg); +} + +RFriendConfirm::RFriendConfirm(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, unsigned destAvatarID, bool confirm) +: GenericRequest(REQUEST_CONFIRMFRIEND), + m_srcAvatarID(srcAvatarID), + m_destAvatarID(destAvatarID), + m_confirm(confirm != 0), + m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RFriendConfirm::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarID); + put(msg, m_confirm); + put(msg, m_srcAddress); +} + +RFriendConfirmReciprocate::RFriendConfirmReciprocate(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, unsigned destAvatarID, bool confirm) +: GenericRequest(REQUEST_CONFIRMFRIEND_RECIPROCATE), +m_srcAvatarID(srcAvatarID), +m_destAvatarID(destAvatarID), +m_confirm(confirm != 0), +m_srcAddress(srcAddress.string_data, srcAddress.string_length) +{ +} + +void RFriendConfirmReciprocate::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarID); + put(msg, m_confirm); + put(msg, m_srcAddress); +} + +RGetFanClubHandle::RGetFanClubHandle(unsigned stationID, unsigned fanClubCode) +: GenericRequest(REQUEST_GETFANCLUBHANDLE), + m_stationID(stationID), + m_fanClubCode(fanClubCode) +{ +} + +void RGetFanClubHandle::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_stationID); + put(msg, m_fanClubCode); +} + +RFindAvatarByUID::RFindAvatarByUID(unsigned userID) +: GenericRequest(REQUEST_FINDAVATARBYUID), + m_userID(userID) +{ +} + +void RFindAvatarByUID::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_userID); +} + +RRegistrarGetChatServer::RRegistrarGetChatServer(std::string &hostname, unsigned short port) +: GenericRequest(REQUEST_REGISTRAR_GETCHATSERVER), + m_hostname(narrowToWide(hostname)), + m_port(port) +{ +} + +void RRegistrarGetChatServer::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_hostname); + put(msg, m_port); +} + +RSendApiVersion::RSendApiVersion(unsigned long version) +: GenericRequest(REQUEST_SETAPIVERSION), + m_version(version) +{ +} + +void RSendApiVersion::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, (uint32)m_version); +} + +RAddSnoopAvatar::RAddSnoopAvatar(unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_ADDSNOOPAVATAR), + m_srcAvatarID(srcAvatarID), + m_destAvatarName(destName.string_data, destName.string_length), + m_destAvatarAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RAddSnoopAvatar::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); +} + +RRemoveSnoopAvatar::RRemoveSnoopAvatar(unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericRequest(REQUEST_REMOVESNOOPAVATAR), + m_srcAvatarID(srcAvatarID), + m_destAvatarName(destName.string_data, destName.string_length), + m_destAvatarAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void RRemoveSnoopAvatar::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_destAvatarName); + put(msg, m_destAvatarAddress); +} + +RAddSnoopRoom::RAddSnoopRoom(unsigned srcAvatarID, const ChatUnicodeString &roomAddress) +: GenericRequest(REQUEST_ADDSNOOPROOM), + m_srcAvatarID(srcAvatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length) +{ +} + +void RAddSnoopRoom::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_roomAddress); +} + +RRemoveSnoopRoom::RRemoveSnoopRoom(unsigned srcAvatarID, const ChatUnicodeString &roomAddress) +: GenericRequest(REQUEST_REMOVESNOOPROOM), + m_srcAvatarID(srcAvatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length) +{ +} + +void RRemoveSnoopRoom::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); + put(msg, m_roomAddress); +} + +RGetSnoopList::RGetSnoopList(unsigned srcAvatarID) +: GenericRequest(REQUEST_GETSNOOPLIST), + m_srcAvatarID(srcAvatarID) +{ +} + +void RGetSnoopList::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_srcAvatarID); +} + +RTransferAvatar::RTransferAvatar(unsigned userID, unsigned newUserID, const ChatUnicodeString &avatarName, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &newAvatarAddress, bool transferPersistentMessages) +: GenericRequest(REQUEST_TRANSFERAVATAR), + m_userID(userID), + m_newUserID(newUserID), + m_avatarName(avatarName.string_data, avatarName.string_length), + m_newAvatarName(newAvatarName.string_data, newAvatarName.string_length), + m_avatarAddress(avatarAddress.string_data, avatarAddress.string_length), + m_newAvatarAddress(newAvatarAddress.string_data, newAvatarAddress.string_length), + m_transferPersistentMessages(transferPersistentMessages) +{ +} + +void RTransferAvatar::pack(Base::ByteStream &msg) +{ + put(msg, m_type); + put(msg, m_track); + put(msg, m_userID); + put(msg, m_newUserID); + put(msg, m_avatarName); + put(msg, m_newAvatarName); + put(msg, m_avatarAddress); + put(msg, m_newAvatarAddress); + put(msg, m_transferPersistentMessages); +} + + +}; + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Request.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Request.h new file mode 100644 index 00000000..d29e00b8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Request.h @@ -0,0 +1,1238 @@ +#if !defined (REQUEST_H_) +#define REQUEST_H_ + +#pragma warning (disable : 4786) + +#include +#include +#include + +#include "ChatEnum.h" +#include "ChatRoom.h" + +#include + +namespace ChatSystem { + + +class RoomParams; +class ChatAvatarCore; +enum PersistentStatus; + +enum RequestType +{ + REQUEST_LOGINAVATAR = 0, + REQUEST_LOGOUTAVATAR, + REQUEST_DESTROYAVATAR, + REQUEST_GETAVATAR, + REQUEST_CREATEROOM, + REQUEST_DESTROYROOM, // 5 + REQUEST_SENDINSTANTMESSAGE, + REQUEST_SENDROOMMESSAGE, + REQUEST_SENDBROADCASTMESSAGE, + REQUEST_ADDFRIEND, + REQUEST_REMOVEFRIEND, // 10 + REQUEST_FRIENDSTATUS, + REQUEST_ADDIGNORE, + REQUEST_REMOVEIGNORE, + REQUEST_ENTERROOM, + REQUEST_LEAVEROOM, // 15 + REQUEST_ADDMODERATOR, + REQUEST_REMOVEMODERATOR, + REQUEST_ADDBAN, + REQUEST_REMOVEBAN, + REQUEST_ADDINVITE, // 20 + REQUEST_REMOVEINVITE, + REQUEST_KICKAVATAR, + REQUEST_SETROOMPARAMS, + REQUEST_GETROOM, + REQUEST_GETROOMSUMMARIES, // 25 + REQUEST_SENDPERSISTENTMESSAGE, + REQUEST_GETPERSISTENTHEADERS, + REQUEST_GETPERSISTENTMESSAGE, + REQUEST_UPDATEPERSISTENTMESSAGE, + REQUEST_UNREGISTERROOM, // 30 + REQUEST_IGNORESTATUS, + REQUEST_FAILOVER_RELOGINAVATAR, + REQUEST_FAILOVER_RECREATEROOM, + REQUEST_CONFIRMFRIEND, + REQUEST_GETAVATARKEYWORDS, // 35 + REQUEST_SETAVATARKEYWORDS, + REQUEST_SEARCHAVATARKEYWORDS, + REQUEST_GETFANCLUBHANDLE, + REQUEST_UPDATEPERSISTENTMESSAGES, + REQUEST_FINDAVATARBYUID, // 40 + REQUEST_CHANGEROOMOWNER, + REQUEST_SETAPIVERSION, + REQUEST_ADDTEMPORARYMODERATOR, + REQUEST_REMOVETEMPORARYMODERATOR, + REQUEST_GRANTVOICE, // 45 + REQUEST_REVOKEVOICE, + REQUEST_SETAVATARATTRIBUTES, + REQUEST_ADDSNOOPAVATAR, + REQUEST_REMOVESNOOPAVATAR, + REQUEST_ADDSNOOPROOM, // 50 + REQUEST_REMOVESNOOPROOM, + REQUEST_GETSNOOPLIST, + REQUEST_PARTIALPERSISTENTHEADERS, + REQUEST_COUNTPERSISTENTMESSAGES, + REQUEST_PURGEPERSISTENTMESSAGES, // 55 + REQUEST_SETFRIENDCOMMENT, + REQUEST_TRANSFERAVATAR, + REQUEST_CHANGEPERSISTENTFOLDER, + REQUEST_ALLOWROOMENTRY, + REQUEST_SETAVATAREMAIL, // 60 + REQUEST_SETAVATARINBOXLIMIT, + REQUEST_SENDMULTIPLEPERSISTENTMESSAGES, + REQUEST_GETMULTIPLEPERSISTENTMESSAGES, + REQUEST_ALTERPERISTENTMESSAGE, + REQUEST_GETANYAVATAR, // 65 + REQUEST_TEMPORARYAVATAR, + REQUEST_AVATARLIST, + REQUEST_SETAVATARSTATUSMESSAGE, + REQUEST_CONFIRMFRIEND_RECIPROCATE, + REQUEST_ADDFRIEND_RECIPROCATE, // 70 + REQUEST_REMOVEFRIEND_RECIPROCATE, + REQUEST_FILTERMESSAGE, + REQUEST_FILTERMESSAGE_EX, + + REQUEST_REGISTRAR_GETCHATSERVER = 20001, +}; + +class RLoginAvatar : public GenericAPI::GenericRequest +{ +public: + RLoginAvatar(unsigned userID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &avatarLoginLocation, int avatarLoginPriority, int avatarLoginAttributes); + virtual ~RLoginAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_userID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_loginLocation; + int m_loginPriority; + int m_loginAttributes; +}; + +class RTemporaryAvatar : public GenericAPI::GenericRequest +{ +public: + RTemporaryAvatar(unsigned userID, const ChatUnicodeString& name, const ChatUnicodeString& address, const ChatUnicodeString& loginLocation ); + virtual ~RTemporaryAvatar() {} + + virtual void pack(Base::ByteStream& msg); + +private: + unsigned m_userID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_loginLocation; +}; + +class RLogoutAvatar : public GenericAPI::GenericRequest +{ +public: + RLogoutAvatar(unsigned avatarID, const ChatUnicodeString & address); + virtual ~RLogoutAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + Plat_Unicode::String m_address; +}; + +class RDestroyAvatar : public GenericAPI::GenericRequest +{ +public: + RDestroyAvatar(unsigned avatarID, const ChatUnicodeString & address); + virtual ~RDestroyAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + Plat_Unicode::String m_address; +}; + +class RSetAvatarKeywords : public GenericAPI::GenericRequest +{ +public: + RSetAvatarKeywords(unsigned srcAvatarID, const ChatUnicodeString *keywordsList, unsigned keywordsLength); + virtual ~RSetAvatarKeywords(); + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_keywordsLength; + Plat_Unicode::String *m_keywordsList; +}; + +class RGetAvatarKeywords : public GenericAPI::GenericRequest +{ +public: + RGetAvatarKeywords(unsigned srcAvatarID); + virtual ~RGetAvatarKeywords() {}; + + virtual void pack(Base::ByteStream &msg); +private: + unsigned m_srcAvatarID; +}; + +class RSearchAvatarKeywords : public GenericAPI::GenericRequest +{ +public: + RSearchAvatarKeywords(const ChatUnicodeString nodeAddress, const ChatUnicodeString *keywordsList, unsigned keywordsLength); + virtual ~RSearchAvatarKeywords(); + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_keywordsLength; + Plat_Unicode::String *m_keywordsList; + Plat_Unicode::String m_nodeAddress; +}; + +class RGetAvatar : public GenericAPI::GenericRequest +{ +public: + RGetAvatar(const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RGetAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; +}; + +class RGetAnyAvatar : public GenericAPI::GenericRequest +{ +public: + RGetAnyAvatar( const ChatUnicodeString& destName, const ChatUnicodeString& destAddress ); + virtual ~RGetAnyAvatar() {} + + virtual void pack(Base::ByteStream& msg); + +private: + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; +}; + +class RAvatarList : public GenericAPI::GenericRequest +{ +public: + RAvatarList( unsigned userID ); + virtual ~RAvatarList() {} + + virtual void pack(Base::ByteStream& msg); + +private: + unsigned m_userID; +}; + +class RSetAvatarAttributes : public GenericAPI::GenericRequest +{ +public: + RSetAvatarAttributes(unsigned avatarID, const ChatUnicodeString &srcAddress, unsigned long avatarAttributes, bool persistent = true ); + virtual ~RSetAvatarAttributes() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + unsigned long m_avatarAttributes; + unsigned m_persistent; + Plat_Unicode::String m_srcAddress; +}; + +class RSetAvatarStatusMessage : public GenericAPI::GenericRequest +{ +public: + RSetAvatarStatusMessage(unsigned avatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString& statusMessage ); + virtual ~RSetAvatarStatusMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + Plat_Unicode::String m_statusMessage; + Plat_Unicode::String m_srcAddress; +}; + +class RSetAvatarForwardingEmail : public GenericAPI::GenericRequest +{ +public: + RSetAvatarForwardingEmail(unsigned avatarID, const ChatUnicodeString &avatarForwardingEmail); + virtual ~RSetAvatarForwardingEmail() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + Plat_Unicode::String m_avatarForwardingEmail; +}; + + +class RSetAvatarInboxLimit : public GenericAPI::GenericRequest +{ +public: + RSetAvatarInboxLimit(unsigned avatarID, unsigned long avatarInboxLimit); + virtual ~RSetAvatarInboxLimit() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + unsigned long m_avatarInboxLimit; +}; + +class RGetRoom : public GenericAPI::GenericRequest +{ +public: + RGetRoom(const ChatUnicodeString &roomAddress); + virtual ~RGetRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_roomAddress; +}; + +class RCreateRoom : public GenericAPI::GenericRequest +{ +public: + RCreateRoom(unsigned avatarID, const ChatUnicodeString &srcAddress, const RoomParams ¶ms, const ChatUnicodeString &roomAddress); + + virtual ~RCreateRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + Plat_Unicode::String m_roomName; + Plat_Unicode::String m_roomTopic; + Plat_Unicode::String m_roomPassword; + unsigned m_roomAttributes; + unsigned m_maxRoomSize; + Plat_Unicode::String m_roomAddress; + Plat_Unicode::String m_srcAddress; +}; + +class RDestroyRoom : public GenericAPI::GenericRequest +{ +public: + RDestroyRoom(unsigned avatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAddress); + virtual ~RDestroyRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_avatarID; + Plat_Unicode::String m_roomAddress; + Plat_Unicode::String m_srcAddress; +}; + +class RSendInstantMessage : public GenericAPI::GenericRequest +{ +public: + RSendInstantMessage(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + virtual ~RSendInstantMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + Plat_Unicode::String m_srcAddress; +}; + +class RSendRoomMessage : public GenericAPI::GenericRequest +{ +public: + RSendRoomMessage(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + virtual ~RSendRoomMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destRoomAddress; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + Plat_Unicode::String m_srcAddress; +}; + +class RSendBroadcastMessage : public GenericAPI::GenericRequest +{ +public: + RSendBroadcastMessage(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAddress, const ChatUnicodeString &msg, const ChatUnicodeString &oob); + virtual ~RSendBroadcastMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + Plat_Unicode::String m_srcAddress; +}; + +class RFilterMessage : public GenericAPI::GenericRequest +{ +public: + RFilterMessage(const ChatUnicodeString &msg); + virtual ~RFilterMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_msg; +}; + +class RFilterMessageEx : public GenericAPI::GenericRequest +{ +public: + RFilterMessageEx(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &msg); + virtual ~RFilterMessageEx() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_msg; +}; + +class RAddFriend : public GenericAPI::GenericRequest +{ +public: + RAddFriend(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment, bool confirm); + virtual ~RAddFriend() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_friendComment; + bool m_confirm; +}; + +class RAddFriendReciprocate : public GenericAPI::GenericRequest +{ +public: + RAddFriendReciprocate(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment, bool confirm); + virtual ~RAddFriendReciprocate() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_friendComment; + bool m_confirm; +}; + + +class RSetFriendComment : public GenericAPI::GenericRequest +{ +public: + RSetFriendComment(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress, const ChatUnicodeString &friendComment); + virtual ~RSetFriendComment() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_friendComment; +}; + +class RRemoveFriend : public GenericAPI::GenericRequest +{ +public: + RRemoveFriend(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RRemoveFriend() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; +}; + +class RRemoveFriendReciprocate : public GenericAPI::GenericRequest +{ +public: + RRemoveFriendReciprocate(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RRemoveFriendReciprocate() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; +}; + +class RFriendStatus : public GenericAPI::GenericRequest +{ +public: + RFriendStatus(unsigned srcAvatarID, const ChatUnicodeString &srcAddress); + virtual ~RFriendStatus() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; +}; + +class RAddIgnore : public GenericAPI::GenericRequest +{ +public: + RAddIgnore(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RAddIgnore() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; +}; + +class RRemoveIgnore : public GenericAPI::GenericRequest +{ +public: + RRemoveIgnore(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RRemoveIgnore() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destName; + Plat_Unicode::String m_destAddress; +}; + +class RIgnoreStatus : public GenericAPI::GenericRequest +{ +public: + RIgnoreStatus(unsigned srcAvatarID, const ChatUnicodeString &srcAddress); + virtual ~RIgnoreStatus() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; +}; + + +class REnterRoom : public GenericAPI::GenericRequest +{ +public: + REnterRoom(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &roomAddress, const ChatUnicodeString &roomPassword, const RoomParams *roomParams, bool requestingEntry); + virtual ~REnterRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_roomAddress; + Plat_Unicode::String m_roomPassword; + bool m_passiveCreate; + Plat_Unicode::String m_paramRoomTopic; + unsigned m_paramRoomAttributes; + unsigned m_paramRoomMaxSize; + bool m_requestingEntry; + Plat_Unicode::String m_srcAddress; +}; + +class RAllowRoomEntry : public GenericAPI::GenericRequest +{ +public: + RAllowRoomEntry(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress, bool allow); + virtual ~RAllowRoomEntry() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; + bool m_allow; +}; + +class RLeaveRoom : public GenericAPI::GenericRequest +{ +public: + RLeaveRoom(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &roomAddress); + virtual ~RLeaveRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_roomAddress; + Plat_Unicode::String m_srcAddress; +}; + +class RAddModerator : public GenericAPI::GenericRequest +{ +public: + RAddModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RAddModerator() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RRemoveModerator : public GenericAPI::GenericRequest +{ +public: + RRemoveModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RRemoveModerator() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RAddTemporaryModerator : public GenericAPI::GenericRequest +{ +public: + RAddTemporaryModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RAddTemporaryModerator() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RRemoveTemporaryModerator : public GenericAPI::GenericRequest +{ +public: + RRemoveTemporaryModerator(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RRemoveTemporaryModerator() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RAddBan : public GenericAPI::GenericRequest +{ +public: + RAddBan(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RAddBan() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RRemoveBan : public GenericAPI::GenericRequest +{ +public: + RRemoveBan(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RRemoveBan() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RAddInvite : public GenericAPI::GenericRequest +{ +public: + RAddInvite(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RAddInvite() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; + Plat_Unicode::String m_srcAddress; +}; + +class RRemoveInvite : public GenericAPI::GenericRequest +{ +public: + RRemoveInvite(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RRemoveInvite() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RGrantVoice : public GenericAPI::GenericRequest +{ +public: + RGrantVoice(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RGrantVoice() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RRevokeVoice : public GenericAPI::GenericRequest +{ +public: + RRevokeVoice(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RRevokeVoice() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RKickAvatar : public GenericAPI::GenericRequest +{ +public: + RKickAvatar(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, const ChatUnicodeString &destRoomAddress); + virtual ~RKickAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + Plat_Unicode::String m_destRoomAddress; +}; + +class RSetRoomParams : public GenericAPI::GenericRequest +{ +public: + RSetRoomParams(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destRoomAddress, const RoomParams *params); + virtual ~RSetRoomParams() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destRoomAddress; + Plat_Unicode::String m_newRoomName; + Plat_Unicode::String m_newRoomTopic; + Plat_Unicode::String m_newRoomPassword; + unsigned m_newRoomAttributes; + unsigned m_newRoomSize; +}; + +class RChangeRoomOwner : public GenericAPI::GenericRequest +{ +public: + RChangeRoomOwner(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, const ChatUnicodeString &destRoomAddress, const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress); + virtual ~RChangeRoomOwner() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcAddress; + Plat_Unicode::String m_destRoomAddress; + Plat_Unicode::String m_newRoomOwnerName; + Plat_Unicode::String m_newRoomOwnerAddress; +}; + +class RGetRoomSummaries : public GenericAPI::GenericRequest +{ +public: + RGetRoomSummaries(const ChatUnicodeString &startNodeAddress, const ChatUnicodeString &roomFilter); + virtual ~RGetRoomSummaries() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_startNodeAddress; + Plat_Unicode::String m_roomFilter; +}; + +class RSendPersistentMessage : public GenericAPI::GenericRequest +{ +public: + RSendPersistentMessage(const ChatUnicodeString &src, const ChatUnicodeString &destAvatar, const ChatUnicodeString &destAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit); + RSendPersistentMessage(unsigned srcAvatarID, const ChatUnicodeString &destAvatar, const ChatUnicodeString &destAddress, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit); + + virtual ~RSendPersistentMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + short m_avatarPresence;; + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcName; + Plat_Unicode::String m_destAvatar; + Plat_Unicode::String m_destAddress; + Plat_Unicode::String m_subject; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + Plat_Unicode::String m_category; + bool m_enforceInboxLimit; + unsigned m_categoryLimit; +}; + +class RSendMultiplePersistentMessages : public GenericAPI::GenericRequest +{ +public: + RSendMultiplePersistentMessages(const ChatUnicodeString &src, unsigned numDestAvatars, const ChatUnicodeString *destAvatars, const ChatUnicodeString *destAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit); + RSendMultiplePersistentMessages(unsigned srcAvatarID, unsigned numDestAvatars, const ChatUnicodeString *destAvatars, const ChatUnicodeString *destAddresses, const ChatUnicodeString &subject, const ChatUnicodeString &msg, const ChatUnicodeString &oob, const ChatUnicodeString &category, bool enforceInboxLimit, unsigned categoryLimit); + + virtual ~RSendMultiplePersistentMessages() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + short m_avatarPresence;; + unsigned m_srcAvatarID; + Plat_Unicode::String m_srcName; + unsigned m_numDestAvatars; + std::vector m_destAvatars; + std::vector m_destAddresses; + Plat_Unicode::String m_subject; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + Plat_Unicode::String m_category; + bool m_enforceInboxLimit; + unsigned m_categoryLimit; +}; + +class RAlterPersistentMessage : public GenericAPI::GenericRequest +{ +public: + RAlterPersistentMessage(const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID, unsigned alterationAttributes, const ChatUnicodeString &newSenderName, const ChatUnicodeString &newSenderAddress, const ChatUnicodeString &newSubject, const ChatUnicodeString &newMsg, const ChatUnicodeString &newOOB, const ChatUnicodeString &newCategory, unsigned newSentTime); + + virtual ~RAlterPersistentMessage(); + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_messageID; + unsigned m_alterationAttributes; + Plat_Unicode::String m_newSenderName; + Plat_Unicode::String m_newSenderAddress; + Plat_Unicode::String m_newSubject; + Plat_Unicode::String m_newMsg; + Plat_Unicode::String m_newOOB; + Plat_Unicode::String m_newCategory; + unsigned m_newSentTime; +}; + +class RGetPersistentHeaders : public GenericAPI::GenericRequest +{ +public: + RGetPersistentHeaders(unsigned srcAvatarID, const ChatUnicodeString &category); + virtual ~RGetPersistentHeaders() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_category; +}; + +class RGetPartialPersistentHeaders : public GenericAPI::GenericRequest +{ +public: + RGetPartialPersistentHeaders(unsigned srcAvatarID, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category); + virtual ~RGetPartialPersistentHeaders() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_maxHeaders; + bool m_inDescendingOrder; + unsigned m_sentTimeStart; + Plat_Unicode::String m_category; +}; + +class RCountPersistentMessages : public GenericAPI::GenericRequest +{ +public: + RCountPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category); + virtual ~RCountPersistentMessages() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_avatarAddress; + Plat_Unicode::String m_category; +}; + +class RGetPersistentMessage : public GenericAPI::GenericRequest +{ +public: + RGetPersistentMessage(unsigned srcAvatarID, unsigned messageID); + virtual ~RGetPersistentMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_messageID; +}; + +class RGetMultiplePersistentMessages : public GenericAPI::GenericRequest +{ +public: + RGetMultiplePersistentMessages(unsigned srcAvatarID, unsigned maxHeaders, bool inDescendingOrder, unsigned sentTimeStart, const ChatUnicodeString &category); + virtual ~RGetMultiplePersistentMessages() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_maxHeaders; + bool m_inDescendingOrder; + unsigned m_sentTimeStart; + Plat_Unicode::String m_category; +}; + +class RUpdatePersistentMessage : public GenericAPI::GenericRequest +{ +public: + RUpdatePersistentMessage(unsigned srcAvatarID, unsigned messageID, PersistentStatus status); + virtual ~RUpdatePersistentMessage() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_messageID; + PersistentStatus m_status; +}; + +class RUpdatePersistentMessages : public GenericAPI::GenericRequest +{ +public: + RUpdatePersistentMessages(unsigned srcAvatarID, PersistentStatus currentStatus, PersistentStatus newStatus, const ChatUnicodeString &category); + virtual ~RUpdatePersistentMessages() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + PersistentStatus m_currentStatus; + PersistentStatus m_newStatus; + Plat_Unicode::String m_category; +}; + +class RClassifyPersistentMessages : public GenericAPI::GenericRequest +{ +public: + RClassifyPersistentMessages(unsigned srcAvatarID, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder); + RClassifyPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, unsigned numIDs, const unsigned *messageIDs, const ChatUnicodeString &newFolder); + virtual ~RClassifyPersistentMessages() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_avatarAddress; + std::set m_messageIDs; + Plat_Unicode::String m_newFolder; +}; + +class RDeleteAllPersistentMessages : public GenericAPI::GenericRequest +{ +public: + RDeleteAllPersistentMessages(const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &category, unsigned olderThan); + virtual ~RDeleteAllPersistentMessages() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_avatarAddress; + Plat_Unicode::String m_category; + unsigned m_olderThan; +}; + + +class RUnregisterRoom : public GenericAPI::GenericRequest +{ +public: + RUnregisterRoom(const ChatUnicodeString &destRoomAddress); + virtual ~RUnregisterRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_destRoomAddress; +}; + +class RFailoverReloginAvatar : public GenericAPI::GenericRequest +{ +public: + RFailoverReloginAvatar(ChatAvatarCore *avatar); + virtual ~RFailoverReloginAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + ChatAvatarCore *m_avatar; +}; + +class RFailoverRecreateRoom : public GenericAPI::GenericRequest +{ +public: + RFailoverRecreateRoom(ChatRoomCore *room); + virtual ~RFailoverRecreateRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + ChatRoomCore *m_room; +}; + +class RFriendConfirm : public GenericAPI::GenericRequest +{ +public: + RFriendConfirm(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, unsigned destAvatarID, bool confirm); + virtual ~RFriendConfirm() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_destAvatarID; + short m_confirm; + Plat_Unicode::String m_srcAddress; +}; + +class RFriendConfirmReciprocate : public GenericAPI::GenericRequest +{ +public: + RFriendConfirmReciprocate(unsigned srcAvatarID, const ChatUnicodeString &srcAddress, unsigned destAvatarID, bool confirm); + virtual ~RFriendConfirmReciprocate() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + unsigned m_destAvatarID; + short m_confirm; + Plat_Unicode::String m_srcAddress; +}; +class RGetFanClubHandle : public GenericAPI::GenericRequest +{ +public: + RGetFanClubHandle(unsigned stationID, unsigned fanClubCode); + virtual ~RGetFanClubHandle() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_stationID; // i.e. userID + unsigned m_fanClubCode; +}; + +class RFindAvatarByUID : public GenericAPI::GenericRequest +{ +public: + RFindAvatarByUID(unsigned userID); + virtual ~RFindAvatarByUID() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_userID; +}; + +class RRegistrarGetChatServer : public GenericAPI::GenericRequest +{ +public: + RRegistrarGetChatServer(std::string &hostname, unsigned short port); + virtual ~RRegistrarGetChatServer() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + Plat_Unicode::String m_hostname; + unsigned short m_port; +}; + +class RSendApiVersion : public GenericAPI::GenericRequest +{ +public: + RSendApiVersion(unsigned long version); + virtual ~RSendApiVersion() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned long m_version; +}; + +class RAddSnoopAvatar : public GenericAPI::GenericRequest +{ +public: + RAddSnoopAvatar(unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RAddSnoopAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; +}; + +class RRemoveSnoopAvatar : public GenericAPI::GenericRequest +{ +public: + RRemoveSnoopAvatar(unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~RRemoveSnoopAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; +}; + +class RAddSnoopRoom : public GenericAPI::GenericRequest +{ +public: + RAddSnoopRoom(unsigned srcAvatarID, const ChatUnicodeString &roomAddress); + virtual ~RAddSnoopRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_roomAddress; +}; + +class RRemoveSnoopRoom : public GenericAPI::GenericRequest +{ +public: + RRemoveSnoopRoom(unsigned srcAvatarID, const ChatUnicodeString &roomAddress); + virtual ~RRemoveSnoopRoom() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_roomAddress; +}; + +class RGetSnoopList : public GenericAPI::GenericRequest +{ +public: + RGetSnoopList(unsigned srcAvatarID); + virtual ~RGetSnoopList() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_srcAvatarID; +}; + +class RTransferAvatar : public GenericAPI::GenericRequest +{ +public: + RTransferAvatar(unsigned userID, unsigned newUserID, const ChatUnicodeString &avatarName, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &newAvatarAddress, bool transferPersistentMessages); + virtual ~RTransferAvatar() {}; + + virtual void pack(Base::ByteStream &msg); + +private: + unsigned m_userID; + unsigned m_newUserID; + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_newAvatarName; + Plat_Unicode::String m_avatarAddress; + Plat_Unicode::String m_newAvatarAddress; + bool m_transferPersistentMessages; +}; + + +}; // end namespace + + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp new file mode 100644 index 00000000..7e88557a --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp @@ -0,0 +1,1681 @@ +#include "Response.h" +#include "ChatEnum.h" +#include "ChatRoom.h" +#include "ChatFriendStatus.h" +#include "ChatFriendStatusCore.h" +#include "ChatRoomCore.h" +#include "ChatAvatarCore.h" +#include "PersistentMessage.h" +#include "PersistentMessageCore.h" +#include "ChatIgnoreStatus.h" +#include "ChatIgnoreStatusCore.h" +#include "AvatarListItem.h" +#include "AvatarListItemCore.h" + +namespace ChatSystem +{ + +using namespace Base; +using namespace Plat_Unicode; + +ResLoginAvatar::ResLoginAvatar(void *user, int avatarLoginPriority) +: GenericResponse(RESPONSE_LOGINAVATAR, CHATRESULT_TIMEOUT, user), + m_avatar(NULL), + m_submittedPriority(avatarLoginPriority), + m_requiredPriority(INT_MAX) +{ +} + +void ResLoginAvatar::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + Plat_Unicode::String email; + unsigned inboxLimit = 0; + + + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if(m_result == 0) + { + m_avatar = new ChatAvatarCore(iter); + + if (iter.getSize() > 0) + { + get(iter, m_requiredPriority); + } + + if (iter.getSize() > 0) + { + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + } + + if (m_avatar) + { + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + + } + } +} + +ResTemporaryAvatar::ResTemporaryAvatar(void *user) +: GenericResponse(RESPONSE_TEMPORARYAVATAR, CHATRESULT_TIMEOUT, user) +, m_avatar(NULL) +{ +} + +void ResTemporaryAvatar::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if(m_result == 0) + { + m_avatar = new ChatAvatarCore(iter); + } +} + +ResLogoutAvatar::ResLogoutAvatar(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_LOGOUTAVATAR, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID) +{ +} + +void ResLogoutAvatar::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResDestroyAvatar::ResDestroyAvatar(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_DESTROYAVATAR, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID) +{ +} + +void ResDestroyAvatar::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResGetAvatar::ResGetAvatar(void *user) +: GenericResponse(RESPONSE_GETAVATAR, CHATRESULT_TIMEOUT, user), + m_avatar(NULL) +{ +} + +void ResGetAvatar::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + Plat_Unicode::String email; + unsigned inboxLimit = 0; + + m_avatar = new ChatAvatarCore(iter); + + if (iter.getSize() > 0) + { + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + } + + if (m_avatar) + { + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + } + } +} + +ResGetAnyAvatar::ResGetAnyAvatar(void* user) + : GenericResponse( RESPONSE_GETANYAVATAR, CHATRESULT_TIMEOUT, user ) + , m_avatar( NULL ) +{ +} + +void ResGetAnyAvatar::unpack(Base::ByteStream::ReadIterator& iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_online); + + if ( m_result == CHATRESULT_SUCCESS ) + { + Plat_Unicode::String email; + unsigned inboxLimit = 0; + + m_avatar = new ChatAvatarCore(iter); + + if ( iter.getSize() > 0) + { + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + + } + + if ( m_avatar ) + { + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + } + } +} + +ResAvatarList::ResAvatarList(void *user) +: GenericResponse(RESPONSE_AVATARLIST, CHATRESULT_TIMEOUT, user) +, m_listLength(0) +, m_avatarList(NULL) +, m_cores(NULL) +{ +} + +ResAvatarList::~ResAvatarList() +{ + delete[] m_avatarList; + delete[] m_cores; +} + +void ResAvatarList::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_listLength); + + if(m_listLength > 0) + { + m_avatarList = new AvatarListItem[m_listLength]; + m_cores = new AvatarListItemCore[m_listLength]; + + for(unsigned i = 0; i < m_listLength; i++) + { + m_cores[i].load(iter, &m_avatarList[i]); + } + } +} + +ResSetAvatarAttributes::ResSetAvatarAttributes(void *user) +: GenericResponse(RESPONSE_SETAVATARATTRIBUTES, CHATRESULT_TIMEOUT, user), + m_avatar(NULL) +{ +} + +void ResSetAvatarAttributes::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + Plat_Unicode::String email; + unsigned inboxLimit = 0; + + m_avatar = new ChatAvatarCore(iter); + + if (iter.getSize() > 0) + { + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + } + + if (m_avatar) + { + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + } + } +} + +ResSetAvatarStatusMessage::ResSetAvatarStatusMessage(void *user) +: GenericResponse(RESPONSE_SETSTATUSMESSAGE, CHATRESULT_TIMEOUT, user), +m_avatar(NULL) +{ +} + +void ResSetAvatarStatusMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + Plat_Unicode::String email; + Plat_Unicode::String statusMessage; + unsigned inboxLimit = 0; + + m_avatar = new ChatAvatarCore(iter); + + if (iter.getSize() > 0) + { + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + ASSERT_VALID_STRING_LENGTH(get(iter, statusMessage)); + } + + if (m_avatar) + { + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + m_avatar->setStatusMessage(statusMessage); + } + } +} + +ResSetAvatarForwardingEmail::ResSetAvatarForwardingEmail(void *user) +: GenericResponse(RESPONSE_SETAVATAREMAIL, CHATRESULT_TIMEOUT, user), + m_avatar(NULL) +{ +} + +void ResSetAvatarForwardingEmail::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + Plat_Unicode::String email; + unsigned inboxLimit = 0; + + m_avatar = new ChatAvatarCore(iter); + + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + } +} + +ResSetAvatarInboxLimit::ResSetAvatarInboxLimit(void *user) +: GenericResponse(RESPONSE_SETAVATARINBOXLIMIT, CHATRESULT_TIMEOUT, user), + m_avatar(NULL) +{ +} + +void ResSetAvatarInboxLimit::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + Plat_Unicode::String email; + unsigned inboxLimit = 0; + + m_avatar = new ChatAvatarCore(iter); + + ASSERT_VALID_STRING_LENGTH(get(iter, email)); + get(iter, inboxLimit); + m_avatar->setEmail(email); + m_avatar->setInboxLimit(inboxLimit); + } +} + +ResSearchAvatarKeywords::ResSearchAvatarKeywords(void *user) +: GenericResponse(RESPONSE_SETAVATARKEYWORDS, CHATRESULT_TIMEOUT, user), + m_numMatches(0), + m_avatarMatches(NULL) +{ +} + +void ResSearchAvatarKeywords::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_numMatches); + if (m_result == CHATRESULT_SUCCESS) + { + m_avatarMatches = new ChatAvatarCore*[m_numMatches]; + for (unsigned i = 0; i < m_numMatches; i++) + { + m_avatarMatches[i] = new ChatAvatarCore(iter); + } + } +} + +ResSearchAvatarKeywords::~ResSearchAvatarKeywords() +{ + for (unsigned i = 0; i < m_numMatches; i++) + { + delete m_avatarMatches[i]; + } + + delete[] m_avatarMatches; +} + +ResSetAvatarKeywords::ResSetAvatarKeywords(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_SETAVATARKEYWORDS, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID) +{ +} + +void ResSetAvatarKeywords::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResGetAvatarKeywords::ResGetAvatarKeywords(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_GETAVATARKEYWORDS, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_keywordList(NULL), + m_chatStrList(NULL) +{ +} + +ResGetAvatarKeywords::~ResGetAvatarKeywords() +{ + delete[] m_keywordList; + delete[] m_chatStrList; +} + +void ResGetAvatarKeywords::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_keywordLength); + if(m_result == CHATRESULT_SUCCESS) + { + m_keywordList = new String[m_keywordLength]; + m_chatStrList = new ChatUnicodeString[m_keywordLength]; + for(unsigned i = 0; i < m_keywordLength; i++) + { + ASSERT_VALID_STRING_LENGTH(get(iter, m_keywordList[i])); + m_chatStrList[i] = m_keywordList[i]; + } + } +} + +ResGetRoom::ResGetRoom(void *user) +: GenericResponse(RESPONSE_GETROOM, CHATRESULT_TIMEOUT, user), + m_room(NULL), + m_numExtraRooms(0) +{ +} + +void ResGetRoom::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + m_room = new ChatRoomCore(iter); + + // any extra parent rooms sent for caching? + get(iter, m_numExtraRooms); + for (unsigned i = 0; i != m_numExtraRooms; i++) + { + m_setExtraRooms.insert(new ChatRoomCore(iter)); + } + } +} + +ResCreateRoom::ResCreateRoom(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_CREATEROOM, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(avatarID), + m_room(NULL), + m_numExtraRooms(0) +{ +} + +void ResCreateRoom::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + if (m_result == 0) + { + m_room = new ChatRoomCore(iter); + + // any extra parent rooms sent for caching? + get(iter, m_numExtraRooms); + for (unsigned i = 0; i != m_numExtraRooms; i++) + { + m_setExtraRooms.insert(new ChatRoomCore(iter)); + } + } +} + +ResDestroyRoom::ResDestroyRoom(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_DESTROYROOM, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_roomID(0) +{ +} + +void ResDestroyRoom::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_roomID); +} + +ResSendInstantMessage::ResSendInstantMessage(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address) +: GenericResponse(RESPONSE_SENDINSTANTMESSAGE, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length) +{ +} + +void ResSendInstantMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResSendRoomMessage::ResSendRoomMessage(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_SENDROOMMESSAGE, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_roomID(0) +{ +} + +void ResSendRoomMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_roomID); +} + +ResSendBroadcastMessage::ResSendBroadcastMessage(void *user, unsigned avatarID, const ChatUnicodeString &address) +: GenericResponse(RESPONSE_SENDBROADCASTMESSAGE, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_address(address.string_data, address.string_length) +{ +} + +void ResSendBroadcastMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResFilterMessage::ResFilterMessage(void *user, unsigned version) +: GenericResponse(version, CHATRESULT_TIMEOUT, user) +,m_version(version) +{ +} + +void ResFilterMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + ASSERT_VALID_STRING_LENGTH(get(iter, m_msg)); +} + +ResAddFriend::ResAddFriend(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &comment) +: GenericResponse(RESPONSE_ADDFRIEND, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length), + m_comment(comment.string_data, comment.string_length) +{ +} + +void ResAddFriend::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResAddFriendReciprocate::ResAddFriendReciprocate(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &comment) +: GenericResponse(RESPONSE_ADDFRIEND_RECIPROCATE, CHATRESULT_TIMEOUT, user), +m_avatarID(avatarID), +m_name(name.string_data, name.string_length), +m_address(address.string_data, address.string_length), +m_comment(comment.string_data, comment.string_length) +{ +} + +void ResAddFriendReciprocate::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + + +ResSetFriendComment::ResSetFriendComment(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &comment) +: GenericResponse(RESPONSE_SETFRIENDCOMMENT, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length), + m_comment(comment.string_data, comment.string_length) +{ +} + +void ResSetFriendComment::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResRemoveFriend::ResRemoveFriend(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address) +: GenericResponse(RESPONSE_REMOVEFRIEND, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length) +{ +} + +void ResRemoveFriend::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} +ResRemoveFriendReciprocate::ResRemoveFriendReciprocate(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address) +: GenericResponse(RESPONSE_REMOVEFRIEND_RECIPROCATE, CHATRESULT_TIMEOUT, user), +m_avatarID(avatarID), +m_name(name.string_data, name.string_length), +m_address(address.string_data, address.string_length) +{ +} + +void ResRemoveFriendReciprocate::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResFriendStatus::ResFriendStatus(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_FRIENDSTATUS, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_listLength(0), + m_friendList(NULL), + m_cores(NULL) +{ +} + +ResFriendStatus::~ResFriendStatus() +{ + delete[] m_friendList; + delete[] m_cores; +} + +void ResFriendStatus::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_listLength); + + if(m_listLength > 0) + { + m_friendList = new ChatFriendStatus[m_listLength]; + m_cores = new ChatFriendStatusCore[m_listLength]; + + for(unsigned i = 0; i < m_listLength; i++) + { + m_cores[i].load(iter, &m_friendList[i]); + } + } +} + +ResAddIgnore::ResAddIgnore(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address) +: GenericResponse(RESPONSE_ADDIGNORE, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length) +{ +} + +void ResAddIgnore::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResRemoveIgnore::ResRemoveIgnore(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address) +: GenericResponse(RESPONSE_REMOVEIGNORE, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_name(name.string_data, name.string_length), + m_address(address.string_data, address.string_length) +{ +} + +void ResRemoveIgnore::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResIgnoreStatus::ResIgnoreStatus(void *user, unsigned avatarID) +: GenericResponse(RESPONSE_IGNORESTATUS, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_listLength(0), + m_ignoreList(NULL), + m_cores(NULL) +{ +} + +ResIgnoreStatus::~ResIgnoreStatus() +{ + delete[] m_ignoreList; + delete[] m_cores; +} + +void ResIgnoreStatus::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_listLength); + + if(m_listLength > 0) + { + m_ignoreList = new ChatIgnoreStatus[m_listLength]; + m_cores = new ChatIgnoreStatusCore[m_listLength]; + + for(unsigned i = 0; i < m_listLength; i++) + { + m_cores[i].load(iter, &m_ignoreList[i]); + } + } +} + +ResEnterRoom::ResEnterRoom(void *user, unsigned avatarID, const ChatUnicodeString &destAddress) +: GenericResponse(RESPONSE_ENTERROOM, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_destAddress(destAddress.string_data, destAddress.string_length), + m_gotRoomObj(false), + m_room(NULL), + m_numExtraRooms(0) +{ +} + +void ResEnterRoom::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_roomID); + get(iter, m_gotRoomObj); + + if (m_gotRoomObj) + { + // we were sent room info to cache, so create a new ChatRoomCore! + m_room = new ChatRoomCore(iter); + + // any extra parent rooms sent for caching? + get(iter, m_numExtraRooms); + for (unsigned i = 0; i != m_numExtraRooms; i++) + { + m_setExtraRooms.insert(new ChatRoomCore(iter)); + } + } +} + +ResAllowRoomEntry::ResAllowRoomEntry(void *user, unsigned srcAvatarID, const ChatUnicodeString &destRoomAddress) + : GenericResponse(RESPONSE_ALLOWROOMENTRY, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_roomID(0), + m_destRoomAddress(destRoomAddress.string_data, destRoomAddress.string_length) +{ +} + +void ResAllowRoomEntry::unpack(Base::ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_roomID); +} + +ResLeaveRoom::ResLeaveRoom(void *user, unsigned avatarID, const ChatUnicodeString &destAddress) +: GenericResponse(RESPONSE_LEAVEROOM, CHATRESULT_TIMEOUT, user), + m_avatarID(avatarID), + m_destAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void ResLeaveRoom::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_roomID); +} + +ResAddModerator::ResAddModerator(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_ADDMODERATOR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResAddModerator::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResRemoveModerator::ResRemoveModerator(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_REMOVEMODERATOR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResRemoveModerator::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResAddTemporaryModerator::ResAddTemporaryModerator(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_ADDTEMPORARYMODERATOR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResAddTemporaryModerator::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResRemoveTemporaryModerator::ResRemoveTemporaryModerator(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_REMOVETEMPORARYMODERATOR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResRemoveTemporaryModerator::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResAddBan::ResAddBan(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_ADDBAN, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResAddBan::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResRemoveBan::ResRemoveBan(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_REMOVEBAN, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResRemoveBan::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResAddInvite::ResAddInvite(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_ADDINVITE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResAddInvite::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResRemoveInvite::ResRemoveInvite(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_REMOVEINVITE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResRemoveInvite::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResGrantVoice::ResGrantVoice(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_GRANTVOICE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResGrantVoice::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResRevokeVoice::ResRevokeVoice(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_REVOKEVOICE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResRevokeVoice::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResKickAvatar::ResKickAvatar(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_KICKAVATAR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResKickAvatar::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResSetRoomParams::ResSetRoomParams(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_SETROOMPARAMS, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResSetRoomParams::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResChangeRoomOwner::ResChangeRoomOwner(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_CHANGEROOMOWNER, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destRoomID(0) +{ +} + +void ResChangeRoomOwner::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResGetRoomSummaries::ResGetRoomSummaries(void *user) +: GenericResponse(RESPONSE_GETROOMSUMMARIES, CHATRESULT_TIMEOUT, user), + m_numRooms(0), + m_roomSummaries(NULL) +{ +} + +ResGetRoomSummaries::~ResGetRoomSummaries() +{ + delete[] m_roomSummaries; +} + +void ResGetRoomSummaries::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_numRooms); + + if (m_numRooms > 0) + { + String tempStr; + unsigned tempNum; + + m_roomSummaries = new RoomSummary[m_numRooms]; + + for (unsigned i = 0; i != m_numRooms; i++) + { + // process RoomSummary objects from message + ASSERT_VALID_STRING_LENGTH(get(iter, tempStr)); + m_roomSummaries[i].setRoomAddress(ChatUnicodeString(tempStr.data(), tempStr.size())); + ASSERT_VALID_STRING_LENGTH(get(iter, tempStr)); + m_roomSummaries[i].setRoomTopic(ChatUnicodeString(tempStr.data(), tempStr.size())); + get(iter, tempNum); + m_roomSummaries[i].setRoomAttributes(tempNum); + get(iter, tempNum); + m_roomSummaries[i].setRoomCurSize(tempNum); + get(iter, tempNum); + m_roomSummaries[i].setRoomMaxSize(tempNum); + } + } +} + +ResSendPersistentMessage::ResSendPersistentMessage(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_SENDPERSISTENTMESSAGE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_messageID(0) +{ +} + +void ResSendPersistentMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (iter.getSize() > 0) + { + get(iter, m_messageID); + } +} + +ResSendMultiplePersistentMessages::ResSendMultiplePersistentMessages(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_SENDMULTIPLEPERSISTENTMESSAGES, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_numResults(0) +{ +} + +void ResSendMultiplePersistentMessages::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + unsigned resultIndex; + + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + get(iter, m_numResults); + + m_resultVector.resize(m_numResults); + m_messageIDvector.resize(m_numResults); + + for (resultIndex = 0; resultIndex < m_numResults; resultIndex++) + { + get(iter, m_resultVector[resultIndex]); + } + + if (iter.getSize() > 0) + { + for (resultIndex = 0; resultIndex < m_numResults; resultIndex++) + { + get(iter, m_messageIDvector[resultIndex]); + } + } +} + +ResAlterPersistentMessage::ResAlterPersistentMessage(const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID, void *user) +: GenericResponse(RESPONSE_ALTERPERSISTENTMESSAGE, CHATRESULT_TIMEOUT, user), + m_destAvatarName(destAvatarName.data(), destAvatarName.length()), + m_destAvatarAddress(destAvatarAddress.data(), destAvatarAddress.length()), + m_messageID(messageID) +{ +} + +ResAlterPersistentMessage::~ResAlterPersistentMessage() +{ +} + +void ResAlterPersistentMessage::unpack(Base::ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResGetPersistentMessage::ResGetPersistentMessage(void *user, unsigned srcAvatarID, unsigned messageID) +: GenericResponse(RESPONSE_GETPERSISTENTMESSAGE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_messageID(messageID), + m_core(NULL), + m_header(NULL) +{ +} + +ResGetPersistentMessage::~ResGetPersistentMessage() +{ + delete m_header; + delete m_core; +} +void ResGetPersistentMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + if(m_result == 0) + { + m_header = new PersistentHeader; + m_core = new PersistentHeaderCore; + m_core->load(iter, m_header); + ASSERT_VALID_STRING_LENGTH(get(iter, m_msg)); + ASSERT_VALID_STRING_LENGTH(get(iter, m_oob)); + + if (iter.getSize() > 0) + { + m_core->setFolder(iter); + m_core->setCategory(iter); + } + } +} + +ResGetMultiplePersistentMessages::ResGetMultiplePersistentMessages(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_GETMULTIPLEPERSISTENTMESSAGES, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_messages(NULL) +{ +} + +ResGetMultiplePersistentMessages::~ResGetMultiplePersistentMessages() +{ + unsigned i; + + if (m_messages) + { + for(i = 0; i < m_listLength; i++) + { + delete m_messages[i]; + } + } + + delete[] m_messages; +} + +PersistentMessage ** const ResGetMultiplePersistentMessages::getList() const +{ + return (PersistentMessage **)m_messages; +} + +void ResGetMultiplePersistentMessages::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_listLength); + + if(m_listLength > 0) + { + unsigned i = 0; + + m_messages = new PersistentMessageCore*[m_listLength]; + + for(i = 0; i < m_listLength; i++) + { + m_messages[i] = new PersistentMessageCore(); + m_messages[i]->load(iter); + } + } +} + +ResGetPersistentHeaders::ResGetPersistentHeaders(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_GETPERSISTENTHEADERS, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_listLength(0), + m_headers(NULL), + m_cores(NULL) +{ +} + +ResGetPersistentHeaders::~ResGetPersistentHeaders() +{ + delete[] m_headers; + delete[] m_cores; +} + +void ResGetPersistentHeaders::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_listLength); + + if(m_listLength > 0) + { + unsigned i = 0; + + this->m_headers = new PersistentHeader[m_listLength]; + m_cores = new PersistentHeaderCore[m_listLength]; + + for(i = 0; i < m_listLength; i++) + { + m_cores[i].load(iter, &m_headers[i]); + } + + if (iter.getSize() > 0) + { + for(i = 0; i < m_listLength; i++) + { + m_cores[i].setFolder(iter); + m_cores[i].setCategory(iter); + } + } + } +} + +ResGetPartialPersistentHeaders::ResGetPartialPersistentHeaders(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_PARTIALPERSISTENTHEADERS, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_listLength(0), + m_headers(NULL), + m_cores(NULL) +{ +} + +ResGetPartialPersistentHeaders::~ResGetPartialPersistentHeaders() +{ + delete[] m_headers; + delete[] m_cores; +} + +void ResGetPartialPersistentHeaders::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_listLength); + + if(m_listLength > 0) + { + unsigned i = 0; + + m_headers = new PersistentHeader[m_listLength]; + m_cores = new PersistentHeaderCore[m_listLength]; + + for(i = 0; i < m_listLength; i++) + { + m_cores[i].load(iter, &m_headers[i]); + } + + if (iter.getSize() > 0) + { + for(i = 0; i < m_listLength; i++) + { + m_cores[i].setFolder(iter); + m_cores[i].setCategory(iter); + } + } + } +} + +ResCountPersistentMessages::ResCountPersistentMessages(void *user, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress) +: GenericResponse(RESPONSE_COUNTPERSISTENTMESSAGES, CHATRESULT_TIMEOUT, user), + m_avatarName(avatarName.string_data, avatarName.string_length), + m_avatarAddress(avatarAddress.string_data, avatarAddress.string_length), + m_numMessages(0) +{ +} + +void ResCountPersistentMessages::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_numMessages); +} + +ResUpdatePersistentMessage::ResUpdatePersistentMessage(void *user, unsigned srcAvatarID, unsigned messageID) +: GenericResponse(RESPONSE_UPDATEPERSISTENTMESSAGE, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_messageID(messageID) +{ +} + +void ResUpdatePersistentMessage::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResUpdatePersistentMessages::ResUpdatePersistentMessages(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_UPDATEPERSISTENTMESSAGES, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID) +{ +} + +void ResUpdatePersistentMessages::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResClassifyPersistentMessages::ResClassifyPersistentMessages(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_CHANGEPERSISTENTFOLDER, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID) +{ +} + +void ResClassifyPersistentMessages::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResDeleteAllPersistentMessages::ResDeleteAllPersistentMessages(void *user, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress) +: GenericResponse(RESPONSE_PURGEPERSISTENTMESSAGES, CHATRESULT_TIMEOUT, user), + m_avatarName(avatarName.string_data, avatarName.string_length), + m_avatarAddress(avatarAddress.string_data, avatarAddress.string_length), + m_numDeleted(0) +{ +} + +void ResDeleteAllPersistentMessages::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_numDeleted); +} + +ResUnregisterRoom::ResUnregisterRoom(void *user) +: GenericResponse(RESPONSE_UNREGISTERROOM, CHATRESULT_TIMEOUT, user), + m_destRoomID(0) +{ +} + +void ResUnregisterRoom::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_destRoomID); +} + +ResFailoverReloginAvatar::ResFailoverReloginAvatar(unsigned avatarID) +: GenericResponse(RESPONSE_FAILOVER_RELOGINAVATAR, CHATRESULT_TIMEOUT, NULL), + m_avatarID(avatarID) +{ +} + +void ResFailoverReloginAvatar::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (iter.getSize() > 0) + { + get(iter, m_requiredPriority); + } +} + +ResFailoverRecreateRoom::ResFailoverRecreateRoom(unsigned roomID, bool forced) +: GenericResponse(RESPONSE_FAILOVER_RECREATEROOM, CHATRESULT_TIMEOUT, NULL), + m_roomID(roomID), + m_room(NULL), + m_forced(forced) +{ +} + +void ResFailoverRecreateRoom::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + + if (m_result == 0) + { + m_room = new ChatRoomCore(iter); + } +} + +ResFriendConfirm::ResFriendConfirm(unsigned srcAvatarID, void *user) +: GenericResponse(RESPONSE_CONFIRMFRIEND, CHATRESULT_TIMEOUT, user), + m_avatarID(srcAvatarID) +{ +} + +void ResFriendConfirmReciprocate::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResFriendConfirmReciprocate::ResFriendConfirmReciprocate(unsigned srcAvatarID, void *user) +: GenericResponse(RESPONSE_CONFIRMFRIEND_RECIPROCATE, CHATRESULT_TIMEOUT, user), +m_avatarID(srcAvatarID) +{ +} + +void ResFriendConfirm::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResGetFanClubHandle::ResGetFanClubHandle(unsigned stationID, unsigned fanClubCode, void *user) +: GenericResponse(RESPONSE_GETFANCLUBHANDLE, CHATRESULT_TIMEOUT, user), + m_stationID(stationID), + m_fanClubCode(fanClubCode) +{ +} + +void ResGetFanClubHandle::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + ASSERT_VALID_STRING_LENGTH(get(iter, m_handle)); +} + +ResFindAvatarByUID::ResFindAvatarByUID(void *user) +: GenericResponse(RESPONSE_FINDAVATARBYUID, CHATRESULT_TIMEOUT, user), + m_numAvatarsOnline(0), + m_avatars(NULL) +{ +} + +ResFindAvatarByUID::~ResFindAvatarByUID() +{ + for (unsigned i = 0; i < m_numAvatarsOnline; i++) + { + delete m_avatars[i]; + } + + delete[] m_avatars; +} + +void ResFindAvatarByUID::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_numAvatarsOnline); + + if (m_numAvatarsOnline > 0) + { + m_avatars = new ChatAvatarCore*[m_numAvatarsOnline]; + + for (unsigned i = 0; i < m_numAvatarsOnline; i++) + { + m_avatars[i] = new ChatAvatarCore(iter); + } + } +} + +ResRegistrarGetChatServer::ResRegistrarGetChatServer() +: GenericResponse(RESPONSE_REGISTRAR_GETCHATSERVER, CHATRESULT_TIMEOUT, NULL) +{ +} + +void ResRegistrarGetChatServer::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + ASSERT_VALID_STRING_LENGTH(get(iter, m_hostname)); + get(iter, m_port); +} + +ResSendApiVersion::ResSendApiVersion() +: GenericResponse(RESPONSE_SETAPIVERSION, CHATRESULT_TIMEOUT, NULL) +{ +} + +void ResSendApiVersion::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, (uint32 &)m_serverVersion); +} + +ResAddSnoopAvatar::ResAddSnoopAvatar(void *user, unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericResponse(RESPONSE_ADDSNOOPAVATAR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destAvatarName(destName.string_data, destName.string_length), + m_destAvatarAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void ResAddSnoopAvatar::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResRemoveSnoopAvatar::ResRemoveSnoopAvatar(void *user, unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress) +: GenericResponse(RESPONSE_REMOVESNOOPAVATAR, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_destAvatarName(destName.string_data, destName.string_length), + m_destAvatarAddress(destAddress.string_data, destAddress.string_length) +{ +} + +void ResRemoveSnoopAvatar::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResAddSnoopRoom::ResAddSnoopRoom(void *user, unsigned srcAvatarID, const ChatUnicodeString &roomAddress) +: GenericResponse(RESPONSE_ADDSNOOPROOM, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length) +{ +} + +void ResAddSnoopRoom::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResRemoveSnoopRoom::ResRemoveSnoopRoom(void *user, unsigned srcAvatarID, const ChatUnicodeString &roomAddress) +: GenericResponse(RESPONSE_REMOVESNOOPROOM, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_roomAddress(roomAddress.string_data, roomAddress.string_length) +{ +} + +void ResRemoveSnoopRoom::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + +ResGetSnoopList::ResGetSnoopList(void *user, unsigned srcAvatarID) +: GenericResponse(RESPONSE_GETSNOOPLIST, CHATRESULT_TIMEOUT, user), + m_srcAvatarID(srcAvatarID), + m_avatarSnoops(NULL), + m_roomSnoops(NULL) +{ +} + +ResGetSnoopList::~ResGetSnoopList() +{ + for (unsigned i = 0; i < m_avatarSnoopListLength; i++) + { + delete m_avatarSnoops[i]; + } + delete[] m_avatarSnoops; + + for (unsigned j = 0; j < m_roomSnoopListLength; j++) + { + delete m_roomSnoops[j]; + } + delete[] m_roomSnoops; +} + +void ResGetSnoopList::unpack(ByteStream::ReadIterator &iter) +{ + unsigned numRead = 0; + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); + get(iter, m_avatarSnoopListLength); + get(iter, m_roomSnoopListLength); + + if (m_avatarSnoopListLength > 0) + { + m_avatarSnoops = new AvatarSnoopPair*[m_avatarSnoopListLength]; + + for (unsigned i = 0; i < m_avatarSnoopListLength; i++) + { + Plat_Unicode::String name; + Plat_Unicode::String addr; + ASSERT_VALID_STRING_LENGTH(get(iter, name)); + ASSERT_VALID_STRING_LENGTH(get(iter, addr)); + + m_avatarSnoops[i] = new AvatarSnoopPair(name, addr); + } + } + + if(m_roomSnoopListLength > 0) + { + m_roomSnoops = new ChatUnicodeString*[m_roomSnoopListLength]; + + for(unsigned j = 0; j < m_roomSnoopListLength; j++) + { + Plat_Unicode::String room; + ASSERT_VALID_STRING_LENGTH(get(iter, room)); + + m_roomSnoops[j] = new ChatUnicodeString(room); + } + } +} + +ResTransferAvatar::ResTransferAvatar(void *user, unsigned userID, unsigned newUserID, const ChatUnicodeString &avatarName, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &newAvatarAddress) +: GenericResponse(RESPONSE_TRANSFERAVATAR, CHATRESULT_TIMEOUT, user), + m_userID(userID), + m_newUserID(newUserID), + m_avatarName(avatarName.string_data, avatarName.string_length), + m_newAvatarName(newAvatarName.string_data, newAvatarName.string_length), + m_avatarAddress(avatarAddress.string_data, avatarAddress.string_length), + m_newAvatarAddress(newAvatarAddress.string_data, newAvatarAddress.string_length) +{ +} + +void ResTransferAvatar::unpack(ByteStream::ReadIterator &iter) +{ + get(iter, m_type); + get(iter, m_track); + get(iter, m_result); +} + + +}; // end namespace + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.h new file mode 100644 index 00000000..b1207746 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.h @@ -0,0 +1,1305 @@ +#if !defined (RESPONSE_H_) +#define RESPONSE_H_ + +#include + +#include "ChatEnum.h" +#include "ChatAvatarCore.h" +#include "ChatRoomCore.h" +#include "ChatFriendStatus.h" +#include "ChatIgnoreStatus.h" +#include "AvatarListItem.h" + +namespace ChatSystem +{ + class ChatRoomCore; + class ChatAvatarCore; + class RoomSummary; + class PersistentHeader; + class PersistentHeaderCore; + class PersistentMessage; + class PersistentMessageCore; + + enum ResponseType + { + RESPONSE_LOGINAVATAR = 0, + RESPONSE_LOGOUTAVATAR, + RESPONSE_DESTROYAVATAR, + RESPONSE_GETAVATAR, + RESPONSE_CREATEROOM, + RESPONSE_DESTROYROOM, + RESPONSE_SENDINSTANTMESSAGE, + RESPONSE_SENDROOMMESSAGE, + RESPONSE_SENDBROADCASTMESSAGE, + RESPONSE_ADDFRIEND, + RESPONSE_REMOVEFRIEND, + RESPONSE_FRIENDSTATUS, + RESPONSE_ADDIGNORE, + RESPONSE_REMOVEIGNORE, + RESPONSE_ENTERROOM, + RESPONSE_LEAVEROOM, + RESPONSE_ADDMODERATOR, + RESPONSE_REMOVEMODERATOR, + RESPONSE_ADDBAN, + RESPONSE_REMOVEBAN, + RESPONSE_ADDINVITE, + RESPONSE_REMOVEINVITE, + RESPONSE_KICKAVATAR, + RESPONSE_SETROOMPARAMS, + RESPONSE_GETROOM, + RESPONSE_GETROOMSUMMARIES, + RESPONSE_SENDPERSISTENTMESSAGE, + RESPONSE_GETPERSISTENTHEADERS, + RESPONSE_GETPERSISTENTMESSAGE, + RESPONSE_UPDATEPERSISTENTMESSAGE, + RESPONSE_UNREGISTERROOM, + RESPONSE_IGNORESTATUS, + RESPONSE_FAILOVER_RELOGINAVATAR, + RESPONSE_FAILOVER_RECREATEROOM, + RESPONSE_CONFIRMFRIEND, + RESPONSE_GETAVATARKEYWORDS, + RESPONSE_SETAVATARKEYWORDS, + RESPONSE_SEARCHAVATARKEYWORDS, + RESPONSE_GETFANCLUBHANDLE, + RESPONSE_UPDATEPERSISTENTMESSAGES, + RESPONSE_FINDAVATARBYUID, + RESPONSE_CHANGEROOMOWNER, + RESPONSE_SETAPIVERSION, + RESPONSE_ADDTEMPORARYMODERATOR, + RESPONSE_REMOVETEMPORARYMODERATOR, + RESPONSE_GRANTVOICE, + RESPONSE_REVOKEVOICE, + RESPONSE_SETAVATARATTRIBUTES, + RESPONSE_ADDSNOOPAVATAR, + RESPONSE_REMOVESNOOPAVATAR, + RESPONSE_ADDSNOOPROOM, + RESPONSE_REMOVESNOOPROOM, + RESPONSE_GETSNOOPLIST, + RESPONSE_PARTIALPERSISTENTHEADERS, + RESPONSE_COUNTPERSISTENTMESSAGES, + RESPONSE_PURGEPERSISTENTMESSAGES, + RESPONSE_SETFRIENDCOMMENT, + RESPONSE_TRANSFERAVATAR, + RESPONSE_CHANGEPERSISTENTFOLDER, + RESPONSE_ALLOWROOMENTRY, + RESPONSE_SETAVATAREMAIL, + RESPONSE_SETAVATARINBOXLIMIT, + RESPONSE_SENDMULTIPLEPERSISTENTMESSAGES, + RESPONSE_GETMULTIPLEPERSISTENTMESSAGES, + RESPONSE_ALTERPERSISTENTMESSAGE, + RESPONSE_GETANYAVATAR, + RESPONSE_TEMPORARYAVATAR, + RESPONSE_AVATARLIST, + RESPONSE_SETSTATUSMESSAGE, + RESPONSE_CONFIRMFRIEND_RECIPROCATE, + RESPONSE_ADDFRIEND_RECIPROCATE, + RESPONSE_REMOVEFRIEND_RECIPROCATE, + RESPONSE_FILTERMESSAGE, + RESPONSE_FILTERMESSAGE_EX, + + RESPONSE_REGISTRAR_GETCHATSERVER = 20001, + }; + + class ResLoginAvatar : public GenericAPI::GenericResponse + { + public: + ResLoginAvatar(void *user, int avatarLoginPriority); + virtual ~ResLoginAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + int getSubmittedLoginPriority() const { return m_submittedPriority; } + int getRequiredLoginPriority() const { return m_requiredPriority; } + private: + ChatAvatarCore *m_avatar; + int m_submittedPriority; + int m_requiredPriority; + }; + + class ResTemporaryAvatar : public GenericAPI::GenericResponse + { + public: + ResTemporaryAvatar(void *user); + virtual ~ResTemporaryAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + + private: + ChatAvatarCore *m_avatar; + }; + + class ResLogoutAvatar : public GenericAPI::GenericResponse + { + public: + ResLogoutAvatar(void *user, unsigned avatarID); + virtual ~ResLogoutAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + + private: + unsigned m_avatarID; + }; + + class ResDestroyAvatar : public GenericAPI::GenericResponse + { + public: + ResDestroyAvatar(void *user, unsigned avatarID); + virtual ~ResDestroyAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + private: + unsigned m_avatarID; + }; + + class ResSetAvatarKeywords : public GenericAPI::GenericResponse + { + public: + ResSetAvatarKeywords(void *user, unsigned avatarID); + virtual ~ResSetAvatarKeywords() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + private: + unsigned m_avatarID; + }; + + class ResGetAvatarKeywords : public GenericAPI::GenericResponse + { + public: + ResGetAvatarKeywords(void *user, unsigned avatarID); + virtual ~ResGetAvatarKeywords(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getListLength() const { return m_keywordLength; } + const ChatUnicodeString *getList() const { return m_chatStrList; } + + private: + unsigned m_avatarID; + unsigned m_keywordLength; + Plat_Unicode::String *m_keywordList; + ChatUnicodeString *m_chatStrList; + + }; + + class ResSearchAvatarKeywords : public GenericAPI::GenericResponse + { + public: + ResSearchAvatarKeywords(void *user); + virtual ~ResSearchAvatarKeywords(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getNumMatches() const { return m_numMatches; } + ChatAvatarCore **getMatches() const { return m_avatarMatches; } + + private: + unsigned m_numMatches; + ChatAvatarCore **m_avatarMatches; + }; + + class ResGetAvatar : public GenericAPI::GenericResponse + { + public: + ResGetAvatar(void *user); + virtual ~ResGetAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + private: + ChatAvatarCore *m_avatar; + }; + + class ResGetAnyAvatar : public GenericAPI::GenericResponse + { + public: + ResGetAnyAvatar(void *user); + virtual ~ResGetAnyAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator& iter); + + bool isLoggedIn() const { return m_online; } + ChatAvatarCore* getAvatar() const { return m_avatar; } + private: + bool m_online; + ChatAvatarCore* m_avatar; + }; + + class ResAvatarList : public GenericAPI::GenericResponse + { + public: + ResAvatarList(void *user); + virtual ~ResAvatarList(); + + virtual void unpack(Base::ByteStream::ReadIterator& iter); + + // TODO: make this ignore status more generic, or make our + // own datatype (e.g. UserAvatarInfo). + unsigned getListLength() const { return m_listLength; } + const AvatarListItem* getAvatarList() const { return m_avatarList; } + + private: + unsigned m_listLength; + AvatarListItem* m_avatarList; + AvatarListItemCore* m_cores; + }; + + class ResSetAvatarAttributes : public GenericAPI::GenericResponse + { + public: + ResSetAvatarAttributes(void *user); + virtual ~ResSetAvatarAttributes() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + private: + ChatAvatarCore *m_avatar; + }; + + class ResSetAvatarStatusMessage: public GenericAPI::GenericResponse + { + public: + ResSetAvatarStatusMessage(void *user); + virtual ~ResSetAvatarStatusMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + private: + ChatAvatarCore *m_avatar; + }; + + class ResSetAvatarForwardingEmail : public GenericAPI::GenericResponse + { + public: + ResSetAvatarForwardingEmail(void *user); + virtual ~ResSetAvatarForwardingEmail() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + private: + ChatAvatarCore *m_avatar; + }; + + class ResSetAvatarInboxLimit : public GenericAPI::GenericResponse + { + public: + ResSetAvatarInboxLimit(void *user); + virtual ~ResSetAvatarInboxLimit() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatAvatarCore *getAvatar() const { return m_avatar; } + private: + ChatAvatarCore *m_avatar; + }; + + class ResGetRoom : public GenericAPI::GenericResponse + { + public: + ResGetRoom(void *user); + virtual ~ResGetRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + ChatRoomCore *getRoom() const { return m_room; } + unsigned getNumExtraRooms() const { return m_numExtraRooms; } + const std::set &getExtraRooms() { return m_setExtraRooms; } + private: + ChatRoomCore *m_room; + unsigned m_numExtraRooms; + std::set m_setExtraRooms; + }; + + class ResCreateRoom : public GenericAPI::GenericResponse + { + public: + ResCreateRoom(void *user, unsigned srcAvatarID); + virtual ~ResCreateRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + ChatRoomCore *getRoom() const { return m_room; } + unsigned getNumExtraRooms() const { return m_numExtraRooms; } + const std::set &getExtraRooms() { return m_setExtraRooms; } + private: + unsigned m_srcAvatarID; + ChatRoomCore *m_room; + unsigned m_numExtraRooms; + std::set m_setExtraRooms; + }; + + class ResDestroyRoom : public GenericAPI::GenericResponse + { + public: + ResDestroyRoom(void *user, unsigned avatarID); + virtual ~ResDestroyRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_avatarID; + unsigned m_roomID; + }; + + class ResSendInstantMessage : public GenericAPI::GenericResponse + { + public: + ResSendInstantMessage(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address); + virtual ~ResSendInstantMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String getName() const { return m_name; } + const Plat_Unicode::String getAddress() const { return m_address; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + + class ResSendRoomMessage : public GenericAPI::GenericResponse + { + public: + ResSendRoomMessage(void *user, unsigned avatarID); + virtual ~ResSendRoomMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + private: + unsigned m_avatarID; + unsigned m_roomID; + }; + + class ResSendBroadcastMessage : public GenericAPI::GenericResponse + { + public: + ResSendBroadcastMessage(void *user, unsigned avatarID, const ChatUnicodeString &address); + virtual ~ResSendBroadcastMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getAddress() const { return m_address; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_address; + }; + + class ResFilterMessage : public GenericAPI::GenericResponse + { + public: + ResFilterMessage(void *user, unsigned version = RESPONSE_FILTERMESSAGE); + virtual ~ResFilterMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + const Plat_Unicode::String getMsg() const { return m_msg; } + private: + Plat_Unicode::String m_msg; + unsigned m_version; + }; + + class ResAddFriend : public GenericAPI::GenericResponse + { + public: + ResAddFriend(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &comment); + virtual ~ResAddFriend() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + const Plat_Unicode::String &getComment() const { return m_comment; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_comment; + }; + + class ResAddFriendReciprocate : public GenericAPI::GenericResponse + { + public: + ResAddFriendReciprocate(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &comment); + virtual ~ResAddFriendReciprocate() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + const Plat_Unicode::String &getComment() const { return m_comment; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_comment; + }; + + class ResSetFriendComment : public GenericAPI::GenericResponse + { + public: + ResSetFriendComment(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address, const ChatUnicodeString &comment); + virtual ~ResSetFriendComment() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + const Plat_Unicode::String &getComment() const { return m_comment; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + Plat_Unicode::String m_comment; + }; + + class ResRemoveFriend : public GenericAPI::GenericResponse + { + public: + ResRemoveFriend(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address); + virtual ~ResRemoveFriend() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + + class ResRemoveFriendReciprocate : public GenericAPI::GenericResponse + { + public: + ResRemoveFriendReciprocate(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address); + virtual ~ResRemoveFriendReciprocate() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() const { return m_name; } + const Plat_Unicode::String &getAddress() const { return m_address; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + + class ResFriendStatus : public GenericAPI::GenericResponse + { + public: + ResFriendStatus(void *user, unsigned avatarID); + virtual ~ResFriendStatus(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getListLength() const { return m_listLength; } + const ChatFriendStatus *getFriendList() const { return m_friendList; } + private: + unsigned m_avatarID; + unsigned m_listLength; + ChatFriendStatus *m_friendList; + ChatFriendStatusCore *m_cores; + }; + + class ResAddIgnore : public GenericAPI::GenericResponse + { + public: + ResAddIgnore(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address); + virtual ~ResAddIgnore() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() { return m_name; } + const Plat_Unicode::String &getAddress() { return m_address; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + + class ResRemoveIgnore : public GenericAPI::GenericResponse + { + public: + ResRemoveIgnore(void *user, unsigned avatarID, const ChatUnicodeString &name, const ChatUnicodeString &address); + virtual ~ResRemoveIgnore() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + const Plat_Unicode::String &getName() { return m_name; } + const Plat_Unicode::String &getAddress() { return m_address; } + private: + unsigned m_avatarID; + Plat_Unicode::String m_name; + Plat_Unicode::String m_address; + }; + + class ResIgnoreStatus : public GenericAPI::GenericResponse + { + public: + ResIgnoreStatus(void *user, unsigned avatarID); + virtual ~ResIgnoreStatus(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getListLength() const { return m_listLength; } + const ChatIgnoreStatus *getIgnoreList() const { return m_ignoreList; } + private: + unsigned m_avatarID; + unsigned m_listLength; + ChatIgnoreStatus *m_ignoreList; + ChatIgnoreStatusCore *m_cores; + }; + + + class ResEnterRoom : public GenericAPI::GenericResponse + { + public: + ResEnterRoom(void *user, unsigned avatarID, const ChatUnicodeString &destAddress); + virtual ~ResEnterRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + const Plat_Unicode::String &getDestAddress() { return m_destAddress; } + ChatRoomCore *getRoom() const { return m_room; } + unsigned getNumExtraRooms() const { return m_numExtraRooms; } + const std::set &getExtraRooms() { return m_setExtraRooms; } + private: + unsigned m_avatarID; + unsigned m_roomID; + Plat_Unicode::String m_destAddress; + bool m_gotRoomObj; + ChatRoomCore* m_room; + unsigned m_numExtraRooms; + std::set m_setExtraRooms; + }; + + class ResAllowRoomEntry : public GenericAPI::GenericResponse + { + public: + ResAllowRoomEntry(void *user, unsigned srcAvatarID, const ChatUnicodeString &destRoomAddress); + virtual ~ResAllowRoomEntry() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestRoomAddress() const { return m_destRoomAddress; } + + private: + unsigned m_srcAvatarID; + unsigned m_roomID; + Plat_Unicode::String m_destRoomAddress; + }; + + class ResLeaveRoom : public GenericAPI::GenericResponse + { + public: + ResLeaveRoom(void *user, unsigned avatarID, const ChatUnicodeString &destAddress); + virtual ~ResLeaveRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + unsigned getRoomID() const { return m_roomID; } + const Plat_Unicode::String &getDestAddress() { return m_destAddress; } + private: + unsigned m_avatarID; + unsigned m_roomID; + Plat_Unicode::String m_destAddress; + }; + + class ResAddModerator : public GenericAPI::GenericResponse + { + public: + ResAddModerator(void *user, unsigned srcAvatarID); + virtual ~ResAddModerator() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResRemoveModerator : public GenericAPI::GenericResponse + { + public: + ResRemoveModerator(void *user, unsigned srcAvatarID); + virtual ~ResRemoveModerator() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResAddTemporaryModerator : public GenericAPI::GenericResponse + { + public: + ResAddTemporaryModerator(void *user, unsigned srcAvatarID); + virtual ~ResAddTemporaryModerator() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResRemoveTemporaryModerator : public GenericAPI::GenericResponse + { + public: + ResRemoveTemporaryModerator(void *user, unsigned srcAvatarID); + virtual ~ResRemoveTemporaryModerator() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResAddBan : public GenericAPI::GenericResponse + { + public: + ResAddBan(void *user, unsigned srcAvatarID); + virtual ~ResAddBan() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResRemoveBan : public GenericAPI::GenericResponse + { + public: + ResRemoveBan(void *user, unsigned srcAvatarID); + virtual ~ResRemoveBan() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResAddInvite : public GenericAPI::GenericResponse + { + public: + ResAddInvite(void *user, unsigned srcAvatarID); + virtual ~ResAddInvite() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResRemoveInvite : public GenericAPI::GenericResponse + { + public: + ResRemoveInvite(void *user, unsigned srcAvatarID); + virtual ~ResRemoveInvite() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResGrantVoice : public GenericAPI::GenericResponse + { + public: + ResGrantVoice(void *user, unsigned srcAvatarID); + virtual ~ResGrantVoice() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResRevokeVoice : public GenericAPI::GenericResponse + { + public: + ResRevokeVoice(void *user, unsigned srcAvatarID); + virtual ~ResRevokeVoice() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + + class ResKickAvatar : public GenericAPI::GenericResponse + { + public: + ResKickAvatar(void *user, unsigned srcAvatarID); + virtual ~ResKickAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResSetRoomParams : public GenericAPI::GenericResponse + { + public: + ResSetRoomParams(void *user, unsigned srcAvatarID); + virtual ~ResSetRoomParams() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResChangeRoomOwner : public GenericAPI::GenericResponse + { + public: + ResChangeRoomOwner(void *user, unsigned srcAvatarID); + virtual ~ResChangeRoomOwner() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_srcAvatarID; + unsigned m_destRoomID; + }; + + class ResGetRoomSummaries : public GenericAPI::GenericResponse + { + public: + ResGetRoomSummaries(void *user); + virtual ~ResGetRoomSummaries(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getNumRooms() const { return m_numRooms; } + RoomSummary *getRoomSummaries() const { return m_roomSummaries; } + private: + unsigned m_numRooms; + RoomSummary *m_roomSummaries; + }; + + class ResSendPersistentMessage : public GenericAPI::GenericResponse + { + public: + ResSendPersistentMessage(void *user, unsigned srcAvatarID); + virtual ~ResSendPersistentMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getMessageID() const { return m_messageID; } + + private: + unsigned m_srcAvatarID; + unsigned m_messageID; + }; + + class ResSendMultiplePersistentMessages : public GenericAPI::GenericResponse + { + public: + ResSendMultiplePersistentMessages(void *user, unsigned srcAvatarID); + virtual ~ResSendMultiplePersistentMessages() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getNumResults() const { return m_numResults; } + const std::vector &getResultVector() const { return m_resultVector; } + const std::vector &getMessageIDvector() const { return m_messageIDvector; } + + private: + unsigned m_srcAvatarID; + unsigned m_numResults; + std::vector m_resultVector; + std::vector m_messageIDvector; + }; + + class ResAlterPersistentMessage : public GenericAPI::GenericResponse + { + public: + ResAlterPersistentMessage(const ChatUnicodeString &destAvatarName, const ChatUnicodeString &destAvatarAddress, unsigned messageID, void *user); + virtual ~ResAlterPersistentMessage(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + unsigned getMessageID() const { return m_messageID; } + + private: + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + unsigned m_messageID; + }; + + class ResGetPersistentHeaders : public GenericAPI::GenericResponse + { + public: + ResGetPersistentHeaders(void *user, unsigned srcAvatarID); + virtual ~ResGetPersistentHeaders(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const PersistentHeader *getList() const { return m_headers; } + unsigned getListLength() const { return m_listLength; } + + private: + unsigned m_srcAvatarID; + unsigned m_listLength; + PersistentHeader *m_headers; + PersistentHeaderCore *m_cores; + }; + + class ResGetPartialPersistentHeaders : public GenericAPI::GenericResponse + { + public: + ResGetPartialPersistentHeaders(void *user, unsigned srcAvatarID); + virtual ~ResGetPartialPersistentHeaders(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const PersistentHeader *getList() const { return m_headers; } + unsigned getListLength() const { return m_listLength; } + + private: + unsigned m_srcAvatarID; + unsigned m_listLength; + PersistentHeader *m_headers; + PersistentHeaderCore *m_cores; + }; + + class ResCountPersistentMessages : public GenericAPI::GenericResponse + { + public: + ResCountPersistentMessages(void *user, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress); + virtual ~ResCountPersistentMessages() { } + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + const Plat_Unicode::String &getAvatarName() const { return m_avatarName; } + const Plat_Unicode::String &getAvatarAddress() const { return m_avatarAddress; } + unsigned getNumberOfMessages() const { return m_numMessages; } + + private: + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_avatarAddress; + unsigned m_numMessages; + }; + + class ResGetPersistentMessage : public GenericAPI::GenericResponse + { + public: + ResGetPersistentMessage(void *user, unsigned srcAvatarID, unsigned messageID); + virtual ~ResGetPersistentMessage(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const PersistentHeader *getHeader() const { return m_header; } + const Plat_Unicode::String &getMsg() const { return m_msg; } + const Plat_Unicode::String &getOOB() const { return m_oob; } + + private: + unsigned m_srcAvatarID; + unsigned m_messageID; + PersistentHeaderCore *m_core; + PersistentHeader *m_header; + Plat_Unicode::String m_msg; + Plat_Unicode::String m_oob; + }; + + class ResGetMultiplePersistentMessages: public GenericAPI::GenericResponse + { + public: + ResGetMultiplePersistentMessages(void *user, unsigned srcAvatarID); + virtual ~ResGetMultiplePersistentMessages(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + PersistentMessage ** const getList() const; + unsigned getListLength() const { return m_listLength; } + + private: + unsigned m_srcAvatarID; + unsigned m_listLength; + PersistentMessageCore **m_messages; + }; + + class ResUpdatePersistentMessage : public GenericAPI::GenericResponse + { + public: + ResUpdatePersistentMessage(void *user, unsigned srcAvatarID, unsigned messageID); + virtual ~ResUpdatePersistentMessage() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + + private: + unsigned m_srcAvatarID; + unsigned m_messageID; + }; + + class ResUpdatePersistentMessages : public GenericAPI::GenericResponse + { + public: + ResUpdatePersistentMessages(void *user, unsigned srcAvatarID); + virtual ~ResUpdatePersistentMessages() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + + private: + unsigned m_srcAvatarID; + }; + + class ResClassifyPersistentMessages : public GenericAPI::GenericResponse + { + public: + ResClassifyPersistentMessages(void *user, unsigned srcAvatarID); + virtual ~ResClassifyPersistentMessages() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + + private: + unsigned m_srcAvatarID; + }; + + class ResDeleteAllPersistentMessages : public GenericAPI::GenericResponse + { + public: + ResDeleteAllPersistentMessages(void *user, const ChatUnicodeString &avatarName, const ChatUnicodeString &avatarAddress); + virtual ~ResDeleteAllPersistentMessages() { } + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + const Plat_Unicode::String &getAvatarName() const { return m_avatarName; } + const Plat_Unicode::String &getAvatarAddress() const { return m_avatarAddress; } + unsigned getNumberDeleted() const { return m_numDeleted; } + + private: + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_avatarAddress; + unsigned m_numDeleted; + }; + + class ResUnregisterRoom : public GenericAPI::GenericResponse + { + public: + ResUnregisterRoom(void *user); + virtual ~ResUnregisterRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getDestRoomID() const { return m_destRoomID; } + private: + unsigned m_destRoomID; + }; + + class ResFailoverReloginAvatar : public GenericAPI::GenericResponse + { + public: + ResFailoverReloginAvatar(unsigned avatarID); + virtual ~ResFailoverReloginAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + int getRequiredLoginPriority() const { return m_requiredPriority; } + private: + unsigned m_avatarID; + int m_requiredPriority; + }; + + class ResFailoverRecreateRoom : public GenericAPI::GenericResponse + { + public: + ResFailoverRecreateRoom(unsigned roomID, bool forced = false); + virtual ~ResFailoverRecreateRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getRoomID() const { return m_roomID; } + ChatRoomCore *getRoom() const { return m_room; } + bool wasFailoverForcedByServer() { return m_forced; } + private: + unsigned m_roomID; + ChatRoomCore *m_room; + bool m_forced; + }; + + class ResFriendConfirm : public GenericAPI::GenericResponse + { + public: + ResFriendConfirm(unsigned srcAvatarID, void *user); + virtual ~ResFriendConfirm() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + private: + unsigned m_avatarID; + }; + + class ResFriendConfirmReciprocate : public GenericAPI::GenericResponse + { + public: + ResFriendConfirmReciprocate(unsigned srcAvatarID, void *user); + virtual ~ResFriendConfirmReciprocate() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getAvatarID() const { return m_avatarID; } + private: + unsigned m_avatarID; + }; + + class ResGetFanClubHandle : public GenericAPI::GenericResponse + { + public: + ResGetFanClubHandle(unsigned stationID, unsigned fanClubHandle, void *user); + virtual ~ResGetFanClubHandle() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getStationID() const { return m_stationID; } + unsigned getFanClubCode() const { return m_fanClubCode; } + const Plat_Unicode::String &getHandle() const { return m_handle; } + private: + unsigned m_stationID; + unsigned m_fanClubCode; + Plat_Unicode::String m_handle; + }; + + class ResFindAvatarByUID : public GenericAPI::GenericResponse + { + public: + ResFindAvatarByUID(void *user); + virtual ~ResFindAvatarByUID(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getNumAvatarsOnline() const { return m_numAvatarsOnline; } + ChatAvatarCore **getAvatarsCore() const { return m_avatars; } + private: + unsigned m_numAvatarsOnline; + ChatAvatarCore **m_avatars; + }; + + class ResRegistrarGetChatServer: public GenericAPI::GenericResponse + { + public: + ResRegistrarGetChatServer(); + virtual ~ResRegistrarGetChatServer() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + const Plat_Unicode::String &getHostname() const { return m_hostname; } + unsigned short getPort() const { return m_port; } + private: + Plat_Unicode::String m_hostname; + unsigned short m_port; + }; + + class ResSendApiVersion: public GenericAPI::GenericResponse + { + public: + ResSendApiVersion(); + virtual ~ResSendApiVersion() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned long getServerVersion() const { return m_serverVersion; } + private: + unsigned long m_serverVersion; + }; + + class ResAddSnoopAvatar : public GenericAPI::GenericResponse + { + public: + ResAddSnoopAvatar(void *user, unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~ResAddSnoopAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + }; + + class ResRemoveSnoopAvatar : public GenericAPI::GenericResponse + { + public: + ResRemoveSnoopAvatar(void *user, unsigned srcAvatarID, const ChatUnicodeString &destName, const ChatUnicodeString &destAddress); + virtual ~ResRemoveSnoopAvatar() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getDestAvatarName() const { return m_destAvatarName; } + const Plat_Unicode::String &getDestAvatarAddress() const { return m_destAvatarAddress; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_destAvatarName; + Plat_Unicode::String m_destAvatarAddress; + }; + + class ResAddSnoopRoom : public GenericAPI::GenericResponse + { + public: + ResAddSnoopRoom(void *user, unsigned srcAvatarID, const ChatUnicodeString &roomAddress); + virtual ~ResAddSnoopRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_roomAddress; + }; + + class ResRemoveSnoopRoom : public GenericAPI::GenericResponse + { + public: + ResRemoveSnoopRoom(void *user, unsigned srcAvatarID, const ChatUnicodeString &roomAddress); + virtual ~ResRemoveSnoopRoom() {}; + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + const Plat_Unicode::String &getRoomAddress() const { return m_roomAddress; } + private: + unsigned m_srcAvatarID; + Plat_Unicode::String m_roomAddress; + }; + + class ResGetSnoopList : public GenericAPI::GenericResponse + { + public: + ResGetSnoopList(void *user, unsigned srcAvatarID); + virtual ~ResGetSnoopList(); + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getSrcAvatarID() const { return m_srcAvatarID; } + unsigned getAvatarSnoopListLength() const { return m_avatarSnoopListLength; } + AvatarSnoopPair **getAvatarSnoopList() const { return m_avatarSnoops; } + unsigned getRoomSnoopListLength() const { return m_roomSnoopListLength; } + ChatUnicodeString **getRoomSnoopList() const { return m_roomSnoops; } + private: + unsigned m_srcAvatarID; + unsigned m_avatarSnoopListLength; + unsigned m_roomSnoopListLength; + AvatarSnoopPair **m_avatarSnoops; + ChatUnicodeString **m_roomSnoops; + }; + + class ResTransferAvatar : public GenericAPI::GenericResponse + { + public: + ResTransferAvatar(void *user, unsigned userID, unsigned newUserID, const ChatUnicodeString &avatarName, const ChatUnicodeString &newAvatarName, const ChatUnicodeString &avatarAddress, const ChatUnicodeString &newAvatarAddress); + virtual ~ResTransferAvatar() {} + + virtual void unpack(Base::ByteStream::ReadIterator &iter); + + unsigned getUserID() const { return m_userID; } + unsigned getNewUserID() const { return m_newUserID; } + const Plat_Unicode::String &getAvatarName() const { return m_avatarName; } + const Plat_Unicode::String &getNewAvatarName() const { return m_newAvatarName; } + const Plat_Unicode::String &getAvatarAddress() const { return m_avatarAddress; } + const Plat_Unicode::String &getNewAvatarAddress() const { return m_newAvatarAddress; } + private: + unsigned m_userID; + unsigned m_newUserID; + Plat_Unicode::String m_avatarName; + Plat_Unicode::String m_newAvatarName; + Plat_Unicode::String m_avatarAddress; + Plat_Unicode::String m_newAvatarAddress; + }; + +}; // end namespace + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/RoomParamsCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/RoomParamsCore.h new file mode 100644 index 00000000..d0dbb8b4 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/RoomParamsCore.h @@ -0,0 +1,28 @@ +#if !defined (ROOMPARAMSCORE_H_) +#define ROOMPARAMSCORE_H_ + +#include + +#include "ChatEnum.h" + +namespace ChatSystem { + + +struct RoomParamsCore +{ + Plat_Unicode::String m_name; + ChatUnicodeString m_cName; + Plat_Unicode::String m_topic; + ChatUnicodeString m_cTopic; + Plat_Unicode::String m_password; + ChatUnicodeString m_cPassword; + + unsigned m_attributes; + unsigned m_size; +}; + +}; + +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/RoomSummaryCore.h b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/RoomSummaryCore.h new file mode 100644 index 00000000..ba620609 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/RoomSummaryCore.h @@ -0,0 +1,25 @@ +#if !defined (ROOMSUMMARYCORE_H_) +#define ROOMSUMMARYCORE_H_ + +#include + +#include "ChatEnum.h" + +namespace ChatSystem { + + +struct RoomSummaryCore +{ + Plat_Unicode::String m_address; + Plat_Unicode::String m_topic; + + + unsigned m_attributes; + unsigned m_curSize; + unsigned m_maxSize; +}; + +}; +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/projects/ChatMono/CMakeLists.txt b/external/3rd/library/soePlatform/ChatAPI/projects/ChatMono/CMakeLists.txt new file mode 100644 index 00000000..fd200c5a --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/projects/ChatMono/CMakeLists.txt @@ -0,0 +1,159 @@ + +set(SHARED_SOURCES + ../ChatAPI/AvatarIteratorCore.cpp + ../ChatAPI/AvatarIteratorCore.h + ../ChatAPI/AvatarListItem.h + ../ChatAPI/AvatarListItemCore.cpp + ../ChatAPI/AvatarListItemCore.h + ../ChatAPI/ChatAPI.cpp + ../ChatAPI/ChatAPI.h + ../ChatAPI/ChatAPICore.cpp + ../ChatAPI/ChatAPICore.h + ../ChatAPI/ChatAvatar.cpp + ../ChatAPI/ChatAvatar.h + ../ChatAPI/ChatAvatarCore.cpp + ../ChatAPI/ChatAvatarCore.h + ../ChatAPI/ChatEnum.cpp + ../ChatAPI/ChatEnum.h + ../ChatAPI/ChatFriendStatus.h + ../ChatAPI/ChatFriendStatusCore.cpp + ../ChatAPI/ChatFriendStatusCore.h + ../ChatAPI/ChatIgnoreStatus.h + ../ChatAPI/ChatIgnoreStatusCore.cpp + ../ChatAPI/ChatIgnoreStatusCore.h + ../ChatAPI/ChatRoom.cpp + ../ChatAPI/ChatRoom.h + ../ChatAPI/ChatRoomCore.cpp + ../ChatAPI/ChatRoomCore.h + ../ChatAPI/Message.cpp + ../ChatAPI/Message.h + ../ChatAPI/PersistentMessage.cpp + ../ChatAPI/PersistentMessage.h + ../ChatAPI/PersistentMessageCore.h + ../ChatAPI/Request.cpp + ../ChatAPI/Request.h + ../ChatAPI/Response.cpp + ../ChatAPI/Response.h + ../ChatAPI/RoomParamsCore.h + ../ChatAPI/RoomSummaryCore.h + + ../../utils/Base/Archive.cpp + ../../utils/Base/Archive.h + ../../utils/Base/AutoLog.cpp + ../../utils/Base/AutoLog.h + ../../utils/Base/Base.cpp + ../../utils/Base/Base.h + ../../utils/Base/Base64.cpp + ../../utils/Base/Base64.h + ../../utils/Base/BlockAllocator.h + ../../utils/Base/ccspanutil.cpp + ../../utils/Base/ccspanutil.h + ../../utils/Base/CmdLine.cpp + ../../utils/Base/CmdLine.h + ../../utils/Base/Config.cpp + ../../utils/Base/Config.h + ../../utils/Base/Event.h + ../../utils/Base/Logger.cpp + ../../utils/Base/Logger.h + ../../utils/Base/MD5.cpp + ../../utils/Base/MD5.h + ../../utils/Base/Mutex.h + ../../utils/Base/Platform.h + ../../utils/Base/ScopeLock.cpp + ../../utils/Base/ScopeLock.h + ../../utils/Base/Statistics.cpp + ../../utils/Base/Statistics.h + ../../utils/Base/TemplateBlockAllocator.h + ../../utils/Base/TemplateObjectAllocator.h + ../../utils/Base/Thread.h + ../../utils/Base/Types.h + ../../utils/Base/WideString.h + + ../../utils/UdpLibrary/UdpConnection.cpp + ../../utils/UdpLibrary/UdpConnection.h + ../../utils/UdpLibrary/UdpDriver.h + ../../utils/UdpLibrary/UdpHandler.h + ../../utils/UdpLibrary/UdpHashTable.h + ../../utils/UdpLibrary/UdpHelper.h + ../../utils/UdpLibrary/UdpLibrary.cpp + ../../utils/UdpLibrary/UdpLibrary.h + ../../utils/UdpLibrary/UdpLinkedList.h + ../../utils/UdpLibrary/UdpLogicalPacket.cpp + ../../utils/UdpLibrary/UdpLogicalPacket.h + ../../utils/UdpLibrary/UdpManager.cpp + ../../utils/UdpLibrary/UdpManager.h + ../../utils/UdpLibrary/UdpMisc.cpp + ../../utils/UdpLibrary/UdpMisc.h + ../../utils/UdpLibrary/UdpPriority.h + ../../utils/UdpLibrary/UdpReliableChannel.cpp + ../../utils/UdpLibrary/UdpReliablechannel.h + ../../utils/UdpLibrary/UdpTypes.h + + ../../utils/Unicode/FirstUnicode.cpp + ../../utils/Unicode/FirstUnicode.h + ../../utils/Unicode/Unicode.cpp + ../../utils/Unicode/Unicode.h + ../../utils/Unicode/UnicodeBlocks.cpp + ../../utils/Unicode/UnicodeBlocks.h + ../../utils/Unicode/UnicodeCharacterData.cpp + ../../utils/Unicode/UnicodeCharacterData.h + ../../utils/Unicode/UnicodeCharacterDataMap.cpp + ../../utils/Unicode/UnicodeCharacterDataMap.h + ../../utils/Unicode/UnicodeCharTraits.cpp + ../../utils/Unicode/UnicodeUtils.cpp + ../../utils/Unicode/UnicodeUtils.h + ../../utils/Unicode/utf8.cpp + ../../utils/Unicode/utf8.h + + ../../utils/GenericAPI/GenericApicore.cpp + ../../utils/GenericAPI/GenericApiCore.h + ../../utils/GenericAPI/GenericConnection.cpp + ../../utils/GenericAPI/GenericConnection.h + ../../utils/GenericAPI/GenericMessage.cpp + ../../utils/GenericAPI/GenericMessage.h +) + +if(WIN32) + set(PLATFORM_SOURCES + ../../utils/Base/win32/Archive.h + ../../utils/Base/win32/BlockAllocator.cpp + ../../utils/Base/win32/Event.cpp + ../../utils/Base/win32/Event.h + ../../utils/Base/win32/Mutex.cpp + ../../utils/Base/win32/Mutex.h + ../../utils/Base/win32/Platform.cpp + ../../utils/Base/win32/Platform.h + ../../utils/Base/win32/Thread.cpp + ../../utils/Base/win32/Thread.h + ../../utils/Base/win32/Types.h + + ../../utils/UdpLibrary/UdpDriverWindows.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../utils/Base/win32) +else() + set(PLATFORM_SOURCES + ../../utils/Base/linux/Archive.h + ../../utils/Base/linux/BlockAllocator.cpp + ../../utils/Base/linux/Event.cpp + ../../utils/Base/linux/Event.h + ../../utils/Base/linux/Mutex.cpp + ../../utils/Base/linux/Mutex.h + ../../utils/Base/linux/Platform.cpp + ../../utils/Base/linux/Platform.h + ../../utils/Base/linux/Thread.cpp + ../../utils/Base/linux/Thread.h + ../../utils/Base/linux/Types.h + + ../../utils/UdpLibrary/UdpDriverLinux.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../utils/Base/linux) +endif() + +include_directories() + +add_library(ChatMono + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) \ No newline at end of file diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Archive.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Archive.cpp new file mode 100644 index 00000000..c7a1b9a8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Archive.cpp @@ -0,0 +1,299 @@ +//////////////////////////////////////////////////////////////////////////////// +// The author of this code is Justin Randall +// +// I have made modifications to the ByteStream +// and AutoByteStream classes in order to make them suitable +// for use in messaging systems which require objects that +// are copyable and assignable. It is also desirable for +// the ByteStream object to use a flexible allocator system +// that may support multi-threaded programming models. + + +#include "Archive.h" + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + +//////////////////////////////////////////////////////////////////////////////// + + +#if defined(USE_ARCHIVE_MUTEX) + CMutex ByteStreamMutex; +#endif + + // Default to Data object reuse + bool ByteStream::ms_reuseData = true; + +#if defined (PASCAL_STRING) +#pragma message ("--- Packing pascal style strings ---") + unsigned get(Base::ByteStream::ReadIterator& source, std::string& target) + { + unsigned int size = 0; + if (source.getSize() < sizeof(size)) + { + return 0; + } + + Base::get (source, size); + + const unsigned char *buf = source.getBuffer(); + + target.assign((const char *)buf, (const char *)(buf + size)); + + const unsigned int readSize = size * sizeof(char); + source.advance(readSize); + + return (readSize + sizeof(size)); + } + + void put(ByteStream& target, const std::string& source) + { + const unsigned int size = source.size(); + put(target, size); + target.put(source.data(), size * sizeof (char)); + } + +#else +#pragma message ("--- Packing c style strings ---") + unsigned get(ByteStream::ReadIterator & source, std::string & target) + { + target = reinterpret_cast(source.getBuffer()); + + if (target.length() > source.getSize()) + return 0; + + source.advance(target.length() + 1); + + return (target.length() + 1); + } + + + void put(ByteStream & target, const std::string & source) + { + target.put(source.c_str(), source.size()+1); + } +#endif + + ByteStream::ReadIterator::ReadIterator() : + readPtr(0), + stream(0) + { + } + + ByteStream::ReadIterator::ReadIterator(const ReadIterator & source) : + readPtr(source.readPtr), + stream(source.stream) + { + } + + ByteStream::ReadIterator::ReadIterator(const ByteStream & source) : + readPtr(0), + stream(&source) + { + } + + ByteStream::ReadIterator::~ReadIterator() + { + stream = 0; + } + + ByteStream::ByteStream() : + allocatedSize(0), + beginReadIterator(), + data(NULL), + size(0), + lastPutSize(0) + { + data = Data::getNewData(); + beginReadIterator = ReadIterator(*this); + } + + ByteStream::ByteStream(const unsigned char * const newBuffer, const unsigned int bufferSize) : + allocatedSize(bufferSize), + data(0), + size(bufferSize), + lastPutSize(0) + { + data = Data::getNewData(); + if(data->size < size) + { + delete[] data->buffer; + data->buffer = new unsigned char[size]; + data->size = size; + } + memcpy(data->buffer, newBuffer, size); + beginReadIterator = ReadIterator(*this); + } + + ByteStream::ByteStream(const ByteStream & source): + allocatedSize(source.getSize()), // only allocate what is really there, be opportinistic when grow()'ing + data(source.data), + size(source.getSize()), + lastPutSize(source.lastPutSize) + { + source.data->ref(); + beginReadIterator = ReadIterator(*this); + } + + ByteStream::ByteStream(ReadIterator & source) : + allocatedSize(0), + size(0), + lastPutSize(0) + { + data = Data::getNewData(); + put(source.getBuffer(), source.getSize()); + source.advance(source.getSize()); + beginReadIterator = ReadIterator(*this); + } + + ByteStream::~ByteStream() + { + data->deref(); + allocatedSize = 0; + data = 0; //lint !e672 (data deref insures the data is deleted if no one references it) + size = 0; + } + + ByteStream & ByteStream::operator=(const ByteStream & rhs) + { + if(this != &rhs) + { + data->deref(); // deref local data + rhs.data->ref(); + allocatedSize = rhs.allocatedSize; + size = rhs.size; + data = rhs.data; //lint !e672 (data is ref counted) + } + return *this; + } + + void ByteStream::get(void * target, ReadIterator & readIterator, const unsigned long int targetSize) const + { + assert(readIterator.getReadPosition() + targetSize <= allocatedSize); + memcpy(target, &data->buffer[readIterator.getReadPosition()], targetSize); + } + + void ByteStream::put(const void * const source, const unsigned int sourceSize) + { + if(data->getRef() > 1) + { + const unsigned char * const tmp = data->buffer; + data->deref(); + data = Data::getNewData(); + if(data->size < sourceSize) + { + delete[] data->buffer; + data->buffer = new unsigned char[size]; + data->size = size; + } + memcpy(data->buffer, tmp, size); + allocatedSize = size; + } + growToAtLeast(size + sourceSize); + memcpy(&data->buffer[size], source, sourceSize); + size += sourceSize; + if (sourceSize > 0) + lastPutSize = sourceSize; + } + + bool ByteStream::overwriteEnd(const void * const source, const unsigned int sourceSize) + { + if(data->getRef() <= 1 && + lastPutSize == sourceSize && + sourceSize <= data->size) + { + memcpy(&data->buffer[size-sourceSize], source, sourceSize); + return true; + } + else + { + return false; + } + } + + void ByteStream::reAllocate(const unsigned int newSize) + { + allocatedSize = newSize; + if(data->size < allocatedSize) + { + unsigned char * tmp = new unsigned char[newSize]; + if(data->buffer != NULL) + memcpy(tmp, data->buffer, size); + delete[] data->buffer; + data->buffer = tmp; + data->size = newSize; + } + } + + +//////////////////////////////////////////////////////////////////////////////// + + + AutoByteStream::AutoByteStream() : + members() + { + } + + AutoByteStream::~AutoByteStream() + { + } + + void AutoByteStream::addVariable(AutoVariableBase & newVariable) + { + members.push_back(&newVariable); + } + + const unsigned int AutoByteStream::getItemCount() const + { + return members.size(); + } + + void AutoByteStream::pack(ByteStream & target) const + { + std::vector::const_iterator i; + unsigned short packedSize=static_cast(members.size()); + put(target,packedSize); + for(i = members.begin(); i != members.end(); ++i) + { + (*i)->pack(target); + } + } + + void AutoByteStream::unpack(ByteStream::ReadIterator & source) + { + std::vector::iterator i; + unsigned short packedSize; + get(source,packedSize); + for(i = members.begin(); i != members.end(); ++i) + { + (*i)->unpack(source); + } + } + + +//////////////////////////////////////////////////////////////////////////////// + + + AutoVariableBase::AutoVariableBase() + { + } + + AutoVariableBase::~AutoVariableBase() + { + } + + +//////////////////////////////////////////////////////////////////////////////// + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Archive.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Archive.h new file mode 100644 index 00000000..d616b8ba --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Archive.h @@ -0,0 +1,756 @@ +//////////////////////////////////////////////////////////////////////////////// +// The author of this code is Justin Randall +// +// I have made modifications to the ByteStream +// and AutoByteStream classes in order to make them suitable +// for use in messaging systems which require objects that +// are copyable and assignable. It is also desirable for +// the ByteStream object to use a flexible allocator system +// that may support multi-threaded programming models. + + +#ifndef BASE_ARCHIVE_H +#define BASE_ARCHIVE_H + + +#include +#include +#include +#include "Platform.h" +#include "Mutex.h" + + +#if defined _MT || defined _REENTRANT +# define USE_ARCHIVE_MUTEX +#endif + +#ifdef WIN32 +# include "win32/Archive.h" +#elif linux +# include "linux/Archive.h" +#elif sparc +# include "solaris/Archive.h" +#else + #error /Base/Archive.h: Undefine platform type +#endif + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +const unsigned MAX_ARRAY_SIZE = 1024; + + +//////////////////////////////////////////////////////////////////////////////// + +#if defined(USE_ARCHIVE_MUTEX) + extern CMutex ByteStreamMutex; +#endif + + class ByteStream + { + public: + class ReadIterator + { + public: + ReadIterator(); + ReadIterator(const ReadIterator & source); + explicit ReadIterator(const ByteStream & source); + ~ReadIterator(); + + ReadIterator & operator = (const ReadIterator & source); + void advance (const unsigned int distance); + unsigned get (void * target, const unsigned long int readSize); + const unsigned int getSize () const; + const unsigned char * const getBuffer () const; + const unsigned int getReadPosition () const; + + private: + unsigned int readPtr; + const ByteStream * stream; + }; + + private: + class Data + { + friend class ByteStream; + friend class ReadIterator; + public: + ~Data(); + + static Data * getNewData(); + + const int getRef () const; + void deref (); + void ref (); + protected: + unsigned char * buffer; + unsigned long size; + private: + struct DataFreeList + { + ~DataFreeList() + { + std::vector::iterator i; + for(i = freeList.begin(); i != freeList.end(); ++i) + { + delete (*i); + } + }; + std::vector freeList; + }; + Data(); + //explicit Data(unsigned char * buffer); + static std::vector & getDataFreeList(); + static void releaseOldData(Data * oldData); + private: + int refCount; + }; + + friend class ReadIterator; + public: + ByteStream(); + ByteStream(const unsigned char * const buffer, const unsigned int bufferSize); + ByteStream(const ByteStream & source); + virtual ~ByteStream(); + + public: + ByteStream(ReadIterator & source); + ByteStream & operator = (const ByteStream & source); + ByteStream & operator = (ReadIterator & source); + const ReadIterator & begin() const; + void clear(); + const unsigned char * const getBuffer() const; + const unsigned int getSize() const; + void put(const void * const source, const unsigned int sourceSize); + bool overwriteEnd(const void * const source, const unsigned int sourceSize); + + static bool ms_reuseData; + + private: + void get(void * target, ReadIterator & readIterator, const unsigned long int readSize) const; + void growToAtLeast(const unsigned int targetSize); + void reAllocate(const unsigned int newSize); + + private: + unsigned int allocatedSize; + ReadIterator beginReadIterator; + Data * data; + unsigned int size; + unsigned int lastPutSize; + + }; + + inline ByteStream::Data::Data() : + buffer(0), + size(0), + refCount(1) + { + } + + inline ByteStream::Data::~Data() + { +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Lock(); +#endif + + refCount = 0; + delete[] buffer; + +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Unlock(); +#endif + } + + inline void ByteStream::Data::deref() + { +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Lock(); +#endif + + refCount--; + +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Unlock(); +#endif + + if(refCount < 1) + releaseOldData(this); + } + + inline std::vector & ByteStream::Data::getDataFreeList() + { + static DataFreeList freeList; + return freeList.freeList; + } + + inline ByteStream::Data * ByteStream::Data::getNewData() + { +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Lock(); +#endif + + Data * result = 0; + if(getDataFreeList().empty()) + { + result = new Data; + } + else + { + result = getDataFreeList().back(); + getDataFreeList().pop_back(); + } + result->refCount = 1; + +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Unlock(); +#endif + + return result; + } + + inline const int ByteStream::Data::getRef() const + { + return refCount; + } + + inline void ByteStream::Data::ref() + { +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Lock(); +#endif + + refCount++; + +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Unlock(); +#endif + } + + inline void ByteStream::Data::releaseOldData(ByteStream::Data * oldData) + { + if (ByteStream::ms_reuseData) + { +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Lock(); +#endif + + getDataFreeList().push_back(oldData); + oldData->refCount = 0; + +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Unlock(); +#endif + } + else + { + delete oldData; + } + } + + inline ByteStream::ReadIterator & ByteStream::ReadIterator::operator = (const ByteStream::ReadIterator & rhs) + { + if(&rhs != this) + { + readPtr = rhs.readPtr; + stream = rhs.stream; + } + return *this; + } + + inline unsigned ByteStream::ReadIterator::get(void * target, const unsigned long int readSize) + { + assert(stream); + stream->get(target, *this, readSize); + readPtr += readSize; + return readSize; + } + + inline const unsigned int ByteStream::ReadIterator::getSize() const + { + assert(stream); + return stream->getSize() - readPtr; + } + + inline const ByteStream::ReadIterator & ByteStream::begin() const + { + return beginReadIterator; + } + + inline void ByteStream::ReadIterator::advance(const unsigned int distance) + { + readPtr += distance; + } + + inline const unsigned int ByteStream::ReadIterator::getReadPosition() const + { + return readPtr; + } + + inline const unsigned char * const ByteStream::ReadIterator::getBuffer() const + { + if(stream) + return &stream->data->buffer[readPtr]; + + return 0; + } + + inline void ByteStream::clear() + { +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Lock(); +#endif + + size = 0; + +#if defined(USE_ARCHIVE_MUTEX) + ByteStreamMutex.Unlock(); +#endif + } + + inline const unsigned char * const ByteStream::getBuffer() const + { + return data->buffer; + } + + inline const unsigned int ByteStream::getSize() const + { + return size; + } + + inline void ByteStream::growToAtLeast(const unsigned int targetSize) + { + if(allocatedSize < targetSize) + { + reAllocate(allocatedSize + allocatedSize + targetSize); + } + } + + +//////////////////////////////////////////////////////////////////////////////// + + + class AutoVariableBase + { + public: + AutoVariableBase(); + virtual ~AutoVariableBase(); + + virtual void pack(ByteStream & target) const = 0; + virtual void unpack(ByteStream::ReadIterator & source) = 0; + }; + + +//////////////////////////////////////////////////////////////////////////////// + + + class AutoByteStream + { + public: + AutoByteStream(); + virtual ~AutoByteStream(); + void addVariable(AutoVariableBase & newVariable); + virtual const unsigned int getItemCount() const; + virtual void pack(ByteStream & target) const; + virtual void unpack(ByteStream::ReadIterator & source); + protected: + std::vector members; + private: + AutoByteStream(const AutoByteStream & source); + }; + + +//////////////////////////////////////////////////////////////////////////////// + + + template + class AutoVariable : public AutoVariableBase + { + public: + AutoVariable(); + explicit AutoVariable(const ValueType & source); + virtual ~AutoVariable(); + + const ValueType & get() const; + virtual void pack(ByteStream & target) const; + void set(const ValueType & rhs); + virtual void unpack(ByteStream::ReadIterator & source); + + private: + ValueType value; + }; + + template + AutoVariable::AutoVariable() : + AutoVariableBase(), + value() + { + } + + template + AutoVariable::AutoVariable(const ValueType & source) : + AutoVariableBase(), + value(source) + { + } + + template + AutoVariable::~AutoVariable() + { + } + + template + const ValueType & AutoVariable::get() const + { + return value; + } + + template + void AutoVariable::pack(ByteStream & target) const + { + Base::put(target, value); + } + + template + void AutoVariable::set(const ValueType & rhs) + { + value = rhs; + } + + template + void AutoVariable::unpack(ByteStream::ReadIterator & source) + { + Base::get(source, value); + } + + +//////////////////////////////////////////////////////////////////////////////// + + + template + class AutoArray : public AutoVariableBase + { + public: + AutoArray(); + AutoArray(const AutoArray & source); + ~AutoArray(); + + const std::vector & get() const; + void set(const std::vector & source); + + virtual void pack(ByteStream & target) const; + virtual void unpack(ByteStream::ReadIterator & source); + + private: + std::vector array; + }; + + template + inline AutoArray::AutoArray() + { + } + + template + inline AutoArray::AutoArray(const AutoArray & source) : + array(source.array) + { + } + + template + inline AutoArray::~AutoArray() + { + } + + template + inline const std::vector & AutoArray::get() const + { + return array; + } + + template + inline void AutoArray::set(const std::vector & source) + { + array = source; + } + + template + inline void AutoArray::pack(ByteStream & target) const + { + unsigned int arraySize = array.size(); + Base::put(target, arraySize); + + typename std::vector::const_iterator i; + for(i = array.begin(); i != array.end(); ++i) + { + ValueType v = (*i); + Base::put(target, v); + } + } + + template + inline void AutoArray::unpack(ByteStream::ReadIterator & source) + { + unsigned int arraySize; + Base::get(source, arraySize); + ValueType v; + + if (arraySize > MAX_ARRAY_SIZE) + arraySize = 0; + + for(unsigned int i = 0; i < arraySize; ++i) + { + Base::get(source, v); + array.push_back(v); + } + } + + +//////////////////////////////////////////////////////////////////////////////// + + + inline void get(ByteStream::ReadIterator & source, ByteStream & target) + { + target.put(source.getBuffer(), source.getSize()); + source.advance(source.getSize()); + } + + inline void get(ByteStream::ReadIterator & source, double & target) + { + source.get(&target, 8); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, float & target) + { + source.get(&target, 4); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, uint64 & target) + { + source.get(&target, 8); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, int64 & target) + { + source.get(&target, 8); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, uint32 & target) + { + source.get(&target, 4); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, int32 & target) + { + source.get(&target, 4); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, uint16 & target) + { + source.get(&target, 2); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, int16 & target) + { + source.get(&target, 2); + target = byteSwap(target); + } + + inline void get(ByteStream::ReadIterator & source, uint8 & target) + { + source.get(&target, 1); + } + + inline void get(ByteStream::ReadIterator & source, int8 & target) + { + source.get(&target, 1); + } + + inline unsigned get(ByteStream::ReadIterator & source, unsigned char * const target, const unsigned int targetSize) + { + return source.get(target, targetSize); + } + + inline void get(ByteStream::ReadIterator & source, bool & target) + { + source.get(&target, 1); + } + + +//////////////////////////////////////////////////////////////////////////////// + + + inline void put(ByteStream & target, ByteStream::ReadIterator & source) + { + target.put(source.getBuffer(), source.getSize()); + source.advance(source.getSize()); + } + + inline void put(ByteStream & target, const double value) + { + double temp = byteSwap(value); + target.put(&temp, 8); + } + + inline void put(ByteStream & target, const float value) + { + float temp = byteSwap(value); + target.put(&temp, 4); + } + + inline void put(ByteStream & target, const uint64 value) + { + uint64 temp = byteSwap(value); + target.put(&temp, 8); + } + + inline void put(ByteStream & target, const int64 value) + { + int64 temp = byteSwap(value); + target.put(&temp, 8); + } + + inline void put(ByteStream & target, const uint32 value) + { + uint32 temp = byteSwap(value); + target.put(&temp, 4); + } + + inline void put(ByteStream & target, const int32 value) + { + int32 temp = byteSwap(value); + target.put(&temp, 4); + } + + inline void put(ByteStream & target, const uint16 value) + { + uint16 temp = byteSwap(value); + target.put(&temp, 2); + } + + inline void put(ByteStream & target, const int16 value) + { + int16 temp = byteSwap(value); + target.put(&temp, 2); + } + + inline void put(ByteStream & target, const uint8 value) + { + target.put(&value, 1); + } + + inline void put(ByteStream & target, const int8 value) + { + target.put(&value, 1); + } + + inline void put(ByteStream & target, const bool & source) + { + target.put(&source, 1); + } + + + inline void put(ByteStream & target, const unsigned char * const source, const unsigned int sourceSize) + { + target.put(source, sourceSize); + } + + inline void put(ByteStream & target, const ByteStream & source) + { + target.put(source.begin().getBuffer(), source.begin().getSize()); + } + + unsigned get(ByteStream::ReadIterator & source, std::string & target); + void put(ByteStream & target, const std::string & source); + + +//////////////////////////////////////////////////////////////////////////////// + + + inline bool overwriteEnd(ByteStream & target, const double value) + { + double temp = byteSwap(value); + return target.overwriteEnd(&temp, 8); + } + + inline bool overwriteEnd(ByteStream & target, const float value) + { + float temp = byteSwap(value); + return target.overwriteEnd(&temp, 4); + } + + inline bool overwriteEnd(ByteStream & target, const uint64 value) + { + uint64 temp = byteSwap(value); + return target.overwriteEnd(&temp, 8); + } + + inline bool overwriteEnd(ByteStream & target, const int64 value) + { + int64 temp = byteSwap(value); + return target.overwriteEnd(&temp, 8); + } + + inline bool overwriteEnd(ByteStream & target, const uint32 value) + { + uint32 temp = byteSwap(value); + return target.overwriteEnd(&temp, 4); + } + + inline bool overwriteEnd(ByteStream & target, const int32 value) + { + int32 temp = byteSwap(value); + return target.overwriteEnd(&temp, 4); + } + + inline bool overwriteEnd(ByteStream & target, const uint16 value) + { + uint16 temp = byteSwap(value); + return target.overwriteEnd(&temp, 2); + } + + inline bool overwriteEnd(ByteStream & target, const int16 value) + { + int16 temp = byteSwap(value); + return target.overwriteEnd(&temp, 2); + } + + inline bool overwriteEnd(ByteStream & target, const uint8 value) + { + return target.overwriteEnd(&value, 1); + } + + inline bool overwriteEnd(ByteStream & target, const int8 value) + { + return target.overwriteEnd(&value, 1); + } + + inline bool overwriteEnd(ByteStream & target, const bool & source) + { + return target.overwriteEnd(&source, 1); + } + + inline bool overwriteEnd(ByteStream & target, const unsigned char * const source, const unsigned int sourceSize) + { + return target.overwriteEnd(source, sourceSize); + } + +//////////////////////////////////////////////////////////////////////////////// + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/AutoLog.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/AutoLog.cpp new file mode 100644 index 00000000..74e80236 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/AutoLog.cpp @@ -0,0 +1,349 @@ +#include "AutoLog.h" + +#include +#include +#include +#include +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +#ifdef WIN32 +#include // for NT directory commands +#define SLASHCHAR "\\" +#define WRONGSLASH '/' +#else +#define SLASHCHAR "/" +#define WRONGSLASH '\\' +#endif + +// set default values for global masks +CAutoLog::eLogLevel CAutoLog::nLogMask = eLOG_NORMAL; // what is logged in log files +CAutoLog::eLogLevel CAutoLog::nPrintMask = eLOG_ERROR; // what is printed on the screen +CAutoLog::eLogLevel CAutoLog::nFlushMask = eLOG_ERROR; // when is file flushed on every entry? + +// class info + +//------------------------------------- +bool CAutoLog::Open(const char * filename) +//------------------------------------- +{ + + if( NULL == filename) + return false; + + if (pFilename) + return false; + + pFilename = strdup(filename); + + // Sanitize slashes + char *ptr; + while ((ptr = strchr(pFilename,WRONGSLASH)) != NULL) + *ptr = SLASHCHAR[0]; + + char strPath[1024]; + strcpy(strPath,pFilename); + ptr = strrchr(strPath, SLASHCHAR[0]); + if (ptr != NULL) + { + *ptr = 0; + +#ifdef WIN32 + char curdir[128]; + + // remember current directory + if( getcwd(curdir,sizeof(curdir)) == NULL ) + { + fprintf(stderr,"CAutoLog::Archive failed to get current directory!\n"); + free(pFilename); + pFilename = NULL; + return false; // error, can't proceed + } + + if (chdir(strPath)) + { + // failed to find the directory, so we must create it + if (mkdir(strPath)) + { + fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath); + free(pFilename); + pFilename = NULL; + return false; // error, can't proceed + } + } + else + { + // found the directory, but we don't want to be there, so go back + chdir(curdir); + } +#else + struct stat SS; + + // see if directory exists + if (stat(strPath,&SS)) + { + // create directory + if (mkdir(strPath,0777)) + { + fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath); + free(pFilename); + pFilename = NULL; + return false; // error, can't proceed + } + } +#endif + } + + + pFile = fopen(pFilename,"a+"); + if( pFile == NULL || pFile == (FILE *)-1) + { + //fprintf(stderr,"CAutoLog::Open failed to open log file: %s\n",pFilename); + Close(); + return false; + } + + time_t t; + time(&t); + struct tm *ptm = localtime(&t); + nTodaysDayOfYear = ptm->tm_yday; + + //printf("Open log file: %s\n",pFilename); + return true; +} + +//------------------------------------- +void CAutoLog::Close(void) +//------------------------------------- +{ + if( pFile != (FILE *)-1 && pFile != NULL) + { + fclose(pFile); + } + pFile = (FILE *)-1; + + if (pFilename) + { + free(pFilename); + } + pFilename = NULL; +} + +//------------------------------------- +void CAutoLog::LogError(char * format, ...) +{ + char strInput[1024]; + + // parse format and input arguments + va_list varg; + va_start(varg, format); + vsprintf(strInput, format, varg); + va_end(varg); + + Log(eLOG_ERROR, strInput); +} + +//------------------------------------- +void CAutoLog::LogAlert(char * format, ...) +{ + char strInput[1024]; + + // parse format and input arguments + va_list varg; + va_start(varg, format); + vsprintf(strInput, format, varg); + va_end(varg); + + Log(eLOG_ALERT, strInput); +} + +//------------------------------------- +void CAutoLog::Log(char * format, ...) +{ + char strInput[1024]; + + // parse format and input arguments + va_list varg; + va_start(varg, format); + vsprintf(strInput, format, varg); + va_end(varg); + + Log(eLOG_NORMAL, strInput); +} + +//------------------------------------- +void CAutoLog::LogDebug(char * format, ...) +{ + char strInput[1024]; + + // parse format and input arguments + va_list varg; + va_start(varg, format); + vsprintf(strInput, format, varg); + va_end(varg); + + Log(eLOG_DEBUG, strInput); +} + +//------------------------------------- +void CAutoLog::Log(eLogLevel severity, char *fmt, ...) +//------------------------------------- +{ + if (pFile == (FILE *)-1 || pFile == NULL) + { + //fprintf(stderr,"CAutoLog::Log called with no file open!\n"); + return; + } + + if (nLogMask == eLOG_NONE || nLogMask < severity) + { + if (nPrintMask == eLOG_NONE || nPrintMask < severity) + { // no point in parsing, we're doing nothing. + return; + } + } + + char strTime[128]; + char strInput[1024]; + char strOutput[1024+128]; + time_t t; + + // parse format and input arguments + va_list varg; + va_start(varg, fmt); + vsprintf(strInput, fmt, varg); + va_end(varg); + + // make timestamp + time(&t); + strftime(strTime, sizeof(strTime), "[%m/%d/%Y %H:%M:%S]", localtime(&t) ); + + // construct output string + sprintf(strOutput, "%s %s\n", strTime, strInput); + + // check to see if current file needs to be archived + Archive(); + + // log to file + if (!(nLogMask == eLOG_NONE || nLogMask < severity)) + { + fwrite(strOutput,strlen(strOutput),1,pFile); + } + + // print as standard output + if (!(nPrintMask == eLOG_NONE || nPrintMask < severity)) + { + printf("%s", strOutput); + } + + // flush file buffer if error is high severity + if (severity <= nFlushMask) + fflush(pFile); +} + +//------------------------------------- +void CAutoLog::Archive(void) +//------------------------------------- +{ + if( pFile == (FILE *)-1 || pFile == NULL) + { + //fprintf(stderr,"CAutoLog::Archive called with no file open!\n"); + return; + } + + // check to see if it's time to archive + time_t t; + time(&t); + struct tm *ptm = localtime(&t); + if (ptm->tm_yday == nTodaysDayOfYear) + { + return; // nope, not time to archive + } + nTodaysDayOfYear = ptm->tm_yday; + + char strPath[1024]; + char strCurrent[1024]; + char strTime[128]; + char * pCurrent; + +#ifdef WIN32 + char curdir[128]; +#else + struct stat SS; +#endif + + strftime(strTime, sizeof(strTime), "%m%d%Y", localtime(&t) ); // numerical time e.g. 041698 + + strcpy(strCurrent,pFilename); + pCurrent = strrchr(strCurrent, SLASHCHAR[0]); + if (pCurrent != NULL) + *pCurrent = 0; + else + sprintf(strCurrent,"."); + + sprintf(strPath,"%s"SLASHCHAR"%s", strCurrent, strTime); // logs/041698 + +#ifdef WIN32 + // remember current directory + if( getcwd(curdir,sizeof(curdir)) == NULL ) + { + fprintf(stderr,"CAutoLog::Archive failed to get current directory!\n"); + return; // error, can't proceed + } + + if (chdir(strPath)) + { + // failed to find the directory, so we must create it + if (mkdir(strPath)) + { + fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath); + return; // error, can't proceed + } + } + else + { + // found the directory, but we don't want to be there, so go back + chdir(curdir); + } +#else + // see if directory exists + if (stat(strPath,&SS)) + { + // create directory + if (mkdir(strPath,0777)) + { + fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath); + return; // error, can't proceed + } + } +#endif + + pCurrent = strrchr(pFilename, SLASHCHAR[0]); + if (pCurrent == NULL) + pCurrent = pFilename; + else + pCurrent++; + + sprintf(strCurrent,"%s"SLASHCHAR"%s",strPath,pCurrent); + + fflush(pFile); + fclose(pFile); + + rename(pFilename,strCurrent); + + pFile = fopen(pFilename,"w+"); +} + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/AutoLog.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/AutoLog.h new file mode 100644 index 00000000..0a90a774 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/AutoLog.h @@ -0,0 +1,117 @@ +#ifndef _AUTOLOG_H +#define _AUTOLOG_H + +#pragma warning (disable : 4786) +#include +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + class CAutoLog + { + public: + enum eLogLevel { + eLOG_NONE = 0, // log entries are discarded + eLOG_ERROR = 1, // log errors only + eLOG_ALERT = 2, // log alerts and errors only + eLOG_NORMAL = 3, // log all normal events, no debug + eLOG_DEBUG = 4 // log everything + }; + + // Global setting for all AutoLog instances for this application. Can be set on the fly. Default is eLOG_NORMAL. + void SetLogLevel(eLogLevel loglevel); + + // Global setting for all AutoLog instances for this application. Can be set on the fly. Default is eLOG_ERROR. + void SetPrintLevel(eLogLevel printlevel); + + // Global setting for all AutoLog instances for this application. Can be set on the fly. Default is eLOG_ERROR. + void SetFlushLevel(eLogLevel flushlevel); + + // constructor, no file loaded + CAutoLog(); + + // version of constructor that calls Open(file) + CAutoLog(const char * file); + + // destructor, will close file if opened + ~CAutoLog(); + + // Open log file. If a file is already open, function will fail. + // returns true if no error + bool Open(const char * file); + + // Close log file if opened. + void Close(void); + + // Make an entry in the log. Format and variable arguments are identical to printf. + // severity will be compared to master log level to determine if the log entry will be made + // severity will be compared to master print level to determine if the log entry will be printed to stdout + void Log(eLogLevel severity, char * format, ...); + + // Equivalent to the above with the approriate severity argument + void LogError(char * format, ...); + void LogAlert(char * format, ...); + void Log(char * format, ...); + void LogDebug(char * format, ...); + + private: + FILE * pFile; // current log file opened + char * pFilename; // current log file opened + int nTodaysDayOfYear; // remember the current day to detect change of day + void Archive(void); // archives current log + + static eLogLevel nLogMask; // master severity level + static eLogLevel nPrintMask; // master severity level + static eLogLevel nFlushMask; // master severity level + }; + + //------------------------------------- + inline void CAutoLog::SetLogLevel(eLogLevel loglevel) + { + nLogMask = loglevel; + } + + //------------------------------------- + inline void CAutoLog::SetPrintLevel(eLogLevel printlevel) + { + nPrintMask = printlevel; + } + + //------------------------------------- + inline void CAutoLog::SetFlushLevel(eLogLevel flushlevel) + { + nFlushMask = flushlevel; + } + + //------------------------------------- + inline CAutoLog::CAutoLog() + { + pFilename = NULL; + pFile = (FILE *)-1; + } + + //------------------------------------- + inline CAutoLog::CAutoLog(const char * file) + { + pFilename = NULL; + pFile = (FILE *)-1; + Open(file); + } + + //------------------------------------- + inline CAutoLog::~CAutoLog() + { + Close(); + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base.cpp new file mode 100644 index 00000000..3d8f8789 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base.cpp @@ -0,0 +1 @@ +#include "Base.h" diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base.h new file mode 100644 index 00000000..90b0587a --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base.h @@ -0,0 +1,63 @@ +//////////////////////////////////////// +// Base.h +// +// Purpose: +// 1. Provide a single header file that may be used to include all +// Base library header files. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef _BASEPCH_H +#define _BASEPCH_H + +#ifdef WIN32 + + #include "win32/Platform.h" + #include "win32/Types.h" + #include "win32/Mutex.h" + #include "win32/Event.h" + #include "win32/Thread.h" + #include "Logger.h" + #include "Config.h" + #include "ScopeLock.h" + #include "Statistics.h" + #include "TemplateObjectAllocator.h" + #include "BlockAllocator.h" + +#elif linux + + #include "linux/Platform.h" + #include "linux/Types.h" + #include "linux/Mutex.h" + #include "linux/Event.h" + #include "linux/Thread.h" + #include "Logger.h" + #include "Config.h" + #include "ScopeLock.h" + #include "Statistics.h" + #include "TemplateObjectAllocator.h" + #include "BlockAllocator.h" + +#elif sparc + + #include "solaris/Platform.h" + #include "solaris/Types.h" + #include "solaris/Mutex.h" + #include "solaris/Event.h" + #include "solaris/Thread.h" + #include "Logger.h" + #include "Config.h" + #include "ScopeLock.h" + #include "Statistics.h" + #include "TemplateObjectAllocator.h" + #include "BlockAllocator.h" + +#else + + #error Base.h: Undefine platform type + +#endif + +#endif // _BASEPCH_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp new file mode 100644 index 00000000..fa769c71 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp @@ -0,0 +1,387 @@ +#include "Base64.h" +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //---------------------------------------------------------------------------- + // Constants + //---------------------------------------------------------------------------- + #define BASE64_PAD '=' + #define BASE64_PAD_INDEX 64 + #define BASE64_ERR ((unsigned char)-1) + #define BASE64_PAD_CODE ((unsigned char)100) + #define BASE64_OUTPUT_LINE 76 + #define BASE64_ENCODE_BUFFER ((BASE64_OUTPUT_LINE*3)/4) + #define BASE64_DECODE_ERROR ((unsigned)-1) + + #define HEX_ERR 16 + #define HEX_LOWER_FORMAT "%2.2x" + #define HEX_UPPER_FORMAT "%2.2X"; + + const char Base64::ms_base64Table[] = + { + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '+', + '/', + BASE64_PAD + }; + + + //---------------------------------------------------------------------------- + // Functions + //---------------------------------------------------------------------------- + + unsigned char Base64::GetBase64Code(char base64char) + { + if (base64char == BASE64_PAD) + return BASE64_PAD_CODE; + + if (base64char >= 'A' && base64char <= 'Z') + return (unsigned char)(base64char - 'A'); + if (base64char >= 'a' && base64char <= 'z') + return (unsigned char)(base64char - 'a' + 26); + if (base64char >= '0' && base64char <= '9') + return (unsigned char)(base64char - '0' + 2*26); + if (base64char == '+') + return 2*26+10; + if (base64char == '/') + return 2*26+11; + + return BASE64_ERR; + } + + unsigned char Base64::GetHexCode(char hexChar) + { + if (hexChar >= '0' && hexChar <= '9') + return (unsigned char)(hexChar - '0'); + if (hexChar >= 'A' && hexChar <= 'F') + return (unsigned char)(hexChar - 'A' + 10); + if (hexChar >= 'a' && hexChar <= 'f') + return (unsigned char)(hexChar - 'a' + 10); + + return HEX_ERR; + } + + unsigned Base64::UUDecodeQuadToTriple(const char *quad, unsigned char *triple) + { + unsigned char b; + unsigned char quadByteCodes[4]; + unsigned bytes = 3, i; + + for (i = 0; i < 4; i++) + { + b = GetBase64Code(quad[i]); + + if (b == BASE64_PAD_CODE) + { + switch(i) + { + case 0: bytes=0; break; + case 1: bytes=0; break; + case 2: bytes=1; break; + case 3: bytes=2; break; + } + break; + } + else if (b == BASE64_ERR) + { + bytes = BASE64_DECODE_ERROR; + } + else + { + quadByteCodes[i] = b; + } + + } + + triple[0] = (quadByteCodes[0] << 2) | (quadByteCodes[1] >> 4); + triple[1] = (quadByteCodes[1] << 4) | (quadByteCodes[2] >> 2); + triple[2] = (quadByteCodes[2] << 6) | (quadByteCodes[3] >> 0); + + return bytes; + } + + bool Base64::UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen) + { + unsigned char q[3]; + unsigned index; + unsigned bytes; + unsigned char *destIn = dest; + bool noErrors = true; + + for (index = 0; index < sourceLen; index += 4) + { + bytes = UUDecodeQuadToTriple(source + index, q); + + if (bytes != BASE64_DECODE_ERROR) { + *destLen -= bytes; + if (*destLen >= 0) { + memcpy(dest, (char*)&q, bytes); + } else { + noErrors = false; + } + dest += bytes; + } else { + noErrors = false; + } + } + *destLen = (int)(dest - destIn); + + return noErrors; + } + + bool Base64::UUDecode(const char *source, unsigned sourceLen, std::string &destString) + { + unsigned char q[3]; + unsigned index; + unsigned bytes; + bool noErrors = true; + + for (index = 0; index < sourceLen; index += 4) + { + bytes = UUDecodeQuadToTriple(source + index, q); + + if (bytes != BASE64_DECODE_ERROR) { + destString.append((char*)&q, bytes); + } else { + noErrors = false; + } + } + + return noErrors; + } + + unsigned Base64::UUEncodeTripleToQuad(const unsigned char *triple, char* quad, unsigned bytes) + { + unsigned char indices[4]; + int quadIndex; + + memset(indices, BASE64_PAD_INDEX, sizeof(indices)); + + switch(bytes) + { + case 3: + indices[3] = (triple[2] ) & 0x0000003F; + indices[2] = (triple[2] >> 6) & 0x0000003F; + case 2: + indices[2] = (indices[2] | (triple[1] << 2)) & 0x0000003F; + indices[1] = (triple[1] >> 4) & 0x0000003F; + case 1: + indices[1] = (indices[1] | (triple[0] << 4)) & 0x0000003F; + indices[0] = (triple[0] >> 2) & 0x0000003F; + case 0: + default: + break; + }; + + for (quadIndex = 0; quadIndex < 4; quadIndex++) { + quad[quadIndex] = ms_base64Table[indices[quadIndex]]; + } + + return 0; + } + + bool Base64::UUEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen) + { + char quad[5]; + unsigned z; + bool noErrors = true; + + quad[4] = 0; + + // The normal case + for(z = 0; z < sourceLen;z += 3) + { + UUEncodeTripleToQuad(source + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z)); + destLen -= strlen(quad); + if (destLen > 0) { + dest += sprintf(dest,quad); + } else { + noErrors = false; + } + } + + return noErrors; + } + + bool Base64::UUEncode(const unsigned char *source, unsigned sourceLen, std::string &destString) + { + char quad[5]; + unsigned z; + bool noErrors = true; + + quad[4] = 0; + + // The normal case + for(z = 0; z < sourceLen;z += 3) + { + UUEncodeTripleToQuad(source + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z)); + + destString.append(quad); + } + + return noErrors; + } + + bool Base64::HexEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen, bool lowercase) + { + const char *format = lowercase ? HEX_LOWER_FORMAT : HEX_UPPER_FORMAT; + bool noErrors = true; + + for (; sourceLen > 0; sourceLen--, source++) + { + if (destLen >= 2) { + destLen -= sprintf(dest, format, *source); + } else { + noErrors = false; + } + } + + return noErrors; + } + + bool Base64::HexEncode(const unsigned char *source, unsigned sourceLen, std::string &destString, bool lowercase) + { + const char *format = lowercase ? HEX_LOWER_FORMAT : HEX_UPPER_FORMAT; + char hexBuffer[3]; + bool noErrors = true; + + hexBuffer[2] = '\0'; + + for (; sourceLen > 0; sourceLen--, source++) + { + hexBuffer[0] = '\0'; + sprintf(hexBuffer, format, *source); + destString.append(hexBuffer); + } + + return noErrors; + } + + bool Base64::HexDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen) + { + unsigned char *destIn = dest; + unsigned char digits[2]; + bool noErrors = true; + + for (; sourceLen > 1; sourceLen -= 2, source += 2) + { + if (*destLen > 0) { + digits[0] = GetHexCode(source[0]); + digits[1] = GetHexCode(source[1]); + if ((digits[0] != HEX_ERR) && (digits[1] != HEX_ERR)) { + *dest = (digits[0] * 16) + digits[1]; + dest++; + (*destLen)--; + } else { + noErrors = false; + } + } else { + noErrors = false; + } + } + *destLen = dest - destIn; + + if (sourceLen == 1) { + noErrors = false; + } + + return noErrors; + } + + bool Base64::HexDecode(const char *source, unsigned sourceLen, std::string &destString) + { + unsigned char digits[2]; + unsigned char byte; + bool noErrors = true; + + for (; sourceLen > 1; sourceLen -= 2, source += 2) + { + digits[0] = GetHexCode(source[0]); + digits[1] = GetHexCode(source[1]); + if ((digits[0] != HEX_ERR) && (digits[1] != HEX_ERR)) { + byte = (digits[0] * 16) + digits[1]; + destString.append((char *)&byte, 1); + } else { + noErrors = false; + } + } + + if (sourceLen == 1) { + noErrors = false; + } + + return noErrors; + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h new file mode 100644 index 00000000..73542495 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h @@ -0,0 +1,42 @@ +#ifndef BASE64_H +#define BASE64_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + class Base64 + { + public: + static bool UUEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen); + static bool UUEncode(const unsigned char *source, unsigned sourceLen, std::string &destString); + static bool UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen); + static bool UUDecode(const char *source, unsigned sourceLen, std::string &destString); + + // these don't *exactly* belong here, but it's a convenient place for them + static bool HexEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen, bool lowercase = false); + static bool HexEncode(const unsigned char *source, unsigned sourceLen, std::string &destString, bool lowercase = false); + static bool HexDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen); + static bool HexDecode(const char *source, unsigned sourceLen, std::string &destString); + + private: + static unsigned UUEncodeTripleToQuad(const unsigned char *triple, char *quad, unsigned bytes); + static unsigned UUDecodeQuadToTriple(const char *quad, unsigned char *triple); + + static void Init(); + static unsigned char GetBase64Code(char base64char); + static unsigned char GetHexCode(char hexChar); + + static const char ms_base64Table[]; + }; +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // BASE64_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/BlockAllocator.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/BlockAllocator.h new file mode 100644 index 00000000..5daf69da --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/BlockAllocator.h @@ -0,0 +1,30 @@ +#if !defined (BLOCKALLOCATOR_H_) +#define BLOCKALLOCATOR_H_ + +#include +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + class BlockAllocator + { + public: + BlockAllocator(); + ~BlockAllocator(); + void *getBlock(unsigned accum); + void returnBlock(unsigned *handle); + + private: + unsigned *m_blocks[31]; + }; +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/CmdLine.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/CmdLine.cpp new file mode 100644 index 00000000..a9ffed0a --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/CmdLine.cpp @@ -0,0 +1,291 @@ +/*------------------------------------------------------ + CCmdLine + + A utility for parsing command lines. + + Copyright (C) 1999 Chris Losinger, Smaller Animals Software. + http://www.smalleranimals.com + + This software is provided 'as-is', without any express + or implied warranty. In no event will the authors be + held liable for any damages arising from the use of this software. + + Permission is granted to anyone to use this software + for any purpose, including commercial applications, and + to alter it and redistribute it freely, subject to the + following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + See SACmds.h for more info. +------------------------------------------------------*/ + +#pragma warning (disable: 4267) +// if you're using MFC, you'll need to un-comment this line +// #include "stdafx.h" + +#include "CmdLine.h" +//#include "crtdbg.h" +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Base +{ + +/*------------------------------------------------------ + int CCmdLine::SplitLine(int argc, char **argv) + + parse the command line into switches and arguments + + returns number of switches found +------------------------------------------------------*/ +int CCmdLine::SplitLine(int argc, char **argv) +{ + clear(); + + StringType curParam; // current argv[x] + + // skip the exe name (start with i = 1) + for (int i = 1; i < argc; i++) + { + // if it's a switch, start a new CCmdLine + if (IsSwitch(argv[i])) + { + curParam = argv[i]; + + StringType arg; + + // look at next input string to see if it's a switch or an argument + if (i + 1 < argc) + { + if (!IsSwitch(argv[i + 1])) + { + // it's an argument, not a switch + arg = argv[i + 1]; + + // skip to next + i++; + } + else + { + arg = ""; + } + } + + // add it + CCmdParam cmd; + + // only add non-empty args + if (arg != "") + { + cmd.m_strings.push_back(arg); + } + + // add the CCmdParam to 'this' + std::pair res = insert(CCmdLine::value_type(curParam, cmd)); + if (res.second) continue; + } + else + { + // it's not a new switch, so it must be more stuff for the last switch + + // ...let's add it + CCmdLine::iterator theIterator; + + // get an iterator for the current param + theIterator = find(curParam); + if (theIterator!=end()) + { + (*theIterator).second.m_strings.push_back(argv[i]); + } + else + { + // ?? + } + } + } + + return size(); +} + +/*------------------------------------------------------ + + protected member function + test a parameter to see if it's a switch : + + switches are of the form : -x + where 'x' is one or more characters. + the first character of a switch must be non-numeric! + +------------------------------------------------------*/ + +bool CCmdLine::IsSwitch(const char *pParam) +{ + if (pParam==NULL) + return false; + + // switches must non-empty + // must have at least one character after the '-' + int len = strlen(pParam); + if (len <= 1) + { + return false; + } + + // switches always start with '-' + if (pParam[0]=='-') + { + // allow negative numbers as arguments. + // ie., don't count them as switches + return (!isdigit(pParam[1])); + } + else + { + return false; + } +} + +/*------------------------------------------------------ + bool CCmdLine::HasSwitch(const char *pSwitch) + + was the switch found on the command line ? + + ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 + + call return + ---- ------ + cmdLine.HasSwitch("-a") true + cmdLine.HasSwitch("-z") false +------------------------------------------------------*/ + +bool CCmdLine::HasSwitch(const char *pSwitch) +{ + CCmdLine::iterator theIterator; + theIterator = find(pSwitch); + return (theIterator!=end()); +} + +/*------------------------------------------------------ + + StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault) + + fetch an argument associated with a switch . if the parameter at + index iIdx is not found, this will return the default that you + provide. + + example : + + command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 + + call return + ---- ------ + cmdLine.GetSafeArgument("-a", 0, "zz") p1 + cmdLine.GetSafeArgument("-a", 1, "zz") p2 + cmdLine.GetSafeArgument("-b", 0, "zz") p4 + cmdLine.GetSafeArgument("-b", 1, "zz") zz + +------------------------------------------------------*/ + +StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault) +{ + StringType sRet; + + if (pDefault!=NULL) + sRet = pDefault; + + try + { + sRet = GetArgument(pSwitch, iIdx); + } + catch (...) + { + } + + return sRet; +} + +/*------------------------------------------------------ + + StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx) + + fetch a argument associated with a switch. throws an exception + of (int)0, if the parameter at index iIdx is not found. + + example : + + command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 + + call return + ---- ------ + cmdLine.GetArgument("-a", 0) p1 + cmdLine.GetArgument("-b", 1) throws (int)0, returns an empty string + +------------------------------------------------------*/ + +StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx) +{ + if (HasSwitch(pSwitch)) + { + CCmdLine::iterator theIterator; + + theIterator = find(pSwitch); + if (theIterator!=end()) + { + if ((int)(*theIterator).second.m_strings.size() > iIdx) + { + return (*theIterator).second.m_strings[iIdx]; + } + } + } + + throw (int)0; + + return ""; +} + +/*------------------------------------------------------ + int CCmdLine::GetArgumentCount(const char *pSwitch) + + returns the number of arguments found for a given switch. + + returns -1 if the switch was not found + +------------------------------------------------------*/ + +int CCmdLine::GetArgumentCount(const char *pSwitch) +{ + int iArgumentCount = -1; + + if (HasSwitch(pSwitch)) + { + CCmdLine::iterator theIterator; + + theIterator = find(pSwitch); + if (theIterator!=end()) + { + iArgumentCount = (*theIterator).second.m_strings.size(); + } + } + + return iArgumentCount; +} + +}; // end namespace Base + +#ifdef EXTERNAL_DISTRO +}; // end namespace NAMESPACE +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/CmdLine.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/CmdLine.h new file mode 100644 index 00000000..1eac0dba --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/CmdLine.h @@ -0,0 +1,251 @@ +/*------------------------------------------------------ + CCmdLine + + A utility for parsing command lines. + + Copyright (C) 1999 Chris Losinger, Smaller Animals Software. + http://www.smalleranimals.com + + This software is provided 'as-is', without any express + or implied warranty. In no event will the authors be + held liable for any damages arising from the use of this software. + + Permission is granted to anyone to use this software + for any purpose, including commercial applications, and + to alter it and redistribute it freely, subject to the + following restrictions: + + 1. The origin of this software must not be misrepresented; + you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, + and must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + ------------------------- + + Example : + + Our example application uses a command line that has two + required switches and two optional switches. The app should abort + if the required switches are not present and continue with default + values if the optional switches are not present. + + Sample command line : + MyApp.exe -p1 text1 text2 -p2 "this is a big argument" -opt1 -55 -opt2 + + Switches -p1 and -p2 are required. + p1 has two arguments and p2 has one. + + Switches -opt1 and -opt2 are optional. + opt1 requires a numeric argument. + opt2 has no arguments. + + Also, assume that the app displays a 'help' screen if the '-h' switch + is present on the command line. + + #include "CmdLine.h" + + void main(int argc, char **argv) + { + // our cmd line parser object + CCmdLine cmdLine; + + // parse argc,argv + if (cmdLine.SplitLine(argc, argv) < 1) + { + // no switches were given on the command line, abort + ASSERT(0); + exit(-1); + } + + // test for the 'help' case + if (cmdLine.HasSwitch("-h")) + { + show_help(); + exit(0); + } + + // get the required arguments + StringType p1_1, p1_2, p2_1; + try + { + // if any of these fail, we'll end up in the catch() block + p1_1 = cmdLine.GetArgument("-p1", 0); + p1_2 = cmdLine.GetArgument("-p1", 1); + p2_1 = cmdLine.GetArgument("-p2", 0); + + } + catch (...) + { + // one of the required arguments was missing, abort + ASSERT(0); + exit(-1); + } + + // get the optional parameters + + // convert to an int, default to '100' + int iOpt1Val = atoi(cmdLine.GetSafeArgument("-opt1", 0, 100)); + + // since opt2 has no arguments, just test for the presence of + // the '-opt2' switch + bool bOptVal2 = cmdLine.HasSwitch("-opt2"); + + .... and so on.... + + } + + If this class is used in an MFC application, StringType is CString, else + it uses the STL 'string' type. + + If this is an MFC app, you can use the __argc and __argv macros from + you CYourWinApp::InitInstance() function in place of the standard argc + and argv variables. + +------------------------------------------------------*/ +#ifndef SACMDSH +#define SACMDSH + + +//#include // you may need this +#include +#include +#include +//using namespace std ; + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Base +{ + +#ifdef __AFX_H__ +// if we're using MFC, use CStrings +#define StringType CString +#else +// if we're not using MFC, use STL strings +#define StringType std::string +#endif + +// tell the compiler to shut up +#pragma warning(disable:4786) + + +// handy little container for our argument vector +struct CCmdParam +{ + std::vector m_strings; +}; + +// this class is actually a map of strings to vectors +typedef std::map _CCmdLine; + +// the command line parser class +class CCmdLine : public _CCmdLine +{ + +public: + /*------------------------------------------------------ + int CCmdLine::SplitLine(int argc, char **argv) + + parse the command line into switches and arguments. + + returns number of switches found + ------------------------------------------------------*/ + int SplitLine(int argc, char **argv); + + /*------------------------------------------------------ + bool CCmdLine::HasSwitch(const char *pSwitch) + + was the switch found on the command line ? + + ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 + + call return + ---- ------ + cmdLine.HasSwitch("-a") true + cmdLine.HasSwitch("-z") false + ------------------------------------------------------*/ + bool HasSwitch(const char *pSwitch); + + /*------------------------------------------------------ + + StringType CCmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault) + + fetch an argument associated with a switch . if the parameter at + index iIdx is not found, this will return the default that you + provide. + + example : + + command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 + + call return + ---- ------ + cmdLine.GetSafeArgument("-a", 0, "zz") p1 + cmdLine.GetSafeArgument("-a", 1, "zz") p2 + cmdLine.GetSafeArgument("-b", 0, "zz") p4 + cmdLine.GetSafeArgument("-b", 1, "zz") zz + + ------------------------------------------------------*/ + + StringType GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault); + + /*------------------------------------------------------ + + StringType CCmdLine::GetArgument(const char *pSwitch, int iIdx) + + fetch a argument associated with a switch. throws an exception + of (int)0, if the parameter at index iIdx is not found. + + example : + + command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5 + + call return + ---- ------ + cmdLine.GetArgument("-a", 0) p1 + cmdLine.GetArgument("-b", 1) throws (int)0, returns an empty string + + ------------------------------------------------------*/ + StringType GetArgument(const char *pSwitch, int iIdx); + + /*------------------------------------------------------ + int CCmdLine::GetArgumentCount(const char *pSwitch) + + returns the number of arguments found for a given switch. + + returns -1 if the switch was not found + + ------------------------------------------------------*/ + int GetArgumentCount(const char *pSwitch); + +protected: + /*------------------------------------------------------ + + protected member function + test a parameter to see if it's a switch : + + switches are of the form : -x + where 'x' is one or more characters. + the first character of a switch must be non-numeric! + + ------------------------------------------------------*/ + bool IsSwitch(const char *pParam); +}; + +}; // end namespace Base + +#ifdef EXTERNAL_DISTRO +}; // end namespace NAMESPACE +#endif + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Config.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Config.cpp new file mode 100644 index 00000000..359af5e7 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Config.cpp @@ -0,0 +1,179 @@ +#include "Config.h" + +//#include +//#include +//#include +#include + +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +//----------------------------------- +/// Read the config file into memory +/// Returns true for success +bool CConfig::LoadFile(char * file) +//----------------------------------- +{ + char ch; + FILE * fp; + + UnloadFile(); + + // open file + fp = fopen(file, "r"); + if (fp == NULL || fp == (FILE *)-1) + { + //fprintf(stderr,"Failed to open config file %s!",file); + return false; + } + + // get length of file + fseek(fp,0,SEEK_END); + long length = ftell(fp); + rewind(fp); + + // allocate buffer + pConfig = new char[length + 1]; + + if (pConfig == NULL) + { + fclose(fp); + fprintf(stderr,"Failed to alloc config buffer length %d",(int32)length); + return false; + } + memset(pConfig,0,length); + + // read data, stripping comments + int i = 0; + while (i < length) + { + ch = fgetc(fp); + if (feof(fp)) + break; + if (ch == '#') + { + while (ch != 10 && !feof (fp)) + { + ch = fgetc(fp); + } + } + pConfig[i++] = ch; + } + pConfig[i] = 0; // mark end of file buffer + + fclose(fp); + return true; +} + +//----------------------------------- +/// remove the config file from memory +void CConfig::UnloadFile(void) +//----------------------------------- +{ + if (pConfig) + delete[] pConfig; + pConfig = NULL; +} + +//----------------------------------- +/// finds a key of the config in memory +// key argument is case-insensitive, but must be upper case in config file +// Returns true for success (passing NULL is a special case returned as success) +bool CConfig::FindKey(char *key) +//----------------------------------- +{ + if (pConfig == NULL) + return false; + + // special case...continue with existing key + if (key == NULL) + return true; + + // form the search key + strcpy(strBuffer, "["); + strcat(strBuffer, key); + strcat(strBuffer,"]"); + strupr(strBuffer); // keywords must be upper case + + // find the key heading + pCursor = strstr(pConfig,strBuffer); + if (pCursor==NULL) + return false; + + // find the closing bracket of key heading + pCursor = strchr(pCursor,']'); + if (pCursor==NULL) + return false; + pCursor++; + + return true; +} + +//----------------------------------- +/// extract a number from the config string +// pass the key to find the first number in the list, else NULL to find the next number in the list +// returns 0 if no number is found, else returns the number +long CConfig::GetLong(char *key) +//----------------------------------- +{ + if (!FindKey(key)) + return 0; + + + // look for start of number or end of key + while (*pCursor && !isdigit(*pCursor) && *pCursor != '[' && *pCursor != '-') + pCursor++; + + int c = 0; + while (*pCursor && (isdigit(*pCursor) || *pCursor == '-') && c < (int)sizeof(strBuffer)) + strBuffer[c++] = *(pCursor++); + strBuffer[c] = '\0'; + + return atol(strBuffer); +} + +//----------------------------------- +/// extract string (in double-quotes) from the list. +// pass the key to find the first string in the list, else NULL to find the next string in the list +// returns NULL if no string found, else returns a temporary copy of the string (without quotes) +char * CConfig::GetString(char *key) +//----------------------------------- +{ + if (!FindKey(key)) + return NULL; + + + // look for start of string or end of key + while (*pCursor && *pCursor != '"' && *pCursor != '[') + pCursor++; + if (*(pCursor++) != '"') + return NULL; + + // until closing quote + int c = 0; + while (*pCursor && c < (int)sizeof(strBuffer)) + { + strBuffer[c++] = *pCursor; // extract string + if (*pCursor++ == '"') + { + strBuffer[--c] = '\0'; + return strBuffer; + } + } + + return NULL; +} + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Config.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Config.h new file mode 100644 index 00000000..56ad96af --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Config.h @@ -0,0 +1,111 @@ +/* +; Example syntax of a config file. +# This is a comment to end of line. +; This is a comment too....both comments are to end of line +[KEYWORD] ; all keywords must be upper case to be recognized + +; single number, with code example +# long number = config.GetLong("PORT"); +[PORT] 5999 ; common single-value case + +; list of strings, with code example +# config.FindKey("NUMBERS"); +# while (number = config.GetLong(NULL)) +# YourHandleNumber(number); +[NUMBERS] 100 + 200, 300 ; formatting is very flexible as long as numbers are delimited by non-numbers + 400 500 + 600 ; This is badly formatted for example purposes only + +; single string, with code example +# strcpy(mystring, config.GetString("STRING")); +[STRING] "This is a string" + +; list of strings, with code example +# config.FindKey("HOSTS"); +# while (string = config.GetString(NULL)) +# YourHandleString(string); +[HOSTS] + "206.19.151.173:5999" + "206.19.151.173:5998" + "206.19.151.173:2000" + +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + class CConfig + { + public: + // constructor, no file loaded + CConfig(); + + // version of constructor that calls LoadFile(file) + CConfig(char * file); + + // destructor, will delete all buffers + ~CConfig(); + + // copy text config file into memory. Required to use extraction methods. + // if called with a different filename, existing file will be discarded. + bool LoadFile(char * file); + + // delete memory buffer of file + void UnloadFile(); + + // set cursor in file based on key name. Alternate way to select first key when extracting lists. + // returns TRUE if key is found. + bool FindKey(char *key); + + // extract string from config. If key is NULL, extract next string in list, else extract first string. + // if key was not found, returns NULL + char * GetString(char *key = NULL); + + // extract number from config. If key is NULL, extract next number in list, else extract first number. + // if key was not found, returns 0 + long GetLong(char *key = NULL); // extract number from config. + + // indicate if config file has been loaded + inline bool FileLoaded() { return pConfig == NULL ? false : true; } + + private: + char * pConfig; // pointer to file memory + char * pCursor; // current cursor into file memory + char strBuffer[8196]; // buffer for GetString return pointer -- reused + }; + + inline CConfig::CConfig() + { + pConfig = NULL; + pCursor = NULL; + } + + inline CConfig::CConfig(char * file) + { + pConfig = NULL; + pCursor = NULL; + LoadFile(file); + } + + inline CConfig::~CConfig() + { + UnloadFile(); + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Event.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Event.h new file mode 100644 index 00000000..3897c6af --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Event.h @@ -0,0 +1,22 @@ +#ifndef BASE_EVENT_H +#define BASE_EVENT_H + +#ifdef WIN32 + + #include "win32/Event.h" + +#elif linux + + #include "linux/Event.h" + +#elif sparc + + #include "solaris/Event.h" + +#else + + #error /Base/Event.h: Undefine platform type + +#endif + +#endif // BASE_EVENT_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Logger.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Logger.cpp new file mode 100644 index 00000000..a2caad55 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Logger.cpp @@ -0,0 +1,756 @@ +#include "Logger.h" +#include "Mutex.h" +#include + +using namespace std; + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +const long kDateLenAllowance = 256; + +#ifndef _BASE_LOGGER_MAX_BUF_SIZE_ +#define _BASE_LOGGER_MAX_BUF_SIZE_ 2048 +#endif + +#ifdef WIN32 +const char file_sep = '\\'; + +#define LOGGER_GET_CURR_TIME(__tm_struct__, __time_t_var__) \ + memcpy(&__tm_struct__, localtime(&__time_t_var__), sizeof(__tm_struct__)) + +#define LOGGER_MAKE_DIR(__dir_name__, __mode__) mkdir(__dir_name__) + +# ifdef _MT +# define LOGGER_LOCK rLock.Lock(); +# define LOGGER_UNLOCK rLock.Unlock(); +# else // ifndef _MT +# define LOGGER_LOCK +# define LOGGER_UNLOCK +# endif // _MT + + + + +#define vsnprintf _vsnprintf + +#else // ifndef WIN32 +const char file_sep = '/'; + +const char *syslogLevels[] = { + "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG" }; + +const int numSysLogLevels = sizeof(syslogLevels) / sizeof(char *); + +#define LOGGER_GET_CURR_TIME(__tm_struct__, __time_t_var__) \ + localtime_r(&__time_t_var__, &__tm_struct__) + +#define LOGGER_MAKE_DIR(__dir_name__, __mode__) mkdir(__dir_name__, __mode__) + +# ifdef _REENTRANT +# define LOGGER_LOCK rLock.Lock(); +# define LOGGER_UNLOCK rLock.Unlock(); +# else // ifndef _REENTRANT +# define LOGGER_LOCK +# define LOGGER_UNLOCK +# endif // _REENTRANT + + + + +#endif // WIN32 + + +Logger::Logger(const char *prefix, + int level, + unsigned size, + bool rollDate) +: m_defaultLevel(level), + m_defaultSize(size), + m_dirPrefix(prefix), + m_rollDate(rollDate), + m_opennedSyslog(false) +{ + ELogType logType = eUseLocalFile; + + m_logLevelToTypeMap[LOG_DEBUG] = logType; + m_logLevelToTypeMap[LOG_INFO] = logType; + m_logLevelToTypeMap[LOG_NOTICE] = logType; + m_logLevelToTypeMap[LOG_WARNING] = logType; + m_logLevelToTypeMap[LOG_ERR] = logType; + m_logLevelToTypeMap[LOG_CRIT] = logType; + m_logLevelToTypeMap[LOG_ALERT] = logType; + m_logLevelToTypeMap[LOG_EMERG] = logType; + m_combinedLogType = logType; + + LoggerInit("UnNamedServer"); +} + +Logger::Logger(const char *programName, + const ELogType logType, + const char *prefix, + int level, + unsigned size, + bool rollDate) +: m_defaultLevel(level), + m_defaultSize(size), + m_dirPrefix(prefix), + m_rollDate(rollDate), + m_opennedSyslog(false) +{ + m_logLevelToTypeMap[LOG_DEBUG] = logType; + m_logLevelToTypeMap[LOG_INFO] = logType; + m_logLevelToTypeMap[LOG_NOTICE] = logType; + m_logLevelToTypeMap[LOG_WARNING] = logType; + m_logLevelToTypeMap[LOG_ERR] = logType; + m_logLevelToTypeMap[LOG_CRIT] = logType; + m_logLevelToTypeMap[LOG_ALERT] = logType; + m_logLevelToTypeMap[LOG_EMERG] = logType; + m_combinedLogType = logType; + + LoggerInit(programName); +} + + +void Logger::LoggerInit(const char *programName) +{ + char buf[1024]; + FILE *logDir = NULL; + + if (0 != (m_combinedLogType & eUseLocalFile)) + { + logDir = fopen(m_dirPrefix.c_str(), "r+"); + if(errno == ENOENT) + { + cmkdir(m_dirPrefix.c_str(), 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + + tm now; + time_t t = time(NULL); + + LOGGER_GET_CURR_TIME(now, t); + + memcpy(&m_lastDateTime, &now, sizeof(tm)); + if(m_rollDate) + { + sprintf(buf, "%s%c%2.2d-%2.2d-%2.2d", m_dirPrefix.c_str(), file_sep, (now.tm_mon + 1), now.tm_mday, (now.tm_year % 100)); + } + else + { + sprintf(buf, "%s", m_dirPrefix.c_str()); + } + logDir = fopen(buf, "r+"); + if(errno == ENOENT) + { + cmkdir(buf, 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + m_logPrefix = buf; + m_logRolloverSize = 0x80000000; // Default: 2 GB upper limit on file size + } + +#ifndef WIN32 + // Open connection to syslog + if (0 != (m_combinedLogType & eUseSysLog)) { + openlog(programName, LOG_NDELAY | LOG_PID, LOG_LOCAL5); + m_opennedSyslog = true; + } +#endif // !WIN32 + +} + +Logger::~Logger() +{ + map::iterator iter; + for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++) + { + logWithSys((*iter).first, LOG_INFO, LOG_FILEONLY, "---=== Log Stopped ===---"); + fflush((*iter).second->file); + fclose((*iter).second->file); + delete((*iter).second); + + } + m_logTable.clear(); + +#ifndef WIN32 + // close connection to syslog + if (m_opennedSyslog) + closelog(); +#endif // !WIN32 +} + +ELogType Logger::getLoggingType(unsigned logLevel) const +{ + std::map::const_iterator levelIter = m_logLevelToTypeMap.find(logLevel); + ELogType logType = eUseNone; + + if (levelIter != m_logLevelToTypeMap.end()) + { + logType = levelIter->second; + } + + return logType; +} + +void Logger::setLoggingType(unsigned logLevel, ELogType logType) +{ + std::map::iterator levelIter = m_logLevelToTypeMap.find(logLevel); + + if (levelIter != m_logLevelToTypeMap.end()) + { + levelIter->second = logType; + + if (logType > m_combinedLogType) { + m_combinedLogType = (ELogType)(m_combinedLogType | logType); + } else { + m_combinedLogType = eUseNone; + + for (levelIter = m_logLevelToTypeMap.begin(); + levelIter != m_logLevelToTypeMap.end(); + levelIter++) + { + m_combinedLogType = (ELogType)(m_combinedLogType | logType); + } + } + } +} + +void Logger::flush(unsigned logenum) +{ + map::iterator iter = m_logTable.find(logenum); + + if(iter != m_logTable.end()) + { + LogInfo *info = (*iter).second; + fflush(info->file); + info->used = 0; + } +} + +void Logger::flushAll() +{ + if (0 != (m_combinedLogType & eUseLocalFile)) + { + map::iterator iter; + + for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++) + { + LogInfo *info = (*iter).second; + fflush(info->file); + info->used = 0; + } + } +} + +void Logger::addLog(const char *id, unsigned logenum, int level, unsigned size) +{ + if (0 != (m_combinedLogType & eUseLocalFile)) + { + LogInfo *newLog = new LogInfo; + newLog->filename = m_logPrefix + file_sep + id + ".log"; + newLog->name = id; + newLog->used = 0; + newLog->max = size; + newLog->last = 0; + newLog->level = level; + + m_logTable.insert(pair(logenum, newLog)); + + if(strcmp("stdout", id) == 0) + { + newLog->file = stdout; + } + else if(strcmp("stderr", id) == 0) + { + newLog->file = stderr; + } + else + { + newLog->file = fopen(newLog->filename.c_str(), "a+"); + if(newLog->file == NULL) + { + printf("Open file %s failed\n", newLog->filename.c_str()); + } + } + logWithSys(logenum, LOG_INFO, LOG_FILEONLY, "---=== Log Started ===---"); + } +} + +void Logger::addLog(const char *id, unsigned logenum) +{ + if (0 != (m_combinedLogType & eUseLocalFile)) + { + LogInfo *newLog = new LogInfo; + newLog->filename = m_logPrefix + file_sep + id + ".log"; + newLog->name = id; + newLog->used = 0; + newLog->max = m_defaultSize; + newLog->last = 0; + newLog->level = m_defaultLevel; + + m_logTable.insert(pair(logenum, newLog)); + + if(strcmp("stdout", id) == 0) + { + newLog->file = stdout; + } + else if(strcmp("stderr", id) == 0) + { + newLog->file = stderr; + } + else + { + newLog->file = fopen(newLog->filename.c_str(), "a+"); + if(newLog->file == NULL) + { + printf("Open file %s failed\n", newLog->filename.c_str()); + } + } + logWithSys(logenum, LOG_INFO, LOG_FILEONLY, "---===Log Started ===---"); + } +} + +void Logger::updateLog(unsigned logenum, int level, unsigned size) +{ + if (0 != (m_combinedLogType & eUseLocalFile)) + { + map::iterator iter = m_logTable.find(logenum); + + if(iter != m_logTable.end()) + { + (*iter).second->level = level; + (*iter).second->max = size; + } + } +} + +void Logger::removeLog(unsigned logenum) +{ + if (0 != (m_combinedLogType & eUseLocalFile)) + { + map::iterator iter = m_logTable.find(logenum); + + if(iter != m_logTable.end()) + { +#ifdef WIN32 + logWithSys((*iter).first, LOG_INFO, LOG_FILEONLY, "---=== Log Stopped ===---"); +#else // ifndef WIN32 + logWithSys((*iter).first, LOG_INFO, LOG_ALWAYS, "---=== Log Stopped ===---"); +#endif // WIN32 + fflush((*iter).second->file); + fclose((*iter).second->file); + delete((*iter).second); + } + } +} + + + + + +void Logger::logSimple(unsigned logenum, int level, const char *message) +{ + map::iterator iter = m_logTable.find(logenum); + + if(iter == m_logTable.end()) + { + return; + } + time_t t = time(NULL); + LogInfo *info = (*iter).second; + if(level >= info->level) + { + return; + } +#ifndef WIN32 + if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout))) + { + return; + } +#endif // !WIN32 + if(info->last != t) + { + memcpy(&info->ts, localtime(&t), sizeof(tm)); + info->last = t; + } + + if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday) + { + LOGGER_LOCK + + if(info->ts.tm_mday != m_lastDateTime.tm_mday) + { + memcpy(&m_lastDateTime, &info->ts, sizeof(tm)); + rollDate(t); + } + + LOGGER_UNLOCK + } + if(iter != m_logTable.end()) + { + if(info->max > 0) + { + info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message); + info->used += fputc('\n', info->file); + if(info->used > info->max) + { + fflush(info->file); + info->used = 0; + } + } + else + { + fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message); + fputc('\n', info->file); + fflush(info->file); + } + } +} + + + + + + + + + + + +void Logger::logSimpleWithSys(unsigned logenum, unsigned priority, int level, const char *message) +{ +#ifndef WIN32 + if (0 != (m_combinedLogType & eUseSysLog)) + syslog(priority, "%s: %s", syslogLevels[priority % numSysLogLevels], message); +#endif // !WIN32 + + if (0 != (m_combinedLogType & eUseLocalFile)) + { + map::iterator iter = m_logTable.find(logenum); + + if(iter == m_logTable.end()) + { + return; + } + time_t t = time(NULL); + LogInfo *info = (*iter).second; + + if(level >= info->level) + { + return; + } + +#ifndef WIN32 + if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout))) + { + return; + } +#endif // !WIN32 + + if(info->last != t) + { + memcpy(&info->ts, localtime(&t), sizeof(tm)); + info->last = t; + } + + if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday) + { + LOGGER_LOCK + + if(info->ts.tm_mday != m_lastDateTime.tm_mday) + { + memcpy(&m_lastDateTime, &info->ts, sizeof(tm)); + rollDate(t); + } + + LOGGER_UNLOCK + } + if(iter != m_logTable.end()) + { + if (m_logRolloverSize> 0) + checkLogRoll(info, ::strlen(message) + kDateLenAllowance); + + if(info->max > 0) + { + info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message); + info->used += fputc('\n', info->file); + if(info->used > info->max) + { + fflush(info->file); + info->used = 0; + } + } + else + { + fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message); + fputc('\n', info->file); + fflush(info->file); + } + } + } +} + +void Logger::log(unsigned logenum, int level, const char *message, ...) +{ + char buf[_BASE_LOGGER_MAX_BUF_SIZE_]; + va_list varg; + va_start(varg, message); + vsnprintf(buf, _BASE_LOGGER_MAX_BUF_SIZE_, message, varg); + buf[_BASE_LOGGER_MAX_BUF_SIZE_ - 1] = 0; + va_end(varg); + + // ensure that the buf does not contain any '%' characters. + // prevent crash problem + char *rv; + while((rv = strchr(buf, '%')) != NULL) + { + *rv = ' '; // replace with space + } + + + logWithSys(logenum, LOG_NOTICE, level, buf); +} + + +void Logger::logWithSys(unsigned logenum, unsigned priority, int level, const char *message, ...) +{ + ELogType logType = getLoggingType(priority); + char buf[_BASE_LOGGER_MAX_BUF_SIZE_]; + va_list varg; + va_start(varg, message); + vsnprintf(buf, _BASE_LOGGER_MAX_BUF_SIZE_, message, varg); + buf[_BASE_LOGGER_MAX_BUF_SIZE_ - 1] = 0; + va_end(varg); + +#ifndef WIN32 + if (0 != (logType & eUseSysLog)) + syslog(priority, "%s: %s", syslogLevels[priority % numSysLogLevels], buf); +#endif // !WIN32 + + if (0 != (logType & eUseLocalFile)) + { + map::iterator iter = m_logTable.find(logenum); + if(iter == m_logTable.end()) + { + return; + } + time_t t = time(NULL); + LogInfo *info = (*iter).second; + + if(level >= info->level) + { + return; + } + if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout))) + { + return; + } + if(info->last != t) + { + LOGGER_GET_CURR_TIME(info->ts, t); + + info->last = t; + } + if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday) + { + LOGGER_LOCK + + if(info->ts.tm_mday != m_lastDateTime.tm_mday) + { + memcpy(&m_lastDateTime, &info->ts, sizeof(tm)); + rollDate(t); + } + + LOGGER_UNLOCK + } + + if(iter != m_logTable.end()) + { + if (m_logRolloverSize> 0) + checkLogRoll(info, ::strlen(buf) + kDateLenAllowance); + + if(info->max > 0) + { + info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf); + info->used += fputc('\n', info->file); + if(info->used > info->max) + { + fflush(info->file); + info->used = 0; + } + } + else + { + fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf); + fputc('\n', info->file); + fflush(info->file); + } + } + } +} + +void Logger::rollDate(time_t t) +{ + char buf[80]; + FILE *logDir = NULL; + + logDir = fopen(m_dirPrefix.c_str(), "r+"); + if(errno == ENOENT) + { + cmkdir(m_dirPrefix.c_str(), 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + + tm now; + + LOGGER_GET_CURR_TIME(now, t); + + sprintf(buf, "%s%c%2.2d-%2.2d-%2.2d", m_dirPrefix.c_str(), file_sep, (now.tm_mon + 1), now.tm_mday, (now.tm_year % 100)); + logDir = fopen(buf, "r+"); + + if(errno == ENOENT) + { + cmkdir(buf, 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + m_logPrefix = buf; + + map::iterator iter; + for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++) + { + (*iter).second->filename = m_logPrefix + file_sep + (*iter).second->name.c_str() + ".log"; + fflush((*iter).second->file); + fclose((*iter).second->file); + (*iter).second->file = fopen((*iter).second->filename.c_str(), "a+"); + if ((*iter).second->file == 0) + abort(); + memcpy(&((*iter).second->ts), &now, sizeof(tm)); + } +} + +// mkdir function that creates intermediate directories +void Logger::cmkdir(const char *dir, int mode) +{ + char dirbuf[128]; + strncpy(dirbuf, dir, 127); + dirbuf[127] = 0; + char *j = dirbuf, *i = dirbuf; + int handle; + + while(*i) + { + if(*i == file_sep) + { + (*i) = 0; +#ifdef WIN32 + handle = open(j, O_EXCL); + + if((handle > 0) || (errno != EISDIR && errno != ENOENT && errno != EACCES)) + { + perror("Logger::cmkdir():"); + abort(); + } +#else // ifndef WIN32 +// handle = open(j, O_EXCL); // Ben's original code +// if((handle > 0) || (errno != EISDIR && errno != ENOENT)) +// { +// perror("Logger::cmkdir():"); +// abort(); +// } + +// This doesnt work under Linux, it returns a valid handle +// Instead: see if file exists. If it doesnt, create directory ok +// If it exists, do stat to see if it is a dir. +// If it is a dir, then ok, create the directory. +// If it is a file, error +// ging 9-16-2002 + + handle = open(j, O_RDONLY); + if (handle > 0) + { + struct stat stat_buffer; + int ret = fstat(handle,&stat_buffer); + if ((ret == -1) || ((stat_buffer.st_mode | S_IFDIR) == 0)) + { + perror("Logger::cmkdir():"); + abort(); + } + } +#endif // WIN32 + LOGGER_MAKE_DIR(j, mode); + close(handle); + (*i) = file_sep; + } + else if(*(i + 1) == 0) + { + LOGGER_MAKE_DIR(j, mode); + } + i++; + } +} + +void Logger::rollLog(LogInfo *logInfo) +{ + std::string newLogName; + char timeStampBuffer[256]; + time_t t = time(NULL); + tm now; + int r; + int nTries = 10; + + fflush(logInfo->file); + fclose(logInfo->file); + + do + { + LOGGER_GET_CURR_TIME(now, t); + sprintf(timeStampBuffer, "-%4.4d-%2.2d-%2.2d-%2.2d-%2.2d-%2.2d.log", + (now.tm_year + 1900), (now.tm_mon + 1), now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); + newLogName = logInfo->filename.substr(0, logInfo->filename.length() - 4) + timeStampBuffer; + r = rename(logInfo->filename.c_str(), newLogName.c_str()); + nTries--; + t++; + } + while ((r != 0) && (nTries > 0)); + + logInfo->file = fopen(logInfo->filename.c_str(), "a+"); + memcpy(&(logInfo->ts), &now, sizeof(tm)); +} + +void Logger::checkLogRoll(LogInfo *logInfo, unsigned long lenToAdd) +{ + unsigned long logSize = ftell(logInfo->file); + + if ((logSize + lenToAdd) > m_logRolloverSize) + { + LOGGER_LOCK + + rollLog(logInfo); + + LOGGER_UNLOCK + } +} + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Logger.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Logger.h new file mode 100644 index 00000000..0116e1bd --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Logger.h @@ -0,0 +1,165 @@ +#ifndef __LOGGER_H__ +#define __LOGGER_H__ + +// make the compiler shut up +#pragma warning (disable : 4786) + +#include "Platform.h" +#include +#include +#include "Mutex.h" +#ifndef WIN32 +#include +#endif + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +#define LOG_ALWAYS -1 +#define LOG_FILEONLY -2 + +struct LogInfo +{ + FILE *file; + unsigned used; + tm ts; + time_t last; + unsigned max; + int level; + std::string filename; + std::string name; +}; + +/* Use these flags defined in syslog.h for the priority level + LOG_EMERG, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG +*/ + +//----------------------------------------------- +// Windows doesn't have syslog (?) so we define the +// syslog warning levels here to satisfy the compiler +// but then ignore them in log() and logSimple() +//----------------------------------------------- + +// PLEASE USE THE FOLLOWING ENUMERATIONS FOR LOGGING INSTEAD OF THE SYSLOG ONES. +enum LogLevel +{ +#ifndef WIN32 + BASE_LOG_EMERG = LOG_EMERG, + BASE_LOG_ALERT = LOG_ALERT, + BASE_LOG_CRIT = LOG_CRIT, + BASE_LOG_ERR = LOG_ERR, + BASE_LOG_WARNING = LOG_WARNING, + BASE_LOG_NOTICE = LOG_NOTICE, + BASE_LOG_INFO = LOG_INFO, + BASE_LOG_DEBUG = LOG_DEBUG +#else + BASE_LOG_EMERG = 0, + BASE_LOG_ALERT, + BASE_LOG_CRIT, + BASE_LOG_ERR, + BASE_LOG_WARNING, + BASE_LOG_NOTICE, + BASE_LOG_INFO, + BASE_LOG_DEBUG +#endif +}; + +// The _WIN32_LOG_LEVELS_ remain for backwards compatability. +#ifdef WIN32 +enum _WIN32_LOG_LEVELS_ +{ + LOG_EMERG = 0, + LOG_ALERT, + LOG_CRIT, + LOG_ERR, + LOG_WARNING, + LOG_NOTICE, + LOG_INFO, + LOG_DEBUG +}; +#endif + +enum ELogType +{ + eUseNone = 0, + eUseLocalFile = 1, + eUseSysLog = 2, + eUseBoth = 3 +}; + +class Logger +{ +public: + Logger(const char *programName, + const ELogType logType = eUseLocalFile, + const char *prefix = "logs", + int level = 10, + unsigned size = 0, + bool rollDate = true); + + Logger(const char *prefix, + int level, + unsigned size, + bool rollDate = true); // Backwards compatibility + void LoggerInit(const char *programName); + + ~Logger(); + void addLog(const char *id, unsigned logenum, int level, unsigned size); + void addLog(const char *id, unsigned logenum); + void removeLog(unsigned logenum); + void updateLog(unsigned logenum, int level, unsigned size); + void logSimple(unsigned logenum, int level, const char *message); + void logSimpleWithSys(unsigned logenum, unsigned priority, int level, const char *message); + void logWithSys(unsigned logenum, unsigned priority, int level, const char *message, ...); + void log(unsigned logenum, int level, const char *message, ...); + + void flushAll(); + void flush(unsigned logenum); + unsigned long getLogRolloverSize() { return m_logRolloverSize; } + void setLogRolloverSize(unsigned long maxLogSize) { m_logRolloverSize = maxLogSize; } + ELogType getLoggingType(unsigned logLevel) const; + void setLoggingType(unsigned logLevel, ELogType logType); + +private: + void rollDate(time_t now); + void cmkdir(const char *dir, int mode); + void rollLog(LogInfo *logInfo); + void checkLogRoll(LogInfo *logInfo, unsigned long lenToAdd); + + unsigned m_defaultLevel; + unsigned m_defaultSize; + std::string m_lastDateText; + tm m_lastDateTime; + std::map m_logTable; + std::string m_logPrefix; + std::string m_dirPrefix; +#if defined (_REENTRANT) || defined (_MT) + Base::CMutex rLock; +#endif + bool m_rollDate; + unsigned long m_logRolloverSize; + std::map m_logLevelToTypeMap; + ELogType m_combinedLogType; + bool m_opennedSyslog; +}; + +extern const char file_sep; + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp new file mode 100644 index 00000000..a988f46b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp @@ -0,0 +1,325 @@ +// MD5.cpp: implementation of the MD5 class. +// +////////////////////////////////////////////////////////////////////// + +#include "MD5.h" +#include "Types.h" + +using namespace std; + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + + MD5::State::State() : + state(4,0), + count(2,0), + buffer(64,0) + { + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + } + + static char const init[64] = + { + -128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + vector MD5::padding(init,init+sizeof(init)/sizeof(init[0])); + + MD5::MD5() + { + Init(); + } + + MD5::MD5(const string & input) + { + Init(); + Update(input); + } + + vector MD5::Decode(vector achar0, int i, int j) + { + vector ai(16,0); + int l; + int k = l = 0; + for(; l < i; l += 4) + { + ai[k] = achar0[l + j] & 0xff | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; + k++; + } + + return ai; + } + + vector MD5::Encode(vector ai, int i) + { + vector achar0(i,0); + int k; + int j = k = 0; + for(; k < i; k += 4){ + achar0[k] = (char)(ai[j] & 0xff); + achar0[k + 1] = (char)(ai[j] >> 8 & 0xff); + achar0[k + 2] = (char)(ai[j] >> 16 & 0xff); + achar0[k + 3] = (char)(ai[j] >> 24 & 0xff); + j++; + } + + return achar0; + } + + int MD5::FF(int i, int j, int k, int l, int i1, int j1, int k1) + { + i = uadd(i, j & k | ~j & l, i1, k1); + return uadd(rotate_left(i, j1), j); + } + + vector MD5::Final() + { + if (finalsNull) + { + State &state1 = state; + vector achar0 = Encode(state1.count, 8); + int i = state1.count[0] >> 3 & 0x3f; + int j = i >= 56 ? 120 - i : 56 - i; + Update(state1, padding, 0, j); + Update(state1, achar0, 0, 8); + finals = state1; + finalsNull = false; + } + return Encode(finals.state, 16); + } + + int MD5::GG(int i, int j, int k, int l, int i1, int j1, int k1) + { + i = uadd(i, j & l | k & ~l, i1, k1); + return uadd(rotate_left(i, j1), j); + } + + int MD5::HH(int i, int j, int k, int l, int i1, int j1, int k1) + { + i = uadd(i, j ^ k ^ l, i1, k1); + return uadd(rotate_left(i, j1), j); + } + + int MD5::II(int i, int j, int k, int l, int i1, int j1, int k1) + { + i = uadd(i, k ^ (j | ~l), i1, k1); + return uadd(rotate_left(i, j1), j); + } + + void MD5::Init() + { + if (padding.size() == 0) + { + padding.resize(64,0); + padding[0] = -128; + } + finalsNull = true; + } + + void MD5::Transform(State & state1, vector achar0, int i) + { + int j = state1.state[0]; + int k = state1.state[1]; + int l = state1.state[2]; + int i1 = state1.state[3]; + vector ai = Decode(achar0, 64, i); + j = FF(j, k, l, i1, ai[0], 7, 0xd76aa478); + i1 = FF(i1, j, k, l, ai[1], 12, 0xe8c7b756); + l = FF(l, i1, j, k, ai[2], 17, 0x242070db); + k = FF(k, l, i1, j, ai[3], 22, 0xc1bdceee); + j = FF(j, k, l, i1, ai[4], 7, 0xf57c0faf); + i1 = FF(i1, j, k, l, ai[5], 12, 0x4787c62a); + l = FF(l, i1, j, k, ai[6], 17, 0xa8304613); + k = FF(k, l, i1, j, ai[7], 22, 0xfd469501); + j = FF(j, k, l, i1, ai[8], 7, 0x698098d8); + i1 = FF(i1, j, k, l, ai[9], 12, 0x8b44f7af); + l = FF(l, i1, j, k, ai[10], 17, -42063); + k = FF(k, l, i1, j, ai[11], 22, 0x895cd7be); + j = FF(j, k, l, i1, ai[12], 7, 0x6b901122); + i1 = FF(i1, j, k, l, ai[13], 12, 0xfd987193); + l = FF(l, i1, j, k, ai[14], 17, 0xa679438e); + k = FF(k, l, i1, j, ai[15], 22, 0x49b40821); + j = GG(j, k, l, i1, ai[1], 5, 0xf61e2562); + i1 = GG(i1, j, k, l, ai[6], 9, 0xc040b340); + l = GG(l, i1, j, k, ai[11], 14, 0x265e5a51); + k = GG(k, l, i1, j, ai[0], 20, 0xe9b6c7aa); + j = GG(j, k, l, i1, ai[5], 5, 0xd62f105d); + i1 = GG(i1, j, k, l, ai[10], 9, 0x2441453); + l = GG(l, i1, j, k, ai[15], 14, 0xd8a1e681); + k = GG(k, l, i1, j, ai[4], 20, 0xe7d3fbc8); + j = GG(j, k, l, i1, ai[9], 5, 0x21e1cde6); + i1 = GG(i1, j, k, l, ai[14], 9, 0xc33707d6); + l = GG(l, i1, j, k, ai[3], 14, 0xf4d50d87); + k = GG(k, l, i1, j, ai[8], 20, 0x455a14ed); + j = GG(j, k, l, i1, ai[13], 5, 0xa9e3e905); + i1 = GG(i1, j, k, l, ai[2], 9, 0xfcefa3f8); + l = GG(l, i1, j, k, ai[7], 14, 0x676f02d9); + k = GG(k, l, i1, j, ai[12], 20, 0x8d2a4c8a); + j = HH(j, k, l, i1, ai[5], 4, 0xfffa3942); + i1 = HH(i1, j, k, l, ai[8], 11, 0x8771f681); + l = HH(l, i1, j, k, ai[11], 16, 0x6d9d6122); + k = HH(k, l, i1, j, ai[14], 23, 0xfde5380c); + j = HH(j, k, l, i1, ai[1], 4, 0xa4beea44); + i1 = HH(i1, j, k, l, ai[4], 11, 0x4bdecfa9); + l = HH(l, i1, j, k, ai[7], 16, 0xf6bb4b60); + k = HH(k, l, i1, j, ai[10], 23, 0xbebfbc70); + j = HH(j, k, l, i1, ai[13], 4, 0x289b7ec6); + i1 = HH(i1, j, k, l, ai[0], 11, 0xeaa127fa); + l = HH(l, i1, j, k, ai[3], 16, 0xd4ef3085); + k = HH(k, l, i1, j, ai[6], 23, 0x4881d05); + j = HH(j, k, l, i1, ai[9], 4, 0xd9d4d039); + i1 = HH(i1, j, k, l, ai[12], 11, 0xe6db99e5); + l = HH(l, i1, j, k, ai[15], 16, 0x1fa27cf8); + k = HH(k, l, i1, j, ai[2], 23, 0xc4ac5665); + j = II(j, k, l, i1, ai[0], 6, 0xf4292244); + i1 = II(i1, j, k, l, ai[7], 10, 0x432aff97); + l = II(l, i1, j, k, ai[14], 15, 0xab9423a7); + k = II(k, l, i1, j, ai[5], 21, 0xfc93a039); + j = II(j, k, l, i1, ai[12], 6, 0x655b59c3); + i1 = II(i1, j, k, l, ai[3], 10, 0x8f0ccc92); + l = II(l, i1, j, k, ai[10], 15, 0xffeff47d); + k = II(k, l, i1, j, ai[1], 21, 0x85845dd1); + j = II(j, k, l, i1, ai[8], 6, 0x6fa87e4f); + i1 = II(i1, j, k, l, ai[15], 10, 0xfe2ce6e0); + l = II(l, i1, j, k, ai[6], 15, 0xa3014314); + k = II(k, l, i1, j, ai[13], 21, 0x4e0811a1); + j = II(j, k, l, i1, ai[4], 6, 0xf7537e82); + i1 = II(i1, j, k, l, ai[11], 10, 0xbd3af235); + l = II(l, i1, j, k, ai[2], 15, 0x2ad7d2bb); + k = II(k, l, i1, j, ai[9], 21, 0xeb86d391); + state1.state[0] += j; + state1.state[1] += k; + state1.state[2] += l; + state1.state[3] += i1; + } + + void MD5::Update(char char0) + { + vector achar0(1,0); + achar0[0] = char0; + Update(achar0, 1); + } + + void MD5::Update(State & state1, vector achar0, int i, int j) + { + finalsNull = true; + if (j - i > (int)achar0.size()) + j = achar0.size() - i; + int k = state1.count[0] >> 3 & 0x3f; + if ((state1.count[0] += j << 3) < j << 3) + state1.count[1]++; + state1.count[1] += j >> 29; + int l = 64 - k; + int j1; + if(j >= l) + { + for(int i1 = 0; i1 < l; i1++) + state1.buffer[i1 + k] = achar0[i1 + i]; + + Transform(state1, state1.buffer, 0); + for(j1 = l; j1 + 63 < j; j1 += 64) + Transform(state1, achar0, j1); + + k = 0; + } + else + { + j1 = 0; + } + if (j1 < j) + { + int k1 = j1; + for(; j1 < j; j1++) + state1.buffer[(k + j1) - k1] = achar0[j1 + i]; + } + } + + void MD5::Update(string s) + { + vector achar(s.size(),0); + for (int i=0; i<(int)s.size(); i++) + achar[i] = s[i]; + Update( achar, achar.size() ); + } + + void MD5::Update(vector achar0) + { + Update(achar0, 0, achar0.size()); + } + + void MD5::Update(vector achar0, int i) + { + Update(state, achar0, 0, i); + } + + void MD5::Update(vector achar0, int i, int j) + { + Update(state, achar0, i, j); + } + + string MD5::asHex() + { + return asHex(Final()); + } + + string MD5::asHex(vector achar0) + { + const string hex = "0123456789abcdef"; + + string stringbuffer; + for (int i = 0; i < (int)achar0.size(); i++) + { + stringbuffer += hex.substr((achar0[i] >> 4) & 0x0f,1); + stringbuffer += hex.substr(achar0[i] & 0x0f,1); + } + + return stringbuffer; + } + + int MD5::rotate_left(int i, int j) + { + unsigned i1 = i; + unsigned j1 = j; + return i1 << j1 | i1 >> (32 - j1); + } + + int MD5::uadd(int i, int j) + { + int64 l = (int64)i & 0x0ffffffffL; + int64 l1 = (int64)j & 0x0ffffffffL; + l += l1; + return (int)(l & 0x0ffffffffL); + } + + int MD5::uadd(int i, int j, int k) + { + return uadd(uadd(i, j), k); + } + + int MD5::uadd(int i, int j, int k, int l) + { + return uadd(uadd(i, j, k), l); + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.h new file mode 100644 index 00000000..b78a8db6 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.h @@ -0,0 +1,75 @@ +// MD5.h: interface for the MD5 class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef MD5_H +#define MD5_H + +#include +#include + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + + class MD5 + { + struct State + { + State(); + + std::vector state; + std::vector count; + std::vector buffer; + }; + + public: + MD5::MD5(); + MD5(const std::string &input); + + void Init(); + std::vector Final(); + void Update(char char0); + void Update(State & state1, std::vector achar0, int i, int j); + void Update(std::string s); + void Update(std::vector achar0); + void Update(std::vector achar0, int i); + void Update(std::vector achar0, int i, int j); + std::string asHex(); + static std::string asHex(std::vector achar0); + + private: + std::vector Decode(std::vector achar0, int i, int j); + std::vector Encode(std::vector ai, int i); + int FF(int i, int j, int k, int l, int i1, int j1, int k1); + int GG(int i, int j, int k, int l, int i1, int j1, int k1); + int HH(int i, int j, int k, int l, int i1, int j1, int k1); + int II(int i, int j, int k, int l, int i1, int j1, int k1); + void Transform(State & state1, std::vector achar0, int i); + int rotate_left(int i, int j); + int uadd(int i, int j); + int uadd(int i, int j, int k); + int uadd(int i, int j, int k, int l); + + private: + State state; + State finals; + bool finalsNull; + static std::vector padding; + + }; + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif // MD5_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Mutex.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Mutex.h new file mode 100644 index 00000000..79b78513 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Mutex.h @@ -0,0 +1,23 @@ +#ifndef BASE_MUTEX_H +#define BASE_MUTEX_H + +#ifdef WIN32 + + #include "win32/Mutex.h" + +#elif linux + + #include "linux/Mutex.h" + +#elif sparc + + #include "solaris/Mutex.h" + +#else + + #error /Base/Mutex.h: Undefine platform type + +#endif + +#endif // BASE_MUTEX_H + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Platform.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Platform.h new file mode 100644 index 00000000..2bdb170b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Platform.h @@ -0,0 +1,105 @@ +#ifndef BASE_PLATFORM_H +#define BASE_PLATFORM_H + +#include + + +#ifdef WIN32 + #include "win32/Platform.h" +#elif linux + #include "linux/Platform.h" +#elif sparc + #include "solaris/Platform.h" +#else + #error /Base/Platform.h: Undefine platform type +#endif + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + + template inline T rotlFixed(T x, unsigned int y) + { + assert(y < sizeof(T)*8); + return (T)((x<>(sizeof(T)*8-y))); + } + + template inline T rotrFixed(T x, unsigned int y) + { + assert(y < sizeof(T)*8); + return (x>>y) | (x<<(sizeof(T)*8-y)); + } + + template inline T rotlMod(T x, unsigned int y) + { + y %= sizeof(T)*8; + return (x<>(sizeof(T)*8-y)); + } + + template inline T rotrMod(T x, unsigned int y) + { + y %= sizeof(T)*8; + return (x>>y) | (x<<(sizeof(T)*8-y)); + } + + inline uint16 byteReverse16(void * data) + { + uint16 value = *static_cast(data); + return *static_cast(data) = rotlFixed(value, 8U); + // return rotlFixed(value, 8U); + } + + inline uint32 byteReverse32(void * data) + { + uint32 value = *static_cast(data); + return *static_cast(data) = (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); + // return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); + } + inline uint64 byteReverse64(void * data) + { + uint64 value = *static_cast(data); + return *static_cast(data) = ( + uint64((rotrFixed(uint32(value), 8U) & 0xff00ff00) | (rotlFixed(uint32(value), 8U) & 0x00ff00ff)) << 32) | + (rotrFixed(uint32(value>>32), 8U) & 0xff00ff00) | (rotlFixed(uint32(value>>32), 8U) & 0x00ff00ff); + // return (uint64(byteReverse(uint32(value))) << 32) | byteReverse(uint32(value>>32)); + } + + inline uint32 strlen(const unsigned short * string) + { + if (string == 0) + return 0; + + uint32 length=0; + while (*(string+length++) != 0); + + return length-1; + } + + inline double getTimerLatency(Base::uint64 startTime, Base::uint64 finishTime=0) + { + Base::int64 requestAge; + Base::int64 freq = Base::getTimerFrequency(); + Base::uint64 finish = (finishTime ? finishTime : Base::getTimer()); + if (finish < startTime) + requestAge = (0 - 1) - startTime - finish; + else + requestAge = finish - startTime; + return (double)requestAge/freq; + } + + +}; + +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif // BASE_PLATFORM_H + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/ScopeLock.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ScopeLock.cpp new file mode 100644 index 00000000..ff531174 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ScopeLock.cpp @@ -0,0 +1,34 @@ +#include "ScopeLock.h" + +#ifdef INCLUDE_SCOPELOCK + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + CScopeLock::CScopeLock(CMutex& mutex) : + mMutex(&mutex) + { + mMutex->Lock(); + } + + CScopeLock::CScopeLock(CScopeLock& lock) : + mMutex(lock.mMutex) + { + mMutex->Lock(); + } + + CScopeLock::~CScopeLock() + { + mMutex->Unlock(); + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // INCLUDE_SCOPELOCK diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/ScopeLock.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ScopeLock.h new file mode 100644 index 00000000..c965b78f --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ScopeLock.h @@ -0,0 +1,40 @@ +// ScopeLock.h: interface for the CScopeLock class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SCOPELOCK_H +#define SCOPELOCK_H + +#if defined _MT || defined _REENTRANT +# define INCLUDE_SCOPELOCK +#endif + +#ifdef INCLUDE_SCOPELOCK + +#include "Mutex.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + class CScopeLock + { + public: + CScopeLock(CMutex& mutex); + CScopeLock(CScopeLock& lock); + virtual ~CScopeLock(); + + private: + CMutex *mMutex; + }; +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // INCLUDE_SCOPELOCK + +#endif // SCOPELOCK_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Statistics.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Statistics.cpp new file mode 100644 index 00000000..19ad34ba --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Statistics.cpp @@ -0,0 +1,45 @@ +#include "Statistics.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + CStatisticTimer::CStatisticTimer(bool running) : + mTotal(0), + mStart(getTimer()), + mRunning(running) + { + } + + double CStatisticTimer::GetTime() + { + uint64 total = mTotal; + + if (mRunning) + total += getTimer()-mStart; + + return (double)((int64)(total/getTimerFrequency())); + } + + uint64 CStatisticTimer::GetFraction(uint32 fraction) + { + uint64 total = mTotal; + + if (mRunning) + total += getTimer()-mStart; + + if (fraction == 0) + return total; + else + return total/(getTimerFrequency()/fraction); + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/Statistics.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Statistics.h new file mode 100644 index 00000000..18e0579e --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/Statistics.h @@ -0,0 +1,140 @@ +#ifndef STATISTICS_H +#define STATISTICS_H + +#include +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + template + class CStatistic + { + public: + CStatistic(uint32 freq=0) : + mSampleFrequency(freq), + mLastSampleTime(0), + mSample(0), + mSampleTotal(0), + mAggregateTotal(0), + mAggregateMaximum(0), + mAggregateMinimum(0), + mAverageTotal(0), + mAverageIndex(0), + mAverageCount(0) + { + } + + bool Sample(TYPE value) + { + bool commit = false; + + if (!mLastSampleTime) + mLastSampleTime = time(NULL); + + if (!mSampleFrequency || mLastSampleTime + mSampleFrequency < (unsigned)time(NULL)) + { + mSampleTotal++; + mAggregateTotal += value; + if (value > mAggregateMaximum) + mAggregateMaximum = value; + if (value < mAggregateMinimum) + mAggregateMinimum = value; + + if (mAverageIndex == COUNT) + mAverageIndex = 0; + if (mAverageCount > COUNT) + mAverageTotal -= mAverageData[mAverageIndex]; + + mAverageData[mAverageIndex++] = value; + mAverageTotal += value; + + if (mAverageCount < COUNT) + mAverageCount++; + + commit = true; + mSample = 0; + } + + mSample += value; + + return commit; + } + + TYPE GetSample(uint32 age = 0) + { + if (age > mAverageCount) + return 0; + + uint32 index = mAverageIndex; + if (age > index) + index = COUNT - (age - index); + else + index -= age; + + return mAverageData[index]; + } + + double GetAverage() + { + return (double)mAverageTotal/mAverageCount; + } + + double GetAggregateAverage() + { + return (double)mAggregateTotal/mSampleTotal; + } + + TYPE GetMaximum() + { + return mAggregateMaximum; + } + + TYPE GetMinimum() + { + return mAggregateMinimum; + } + + private: + uint32 mSampleFrequency; + time_t mLastSampleTime; + TYPE mSample; + uint32 mSampleTotal; + TYPE mAggregateTotal; + TYPE mAggregateMaximum; + TYPE mAggregateMinimum; + + TYPE mAverageData[COUNT]; + TYPE mAverageTotal; + uint32 mAverageIndex; + uint32 mAverageCount; + }; + + class CStatisticTimer + { + public: + CStatisticTimer(bool running = true); + + void Start() { if (mRunning) return; mStart = getTimer(); mRunning = true; } + void Stop() { if (!mRunning) return; mTotal += getTimer()-mStart; mRunning = false; } + void Reset() { mTotal = 0; mStart = getTimer(); } + + double GetTime(); + uint64 GetFraction(uint32 fraction=1000); + + private: + uint64 mTotal; + uint64 mStart; + bool mRunning; + }; + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // STATISTICS_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/TemplateBlockAllocator.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/TemplateBlockAllocator.h new file mode 100644 index 00000000..2f211797 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/TemplateBlockAllocator.h @@ -0,0 +1,238 @@ +#ifndef BLOCK_ALLOCATOR_H +#define BLOCK_ALLOCATOR_H + +#if defined _MT || defined _REENTRANT +# define USE_ALLOCATOR_MUTEX +#endif + + +#include +#include "Mutex.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + template + class CBlockAllocator + { + + private: + class Node + { + public: + Node * mNext; + unsigned mBuffer[(BLOCK_SIZE-1)/sizeof(unsigned)+1]; + }; + + public: + CBlockAllocator() : + mMemoryBlockCount(0), + mNodesAllocated(0), + mNodesUsed(0), + mUnusedList(0) + { + for (int block=0; blockmNext; + node->mNext = (Node *)1; + + data = node->mBuffer; + + mNodesUsed++; + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + + return data; + } + + void Deallocate(void * data) + { + if (!data) + return; + + char * memoryPtr = reinterpret_cast(data) - sizeof(Node *); + Node * node = reinterpret_cast(memoryPtr); + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Lock(); +#endif + + node->mNext = mUnusedList; + mUnusedList = node; + mNodesUsed--; + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + } + + template T * Construct(const T & object) + { + T * objectPtr; + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Lock(); +#endif + if (sizeof(T) > BLOCK_SIZE || (!mUnusedList && !Allocate())) + { + char * memoryPtr = reinterpret_cast(new unsigned[(sizeof(Node *)+sizeof(T)-1)/sizeof(unsigned)+1]); + objectPtr = reinterpret_cast(memoryPtr+sizeof(Node *)); + + *reinterpret_cast(memoryPtr) = 0; + } + else + { + Node * node = mUnusedList; + mUnusedList = node->mNext; + node->mNext = (Node *)1; + + objectPtr = reinterpret_cast(node->mBuffer); + + mNodesUsed++; + } + + new (objectPtr) T(object); + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + return objectPtr; + } + + template void Destroy(T * object) + { + if (!object) + return; + + char * memoryPtr = reinterpret_cast(object) - sizeof(Node *); + Node * node = reinterpret_cast(memoryPtr); + + object->~T(); + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Lock(); +#endif + if (node->mNext == 0) + delete []memoryPtr; + else + { + node->mNext = mUnusedList; + mUnusedList = node; + mNodesUsed--; + } +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + } + + template T * FastConstruct(const T & object) + { + T * objectPtr; + + if (sizeof(T) > BLOCK_SIZE || (!mUnusedList && !Allocate())) + { + char * memoryPtr = reinterpret_cast(new unsigned[(sizeof(Node *)+sizeof(T)-1)/sizeof(unsigned)+1]); + objectPtr = reinterpret_cast(memoryPtr+sizeof(Node *)); + + *reinterpret_cast(memoryPtr) = 0; + } + else + { + Node * node = mUnusedList; + mUnusedList = node->mNext; + node->mNext = (Node *)1; + + objectPtr = reinterpret_cast(node->mBuffer); + + mNodesUsed++; + } + + new (objectPtr) T(object); + + return objectPtr; + } + + template void FastDestroy(T * object) + { + if (!object) + return; + + char * memoryPtr = reinterpret_cast(object) - sizeof(Node *); + Node * node = reinterpret_cast(memoryPtr); + + object->~T(); + + if (node->mNext == 0) + delete []memoryPtr; + else + { + node->mNext = mUnusedList; + mUnusedList = node; + mNodesUsed--; + } + } + + bool Allocate() + { + if (mMemoryBlockCount == MAX_BLOCK_COUNT) + return false; + + unsigned count = (mNodesAllocated ? mNodesAllocated : 32); + + Node* newMemoryBlock = new Node[count]; + for (unsigned i=0; i +#include "Types.h" +#include "Mutex.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + const uint32 MAX_BLOCK_COUNT = 32; + + template + class CObjectAllocator + { + public: + CObjectAllocator(uint32 size=32) + { + if (size < 32) + size = 32; + + for (uint32 index=0; indexnext; + + new (node) TYPE; + + mObjectCount++; +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + return (TYPE *)node; + } + + TYPE *Construct(const TYPE& object) + { +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Lock(); +#endif + if (!mUnusedList) + Allocate(mObjectCount); + + Node *node = mUnusedList; + mUnusedList = mUnusedList->next; + + new (node) TYPE(object); + + mObjectCount++; +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + return (TYPE *)node; + } + + void Destroy(TYPE *object) + { + if (object == NULL) + return; + +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Lock(); +#endif + object->~TYPE(); + + Node *node = reinterpret_cast(object); + + node->next = mUnusedList; + mUnusedList = node; + + mObjectCount--; +#ifdef USE_ALLOCATOR_MUTEX + mMutex.Unlock(); +#endif + } + + TYPE *FastConstruct() + { + if (!mUnusedList) + Allocate(mObjectCount); + + Node *node = mUnusedList; + mUnusedList = mUnusedList->next; + + new (node) TYPE; + + mObjectCount++; + return (TYPE *)node; + } + + TYPE *FastConstruct(const TYPE& object) + { + if (!mUnusedList) + Allocate(mObjectCount); + + Node *node = mUnusedList; + mUnusedList = mUnusedList->next; + + new (node) TYPE(object); + + mObjectCount++; + return (TYPE *)node; + } + + void FastDestroy(TYPE *object) + { + if (object == NULL) + return; + + object->~TYPE(); + + Node *node = reinterpret_cast(object); + + node->next = mUnusedList; + mUnusedList = node; + + mObjectCount--; + } + + private: + struct Node + { + char buffer[sizeof(TYPE)]; + Node* next; + }; + + bool Allocate(uint32 size) + { + if (mMemoryBlockCount == MAX_BLOCK_COUNT) + return false; + + Node* newMemoryBlock = new Node[size]; + mBytesAllocated += size * sizeof(Node); + + for (uint32 i=0; i +#include +#include +#include "Base/Archive.h" + + +namespace ucs2 +{ + + class string + { + public: + typedef unsigned short char_type; + typedef unsigned size_type; + + public: + string(); + string(const string & copy); + string(const char * copy); + string(const char_type * copy); + explicit string(const std::string & copy); + ~string(); + + string & operator=(const char * rhs); + string & operator=(const std::string & rhs); + string & operator=(const char_type * rhs); + string & operator=(const string & rhs); + + string & operator+=(const char * rhs); + string & operator+=(const std::string & rhs); + string & operator+=(const char_type * rhs); + string & operator+=(const string & rhs); + + const char_type & at(size_type index) const; + char_type & at(size_type index); + + const char_type & operator[](size_type index) const; + char_type & operator[](size_type index); + + bool operator==(const string & rhs) const; + bool operator!=(const string & rhs) const; + bool operator<(const string & rhs) const; + bool operator<=(const string & rhs) const; + bool operator>(const string & rhs) const; + bool operator>=(const string & rhs) const; + + string & assign(const char_type * rhs); + string & assign(const char_type * rhs, size_type count); + string & assign(const string & rhs, size_type position, size_type count); + string & assign(const string & rhs); + string & assign(size_type count, char_type c); + string & assign(const char_type * first, const char_type * last); + + string & append(const char_type * rhs); + string & append(const char_type * rhs, size_type count); + string & append(const string & rhs, size_type position, size_type count); + string & append(const string & rhs); + string & append(size_type count, char_type c); + string & append(const char_type * first, const char_type * last); + + std::string narrow() const; + const char_type * c_str() const; + const char_type * data() const; + + size_type length() const; + size_type size() const; + size_type max_size() const; + void resize(size_type n, char_type c = 0x0032); + size_type capacity() const; + void reserve(size_type n = 0); + bool empty() const; + + private: + size_type mLength; + std::vector mData; + static char_type mOutOfRangeCharacter; + }; + + inline char WideToNarrow(string::char_type c) { return (char)c; } + inline string::char_type NarrowToWide(char c) { return (string::char_type)c; } + + string::char_type string::mOutOfRangeCharacter(0); + + //////////////////////////////////////// + // default constructor allocates 8 characters and sets length to zero + inline string::string() : + mLength(0), + mData(8,0) + { + } + + //////////////////////////////////////// + // target string is a null-terminated C string + inline string::string(const char * copy) : + mLength(0), + mData(8,0) + { + // (1) protect from null pointer + if (!copy) + { + return; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*copy) + { + reserve(mLength+1); + mData[mLength++] = *copy++; + } + // (3) ensure null termination + mData[mLength]=0; + } + + //////////////////////////////////////// + // target string is a C string that may or may not include null characters + inline string::string(const std::string & copy) : + mLength(copy.length()), + mData(8,0) + { + // (1) ensure we have the storage for the entire string + reserve(mLength); + // (2) perform transform to copy the narrow string to our + // wide string + std::transform(copy.begin(), copy.end(), mData.begin(), NarrowToWide); + // (3) ensure null termination + mData[mLength] = 0; + } + + //////////////////////////////////////// + // target string is a wide null-terminated C string + inline string::string(const char_type * copy) : + mLength(0), + mData(8,0) + { + // (1) protect from null pointer + if (!copy) + { + return; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*copy) + { + reserve(mLength+1); + mData[mLength++] = *copy++; + } + // (3) ensure null termination + mData[mLength]=0; + } + + //////////////////////////////////////// + // copy constructor + inline string::string(const string & copy) : + mLength(copy.mLength), + mData(8,0) + { + reserve(mLength); + mData.assign(copy.mData.begin(), copy.mData.begin()+copy.mLength+1); + } + + inline string::~string() + { + } + + inline string & string::operator=(const char * rhs) + { + mLength = 0; + // (1) protect from null pointer + if (!rhs) + { + mData[0] = 0; + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*rhs) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::operator=(const std::string & rhs) + { + mLength = rhs.length(); + // (1) ensure we have the storage for the entire string + reserve(mLength); + // (2) perform transform to copy the narrow string to our + // wide string + std::transform(rhs.begin(), rhs.end(), mData.begin(), NarrowToWide); + // (3) ensure null termination + mData[mLength] = 0; + return *this; + } + + inline string & string::operator=(const char_type * rhs) + { + mLength = 0; + // (1) protect from null pointer + if (!rhs) + { + mData[0] = 0; + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*rhs) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::operator=(const string & rhs) + { + // (1) protect from assigning to self + if (&rhs != this) + { + mLength = rhs.mLength; + reserve(mLength); + mData.assign(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1); + } + return *this; + } + + inline string & string::operator+=(const char * rhs) + { + // (1) protect from null pointer + if (!rhs) + { + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*rhs) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::operator+=(const std::string & rhs) + { + // (1) ensure we have the storage for the entire string + reserve(mLength+rhs.length()); + // (2) perform transform to copy the narrow string to our + // wide string + std::transform(rhs.begin(), rhs.end(), mData.begin()+mLength, NarrowToWide); + // (3) ensure null termination + mLength += rhs.length(); + mData[mLength] = 0; + return *this; + } + + inline string & string::operator+=(const char_type * rhs) + { + // (1) protect from null pointer + if (!rhs) + { + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*rhs) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::operator+=(const string & rhs) + { + reserve(mLength+rhs.mLength); + std::copy(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1, mData.begin()+mLength); + mLength += rhs.mLength; + + return *this; + } + + inline const string::char_type & string::at(string::size_type index) const + { + return (index > mLength) ? mOutOfRangeCharacter : mData[index]; + } + + inline string::char_type & string::at(string::size_type index) + { + return (index > mLength) ? mOutOfRangeCharacter : mData[index]; + } + + inline const string::char_type & string::operator[](string::size_type index) const + { + return (index > mLength) ? mOutOfRangeCharacter : mData[index]; + } + + inline string::char_type & string::operator[](string::size_type index) + { + return (index > mLength) ? mOutOfRangeCharacter : mData[index]; + } + + inline bool string::operator==(const string & rhs) const + { + if (mLength != rhs.mLength) + { + return false; + } + else + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) == 0); + } + } + + inline bool string::operator!=(const string & rhs) const + { + if (mLength != rhs.mLength) + { + return true; + } + else + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) != 0); + } + } + + inline bool string::operator<(const string & rhs) const + { + if (mLength <= rhs.mLength) + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) < 0); + } + else + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) < 0); + } + } + + inline bool string::operator<=(const string & rhs) const + { + if (mLength <= rhs.mLength) + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) <= 0); + } + else + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) <= 0); + } + } + + inline bool string::operator>(const string & rhs) const + { + if (mLength <= rhs.mLength) + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) > 0); + } + else + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) > 0); + } + } + + inline bool string::operator>=(const string & rhs) const + { + if (mLength <= rhs.mLength) + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) >= 0); + } + else + { + return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) >= 0); + } + } + + inline string & string::assign(const char_type * rhs) + { + mLength = 0; + // (1) protect from null pointer + if (!rhs) + { + mData[0] = 0; + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*rhs) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::assign(const char_type * rhs, size_type count) + { + mLength = 0; + // (1) protect from null pointer + if (!rhs) + { + mData[0] = 0; + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (count--) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::assign(const string & rhs, size_type position, size_type count) + { + // (1) protect from assigning to self + if (&rhs != this) + { + mLength = count; + reserve(mLength); + mData.assign(rhs.mData.begin()+position, rhs.mData.begin()+position+count+1); + } + return *this; + } + + inline string & string::assign(const string & rhs) + { + // (1) protect from assigning to self + if (&rhs != this) + { + mLength = rhs.mLength; + reserve(mLength); + mData.assign(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1); + } + return *this; + } + + inline string & string::assign(size_type count, char_type c) + { + mLength = count; + reserve(mLength); + std::fill(mData.begin(), mData.end(), c); + mData[mLength]=0; + return *this; + } + + inline string & string::assign(const char_type * first, const char_type * last) + { + mLength = 0; + // (1) protect from null pointer + if (!first || !last) + { + mData[0] = 0; + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (first != last) + { + reserve(mLength+1); + mData[mLength++] = *first++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::append(const char_type * rhs) + { + // (1) protect from null pointer + if (!rhs) + { + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (*rhs) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::append(const char_type * rhs, size_type count) + { + // (1) protect from null pointer + if (!rhs) + { + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (count--) + { + reserve(mLength+1); + mData[mLength++] = *rhs++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline string & string::append(const string & rhs, size_type position, size_type count) + { + // (1) protect from invalid position value + if (rhs.mLength <= position) + { + return *this; + } + // (2) make sure we copy count charatcers, or to the end of the string + if (rhs.mLength < position+count) + { + count = rhs.mLength-position; + } + // (3) perform copy + reserve(mLength+count); + std::copy(rhs.mData.begin()+position, rhs.mData.begin()+position+count+1, mData.begin()+mLength); + mLength += count; + return *this; + } + + inline string & string::append(const string & rhs) + { + // (1) perform copy + reserve(mLength+rhs.mLength); + std::copy(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1, mData.begin()+mLength); + mLength += rhs.mLength; + return *this; + } + + inline string & string::append(size_type count, char_type c) + { + reserve(mLength+count); + std::fill(mData.begin()+mLength, mData.begin()+mLength+count, c); + mLength += count; + mData[mLength]=0; + return *this; + } + + inline string & string::append(const char_type * first, const char_type * last) + { + // (1) protect from null pointer + if (!first || !last) + { + return *this; + } + // (2) linear copy the string, must reserve before each character + // because the string length is unknown + while (first != last) + { + reserve(mLength+1); + mData[mLength++] = *first++; + } + // (3) ensure null termination + mData[mLength]=0; + return *this; + } + + inline std::string string::narrow() const + { + std::string narrow; + narrow.resize(mLength); + std::transform(mData.begin(), mData.begin()+mLength+1, narrow.begin(), WideToNarrow); + return narrow; + } + + inline const string::char_type * string::c_str() const + { + return &mData[0]; + } + + inline const string::char_type * string::data() const + { + return &mData[0]; + } + + inline string::size_type string::length() const + { + return mLength; + } + + inline string::size_type string::size() const + { + return mLength; + } + + inline void string::resize(string::size_type n, string::char_type c) + { + reserve(n); + + while (mLength capacity()) + mData.resize((capacity()+1)*2,0x0000); + } + + inline bool string::empty() const + { + return mLength == 0; + } + + +} + +namespace Base +{ + + + inline void get(ByteStream::ReadIterator & source, ucs2::string & target) + { + unsigned int size = 0; + get(source, size); + + const unsigned char * const buf = source.getBuffer(); + const ucs2::string::char_type * const ubuf = reinterpret_cast(buf); + + target.assign(ubuf, ubuf + size); + + const unsigned int readSize = size * sizeof(ucs2::string::char_type); + source.advance(readSize); + } + + inline void put(ByteStream & target, const ucs2::string & source) + { + const unsigned int size = source.size(); + put(target, size); + put(target, (const unsigned char *)source.data(), size*sizeof(ucs2::string::char_type)); + } + + +} + + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp new file mode 100644 index 00000000..28781273 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp @@ -0,0 +1,165 @@ +#include "ccspanutil.h" + +#include +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +char * CSpanUtil::getDescriptionFromCardNum(const char *cardNum) +{ + // if the card number is less than this we wont be able to determine it, and we dont want to crash so . . . + if(strlen(cardNum) < 8 ) + return "Credit Card"; + + switch(cardNum[0]) + { + case '3': + if(cardNum[1] == '4') + return "AMEX"; + + if(cardNum[1] == '7') + { + // RG 5/9 changed to fix rrc=233. We do not support OP anyway. + // Card prefix check is unclear. + // + // if(cardNum[3] == '7') + // return "OP"; + // else + return "AMEX"; + } + if((cardNum[1] == '0') || (cardNum[1] == '6')) + return "DINERS"; + if(cardNum[1] == '8') + { + if((cardNum[2] >= '1') && (cardNum[2] <= '8')) + return "DINERS"; + } + if(cardNum[1] == '5') + { + char temp[3]; + memcpy(temp, &cardNum[2], 2); + temp[2] = 0; + + int value = atoi(temp); + if((value >= 28) && (value <= 89)) + return "JCB"; + } + break; + case '4': + // RG 5/6 changed to fix rrc=233. We do not support SW anyway. + // Card prefix check is unclear. + // + // if(cardNum[1] == '9') + // return "SW"; + // else + return "VISA"; + break; + case '5': + if(cardNum[1] == '6') + return "Switch/solo"; + if((cardNum[1] >= '1') && (cardNum[1] <= '5')) + return "MC"; + if(memcmp(cardNum, "504990", 6) == 0) + return "Bill me Later"; + break; + case '6': + { + char temp[8]; + memcpy(temp, cardNum, 7); + temp[7] = 0; + int value7 = atoi(temp); + temp[6] = 0; + int value6 = atoi(temp); + temp[5] = 0; + int value5 = atoi(temp); + + // september 29 2005 added new card IIN ranges for Discover per email from + // paymentTech email effective Oct 1, 2005 + if((value5 == 60110) || + (value5 == 60112) || + (value5 == 60113) || + (value5 == 60114) || + (value5 == 60115) || + (value5 == 60116) || + (value6 == 601174) || + (value6 >= 601177 && value6 <= 601179) || + (value6 >=601186 && value6 <= 600189) || + (value5 == 60119) || + (value6 >= 650000 && value6 <=650999)) + return "DISCOVER"; + + if(value6 == 603571) + return "Saved Value"; + + return "Switch/Solo"; + } + break; + case '7': + return "Switch/Solo"; + break; + case '9': + //if((cardNum[1] == '4') && (cardNum[1] == '5')) + return "Carte Blanche"; + break; + } + + return "Credit Card"; +} + + +// generates a credit card span for an account number string up to a length of any size. +std::string CSpanUtil::generateCCSpan(std::string cardNumber) +{ + // according to the PCI standard on visa's web site, the max number of displayable digits for a cc are the first 6 and last 4 + // we will however require that at least the middle half of the card is not shown + std::string ccSpan; + const std::string asteriks = "*"; + + // if the length of the card is an odd number we will display the larger portion of the card on the front viewable amount. + // for Amex this will look like 1234********123 + // on a 16 digit card, the most digits will be displayed being 1234********1234 + // a 12 digit card would look like 123******123 + + // as per qa request and devtrack bug 2440 masking is first 4 and las 4 visible + + unsigned displayableBeginningDigits = 4; + unsigned displayableEndingDigits = 4; + + if(cardNumber.length() <= 8) + return cardNumber; + + ccSpan = cardNumber.substr(0, displayableBeginningDigits); + + unsigned totalMasked = cardNumber.length() - displayableBeginningDigits - displayableEndingDigits; + + // now add in characters to mask the middle numbers + for(unsigned maskedDigits = 0; maskedDigits < totalMasked; maskedDigits++) + ccSpan += asteriks; + + ccSpan += cardNumber.substr((totalMasked+displayableBeginningDigits)); + + return ccSpan; +} + +std::string CSpanUtil::generateCCDescription(std::string cardNumber) +{ + std::string ccDescription; + + // get the card type + + ccDescription = std::string(getDescriptionFromCardNum(cardNumber.c_str())) + std::string("(") + generateCCSpan(cardNumber) + std::string(")"); + + return ccDescription; +} +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.h new file mode 100644 index 00000000..7f31f57a --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.h @@ -0,0 +1,40 @@ +#ifndef _CCSPANUTIL_H +#define _CCSPANUTIL_H + +#pragma warning (disable : 4786) +#include +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + class CSpanUtil + { + public: + + //determine the type of credit card according to credit number + static char *getDescriptionFromCardNum(const char *cardNum); + + // generates a credit card span for an account number string up to a length of any size. + static std::string generateCCSpan(std::string cardNumber); + + // generartes credit card description consist of card type + a credit card span + static std::string generateCCDescription(std::string cardNumber); + + // constructor + CSpanUtil(); + + // destructor + ~CSpanUtil(); + }; +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Archive.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Archive.h new file mode 100644 index 00000000..bb623b49 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Archive.h @@ -0,0 +1,44 @@ +#ifndef BASE_LINUX_ARCHIVE_H +#define BASE_LINUX_ARCHIVE_H + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif + +namespace Base +{ + + +#ifdef PACK_BIG_ENDIAN + + inline double byteSwap(double value) { byteReverse(&value); return value; } + inline float byteSwap(float value) { byteReverse(&value); return value; } + inline uint64 byteSwap(uint64 value) { byteReverse(&value); return value; } + inline int64 byteSwap(int64 value) { byteReverse(&value); return value; } + inline uint32 byteSwap(uint32 value) { byteReverse(&value); return value; } + inline int32 byteSwap(int32 value) { byteReverse(&value); return value; } + inline uint16 byteSwap(uint16 value) { byteReverse(&value); return value; } + inline int16 byteSwap(int16 value) { byteReverse(&value); return value; } + +#else + + inline double byteSwap(double value) { return value; } + inline float byteSwap(float value) { return value; } + inline uint64 byteSwap(uint64 value) { return value; } + inline int64 byteSwap(int64 value) { return value; } + inline uint32 byteSwap(uint32 value) { return value; } + inline int32 byteSwap(int32 value) { return value; } + inline uint16 byteSwap(uint16 value) { return value; } + inline int16 byteSwap(int16 value) { return value; } + +#endif + + +} +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/BlockAllocator.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/BlockAllocator.cpp new file mode 100644 index 00000000..00d01ec9 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/BlockAllocator.cpp @@ -0,0 +1,110 @@ +#include "../BlockAllocator.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + BlockAllocator::BlockAllocator() + { + for(unsigned i = 0; i < 31; i++) + { + m_blocks[i] = NULL; + } + } + + BlockAllocator::~BlockAllocator() + { + // free all allocated memory blocks + for(unsigned i = 0; i < 31; i++) + { + while(m_blocks[i] != NULL) + { + unsigned *tmp = m_blocks[i]; + m_blocks[i] = (unsigned *)*m_blocks[i]; + free(tmp); + } + } + } + +// Allocate a block that is the next power of two greater than the # of bytes passed. +// 33 bytes yields a 64 byte block of memory and so forth. + + void *BlockAllocator::getBlock(unsigned bytes) + { + unsigned accum = 16, bits = 16; + unsigned *handle = NULL; + + // Perform a binary search looking for the highest bit. + + while(bits != 0) + { + // If bytes is less than the bit we're testing for, subtract half + // from the bit value and repeat + if(bytes < (unsigned)(1 << accum)) + { + bits /= 2; + accum -= bits; + } + // If bytes is greater than the bit we're testing for, add half + // from the but value and repeat + else if(bytes > (unsigned)(1 << accum)) + { + bits /= 2; + accum += bits; + } + // Got lucky and hit the value dead on + else + { + break; + } + } + // At this point accum contains the most significant bit index, increment + accum++; + if(accum < 2) + { + accum = 2; + } + + // Note that when memory is actually allocated, 8 extra bytes will be allocated.at the front + // The first integer is the address of the next block of memory when the block is in the allocator + // The second integer is the bit length of the block + // Memory is allocated on 4 byte boundaries to sidestep byte alignment problems + + + // Check if the allocator already has a block of that size + if(m_blocks[accum] == 0) + { + // remove the pre allocated block from the linked list + handle = (unsigned *)calloc(((1 << accum) / 4) + 2, sizeof(unsigned)); + handle[1] = accum; + handle[0] = 0; + } + else + { + // Allocate a new block + handle = m_blocks[accum]; + m_blocks[accum] = (unsigned *)handle[0]; + handle[0] = 0; + } + // return a pointer that skips over the header used for the allocator's purposes + return(handle + 2); + } + + void BlockAllocator::returnBlock(unsigned *handle) + { + // C++ allows for safe deletion of a NULL pointer + if(handle) + { + // Update the allocator linked list, insert this entry at the head + *(handle - 2) = (unsigned)m_blocks[*(handle - 1)]; + // Add this entry to the proper linked list node + m_blocks[*(handle - 1)] = (handle - 2); + } + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Event.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Event.cpp new file mode 100644 index 00000000..a3cce3b1 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Event.cpp @@ -0,0 +1,103 @@ +//////////////////////////////////////// +// Event.cpp +// +// Purpose: +// 1. Implementation of the CEvent class. +// +// Revisions: +// 07/10/2001 Created +// + +#if defined(_REENTRANT) + + +#include "Event.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + CEvent::CEvent() : + mMutex(), + mCond(), + mThreadCount(0) + { + pthread_mutex_init(&mMutex, NULL); + pthread_cond_init(&mCond, NULL); + } + + CEvent::~CEvent() + { + pthread_cond_destroy(&mCond); + pthread_mutex_destroy(&mMutex); + } + + bool CEvent::Signal() + { + pthread_mutex_lock(&mMutex); + if (mThreadCount == 0) + mThreadCount = SIGNALED; + pthread_cond_signal(&mCond); + + pthread_mutex_unlock(&mMutex); + + return true; + } + + int32 CEvent::Wait(uint32 timeout) + { + int result; + + pthread_mutex_lock(&mMutex); + if (mThreadCount == SIGNALED) + { + mThreadCount = 0; + pthread_mutex_unlock(&mMutex); + + return eWAIT_SIGNAL; + } + + if (!timeout) + { + mThreadCount++; + result = pthread_cond_wait(&mCond, &mMutex); + mThreadCount--; + + pthread_mutex_unlock(&mMutex); + } + else + { + struct timeval now; + struct timespec abs_timeout; + + gettimeofday(&now, NULL); + abs_timeout.tv_sec = now.tv_sec + timeout/1000; + abs_timeout.tv_nsec = now.tv_usec * 1000 + (timeout%1000)*1000000; + abs_timeout.tv_sec += abs_timeout.tv_nsec / 1000000000; + abs_timeout.tv_nsec %= 1000000000; + + mThreadCount++; + result = pthread_cond_timedwait(&mCond, &mMutex, &abs_timeout); + mThreadCount--; + + pthread_mutex_unlock(&mMutex); + } + + if (result == 0 || result == EINTR) + return eWAIT_SIGNAL; + else if (result == ETIMEDOUT) + return eWAIT_TIMEOUT; + else + return eWAIT_ERROR; + } + +} + +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // #if defined(_REENTRANT) diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Event.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Event.h new file mode 100644 index 00000000..4801a9b2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Event.h @@ -0,0 +1,74 @@ +//////////////////////////////////////// +// Event.h +// +// Purpose: +// 1. Declair the CEvent class that encapsulates the functionality of a +// single-locking semaphore. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_EVENT_H +#define BASE_LINUX_EVENT_H + +#if !defined(_REENTRANT) +# pragma message( "Excluding Base::CEvent - requires multi-threaded compile. (_REENTRANT)" ) +#else + + +#include +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CEvent + // + // Purpose: + // Encapsulates the functionality of a singal-locking semaphore. + // This class is valuable for thread syncronization when a thead's + // execution needs to be dependent upon another thread. + // + // Public Methods: + // Signal() : Signals a thread that has called Wait() so that it can + // continue execution. This function returns true if the waiting + // thread was signalled successfully, otherwise false is returned. + // Wait() : Halts the calling thread's execution indefinately until + // a Singal() call is made by an external thread. If the thread is + // successfully signalled, the function returns eWAIT_SIGNAL. If + // timeout period expires without a signal, eWAIT_TIMEOUT is returned. + // If the function fails, eWAIT_ERROR is returned. + // + class CEvent + { + public: + CEvent(); + virtual ~CEvent(); + + bool Signal(); + int32 Wait(uint32 timeout = 0); + + public: + enum { eWAIT_ERROR, eWAIT_SIGNAL, eWAIT_TIMEOUT }; + enum { SIGNALED = -1 }; + private: + pthread_mutex_t mMutex; + pthread_cond_t mCond; + int mThreadCount; + }; + +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // #if defined(_MT) + +#endif // BASE_LINUX_EVENT_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Mutex.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Mutex.cpp new file mode 100644 index 00000000..36fe5b29 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Mutex.cpp @@ -0,0 +1,40 @@ +//////////////////////////////////////// +// Mutex.cpp +// +// Purpose: +// 1. Implementation of the CMutex class. +// +// Revisions: +// 07/10/2001 Created +// + +#if defined(_REENTRANT) + + +#include "Mutex.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +CMutex::CMutex() + { + mInitialized = (pthread_mutex_init(&mMutex, 0) == 0); + } + +CMutex::~CMutex() + { + if (mInitialized) + pthread_mutex_destroy(&mMutex); + } + +} +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // #if defined(_REENTRANT) diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Mutex.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Mutex.h new file mode 100644 index 00000000..dd56e3fc --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Mutex.h @@ -0,0 +1,79 @@ +//////////////////////////////////////// +// Mutex.h +// +// Purpose: +// 1. Declair the CMutex class that encapsulates the functionality of a +// mutually-exclusive device. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_MUTEX_H +#define BASE_LINUX_MUTEX_H + +#if !defined(_REENTRANT) +# pragma message( "Excluding Base::CMutex - requires multi-threaded compile. (_REENTRANT)" ) +#else + + +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CMutex + // + // Purpose: + // Encapsulates the functionality of a mutually-exclusive device. + // This class is valuable for protecting against race conditions + // within threaded applications. The CMutex class can be used to + // only allow a single thread to run within a specified code + // segment at a time. + // + // Public Methods: + // Lock() : Locks the mutex. If the mutex is already locked, the + // operating system will block the calling thread until another + // thread has unlocked the mutex. + // Unlock() : Unlocks the mutex. + // + class CMutex + { + public: + CMutex(); + ~CMutex(); + + void Lock(); + void Unlock(); + private: + pthread_mutex_t mMutex; + bool mInitialized; + }; + + inline void CMutex::Lock(void) + { + if (mInitialized) + pthread_mutex_lock(&mMutex); + } + + inline void CMutex::Unlock(void) + { + if (mInitialized) + pthread_mutex_unlock(&mMutex); + } + +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // #if defined(_MT) + +#endif // BASE_LINUX_MUTEX_H + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Platform.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Platform.cpp new file mode 100644 index 00000000..eeadd498 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Platform.cpp @@ -0,0 +1,55 @@ +//////////////////////////////////////// +// Platform.cpp +// +// Purpose: +// 1. Implementation of the global functionality declaired in Platform.h. +// +// Revisions: +// 07/10/2001 Created +// + +#include +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + // Implementation of microsoft strlwr extension + // This non-ANSI function is not supported under UNIX + void strlwr(char * s) + { + while (*s) + { + *s = tolower(*s); + s++; + } + } + + // Implementation of microsoft strlwr extension + // This non-ANSI function is not supported under UNIX + void strupr(char * s) + { + while (*s) + { + *s = toupper(*s); + s++; + } + } + + + CTimer::CTimer() : + mTimer(0) + { + } + + +} +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Platform.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Platform.h new file mode 100644 index 00000000..9e6d51b4 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Platform.h @@ -0,0 +1,112 @@ +//////////////////////////////////////// +// Platform.h +// +// Purpose: +// 1. Include relevent system headers that are platform specific. +// 2. Declair global platform specific functionality. +// 3. Include primative type definitions +// +// Global Functions: +// getTimer() : Return the current high resolution clock count. +// getTimerFrequency() : Return the frequency of the high resolution clock. +// sleep() : Voluntarily relinquish timeslice of the calling thread for a +// specified number of milliseconds. +// strlwr() : Alters the contents of a string, making it all lower-case. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_PLATFORM_H +#define BASE_LINUX_PLATFORM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Types.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + uint64 getTimer(void); + uint64 getTimerFrequency(void); + void sleep(uint32 ms); + + inline uint64 getTimer(void) + { + uint64 t; + struct timeval tv; + + gettimeofday(&tv, 0); + t = tv.tv_sec; + t = t * 1000000; + t += tv.tv_usec; + return t; + } + + inline uint64 getTimerFrequency(void) + { + uint64 f = 1000000; + return f; + } + + inline void sleep(uint32 ms) + { + usleep(static_cast(ms * 1000)); + } + + void strlwr(char * s); + void strupr(char * s); + + + class CTimer + { + public: + CTimer(); + + void Set(uint32 seconds); + void Signal(); + bool Expired(); + + private: + uint32 mTimer; + }; + + inline void CTimer::Set(uint32 interval) + { + mTimer = (uint32)time(0) + interval; + } + + inline void CTimer::Signal() + { + mTimer = 0; + } + + inline bool CTimer::Expired() + { + return (mTimer <= (uint32)time(0)); + } + + +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // BASE_LINUX_PLATFORM_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Thread.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Thread.cpp new file mode 100644 index 00000000..a4b1e3a2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Thread.cpp @@ -0,0 +1,299 @@ +//////////////////////////////////////// +// Thread.cpp +// +// Purpose: +// 1. Implementation of the CThread class. +// +// Revisions: +// 07/10/2001 Created +// + +#if defined(_REENTRANT) + + +#include +#include +#include "Thread.h" + +using namespace std; + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + void *threadProc(void *threadPtr) + { + CThread &thread = *((CThread*)threadPtr); + thread.mThreadActive = true; + thread.ThreadProc(); + thread.mThreadActive = false; + + return 0; + } + + CThread::CThread() + { + mThreadID = 0; + mThreadActive = false; + mThreadContinue = false; + } + + CThread::~CThread() + { + StopThread(); + } + + void CThread::StartThread() + { + mThreadContinue = true; + if (pthread_create(&mThreadID,0,threadProc,this) == 0) + pthread_detach(mThreadID); + while (!IsThreadActive()) + Base::sleep(1); + } + + int32 CThread::StopThread(int timeout) + { + timeout += time(0); + + mThreadContinue = false; + while (mThreadActive && time(0)OnStartup(this); + while (mThreadContinue) + { + mParent->OnIdle(this); + mSemaphore.Wait(mParent->GetTimeOut()*1000); + + if (mFunction) + { + mFunction(mArgument); + mArgument = NULL; + mFunction = NULL; + } + else if (mParent->OnDestory(this)) + mThreadContinue = false; + } + } + + +//////////////////////////////////////////////////////////////////////////////// + + + CThreadPool::CThreadPool(uint32 maxThreads, uint32 minThreads, uint32 timeout) : + mMutex(), + mIdleMember(), + mBusyMember(), + mNullMember(), + mThreadCount(0), + mMaxThreads(maxThreads), + mMinThreads(minThreads), + mTimeOut(timeout) + { + if (mMaxThreads == 0) mMaxThreads = 1; + if (mMinThreads == 0) mMinThreads = 1; + if (mMinThreads > mMaxThreads) mMinThreads = mMaxThreads; + + for (uint32 i=0; i::iterator setIterator; + + //////////////////////////////////////// + // (1) Destory all busy member threads + mMutex.Lock(); + setIterator = mBusyMember.begin(); + while (setIterator != mBusyMember.end()) + (*setIterator++)->Destroy(); + mMutex.Unlock(); + + //////////////////////////////////////// + // (2) Destory all idle member threads + while (mThreadCount) + { + mMutex.Lock(); + setIterator = mIdleMember.begin(); + while (setIterator != mIdleMember.end()) + (*setIterator++)->Destroy(); + mMutex.Unlock(); + + sleep(1); + } + + //////////////////////////////////////// + // (3) Delete the null member threads + mMutex.Lock(); + while (!mNullMember.empty()) + { + delete mNullMember.front(); + mNullMember.pop_front(); + } + mMutex.Unlock(); + } + + bool CThreadPool::Execute(void( *function )( void * ), void * arg, uint32 poolGrowthSize ) + { + mMutex.Lock(); + + //////////////////////////////////////// + // (1) If no idle members, return false to indicate that no threads + // were available. If the thread count is below the max, create + // a new thread. + if (mIdleMember.empty()) + { + if (mThreadCount < mMaxThreads) + { + if (!poolGrowthSize) + poolGrowthSize = mMinThreads; + + if ((mThreadCount + poolGrowthSize) > mMaxThreads) + poolGrowthSize = mMaxThreads - mThreadCount; + + for (uint32 i(0); i < poolGrowthSize; i++) + new CMember(this); + mMutex.Unlock(); + time_t idleTimeout = time(0) + 5; + while(mIdleMember.empty()) + { + if (time(0) >= idleTimeout) + { + return false; + } + Base::sleep(10); + } + mMutex.Lock(); + + } + else + { + mMutex.Unlock(); + return false; + } + } + + //////////////////////////////////////// + // (2) Delete any null member threads. + while (!mNullMember.empty()) + { + delete mNullMember.front(); + mNullMember.pop_front(); + } + + //////////////////////////////////////// + // (3) Move the first idle thread to the busy set and signal the + // thread to execute the specified function. + CMember * member = *(mIdleMember.begin()); + mIdleMember.erase(member); + mBusyMember.insert(member); + member->Execute(function,arg); + + mMutex.Unlock(); + return true; + } + + uint32 CThreadPool::GetTimeOut() + { + return mTimeOut; + } + + void CThreadPool::OnStartup(CMember * member) + { + mMutex.Lock(); + + mThreadCount++; + mIdleMember.insert(member); + + mMutex.Unlock(); + } + + void CThreadPool::OnIdle(CMember * member) + { + mMutex.Lock(); + + mBusyMember.erase(member); + mIdleMember.insert(member); + + mMutex.Unlock(); + } + + bool CThreadPool::OnDestory(CMember * member) + { + set::iterator setIterator; + + mMutex.Lock(); + + bool result = (setIterator = mIdleMember.find(member)) != mIdleMember.end(); + if (result) + { + mNullMember.push_back(member); + mIdleMember.erase(setIterator); + mThreadCount--; + } + + mMutex.Unlock(); + + return result; + } + + +//////////////////////////////////////////////////////////////////////////////// + + +} + +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // #if defined(_REENTRANT) diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Thread.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Thread.h new file mode 100644 index 00000000..bb6d1cb2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Thread.h @@ -0,0 +1,146 @@ +//////////////////////////////////////// +// Thread.h +// +// Purpose: +// 1. Declair the CThread class that encapsulates threading functionality. +// This abstract base class in intended to be used to encapsulate +// individual tasks that require threading in derived classes. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_THREAD_H +#define BASE_LINUX_THREAD_H + +#if !defined(_REENTRANT) +# pragma message( "Excluding Base::CThread - requires multi-threaded compile. (_REENTRANT)" ) +#else + + +#pragma warning( disable : 4786) + +#include +#include +#include "Platform.h" +#include "Mutex.h" +#include "Event.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CThread + // + // Purpose: + // Encapsulates threading functionality. Creating classes derived + // from CThread provides an easy way to encapsulate tasks that require + // their own thread. + // + // Public Methods: + // StartThread() : Creates the low-level thread handle and begins executing + // the CThread::ThreadProc() function within the new thread. + // StopThread() : Signals the ThreadProc() function to stop executing using + // the mThreadContinue member variable, and waits for the ThreadProc() + // function to exit. By default, the function will block for a maximum + // of 5 seconds before exiting without the thread halting. + // IsThreadActive() : Returns true if the physical thread is still executing + // within the ThreadProc() function, otherwise it returns false. + // ThreadProc() : Pure-virtual function that will be executed when the StartThread() + // function is called. Derived classes must implement this function. The + // mThreadContinue member variable should be used internal the the ThreadProc() + // function to indicate whether it should continue executing or exit. + // Protected Attributes: + // mThreadContinue : Boolean value indicating to the ThreadProc() function + // whether to continue executing or to exit. If mThreadContinue is true, + // ThreadProc() should continue, otherwise ThreadProc() should exit. It + // left up to the derived class to implement a ThreadProc() function that + // uses the mThreadContinue member. + // + // + class CThread + { + friend void * threadProc(void *); + + public: + enum { eSTOP_SUCCESS, eSTOP_TIMEOUT }; + public: + CThread(); + virtual ~CThread(); + + void StartThread(); + int32 StopThread(int timeout=5); + bool IsThreadActive() { return mThreadActive; } + + protected: + virtual void ThreadProc() {} + + protected: + bool mThreadContinue; + private: + pthread_t mThreadID; + bool mThreadActive; + }; + + + class CThreadPool + { + private: + class CMember : public CThread + { + public: + CMember(CThreadPool * parent); + virtual ~CMember(); + + bool Execute(void( *function )( void * ), void * arg); + void Destroy(); + + protected: + virtual void ThreadProc(); + + private: + CThreadPool * mParent; + void( * mFunction )( void * ); + void * mArgument; + CEvent mSemaphore; + }; + friend class CMember; + + public: + CThreadPool(uint32 maxThreads, uint32 minThreads=1, uint32 timeout=15*60); + virtual ~CThreadPool(); + + virtual bool Execute(void( *function )( void * ), void * arg, uint32 poolGrowthSize = 0); + + private: + uint32 GetTimeOut(); + void OnStartup(CMember * member); + void OnIdle(CMember * member); + bool OnDestory(CMember * member); + + private: + CMutex mMutex; + std::set mIdleMember; + std::set mBusyMember; + std::list mNullMember; + uint32 mThreadCount; + + uint32 mMaxThreads; + uint32 mMinThreads; + uint32 mTimeOut; + }; + + +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // #if defined(_REENTRANT) + +#endif // BASE_LINUX_THREAD_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Types.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Types.h new file mode 100644 index 00000000..bc869bac --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/linux/Types.h @@ -0,0 +1,42 @@ +//////////////////////////////////////// +// Types.h +// +// Purpose: +// 1. Define integer types that are unambiguous with respect to size +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_TYPES_H +#define BASE_LINUX_TYPES_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif + +namespace Base +{ +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define UINT32_MAX 0xFFFFFFFF + +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; + +typedef int32_t int32; +typedef u_int32_t uint32; +typedef int64_t int64; +typedef u_int64_t uint64; +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // BASE_LINUX_TYPES_H + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/serialize.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/serialize.h new file mode 100644 index 00000000..650681b5 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/serialize.h @@ -0,0 +1,585 @@ +#ifndef SOE__SERIALIZE_H +#define SOE__SERIALIZE_H + + +#include +#include +#include +#include "Types.h" + +#if (defined(WIN32) || defined(linux)) && !defined(NETWORK_BIG_ENDIAN) + #define BYTE1 0 + #define BYTE2 1 + #define BYTE3 2 + #define BYTE4 3 + #define BYTE5 4 + #define BYTE6 5 + #define BYTE7 6 + #define BYTE8 7 +#elif defined(sparc) || defined(NETWORK_BIG_ENDIAN) + #define BYTE1 7 + #define BYTE2 6 + #define BYTE3 5 + #define BYTE4 4 + #define BYTE5 3 + #define BYTE6 2 + #define BYTE7 1 + #define BYTE8 0 +#endif + + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif + +namespace soe +{ + + using namespace Base;//for types + //////////////////////////////////////////////////////////////////////////////// + + + // 388 ns (50 bytes) + inline unsigned Write(unsigned char * stream, unsigned size, const unsigned char * data, unsigned dataLen) + { + if (size < dataLen) + return 0; + memcpy(stream, data, dataLen); + return dataLen; + } + + // 353 ns + inline unsigned Write(unsigned char * stream, unsigned size, bool data) + { + if (size < sizeof(uint8)) + return 0; + stream[BYTE1] = data; + return sizeof(uint8); + } + + // 362 ns + inline unsigned Write(unsigned char * stream, unsigned size, int8 data) + { + if (size < sizeof(int8)) + return 0; + stream[BYTE1] = data; + return sizeof(int8); + } + + // 362 ns + inline unsigned Write(unsigned char * stream, unsigned size, uint8 data) + { + if (size < sizeof(uint8)) + return 0; + stream[BYTE1] = data; + return sizeof(uint8); + } + + // 355 ns + inline unsigned Write(unsigned char * stream, unsigned size, int16 data) + { + if (size < sizeof(int16)) + return 0; + stream[BYTE1] = data&0xff; + stream[BYTE2] = (data>>8)&0xff; + return sizeof(int16); + } + + // 360 ns + inline unsigned Write(unsigned char * stream, unsigned size, uint16 data) + { + if (size < sizeof(uint16)) + return 0; + stream[BYTE1] = data&0xff; + stream[BYTE2] = (data>>8)&0xff; + return sizeof(uint16); + } + + // 360 ns + inline unsigned Write(unsigned char * stream, unsigned size, int32 data) + { + if (size < sizeof(int32)) + return 0; + stream[BYTE1] = data&0xff; + stream[BYTE2] = (data>>8)&0xff; + stream[BYTE3] = (data>>16)&0xff; + stream[BYTE4] = (data>>24)&0xff; + return sizeof(int32); + } + + // 360 ns + inline unsigned Write(unsigned char * stream, unsigned size, uint32 data) + { + if (size < sizeof(uint32)) + return 0; + stream[BYTE1] = data&0xff; + stream[BYTE2] = (data>>8)&0xff; + stream[BYTE3] = (data>>16)&0xff; + stream[BYTE4] = (data>>24)&0xff; + return sizeof(uint32); + } + + // 370 ns + inline unsigned Write(unsigned char * stream, unsigned size, int64 data) + { + if (size < sizeof(int64)) + return 0; +#if (defined(WIN32) || defined(linux)) + uint32 low = *(uint32 *)(&data); + uint32 high = *((uint32 *)&data+1); +#elif defined(sparc) + uint32 low = *((uint32 *)&data+1); + uint32 high = *(uint32 *)(&data); +#endif + stream[BYTE1] = (unsigned char)low&0xff; + stream[BYTE2] = (unsigned char)(low>>8)&0xff; + stream[BYTE3] = (unsigned char)(low>>16)&0xff; + stream[BYTE4] = (unsigned char)(low>>24)&0xff; + stream[BYTE5] = (unsigned char)high&0xff; + stream[BYTE6] = (unsigned char)(high>>8)&0xff; + stream[BYTE7] = (unsigned char)(high>>16)&0xff; + stream[BYTE8] = (unsigned char)(high>>24)&0xff; + return sizeof(int64); + } + + // 370 ns + inline unsigned Write(unsigned char * stream, unsigned size, uint64 data) + { + if (size < sizeof(uint64)) + return 0; +#if (defined(WIN32) || defined(linux)) + uint32 low = *(uint32 *)(&data); + uint32 high = *((uint32 *)&data+1); +#elif defined(sparc) + uint32 low = *((uint32 *)&data+1); + uint32 high = *(uint32 *)(&data); +#endif + stream[BYTE1] = (unsigned char)low&0xff; + stream[BYTE2] = (unsigned char)(low>>8)&0xff; + stream[BYTE3] = (unsigned char)(low>>16)&0xff; + stream[BYTE4] = (unsigned char)(low>>24)&0xff; + stream[BYTE5] = (unsigned char)high&0xff; + stream[BYTE6] = (unsigned char)(high>>8)&0xff; + stream[BYTE7] = (unsigned char)(high>>16)&0xff; + stream[BYTE8] = (unsigned char)(high>>24)&0xff; + return sizeof(uint64); + } + + // 360 ns + inline unsigned Write(unsigned char * stream, unsigned size, float data) + { + uint32 & dataRef = *(uint32 *)(&data); + if (size < sizeof(float)) + return 0; + stream[BYTE1] = dataRef&0xff; + stream[BYTE2] = (dataRef>>8)&0xff; + stream[BYTE3] = (dataRef>>16)&0xff; + stream[BYTE4] = (dataRef>>24)&0xff; + return sizeof(float); + } + + // 370 ns + inline unsigned Write(unsigned char * stream, unsigned size, double data) + { + if (size < sizeof(double)) + return 0; +#if (defined(WIN32) || defined(linux)) + uint32 low = *(uint32 *)(&data); + uint32 high = *((uint32 *)&data+1); +#elif defined(sparc) + uint32 low = *((uint32 *)&data+1); + uint32 high = *(uint32 *)(&data); +#endif + stream[BYTE1] = (unsigned char)low&0xff; + stream[BYTE2] = (unsigned char)(low>>8)&0xff; + stream[BYTE3] = (unsigned char)(low>>16)&0xff; + stream[BYTE4] = (unsigned char)(low>>24)&0xff; + stream[BYTE5] = (unsigned char)high&0xff; + stream[BYTE6] = (unsigned char)(high>>8)&0xff; + stream[BYTE7] = (unsigned char)(high>>16)&0xff; + stream[BYTE8] = (unsigned char)(high>>24)&0xff; + return sizeof(double); + } + + // 361 ns + inline unsigned WriteEncoded(unsigned char * stream, unsigned size, uint32 data) + { + unsigned encoded = ((data & 0xffffffc0) << 2) | (data & 0x3f); + if (data > 0x3fffffff) + { + return 0; + } + else if (data > 0x3fffff && size >= 4) + { + encoded |= 0xc0; + stream[BYTE1] = encoded & 0xff; + stream[BYTE2] = (encoded>>8) & 0xff; + stream[BYTE3] = (encoded>>16) & 0xff; + stream[BYTE4] = (encoded>>24) & 0xff; + return 4; + } + else if (data > 0x3fff) + { + encoded |= 0x80; + stream[BYTE1] = encoded & 0xff; + stream[BYTE2] = (encoded>>8) & 0xff; + stream[BYTE3] = (encoded>>16) & 0xff; + return 3; + } + else if (data > 0x3f) + { + encoded |= 0x40; + stream[BYTE1] = encoded & 0xff; + stream[BYTE2] = (encoded>>8) & 0xff; + return 2; + } + else if (size >= 1) + { + stream[BYTE1] = encoded & 0xff; + return 1; + } + return 0; + } + + // 630 ns + inline unsigned Write(unsigned char * stream, unsigned size, const std::string & data, bool isPascal=true) + { + if (isPascal) + { + unsigned fieldLen = 0; + unsigned bytes = 0; + fieldLen = Write(stream, size, static_cast(data.length())); + if (!fieldLen) + return 0; + bytes += fieldLen; + if (data.length()) + { + fieldLen = Write(stream+bytes, size-bytes, reinterpret_cast(data.data()), data.length()); + if (!fieldLen) + return 0; + bytes += fieldLen; + } + return bytes; + } + else + { + unsigned bytes = Write(stream, size, reinterpret_cast(data.c_str()), data.size()+1); + if (!bytes) + return 0; + return bytes; + } + } + + template + inline unsigned Write(unsigned char * stream, unsigned size, const std::vector & data) + { + unsigned bytes = 0; + unsigned elementBytes = 0; + bytes += Write(stream, size, static_cast(data.size())); + if (!bytes) + return 0; + for (typename std::vector::const_iterator iter = data.begin(); iter != data.end(); iter++) + { + elementBytes = Write(stream+bytes, size-bytes, *iter); + if (!elementBytes) + return 0; + bytes += elementBytes; + } + + return bytes; + } + + inline unsigned Read(const unsigned char * stream, unsigned size, unsigned char * data, unsigned dataLen) + { + if (size < dataLen) + return 0; + memcpy(data, stream, dataLen); + return dataLen; + } + + // 355 ns + inline unsigned Read(const unsigned char * stream, unsigned size, bool & data, unsigned = 1/*unused*/) + { + if (size < sizeof(uint8)) + return 0; + data = stream[BYTE1] != 0; + return sizeof(uint8); + } + + // 355 ns + inline unsigned Read(const unsigned char * stream, unsigned size, int8 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(int8)) + return 0; + data = stream[BYTE1]; + return sizeof(int8); + } + + // 355 ns + inline unsigned Read(const unsigned char * stream, unsigned size, uint8 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(uint8)) + return 0; + data = stream[BYTE1]; + return sizeof(uint8); + } + + // 355 ns + inline unsigned Read(const unsigned char * stream, unsigned size, int16 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(int16)) + return 0; + data = stream[BYTE1]; + data |= stream[BYTE2]<<8; + return sizeof(int16); + } + + // 355 ns + inline unsigned Read(const unsigned char * stream, unsigned size, uint16 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(uint16)) + return 0; + data = stream[BYTE1]; + data |= stream[BYTE2]<<8; + return sizeof(uint16); + } + + // 360 ns + inline unsigned Read(const unsigned char * stream, unsigned size, int32 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(int32)) + return 0; + data = stream[BYTE1]; + data |= stream[BYTE2]<<8; + data |= stream[BYTE3]<<16; + data |= stream[BYTE4]<<24; + return sizeof(int32); + } + + // 360 ns + inline unsigned Read(const unsigned char * stream, unsigned size, uint32 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(uint32)) + return 0; + data = stream[BYTE1]; + data |= stream[BYTE2]<<8; + data |= stream[BYTE3]<<16; + data |= stream[BYTE4]<<24; + return sizeof(uint32); + } + + // 380 ns + inline unsigned Read(const unsigned char * stream, unsigned size, int64 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(int64)) + return 0; +#if (defined(WIN32) || defined(linux)) + uint32 & low = *(uint32 *)(&data); + uint32 & high = *((uint32 *)&data+1); +#elif defined(sparc) + uint32 & low = *(uint32 *)(&data+1); + uint32 & high = *(uint32 *)(&data); +#endif + low = stream[BYTE1]; + low |= stream[BYTE2]<<8; + low |= stream[BYTE3]<<16; + low |= stream[BYTE4]<<24; + high = stream[BYTE5]; + high |= stream[BYTE6]<<8; + high |= stream[BYTE7]<<16; + high |= stream[BYTE8]<<24; + return sizeof(int64); + } + + // 380 ns + inline unsigned Read(const unsigned char * stream, unsigned size, uint64 & data, unsigned = 1/*unused*/) + { + if (size < sizeof(uint64)) + return 0; +#if (defined(WIN32) || defined(linux)) + uint32 & low = *(uint32 *)(&data); + uint32 & high = *((uint32 *)&data+1); +#elif defined(sparc) + uint32 & low = *(uint32 *)(&data+1); + uint32 & high = *(uint32 *)(&data); +#endif + low = stream[BYTE1]; + low |= stream[BYTE2]<<8; + low |= stream[BYTE3]<<16; + low |= stream[BYTE4]<<24; + high = stream[BYTE5]; + high |= stream[BYTE6]<<8; + high |= stream[BYTE7]<<16; + high |= stream[BYTE8]<<24; + return sizeof(uint64); + } + + // 370 ns + inline unsigned Read(const unsigned char * stream, unsigned size, float & data, unsigned = 1/*unused*/) + { + assert(sizeof(float) == 4); + uint32 & dataRef = *(uint32 *)(&data); + if (size < sizeof(float)) + return 0; + dataRef = stream[BYTE1]; + dataRef |= stream[BYTE2]<<8; + dataRef |= stream[BYTE3]<<16; + dataRef |= stream[BYTE4]<<24; + return sizeof(float); + } + + // 380 ns + inline unsigned Read(const unsigned char * stream, unsigned size, double & data, unsigned = 1/*unused*/) + { + assert(sizeof(double) == 8); + if (size < sizeof(double)) + return 0; +#if (defined(WIN32) || defined(linux)) + uint32 & low = *(uint32 *)(&data); + uint32 & high = *((uint32 *)&data+1); +#elif defined(sparc) + uint32 & low = *(uint32 *)(&data+1); + uint32 & high = *(uint32 *)(&data); +#endif + low = stream[BYTE1]; + low |= stream[BYTE2]<<8; + low |= stream[BYTE3]<<16; + low |= stream[BYTE4]<<24; + high = stream[BYTE5]; + high |= stream[BYTE6]<<8; + high |= stream[BYTE7]<<16; + high |= stream[BYTE8]<<24; + return sizeof(double); + } + + // 360 ns + inline unsigned ReadEncoded(const unsigned char * stream, unsigned size, uint32 & data) + { + if (size < 1) + return 0; + + unsigned encoded = stream[BYTE1]; + unsigned mask = encoded & 0xc0; + if (mask == 0) + { + data = encoded & 0x3f; + return 1; + } + else if (mask == 0x40 && size >=2) + { + data = (stream[BYTE2]<<6) | (encoded & 0x3f); + return 2; + } + else if (mask == 0x80 && size >=3) + { + data = (stream[BYTE3]<<14) | (stream[BYTE2]<<6) | (encoded & 0x3f); + return 3; + } + else if (mask == 0xc0 && size >=4) + { + data = (stream[BYTE4]<<22) | (stream[BYTE3]<<14) | (stream[BYTE2]<<6) | (encoded & 0x3f); + return 4; + } + return 0; + } + + inline unsigned Read(const unsigned char * stream, unsigned size, std::string & data, unsigned maxLen, bool isPascal=true) + { + if (isPascal) + { + unsigned bytes = 0; + unsigned length = 0; + bytes += Read(stream, size, length); + if (!bytes || size < bytes+length || length > maxLen) + return 0; + data.assign((const char *)stream+bytes, (const char *)stream+bytes+length); // assign would be dangerous if unicode, single-byte characters are ok + return bytes + length; + } + else + { + //find null terminator, if don't find it before maxLen, then err + const unsigned char *strEnd = NULL; + unsigned strLen = 0; + for (;strLen + inline unsigned Read(const unsigned char * stream, unsigned size, std::vector & data, unsigned maxVecLen, unsigned maxFieldLen = 1) + { + T element; + unsigned bytes = 0; + unsigned elementBytes = 0; + unsigned length = 0; + data.clear(); + bytes += Read(stream, size, length); + if (!bytes || length > maxVecLen) + return 0; + for (unsigned i=0; i + class AutoVariable : public AutoVariableBase + { + public: + AutoVariable() : AutoVariableBase(), mValue() {} + explicit AutoVariable(const ValueType & source) : AutoVariableBase(), mValue(source) {} + AutoVariable(const AutoVariable & copy) : AutoVariableBase(), mValue(copy.mValue) {} + virtual ~AutoVariable() {} + + const ValueType & Get() const { return mValue; } + void Set(const ValueType & rhs) { mValue = rhs; } + virtual unsigned Write(unsigned char * stream, unsigned size) const { return soe::Write(stream, size, mValue); } + virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned maxLen) { return soe::Read(stream, size, mValue, maxLen); } + + private: + ValueType mValue; + }; + + + //////////////////////////////////////////////////////////////////////////////// + + +} +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Archive.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Archive.h new file mode 100644 index 00000000..538620da --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Archive.h @@ -0,0 +1,36 @@ +#ifndef BASE_SOLARIS_ARCHIVE_H +#define BASE_SOLARIS_ARCHIVE_H + + +namespace Base +{ + + +#ifdef PACK_BIG_ENDIAN + + inline double byteSwap(double value) { return value; } + inline float byteSwap(float value) { return value; } + inline uint64 byteSwap(uint64 value) { return value; } + inline int64 byteSwap(int64 value) { return value; } + inline uint32 byteSwap(uint32 value) { return value; } + inline int32 byteSwap(int32 value) { return value; } + inline uint16 byteSwap(uint16 value) { return value; } + inline int16 byteSwap(int16 value) { return value; } + +#else + + inline double byteSwap(double value) { byteReverse64(&value); return value; } + inline float byteSwap(float value) { byteReverse32(&value); return value; } + inline uint64 byteSwap(uint64 value) { byteReverse64(&value); return value; } + inline int64 byteSwap(int64 value) { byteReverse64(&value); return value; } + inline uint32 byteSwap(uint32 value) { byteReverse32(&value); return value; } + inline int32 byteSwap(int32 value) { byteReverse32(&value); return value; } + inline uint16 byteSwap(uint16 value) { byteReverse16(&value); return value; } + inline int16 byteSwap(int16 value) { byteReverse16(&value); return value; } + +#endif + + +} + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/BlockAllocator.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/BlockAllocator.cpp new file mode 100644 index 00000000..beed79dd --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/BlockAllocator.cpp @@ -0,0 +1,102 @@ +#include "../BlockAllocator.h" + +namespace Base +{ + BlockAllocator::BlockAllocator() + { + for(unsigned i = 0; i < 31; i++) + { + m_blocks[i] = NULL; + } + } + + BlockAllocator::~BlockAllocator() + { + // free all allocated memory blocks + for(unsigned i = 0; i < 31; i++) + { + while(m_blocks[i] != NULL) + { + unsigned *tmp = m_blocks[i]; + m_blocks[i] = (unsigned *)*m_blocks[i]; + free(tmp); + } + } + } + +// Allocate a block that is the next power of two greater than the # of bytes passed. +// 33 bytes yields a 64 byte block of memory and so forth. + + void *BlockAllocator::getBlock(unsigned bytes) + { + unsigned accum = 16, bits = 16; + unsigned *handle = NULL; + + // Perform a binary search looking for the highest bit. + + while(bits != 0) + { + // If bytes is less than the bit we're testing for, subtract half + // from the bit value and repeat + if(bytes < (unsigned)(1 << accum)) + { + bits /= 2; + accum -= bits; + } + // If bytes is greater than the bit we're testing for, add half + // from the but value and repeat + else if(bytes > (unsigned)(1 << accum)) + { + bits /= 2; + accum += bits; + } + // Got lucky and hit the value dead on + else + { + break; + } + } + // At this point accum contains the most significant bit index, increment + accum++; + if(accum < 2) + { + accum = 2; + } + + // Note that when memory is actually allocated, 8 extra bytes will be allocated.at the front + // The first integer is the address of the next block of memory when the block is in the allocator + // The second integer is the bit length of the block + // Memory is allocated on 4 byte boundaries to sidestep byte alignment problems + + + // Check if the allocator already has a block of that size + if(m_blocks[accum] == 0) + { + // remove the pre allocated block from the linked list + handle = (unsigned *)calloc(((1 << accum) / 4) + 2, sizeof(unsigned)); + handle[1] = accum; + handle[0] = 0; + } + else + { + // Allocate a new block + handle = m_blocks[accum]; + m_blocks[accum] = (unsigned *)handle[0]; + handle[0] = 0; + } + // return a pointer that skips over the header used for the allocator's purposes + return(handle + 2); + } + + void BlockAllocator::returnBlock(unsigned *handle) + { + // C++ allows for safe deletion of a NULL pointer + if(handle) + { + // Update the allocator linked list, insert this entry at the head + *(handle - 2) = (unsigned)m_blocks[*(handle - 1)]; + // Add this entry to the proper linked list node + m_blocks[*(handle - 1)] = (handle - 2); + } + } +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Event.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Event.cpp new file mode 100644 index 00000000..1cdbf47e --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Event.cpp @@ -0,0 +1,93 @@ +//////////////////////////////////////// +// Event.cpp +// +// Purpose: +// 1. Implementation of the CEvent class. +// +// Revisions: +// 07/10/2001 Created +// + +#if defined(_REENTRANT) + + +#include "Event.h" + +namespace Base +{ + + CEvent::CEvent() + { + mWaiting = 0; + mSignaled = false; + mInitialized = false; + if (pthread_cond_init( &mCond, NULL ) != 0) + { + return; + } + + if (pthread_mutex_init( &mMutex, NULL ) != 0) + { + pthread_cond_destroy( &mCond ); + return; + } + mInitialized = true; + } + + CEvent::~CEvent() + { + if (mInitialized) + { + pthread_cond_destroy(&mCond); + pthread_mutex_destroy(&mMutex); + } + } + + int32 CEvent::Wait(uint32 timeout) + { + if (!mInitialized) + return CEvent::eWAIT_ERROR; + + int result; + pthread_mutex_lock(&mMutex); + + if (mSignaled) + { + mSignaled = false; + } + else if (!timeout) + { + mWaiting++; + result = pthread_cond_wait(&mCond, &mMutex); + mWaiting--; + } + else + { + struct timespec wake_time; + + clock_gettime( CLOCK_REALTIME, &wake_time ); + wake_time.tv_sec += timeout/1000; + wake_time.tv_nsec += (timeout%1000)*1000000; + + // normalize new time + wake_time.tv_sec += wake_time.tv_nsec / 1000000000; + wake_time.tv_nsec %= 1000000000; + + mWaiting++; + result = pthread_cond_timedwait( &mCond, &mMutex, &wake_time ); + mWaiting--; + } + pthread_mutex_unlock(&mMutex); + + if (result == 0) + return CEvent::eWAIT_SIGNAL; + else if (result == ETIMEDOUT) + return CEvent::eWAIT_TIMEOUT; + else + return CEvent::eWAIT_ERROR; + } + +} + + +#endif // #if defined(_REENTRANT) diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Event.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Event.h new file mode 100644 index 00000000..b2101e24 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Event.h @@ -0,0 +1,83 @@ +//////////////////////////////////////// +// Event.h +// +// Purpose: +// 1. Declair the CEvent class that encapsulates the functionality of a +// single-locking semaphore. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_SOLARIS_EVENT_H +#define BASE_SOLARIS_EVENT_H + +#if !defined(_REENTRANT) +# pragma message( "Excluding Base::CEvent - requires multi-threaded compile. (_REENTRANT)" ) +#else + + +#include "Platform.h" + +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CEvent + // + // Purpose: + // Encapsulates the functionality of a singal-locking semaphore. + // This class is valuable for thread syncronization when a thead's + // execution needs to be dependent upon another thread. + // + // Public Methods: + // Signal() : Signals a thread that has called Wait() so that it can + // continue execution. This function returns true if the waiting + // thread was signalled successfully, otherwise false is returned. + // Wait() : Halts the calling thread's execution indefinately until + // a Singal() call is made by an external thread. If the thread is + // successfully signalled, the function returns eWAIT_SIGNAL. If + // timeout period expires without a signal, eWAIT_TIMEOUT is returned. + // If the function fails, eWAIT_ERROR is returned. + // + class CEvent + { + public: + CEvent(); + virtual ~CEvent(); + + bool Signal(); + int32 Wait(uint32 timeout = 0); + public: + enum { eWAIT_ERROR, eWAIT_SIGNAL, eWAIT_TIMEOUT }; + private: + pthread_mutex_t mMutex; + pthread_cond_t mCond; + bool mInitialized; + bool mSignaled; + int32 mWaiting; + }; + + inline bool CEvent::Signal() + { + if (!mInitialized) + return false; + pthread_mutex_lock(&mMutex); + if(mWaiting > 0) + { + pthread_cond_signal(&mCond); + } + else + { + mWaiting = true; + } + pthread_mutex_unlock(&mMutex); + return true; + } + +} + +#endif // #if defined(_MT) + +#endif // BASE_SOLARIS_EVENT_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Logger.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Logger.cpp new file mode 100644 index 00000000..3f7b1fd1 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Logger.cpp @@ -0,0 +1,387 @@ +#include "../Logger.h" +#include "Mutex.h" +#include + +using namespace std; + +namespace Base +{ +const char file_sep = '/'; + +Logger::Logger(const char *prefix, int level, unsigned size, bool rollDate) +: m_defaultLevel(level), m_defaultSize(size), m_dirPrefix(prefix), m_rollDate(rollDate) +{ + char buf[1024]; + FILE *logDir = NULL; + + logDir = fopen(m_dirPrefix.c_str(), "r+"); + if(errno == ENOENT) + { + cmkdir(m_dirPrefix.c_str(), 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + + tm now; + time_t t = time(NULL); +#ifdef REENTRANT + localtime_r(&t, &now); +#else + now = *(localtime(&t)); +#endif + + memcpy(&m_lastDateTime, &now, sizeof(tm)); + if(m_rollDate) + { + sprintf(buf, "%s%c%2.2d-%2.2d-%2.2d", m_dirPrefix.c_str(), file_sep, (now.tm_mon + 1), now.tm_mday, (now.tm_year % 100)); + } + else + { + sprintf(buf, "%s", m_dirPrefix.c_str()); + } + logDir = fopen(buf, "r+"); + if(errno == ENOENT) + { + cmkdir(buf, 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + m_logPrefix = buf; +} + +Logger::~Logger() +{ + map::iterator iter; + for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++) + { + log((*iter).first, LOG_FILEONLY, "---=== Log Stopped ===---"); + fflush((*iter).second->file); + fclose((*iter).second->file); + delete((*iter).second); + + } + m_logTable.clear(); +} + +void Logger::flush(unsigned logenum) +{ + map::iterator iter = m_logTable.find(logenum); + + if(iter != m_logTable.end()) + { + LogInfo *info = (*iter).second; + fflush(info->file); + info->used = 0; + } +} + +void Logger::flushAll() +{ + map::iterator iter; + + for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++) + { + LogInfo *info = (*iter).second; + fflush(info->file); + info->used = 0; + } +} + +void Logger::addLog(const char *id, unsigned logenum, int level, unsigned size) +{ + LogInfo *newLog = new LogInfo; + newLog->filename = m_logPrefix + file_sep + id + ".log"; + newLog->name = id; + newLog->used = 0; + newLog->max = size; + newLog->last = 0; + newLog->level = level; + + m_logTable.insert(pair(logenum, newLog)); + + if(strcmp("stdout", id) == 0) + { + newLog->file = stdout; + } + else if(strcmp("stderr", id) == 0) + { + newLog->file = stderr; + } + else + { + newLog->file = fopen(newLog->filename.c_str(), "a+"); + } + log(logenum, LOG_FILEONLY, "---=== Log Started ===---"); +} + +void Logger::addLog(const char *id, unsigned logenum) +{ + LogInfo *newLog = new LogInfo; + newLog->filename = m_logPrefix + file_sep + id + ".log"; + newLog->name = id; + newLog->used = 0; + newLog->max = m_defaultSize; + newLog->last = 0; + newLog->level = m_defaultLevel; + + m_logTable.insert(pair(logenum, newLog)); + + if(strcmp("stdout", id) == 0) + { + newLog->file = stdout; + } + else if(strcmp("stderr", id) == 0) + { + newLog->file = stderr; + } + else + { + newLog->file = fopen(newLog->filename.c_str(), "a+"); + } + log(logenum, LOG_FILEONLY, "---===Log Started ===---"); +} + +void Logger::updateLog(unsigned logenum, int level, unsigned size) +{ + map::iterator iter = m_logTable.find(logenum); + + if(iter != m_logTable.end()) + { + (*iter).second->level = level; + (*iter).second->max = size; + } +} + +void Logger::removeLog(unsigned logenum) +{ + map::iterator iter = m_logTable.find(logenum); + + if(iter != m_logTable.end()) + { + log((*iter).first, LOG_ALWAYS, "---=== Log Stopped ===---"); + fflush((*iter).second->file); + fclose((*iter).second->file); + delete((*iter).second); + } +} + +void Logger::logSimple(unsigned logenum, int level, const char *message) +{ + map::iterator iter = m_logTable.find(logenum); + if(iter == m_logTable.end()) + { + return; + } + time_t t = time(NULL); + LogInfo *info = (*iter).second; + if(level >= info->level) + { + return; + } + if(info->last != t) + { + memcpy(&info->ts, localtime(&t), sizeof(tm)); + info->last = t; + } + + if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday) + { +#if defined(_REENTRANT) + rLock.Lock(); +#endif + if(info->ts.tm_mday != m_lastDateTime.tm_mday) + { + memcpy(&m_lastDateTime, &info->ts, sizeof(tm)); + rollDate(t); + } +#if defined(_REENTRANT) + rLock.Unlock(); +#endif + } + if(iter != m_logTable.end()) + { + if(info->max > 0) + { + int tmp = fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message); + info->used += tmp; + if(info->used > info->max) + { + fflush(info->file); + info->used = 0; + } + } + else + { + fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message); + fflush(info->file); + } + } +} +void Logger::log(unsigned logenum, int level, const char *message, ...) +{ + char buf[2048]; + va_list varg; + va_start(varg, message); + vsnprintf(buf, 2047, message, varg); + buf[2047] = 0; + va_end(varg); + + map::iterator iter = m_logTable.find(logenum); + if(iter == m_logTable.end()) + { + return; + } + time_t t = time(NULL); + LogInfo *info = (*iter).second; + if(level >= info->level) + { + return; + } + if(info->last != t) + { +#ifdef REENTRANT + localtime_r(&t, &info->ts); +#else + info->ts = *(localtime(&t)); +#endif + + info->last = t; + } + if(info->ts.tm_mday != m_lastDateTime.tm_mday) + { +#if defined(_REENTRANT) + rLock.Lock(); +#endif + if(info->ts.tm_mday != m_lastDateTime.tm_mday) + { + memcpy(&m_lastDateTime, &info->ts, sizeof(tm)); + rollDate(t); + } +#if defined(_REENTRANT) + rLock.Unlock(); +#endif + } + + if(iter != m_logTable.end()) + { + if(info->max > 0) + { + int tmp = fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf); + info->used += tmp; + if(info->used > info->max) + { + fflush(info->file); + info->used = 0; + } + } + else + { + fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf); + fflush(info->file); + } + } +} + +void Logger::rollDate(time_t t) +{ + char buf[80]; + FILE *logDir = NULL; + + logDir = fopen(m_dirPrefix.c_str(), "r+"); + if(errno == ENOENT) + { + cmkdir(m_dirPrefix.c_str(), 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + + tm now; +#ifdef REENTRANT + localtime_r(&t, &now); +#else + now = *(localtime(&t)); +#endif + + sprintf(buf, "%s%c%2.2d-%2.2d-%2.2d", m_dirPrefix.c_str(), file_sep, (now.tm_mon + 1), now.tm_mday, (now.tm_year % 100)); + logDir = fopen(buf, "r+"); + + if(errno == ENOENT) + { + cmkdir(buf, 0755); + } + else if(logDir != NULL) + { + fclose(logDir); + } + m_logPrefix = buf; + + map::iterator iter; + for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++) + { + (*iter).second->filename = m_logPrefix + file_sep + (*iter).second->name.c_str() + ".log"; + fflush((*iter).second->file); + fclose((*iter).second->file); + (*iter).second->file = fopen((*iter).second->filename.c_str(), "a+"); + memcpy(&((*iter).second->ts), &now, sizeof(tm)); + } +} + +// mkdir function that creates intermediate directories +void Logger::cmkdir(const char *dir, int mode) +{ + char dirbuf[128]; + strncpy(dirbuf, dir, 127); + dirbuf[127] = 0; + char *j = dirbuf, *i = dirbuf; + int handle; + + while(*i) + { + if(*i == file_sep) + { + (*i) = 0; +// handle = open(j, O_EXCL); // Ben's original code +// if((handle > 0) || (errno != EISDIR && errno != ENOENT)) +// { +// perror("Logger::cmkdir():"); +// abort(); +// } + +// This doesnt work under Linux, it returns a valid handle +// Instead: see if file exists. If it doesnt, create directory ok +// If it exists, do stat to see if it is a dir. +// If it is a dir, then ok, create the directory. +// If it is a file, error +// ging 9-16-2002 + + handle = open(j, O_RDONLY); + if (handle > 0) + { + struct stat stat_buffer; + int ret = fstat(handle,&stat_buffer); + if ((ret == -1) || ((stat_buffer.st_mode | S_IFDIR) == 0)) + { + perror("Logger::cmkdir():"); + abort(); + } + } + + mkdir(j, mode); + close(handle); + (*i) = file_sep; + } + else if(*(i + 1) == 0) + { + mkdir(j, mode); + } + i++; + } +} + +}; diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Mutex.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Mutex.cpp new file mode 100644 index 00000000..a3718b38 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Mutex.cpp @@ -0,0 +1,32 @@ +//////////////////////////////////////// +// Mutex.cpp +// +// Purpose: +// 1. Implementation of the CMutex class. +// +// Revisions: +// 07/10/2001 Created +// + +#if defined(_REENTRANT) + + +#include "Mutex.h" + +namespace Base +{ + +CMutex::CMutex() + { + mInitialized = (pthread_mutex_init(&mMutex, 0) == 0); + } + +CMutex::~CMutex() + { + if (mInitialized) + pthread_mutex_destroy(&mMutex); + } + +} + +#endif // #if defined(_REENTRANT) diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Mutex.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Mutex.h new file mode 100644 index 00000000..eba47fd8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Mutex.h @@ -0,0 +1,71 @@ +//////////////////////////////////////// +// Mutex.h +// +// Purpose: +// 1. Declair the CMutex class that encapsulates the functionality of a +// mutually-exclusive device. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_SOLARIS_MUTEX_H +#define BASE_SOLARIS_MUTEX_H + +#if !defined(_REENTRANT) +# pragma message( "Excluding Base::CMutex - requires multi-threaded compile. (_REENTRANT)" ) +#else + + +#include "Platform.h" + +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CMutex + // + // Purpose: + // Encapsulates the functionality of a mutually-exclusive device. + // This class is valuable for protecting against race conditions + // within threaded applications. The CMutex class can be used to + // only allow a single thread to run within a specified code + // segment at a time. + // + // Public Methods: + // Lock() : Locks the mutex. If the mutex is already locked, the + // operating system will block the calling thread until another + // thread has unlocked the mutex. + // Unlock() : Unlocks the mutex. + // + class CMutex + { + public: + CMutex(); + ~CMutex(); + + void Lock(); + void Unlock(); + private: + pthread_mutex_t mMutex; + bool mInitialized; + }; + + inline void CMutex::Lock(void) + { + if (mInitialized) + pthread_mutex_lock(&mMutex); + } + + inline void CMutex::Unlock(void) + { + if (mInitialized) + pthread_mutex_unlock(&mMutex); + } + +} + +#endif // #if defined(_MT) + +#endif // BASE_SOLARIS_MUTEX_H \ No newline at end of file diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Platform.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Platform.cpp new file mode 100644 index 00000000..2950d254 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Platform.cpp @@ -0,0 +1,46 @@ +//////////////////////////////////////// +// Platform.cpp +// +// Purpose: +// 1. Implementation of the global functionality declaired in Platform.h. +// +// Revisions: +// 07/10/2001 Created +// + +#include +#include "Platform.h" + +namespace Base +{ + + // Implementation of microsoft strlwr extension + // This non-ANSI function is not supported under UNIX + void strlwr(char * s) + { + while (*s) + { + *s = tolower(*s); + s++; + } + } + + // Implementation of microsoft strupr extension + // This non-ANSI function is not supported under UNIX + void strupr(char * s) + { + while (*s) + { + *s = toupper(*s); + s++; + } + } + + + CTimer::CTimer() : + mTimer(0) + { + } + + +} \ No newline at end of file diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Platform.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Platform.h new file mode 100644 index 00000000..37423fb2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Platform.h @@ -0,0 +1,107 @@ +//////////////////////////////////////// +// Platform.h +// +// Purpose: +// 1. Include relevent system headers that are platform specific. +// 2. Declair global platform specific functionality. +// 3. Include primative type definitions +// +// Global Functions: +// getTimer() : Return the current high resolution clock count. +// getTimerFrequency() : Return the frequency of the high resolution clock. +// sleep() : Voluntarily relinquish timeslice of the calling thread for a +// specified number of milliseconds. +// strlwr() : Alters the contents of a string, making it all lower-case. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_SOLARIS_PLATFORM_H +#define BASE_SOLARIS_PLATFORM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Types.h" + + +namespace Base +{ + uint64 getTimer(void); + uint64 getTimerFrequency(void); + void Sleep(uint32 ms); + + inline uint64 getTimer(void) + { + uint64 t; + struct timeval tv; + + gettimeofday(&tv, 0); + t = tv.tv_sec; + t = t * 1000000; + t += tv.tv_usec; + return t; + } + + inline uint64 getTimerFrequency(void) + { + uint64 f = 1000000; + return f; + } + + inline void sleep(uint32 ms) + { + //usleep(static_cast(ms * 1000)); + struct timeval sleep_tv; + sleep_tv.tv_sec = ms / 1000; + sleep_tv.tv_usec = (ms % 1000) * 1000; + select(1, NULL, NULL, NULL, &sleep_tv); + } + + void strlwr(char * s); + void strupr(char * s); + + + class CTimer + { + public: + CTimer(); + + void Set(uint32 seconds); + void Signal(); + bool Expired(); + + private: + uint32 mTimer; + }; + + inline void CTimer::Set(uint32 interval) + { + mTimer = (uint32)time(0) + interval; + } + + inline void CTimer::Signal() + { + mTimer = 0; + } + + inline bool CTimer::Expired() + { + return (mTimer <= (uint32)time(0)); + } + + +} + +#endif BASE_SOLARIS_PLATFORM_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Thread.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Thread.cpp new file mode 100644 index 00000000..ed9392fb --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Thread.cpp @@ -0,0 +1,282 @@ +//////////////////////////////////////// +// Thread.cpp +// +// Purpose: +// 1. Implementation of the CThread class. +// +// Revisions: +// 07/10/2001 Created +// + +#if defined(_REENTRANT) + + +#include +#include +#include "Thread.h" + +using namespace std; + + +namespace Base +{ + + void *threadProc(void *threadPtr) + { + CThread &thread = *((CThread*)threadPtr); + thread.mThreadActive = true; + thread.ThreadProc(); + thread.mThreadActive = false; + + return 0; + } + + CThread::CThread() + { + mThreadID = 0; + mThreadActive = false; + mThreadContinue = false; + } + + CThread::~CThread() + { + StopThread(); + } + + void CThread::StartThread() + { + mThreadContinue = true; + pthread_create(&mThreadID,0,threadProc,this); + while (!IsThreadActive()) + Base::sleep(1); + } + + int32 CThread::StopThread(int timeout) + { + timeout += time(0); + + mThreadContinue = false; + while (mThreadActive && time(0)OnIdle(this); + mSemaphore.Wait(mParent->GetTimeOut()*1000); + mParent->OnBusy(this); + + if (mFunction) + { + mFunction(mArgument); + mArgument = NULL; + mFunction = NULL; + } + else + mThreadContinue = false; + } + + mParent->OnDestory(this); + } + + +//////////////////////////////////////////////////////////////////////////////// + + + CThreadPool::CThreadPool(uint32 maxThreads, uint32 minThreads, uint32 timeout) : + mMutex(), + mIdleMember(), + mBusyMember(), + mNullMember(), + mThreadCount(0), + mMaxThreads(maxThreads), + mMinThreads(minThreads), + mTimeOut(timeout) + { + if (mMaxThreads == 0) mMaxThreads = 1; + if (mMinThreads == 0) mMinThreads = 1; + if (mMinThreads > mMaxThreads) mMinThreads = mMaxThreads; + + if (mTimeOut < 60) + mTimeOut = 60; + + for (uint32 i=0; i::iterator setIterator; + + mMutex.Lock(); + setIterator = mBusyMember.begin(); + while (setIterator != mBusyMember.end()) + (*setIterator++)->Destroy(); + mMutex.Unlock(); + + while (mThreadCount) + { + mMutex.Lock(); + setIterator = mIdleMember.begin(); + while (setIterator != mIdleMember.end()) + (*setIterator++)->Destroy(); + mMutex.Unlock(); + + sleep(1); + } + + mMutex.Lock(); + while (!mNullMember.empty()) + { + delete mNullMember.front(); + mNullMember.pop_front(); + } + mMutex.Unlock(); + } + + bool CThreadPool::Execute(void( *function )( void * ), void * arg, uint32 poolGrowthSize ) + { + mMutex.Lock(); + + if (mIdleMember.empty()) + { + if (mThreadCount < mMaxThreads) + { + if (!poolGrowthSize) + poolGrowthSize = mMinThreads; + + if ((mThreadCount + poolGrowthSize) > mMaxThreads) + poolGrowthSize = mMaxThreads - mThreadCount; + + for (uint32 i(0); i < poolGrowthSize; i++) + new CMember(this); + mMutex.Unlock(); + time_t idleTimeout = time(0) + 5; + while(mIdleMember.empty()) + { + if (time(0) >= idleTimeout) + { + return false; + } + Base::sleep(10); + } + mMutex.Lock(); + + } + else + { + mMutex.Unlock(); + return false; + } + } + + while (!mNullMember.empty()) + { + delete mNullMember.front(); + mNullMember.pop_front(); + } + + CMember * member = *(mIdleMember.begin()); + mIdleMember.erase(member); + member->Execute(function,arg); + + mMutex.Unlock(); + return true; + } + + uint32 CThreadPool::GetTimeOut() + { + return mTimeOut; + } + + void CThreadPool::OnIdle(CMember * member) + { + mMutex.Lock(); + + set::iterator setIterator = mBusyMember.find(member); + if (setIterator != mBusyMember.end()) + mBusyMember.erase(member); + else + mThreadCount++; + mIdleMember.insert(member); + + mMutex.Unlock(); + } + + void CThreadPool::OnBusy(CMember * member) + { + mMutex.Lock(); + + mBusyMember.insert(member); + + mMutex.Unlock(); + } + + void CThreadPool::OnDestory(CMember * member) + { + set::iterator setIterator; + + mMutex.Lock(); + + setIterator = mBusyMember.find(member); + if (setIterator != mBusyMember.end()) + { + mNullMember.push_back(member); + mBusyMember.erase(member); + mThreadCount--; + } + + mMutex.Unlock(); + } + + +//////////////////////////////////////////////////////////////////////////////// + + +} + + +#endif // #if defined(_REENTRANT) diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Thread.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Thread.h new file mode 100644 index 00000000..95fb15fc --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Thread.h @@ -0,0 +1,139 @@ +//////////////////////////////////////// +// Thread.h +// +// Purpose: +// 1. Declair the CThread class that encapsulates threading functionality. +// This abstract base class in intended to be used to encapsulate +// individual tasks that require threading in derived classes. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_SOLARIS_THREAD_H +#define BASE_SOLARIS_THREAD_H + +#if !defined(_REENTRANT) +# pragma message( "Excluding Base::CThread - requires multi-threaded compile. (_REENTRANT)" ) +#else + + +#pragma warning( disable : 4786) + +#include +#include +#include "Platform.h" +#include "Mutex.h" +#include "Event.h" + +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CThread + // + // Purpose: + // Encapsulates threading functionality. Creating classes derived + // from CThread provides an easy way to encapsulate tasks that require + // their own thread. + // + // Public Methods: + // StartThread() : Creates the low-level thread handle and begins executing + // the CThread::ThreadProc() function within the new thread. + // StopThread() : Signals the ThreadProc() function to stop executing using + // the mThreadContinue member variable, and waits for the ThreadProc() + // function to exit. By default, the function will block for a maximum + // of 5 seconds before exiting without the thread halting. + // IsThreadActive() : Returns true if the physical thread is still executing + // within the ThreadProc() function, otherwise it returns false. + // ThreadProc() : Pure-virtual function that will be executed when the StartThread() + // function is called. Derived classes must implement this function. The + // mThreadContinue member variable should be used internal the the ThreadProc() + // function to indicate whether it should continue executing or exit. + // Protected Attributes: + // mThreadContinue : Boolean value indicating to the ThreadProc() function + // whether to continue executing or to exit. If mThreadContinue is true, + // ThreadProc() should continue, otherwise ThreadProc() should exit. It + // left up to the derived class to implement a ThreadProc() function that + // uses the mThreadContinue member. + // + // + class CThread + { + friend void * threadProc(void *); + + public: + enum { eSTOP_SUCCESS, eSTOP_TIMEOUT }; + public: + CThread(); + virtual ~CThread(); + + void StartThread(); + int32 StopThread(int timeout=5); + bool IsThreadActive() { return mThreadActive; } + + protected: + virtual void ThreadProc() = 0; + + protected: + bool mThreadContinue; + private: + bool mThreadActive; + pthread_t mThreadID; + }; + + + class CThreadPool + { + private: + class CMember : public CThread + { + public: + CMember(CThreadPool * parent); + virtual ~CMember(); + + bool Execute(void( *function )( void * ), void * arg); + void Destroy(); + + protected: + virtual void ThreadProc(); + + private: + CThreadPool * mParent; + void( * mFunction )( void * ); + void * mArgument; + CEvent mSemaphore; + }; + friend class CMember; + + public: + CThreadPool(uint32 maxThreads, uint32 minThreads=1, uint32 timeout=15*60); + virtual ~CThreadPool(); + + virtual bool Execute(void( *function )( void * ), void * arg, uint32 poolGrowthSize = 0); + + private: + uint32 GetTimeOut(); + void OnIdle(CMember * member); + void OnBusy(CMember * member); + void OnDestory(CMember * member); + + private: + CMutex mMutex; + std::set mIdleMember; + std::set mBusyMember; + std::list mNullMember; + uint32 mThreadCount; + + uint32 mMaxThreads; + uint32 mMinThreads; + uint32 mTimeOut; + }; + + +} + +#endif // #if defined(_MT) + +#endif // BASE_SOLARIS_THREAD_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Types.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Types.h new file mode 100644 index 00000000..8e396f1e --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/solaris/Types.h @@ -0,0 +1,28 @@ +//////////////////////////////////////// +// Types.h +// +// Purpose: +// 1. Define integer types that are unambiguous with respect to size +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_SOLARIS_TYPES_H +#define BASE_SOLARIS_TYPES_H + +namespace Base +{ +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; + +typedef signed int int32; +typedef unsigned int uint32; +typedef signed long long int64; +typedef unsigned long long uint64; +} + +#endif // BASE_SOLARIS_TYPES_H + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Archive.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Archive.h new file mode 100644 index 00000000..30ddce43 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Archive.h @@ -0,0 +1,42 @@ +#ifndef BASE_WIN32_ARCHIVE_H +#define BASE_WIN32_ARCHIVE_H + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + +#ifdef PACK_BIG_ENDIAN + + inline double byteSwap(double value) { byteReverse64(&value); return value; } + inline float byteSwap(float value) { byteReverse32(&value); return value; } + inline uint64 byteSwap(uint64 value) { byteReverse64(&value); return value; } + inline int64 byteSwap(int64 value) { byteReverse64(&value); return value; } + inline uint32 byteSwap(uint32 value) { byteReverse32(&value); return value; } + inline int32 byteSwap(int32 value) { byteReverse32(&value); return value; } + inline uint16 byteSwap(uint16 value) { byteReverse16(&value); return value; } + inline int16 byteSwap(int16 value) { byteReverse16(&value); return value; } + +#else + + inline double byteSwap(double value) { return value; } + inline float byteSwap(float value) { return value; } + inline uint64 byteSwap(uint64 value) { return value; } + inline int64 byteSwap(int64 value) { return value; } + inline uint32 byteSwap(uint32 value) { return value; } + inline int32 byteSwap(int32 value) { return value; } + inline uint16 byteSwap(uint16 value) { return value; } + inline int16 byteSwap(int16 value) { return value; } + +#endif + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/BlockAllocator.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/BlockAllocator.cpp new file mode 100644 index 00000000..9fa8b645 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/BlockAllocator.cpp @@ -0,0 +1,112 @@ +#include "../BlockAllocator.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + BlockAllocator::BlockAllocator() + { + for(unsigned i = 0; i < 31; i++) + { + m_blocks[i] = NULL; + } + } + + BlockAllocator::~BlockAllocator() + { + // free all allocated memory blocks + for(unsigned i = 0; i < 31; i++) + { + while(m_blocks[i] != NULL) + { + unsigned *tmp = m_blocks[i]; + m_blocks[i] = (unsigned *)*m_blocks[i]; + free(tmp); + } + } + } + +// Allocate a block that is the next power of two greater than the # of bytes passed. +// 33 bytes yields a 64 byte block of memory and so forth. + + void *BlockAllocator::getBlock(unsigned bytes) + { + unsigned accum = 16, bits = 16; + unsigned *handle = NULL; + + // Perform a binary search looking for the highest bit. + + while(bits != 0) + { + // If bytes is less than the bit we're testing for, subtract half + // from the bit value and repeat + if(bytes < (unsigned)(1 << accum)) + { + bits /= 2; + accum -= bits; + } + // If bytes is greater than the bit we're testing for, add half + // from the but value and repeat + else if(bytes > (unsigned)(1 << accum)) + { + bits /= 2; + accum += bits; + } + // Got lucky and hit the value dead on + else + { + break; + } + } + // At this point accum contains the most significant bit index, increment + accum++; + if(accum < 2) + { + accum = 2; + } + + // Note that when memory is actually allocated, 8 extra bytes will be allocated.at the front + // The first integer is the address of the next block of memory when the block is in the allocator + // The second integer is the bit length of the block + // Memory is allocated on 4 byte boundaries to sidestep byte alignment problems + + + // Check if the allocator already has a block of that size + if(m_blocks[accum] == 0) + { + // remove the pre allocated block from the linked list + handle = (unsigned *)calloc(((1 << accum) / 4) + 2, sizeof(unsigned)); + handle[1] = accum; + handle[0] = 0; + } + else + { + // Allocate a new block + handle = m_blocks[accum]; + m_blocks[accum] = (unsigned *)handle[0]; + handle[0] = 0; + } + // return a pointer that skips over the header used for the allocator's purposes + return(handle + 2); + } + + void BlockAllocator::returnBlock(unsigned *handle) + { + // C++ allows for safe deletion of a NULL pointer + if(handle) + { + // Update the allocator linked list, insert this entry at the head + *(handle - 2) = (unsigned)m_blocks[*(handle - 1)]; + // Add this entry to the proper linked list node + m_blocks[*(handle - 1)] = (handle - 2); + } + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Event.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Event.cpp new file mode 100644 index 00000000..12ee8fe7 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Event.cpp @@ -0,0 +1,44 @@ +//////////////////////////////////////// +// Event.cpp +// +// Purpose: +// 1. Implementation of the CEvent class. +// +// Revisions: +// 07/10/2001 Created +// + + +#if !defined(_MT) +# pragma message( "Excluding Base::CEvent - requires multi-threaded compile. (_MT)" ) +#else + +#include "Event.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + CEvent::CEvent() + { + mEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + } + + CEvent::~CEvent() + { + if (mEvent) + CloseHandle(mEvent); + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif // #if defined(_MT) + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Event.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Event.h new file mode 100644 index 00000000..5d2bc712 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Event.h @@ -0,0 +1,92 @@ +//////////////////////////////////////// +// Event.h +// +// Purpose: +// 1. Declair the CEvent class that encapsulates the functionality of a +// single-locking semaphore. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_WIN32_EVENT_H +#define BASE_WIN32_EVENT_H + +#if defined(_MT) + + + +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CEvent + // + // Purpose: + // Encapsulates the functionality of a singal-locking semaphore. + // This class is valuable for thread syncronization when a thead's + // execution needs to be dependent upon another thread. + // + // Public Methods: + // Signal() : Signals a thread that has called Wait() so that it can + // continue execution. This function returns true if the waiting + // thread was signalled successfully, otherwise false is returned. + // Wait() : Halts the calling thread's execution indefinately until + // a Singal() call is made by an external thread. If the thread is + // successfully signalled, the function returns eWAIT_SIGNAL. If + // timeout period expires without a signal, eWAIT_TIMEOUT is returned. + // If the function fails, eWAIT_ERROR is returned. + // + class CEvent + { + public: + CEvent(); + virtual ~CEvent(); + + bool Signal(); + int32 Wait(uint32 timeout = 0); + + public: + enum { eWAIT_ERROR, eWAIT_SIGNAL, eWAIT_TIMEOUT }; + private: + HANDLE mEvent; + }; + + inline bool CEvent::Signal() + { + if (mEvent) + return SetEvent(mEvent)!=0; + + return false; + } + + inline int32 CEvent::Wait(uint32 timeout) + { + if (!mEvent) + return CEvent::eWAIT_ERROR; + + DWORD result = WaitForSingleObjectEx(mEvent, timeout ? timeout : INFINITE, FALSE); + if (result == WAIT_OBJECT_0) + return CEvent::eWAIT_SIGNAL; + else if (result == WAIT_TIMEOUT) + return CEvent::eWAIT_TIMEOUT; + else + return CEvent::eWAIT_ERROR; + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // #if defined(_MT) + + +#endif // BASE_WIN32_EVENT_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/File.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/File.cpp new file mode 100644 index 00000000..c888e545 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/File.cpp @@ -0,0 +1,22 @@ +// File.cpp: implementation of the CFile class. +// +////////////////////////////////////////////////////////////////////// + +#include "File.h" + +namespace Base +{ + ////////////////////////////////////////////////////////////////////// + // Construction/Destruction + ////////////////////////////////////////////////////////////////////// + + CFile::CFile(const char *) + { + + } + + CFile::~CFile() + { + + } +} diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/File.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/File.h new file mode 100644 index 00000000..fb15ccf1 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/File.h @@ -0,0 +1,26 @@ +// File.h: interface for the CFile class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef BASE_FILE_H +#define BASE_FILE_H + +#include + +namespace Base +{ + + class CFile + { + public: + CFile(const char *); + virtual ~CFile(); + + bool IsOpen(); + + private: + FILE* mFileHandle; + }; +} + +#endif // BASE_FILE_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Mutex.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Mutex.cpp new file mode 100644 index 00000000..482481e8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Mutex.cpp @@ -0,0 +1,40 @@ +//////////////////////////////////////// +// Mutex.cpp +// +// Purpose: +// 1. Implementation of the CMutex class. +// +// Revisions: +// 07/10/2001 Created +// +#if !defined(_MT) +# pragma message( "Excluding Base::CMutex - requires multi-threaded compile. (_MT)" ) +#else + +#include "Mutex.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +CMutex::CMutex() + { + InitializeCriticalSection(&mCriticalSection); + } + +CMutex::~CMutex() + { + DeleteCriticalSection(&mCriticalSection); + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif // #if defined(_MT) + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Mutex.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Mutex.h new file mode 100644 index 00000000..66e1c08b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Mutex.h @@ -0,0 +1,73 @@ +//////////////////////////////////////// +// Mutex.h +// +// Purpose: +// 1. Declair the CMutex class that encapsulates the functionality of a +// mutually-exclusive device. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_WIN32_MUTEX_H +#define BASE_WIN32_MUTEX_H + +#if defined (_MT) + +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CMutex + // + // Purpose: + // Encapsulates the functionality of a mutually-exclusive device. + // This class is valuable for protecting against race conditions + // within threaded applications. The CMutex class can be used to + // only allow a single thread to run within a specified code + // segment at a time. + // + // Public Methods: + // Lock() : Locks the mutex. If the mutex is already locked, the + // operating system will block the calling thread until another + // thread has unlocked the mutex. + // Unlock() : Unlocks the mutex. + // + class CMutex + { + public: + CMutex(); + ~CMutex(); + + void Lock(); + void Unlock(); + private: + CRITICAL_SECTION mCriticalSection; + }; + + inline void CMutex::Lock() + { + EnterCriticalSection(&mCriticalSection); + } + + inline void CMutex::Unlock() + { + LeaveCriticalSection(&mCriticalSection); + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // #if defined(_MT) + +#endif // BASE_WIN32_MUTEX_H \ No newline at end of file diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Platform.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Platform.cpp new file mode 100644 index 00000000..3b52563e --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Platform.cpp @@ -0,0 +1,31 @@ +//////////////////////////////////////// +// Platform.cpp +// +// Purpose: +// 1. Implementation of the global functionality declaired in Platform.h. +// +// Revisions: +// 07/10/2001 Created +// + +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + + CTimer::CTimer() : + mTimer(0) + { + } + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Platform.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Platform.h new file mode 100644 index 00000000..aaee37b7 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Platform.h @@ -0,0 +1,98 @@ +//////////////////////////////////////// +// Platform.h +// +// Purpose: +// 1. Include relevent system headers that are platform specific. +// 2. Declair global platform specific functionality. +// 3. Include primative type definitions +// +// Global Functions: +// getTimer() : Return the current high resolution clock count. +// getTimerFrequency() : Return the frequency of the high resolution clock. +// sleep() : Voluntarily relinquish timeslice of the calling thread for a +// specified number of milliseconds. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_WIN32_PLATFORM_H +#define BASE_WIN32_PLATFORM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Types.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + uint64 getTimer(void); + uint64 getTimerFrequency(void); + + inline uint64 getTimer(void) + { + uint64 result; + if (!QueryPerformanceCounter(reinterpret_cast(&result))) + result = 0; + return result; + } + + inline uint64 getTimerFrequency(void) + { + uint64 result; + if (!QueryPerformanceFrequency(reinterpret_cast(&result))) + result = 0; + return result; + } + + inline void sleep(uint32 ms) + { + Sleep(ms); + } + + + class CTimer + { + public: + CTimer(); + + void Set(uint32 seconds); + void Signal(); + bool Expired(); + + private: + uint32 mTimer; + }; + + inline void CTimer::Set(uint32 interval) + { + mTimer = (uint32)time(0) + interval; + } + + inline void CTimer::Signal() + { + mTimer = 0; + } + + inline bool CTimer::Expired() + { + return (mTimer <= (uint32)time(0)); + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif BASE_WIN32_PLATFORM_H \ No newline at end of file diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Thread.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Thread.cpp new file mode 100644 index 00000000..9dcbb9a9 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Thread.cpp @@ -0,0 +1,315 @@ +//////////////////////////////////////// +// Thread.cpp +// +// Purpose: +// 1. Implementation of the CThread class. +// +// Revisions: +// 07/10/2001 Created +// + + +#pragma warning ( disable: 4786 ) + + +#if !defined(_MT) +# pragma message( "Excluding Base::CThread - requires multi-threaded compile. (_MT)" ) +#else + +#include +#include +#include "Thread.h" + +using namespace std; + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + void threadProc(void *threadPtr) + { + CThread &thread = *((CThread*)threadPtr); + thread.mThreadActive = true; + thread.ThreadProc(); + thread.mThreadActive = false; + } + + CThread::CThread() + { + mThreadID = 0; + mThreadActive = false; + mThreadContinue = false; + } + + CThread::~CThread() + { + StopThread(); + } + + void CThread::StartThread() + { + mThreadContinue = true; + mThreadID = _beginthread(threadProc,0,this); + while (!IsThreadActive()) + Base::sleep(1); + } + + int32 CThread::StopThread(int32 timeout) + { + timeout += time(0); + + mThreadContinue = false; + while (mThreadActive && time(0)OnStartup(this); + while (mThreadContinue) + { + mParent->OnIdle(this); + mSemaphore.Wait(mParent->GetTimeOut()*1000); + + if (mFunction) + { + mFunction(mArgument); + mArgument = NULL; + mFunction = NULL; + } + else if (mParent->OnDestory(this)) + mThreadContinue = false; + } + } + + +//////////////////////////////////////////////////////////////////////////////// + + + CThreadPool::CThreadPool(uint32 maxThreads, uint32 minThreads, uint32 timeout) : + mMutex(), + mIdleMember(), + mBusyMember(), + mNullMember(), + mThreadCount(0), + mMaxThreads(maxThreads), + mMinThreads(minThreads), + mTimeOut(timeout) + { + if (mMaxThreads == 0) mMaxThreads = 1; + if (mMinThreads == 0) mMinThreads = 1; + if (mMinThreads > mMaxThreads) mMinThreads = mMaxThreads; + + for (uint32 i=0; i::iterator setIterator; + + //////////////////////////////////////// + // (1) Destory all busy member threads + mMutex.Lock(); + setIterator = mBusyMember.begin(); + while (setIterator != mBusyMember.end()) + (*setIterator++)->Destroy(); + mMutex.Unlock(); + + //////////////////////////////////////// + // (2) Destory all idle member threads + while (mThreadCount) + { + mMutex.Lock(); + setIterator = mIdleMember.begin(); + while (setIterator != mIdleMember.end()) + (*setIterator++)->Destroy(); + mMutex.Unlock(); + + sleep(1); + } + + //////////////////////////////////////// + // (3) Delete the null member threads + mMutex.Lock(); + while (!mNullMember.empty()) + { + delete mNullMember.front(); + mNullMember.pop_front(); + } + mMutex.Unlock(); + } + + bool CThreadPool::Execute(void( __cdecl *function )( void * ), void * arg, uint32 poolGrowthSize ) + { + mMutex.Lock(); + + //////////////////////////////////////// + // (1) If no idle members, return false to indicate that no threads + // were available. If the thread count is below the max, create + // a new thread. + if (mIdleMember.empty()) + { + if (mThreadCount < mMaxThreads) + { + if (!poolGrowthSize) + poolGrowthSize = mMinThreads; + + if ((mThreadCount + poolGrowthSize) > mMaxThreads) + poolGrowthSize = mMaxThreads - mThreadCount; + + for (uint32 i(0); i < poolGrowthSize; i++) + new CMember(this); + mMutex.Unlock(); + time_t idleTimeout = time(0) + 5; + while(mIdleMember.empty()) + { + if (time(0) >= idleTimeout) + { + return false; + } + Base::sleep(10); + } + mMutex.Lock(); + + } + else + { + mMutex.Unlock(); + return false; + } + } + + //////////////////////////////////////// + // (2) Delete any null member threads. + while (!mNullMember.empty()) + { + delete mNullMember.front(); + mNullMember.pop_front(); + } + + //////////////////////////////////////// + // (3) Move the first idle thread to the busy set and signal the + // thread to execute the specified function. + CMember * member = *(mIdleMember.begin()); + mIdleMember.erase(member); + mBusyMember.insert(member); + member->Execute(function,arg); + + mMutex.Unlock(); + return true; + } + + uint32 CThreadPool::GetTimeOut() + { + return mTimeOut; + } + + void CThreadPool::OnStartup(CMember * member) + { + mMutex.Lock(); + + mThreadCount++; + mIdleMember.insert(member); + + mMutex.Unlock(); + } + + void CThreadPool::OnIdle(CMember * member) + { + mMutex.Lock(); + + mBusyMember.erase(member); + mIdleMember.insert(member); + + mMutex.Unlock(); + } + + bool CThreadPool::OnDestory(CMember * member) + { + set::iterator setIterator; + + mMutex.Lock(); + + bool result = (setIterator = mIdleMember.find(member)) != mIdleMember.end(); + if (result) + { + mNullMember.push_back(member); + mIdleMember.erase(setIterator); + mThreadCount--; + } + + mMutex.Unlock(); + + return result; + } + + SwitchableScopeLock::SwitchableScopeLock(CMutex & mutex, bool isOn) : + mMutex(mutex), + mIsOn(isOn) + { + if(mIsOn) { mMutex.Lock(); } + } + + SwitchableScopeLock::~SwitchableScopeLock() + { + if(mIsOn) { mMutex.Unlock(); } + } + + +//////////////////////////////////////////////////////////////////////////////// + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif // #if defined(_MT) + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Thread.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Thread.h new file mode 100644 index 00000000..cbffabb6 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Thread.h @@ -0,0 +1,152 @@ +//////////////////////////////////////// +// Thread.h +// +// Purpose: +// 1. Declair the CThread class that encapsulates threading functionality. +// This abstract base class in intended to be used to encapsulate +// individual tasks that require threading in derived classes. +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_WIN32_THREAD_H +#define BASE_WIN32_THREAD_H + +#if defined(_MT) + +#pragma warning( disable : 4786) + +#include +#include +#include "Platform.h" +#include "Mutex.h" +#include "Event.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + //////////////////////////////////////// + // Class: + // CThread + // + // Purpose: + // Encapsulates threading functionality. Creating classes derived + // from CThread provides an easy way to encapsulate tasks that require + // their own thread. + // + // Public Methods: + // StartThread() : Creates the low-level thread handle and begins executing + // the CThread::ThreadProc() function within the new thread. + // StopThread() : Signals the ThreadProc() function to stop executing using + // the mThreadContinue member variable, and waits for the ThreadProc() + // function to exit. By default, the function will block for a maximum + // of 5 seconds before exiting without the thread halting. + // IsThreadActive() : Returns true if the physical thread is still executing + // within the ThreadProc() function, otherwise it returns false. + // ThreadProc() : Pure-virtual function that will be executed when the StartThread() + // function is called. Derived classes must implement this function. The + // mThreadContinue member variable should be used internal the the ThreadProc() + // function to indicate whether it should continue executing or exit. + // Protected Attributes: + // mThreadContinue : Boolean value indicating to the ThreadProc() function + // whether to continue executing or to exit. If mThreadContinue is true, + // ThreadProc() should continue, otherwise ThreadProc() should exit. It + // left up to the derived class to implement a ThreadProc() function that + // uses the mThreadContinue member. + // + // + class CThread + { + friend void threadProc(void *); + + public: + enum { eSTOP_SUCCESS, eSTOP_TIMEOUT }; + public: + CThread(); + virtual ~CThread(); + + void StartThread(); + int32 StopThread(int32 timeout=5); + bool IsThreadActive() { return mThreadActive; } + + protected: + virtual void ThreadProc() = 0; + + protected: + bool mThreadContinue; + private: + uint32 mThreadID; + bool mThreadActive; + }; + + + class CThreadPool + { + private: + class CMember : public CThread + { + public: + CMember(CThreadPool * parent); + virtual ~CMember(); + + bool Execute(void( __cdecl *function )( void * ), void * arg); + void Destroy(); + + protected: + virtual void ThreadProc(); + + private: + CThreadPool * mParent; + void( __cdecl * mFunction )( void * ); + void * mArgument; + CEvent mSemaphore; + }; + friend class CMember; + + public: + CThreadPool(uint32 maxThreads, uint32 minThreads=1, uint32 timeout=15*60); + ~CThreadPool(); + + virtual bool Execute(void( __cdecl *function )( void * ), void * arg, uint32 poolGrowthSize = 0); + + private: + uint32 GetTimeOut(); + void OnStartup(CMember * member); + void OnIdle(CMember * member); + bool OnDestory(CMember * member); + + private: + CMutex mMutex; + std::set mIdleMember; + std::set mBusyMember; + std::list mNullMember; + uint32 mThreadCount; + + uint32 mMaxThreads; + uint32 mMinThreads; + uint32 mTimeOut; + }; + + class SwitchableScopeLock + { + public: + SwitchableScopeLock(CMutex & mutex, bool isOn); + ~SwitchableScopeLock(); + private: + CMutex & mMutex; + bool mIsOn; + }; +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // #if defined(_MT) + +#endif // BASE_WIN32_THREAD_H diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Types.h b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Types.h new file mode 100644 index 00000000..0c64cb2c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Base/win32/Types.h @@ -0,0 +1,42 @@ +//////////////////////////////////////// +// Types.h +// +// Purpose: +// 1. Define integer types that are unambiguous with respect to size +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_WIN32_TYPES_H +#define BASE_WIN32_TYPES_H + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define UINT32_MAX 0xFFFFFFFF + +typedef signed char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; + +typedef int int32; +typedef unsigned uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif // BASE_WIN32_TYPES_H + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericApiCore.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericApiCore.cpp new file mode 100644 index 00000000..d41c0d5b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericApiCore.cpp @@ -0,0 +1,256 @@ +#include "GenericApiCore.h" +#include "GenericConnection.h" +#include "GenericMessage.h" + + +#ifdef USE_SERIALIZE_LIB + #include +#endif + +using namespace std; + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace GenericAPI +{ + + +GenericAPICore::GenericAPICore(const char *host, + short port, + unsigned reqTimeout, + unsigned reconnectTimeout, + unsigned noDataTimeoutSecs, + unsigned noAckTimeoutSecs, + unsigned incomingBufSizeInKB, + unsigned outgoingBufSizeInKB, + unsigned keepAlive, + unsigned maxRecvMessageSizeInKB) +: m_currTrack(0), + m_reconnectTimeout(0), + m_outCount(0), + m_pendingCount(0), + m_requestTimeout(reqTimeout), + m_suspended(false), + m_nextConnectionIndex(0) +{ + m_serverConnections.push_back(new GenericConnection(host, port, this, reconnectTimeout, noDataTimeoutSecs, noAckTimeoutSecs, incomingBufSizeInKB, outgoingBufSizeInKB, keepAlive, maxRecvMessageSizeInKB)); +} + +GenericAPICore::GenericAPICore(const char *hosts[], + const short port[], + unsigned arraySize, + unsigned reqTimeout, + unsigned reconnectTimeout, + unsigned noDataTimeoutSecs, + unsigned noAckTimeoutSecs, + unsigned incomingBufSizeInKB, + unsigned outgoingBufSizeInKB, + unsigned keepAlive, + unsigned maxRecvMessageSizeInKB) +: m_currTrack(0), + m_reconnectTimeout(0), + m_outCount(0), + m_pendingCount(0), + m_requestTimeout(reqTimeout), + m_suspended(false), + m_nextConnectionIndex(0) +{ + for (unsigned i=0; i::iterator conIter = m_serverConnections.begin(); conIter != m_serverConnections.end(); conIter++) + { + GenericConnection *con = *conIter; + delete con; + } + m_serverConnections.clear(); + + for(map::iterator iter = m_pending.begin(); iter != m_pending.end(); ++iter) + { + delete (*iter).second; + } + + m_pending.empty(); + + while(m_outCount > 0) + { + delete m_outboundQueue.front().second; + delete m_outboundQueue.front().first; + m_outboundQueue.pop(); + --m_outCount; + } +} + +void GenericAPICore::changeHostPort(unsigned connectionIndex, const char *host, short port) +{ + if (connectionIndex <= m_serverConnections.size() - 1) + { + m_serverConnections[connectionIndex]->changeHostPort(host, port); + } +} + +unsigned GenericAPICore::submitRequest(GenericRequest *req, GenericResponse *res) +{ + ++m_outCount; + if(m_currTrack == 0) + { + m_currTrack++; + } + req->setTrack(m_currTrack); + res->setTrack(m_currTrack); + time_t timeout = time(NULL) + m_requestTimeout; + + req->setTimeout(timeout); + res->setTimeout(timeout); + + m_outboundQueue.push(pair(req, res)); + return(m_currTrack++); +} + +unsigned GenericAPICore::submitRequest(GenericRequest *req, GenericResponse *res, unsigned reqTimeout) +{ + ++m_outCount; + if(m_currTrack == 0) + { + m_currTrack++; + } + req->setTrack(m_currTrack); + res->setTrack(m_currTrack); + time_t timeout = time(NULL) + reqTimeout; + + req->setTimeout(timeout); + res->setTimeout(timeout); + + m_outboundQueue.push(pair(req, res)); + return(m_currTrack++); +} + +void GenericAPICore::process() +{ + GenericRequest *req; + GenericResponse *res; + + // Process timeout on pending requests - regardless of whether processing is suspended or not + while((m_outCount > 0) && ((req = m_outboundQueue.front().first)->getTimeout() <= time(NULL))) + { + --m_outCount; + res = m_outboundQueue.front().second; + m_outboundQueue.pop(); + + responseCallback(res); + delete res; + delete req; + } + + // Process timeout on pending responses + while((m_pendingCount > 0) && ((res = (*m_pending.begin()).second)->getTimeout() <= time(NULL))) + { + --m_pendingCount; + m_pending.erase(m_pending.begin()); + responseCallback(res); + delete res; + } + + if (!m_suspended) + { + while(m_outCount > 0) + { + GenericConnection *con = getNextActiveConnection(); + if (con != NULL) + { + pair out_pair = m_outboundQueue.front(); + + req = out_pair.first; + res = out_pair.second; + if (!req->isInputValid()) + { + res->setResult(req->getInputError()); + --m_outCount; + m_outboundQueue.pop(); + + responseCallback(res); + delete res; + delete req; + } + else + { +#ifdef USE_SERIALIZE_LIB + const unsigned char *msgBuf = NULL; + unsigned msgSize = 0; + msgBuf = req->pack(msgSize); + con->Send(msgBuf, msgSize); +#else + Base::ByteStream msg; + req->pack(msg); + con->Send(msg); +#endif + m_pending.insert(pair(res->getTrack(), res)); + --m_outCount; + ++m_pendingCount; + m_outboundQueue.pop(); + delete req; + } + } + else + { + //no active connections + break; //from while loop + } + + } + } + + for (std::vector::iterator conIter = m_serverConnections.begin(); conIter != m_serverConnections.end(); conIter++) + { + GenericConnection *con = *conIter; + con->process(); + } +} + + +GenericConnection *GenericAPICore::getNextActiveConnection() +{ + unsigned startIndex = m_nextConnectionIndex; + unsigned maxIndex = m_serverConnections.size() - 1; + + GenericConnection *con = NULL; + + //loop until we find an active connection, or until we get back + // to where we started + do + { + if (m_serverConnections[m_nextConnectionIndex]->isConnected()) + { + con = m_serverConnections[m_nextConnectionIndex]; + if (m_nextConnectionIndex == maxIndex) + m_nextConnectionIndex = 0; + else + m_nextConnectionIndex++; + + } + else if (++m_nextConnectionIndex > maxIndex) + { + //went past end of vector, start back at 0 + m_nextConnectionIndex = 0; + } + }while (con == NULL && m_nextConnectionIndex != startIndex); + + return con; +} + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericApiCore.h b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericApiCore.h new file mode 100644 index 00000000..6313a999 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericApiCore.h @@ -0,0 +1,102 @@ +#if !defined (GENERICAPICORE_H_) +#define GENERICAPICORE_H_ + +#pragma warning (disable: 4786) + +#include +#include + +#include + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace GenericAPI +{ + +class GenericRequest; +class GenericResponse; +class GenericConnection; +class GenericAPI; + +class GenericAPICore +{ +public: + friend class GenericConnection; + friend class GenericAPI; + + GenericAPICore::GenericAPICore(const char *host, + short port, + unsigned reqTimeout, + unsigned reconnectTimeout, + unsigned noDataTimeoutSecs = 5, + unsigned noAckTimeoutSecs = 5, + unsigned incomingBufSizeInKB = 32, + unsigned outgoingBufSizeInKB = 32, + unsigned keepAlive = 1, + unsigned maxRecvMessageSizeInKB = 0); + + /** + * NOTE: arraySize must be actual size of host and port arrays. + * ALSO: cannot specify a 0 array size. + */ + GenericAPICore(const char *hosts[], + const short port[], + unsigned arraySize, + unsigned reqTimeout, + unsigned reconnectTimeout, + unsigned noDataTimeoutSecs = 5, + unsigned noAckTimeoutSecs = 5, + unsigned incomingBufSizeInKB = 32, + unsigned outgoingBufSizeInKB = 32, + unsigned keepAlive = 1, + unsigned maxRecvMessageSizeInKB = 0); + + virtual ~GenericAPICore(); + + void process(); +#ifdef USE_SERIALIZE_LIB + virtual void responseCallback(short type, const unsigned char *data, unsigned dataLen) = 0; +#else + virtual void responseCallback(short type, Base::ByteStream::ReadIterator &iter) = 0; +#endif + virtual void responseCallback(GenericResponse *R) = 0; + + virtual void OnDisconnect(const char *host, short port) = 0; + virtual void OnConnect(const char *host, short port) = 0; + + void suspendProcessing() { m_suspended = true; } + void resumeProcessing() { m_suspended = false; } + + // change the host and port for a connection object, will take effect + // on connection's next CON_DISCONNECT state. + void changeHostPort(unsigned connectionIndex, const char *host, short port); + + unsigned submitRequest(GenericRequest *req, GenericResponse *res); + unsigned submitRequest(GenericRequest *req, GenericResponse *res, unsigned reqTimeout); + +protected: + std::vector m_serverConnections; + std::map m_pending; + std::queue > m_outboundQueue; + unsigned m_currTrack; + time_t m_reconnectTimeout; + unsigned m_outCount; + unsigned m_pendingCount; + unsigned m_requestTimeout; +private: + bool m_suspended; + unsigned m_nextConnectionIndex; + + GenericConnection *getNextActiveConnection(); +}; + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericConnection.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericConnection.cpp new file mode 100644 index 00000000..3b677c70 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericConnection.cpp @@ -0,0 +1,298 @@ +#include "GenericAPI/GenericApiCore.h" +#include "GenericAPI/GenericConnection.h" +#include "GenericAPI/GenericMessage.h" + + +using namespace UdpLibrary; + +#ifdef USE_SERIALIZE_LIB + #include +#endif + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + + +#endif +namespace GenericAPI +{ + + +using namespace std; +using namespace Base; + +unsigned GenericConnection::ms_crcBytes = 0; + +GenericConnection::GenericConnection(const char *host, short port, GenericAPICore *apiCore, unsigned reconnectTimeout, unsigned noDataTimeoutSecs, unsigned noAckTimeoutSecs, unsigned incomingBufSizeInKB, unsigned outgoingBufSizeInKB, unsigned keepAlive, unsigned maxRecvMessageSizeInKB, unsigned holdTime) +: m_bConnected(false), + m_apiCore(apiCore), + m_con(NULL), + m_host(host), + m_nextHost(host), + m_port(port), + m_nextPort(port), + m_lastTrack(123455), //random choice != 1 + m_conState(CON_DISCONNECT), + m_reconnectTimeout(reconnectTimeout) +{ +#ifdef USE_TCP_LIBRARY + TcpManager::TcpParams params; + + params.incomingBufferSize = incomingBufSizeInKB * 1024; + params.outgoingBufferSize = outgoingBufSizeInKB * 1024; + params.maxConnections = 1; + params.port = 0; + params.maxRecvMessageSize = maxRecvMessageSizeInKB*1024; + params.keepAliveDelay = keepAlive * 1000; + params.noDataTimeout = noDataTimeoutSecs * 1000; + //params.oldestUnacknowledgedTimeout = noAckTimeoutSecs * 1000; + + m_manager = new TcpManager(params); +#else //default to UDP_LIBRARY + UdpManager::Params params; + + params.keepAliveDelay = keepAlive * 1000; + params.maxDataHoldTime = holdTime; + params.incomingBufferSize = incomingBufSizeInKB * 1024; + params.outgoingBufferSize = outgoingBufSizeInKB * 1024; + params.maxConnections = 1; + params.port = 0; + params.noDataTimeout = noDataTimeoutSecs * 1000; + params.oldestUnacknowledgedTimeout = noAckTimeoutSecs * 1000; + params.crcBytes = ms_crcBytes; + + m_manager = new UdpManager(¶ms); +#endif //USE_TCP_LIBRARY + +} + +GenericConnection::~GenericConnection() +{ + if(m_con) + { + m_con->SetHandler(NULL); + m_con->Disconnect();//don't worry about onterminated being called, we've set it's handler to null, so it wont + m_con->Release(); + } + + m_manager->Release(); +} + +void GenericConnection::changeHostPort(const char *host, short port) +{ + if (host && + strcmp(host, "") != 0) + { + m_nextHost = host; + m_nextPort = port; + } +} + +void GenericConnection::disconnect() +{ + if (m_con) + { + m_con->Disconnect(); + //no need to release, since callback to onTerminated releases it, and callback is allways made m_con->Release(); + m_con = NULL; + } + m_conState = CON_DISCONNECT; + m_bConnected = false; +} + +#ifdef USE_TCP_LIBRARY +void GenericConnection::OnTerminated(TcpConnection *con) +#else //default to UDP_LIBRARY +void GenericConnection::OnTerminated(UdpConnection *con) +#endif +{ + m_apiCore->OnDisconnect(m_host.c_str(), m_port); + if(m_con) + { + m_con->Release(); + m_con = NULL; + } + m_conState = CON_DISCONNECT; + m_bConnected = false; +} + +#ifdef USE_TCP_LIBRARY +void GenericConnection::OnRoutePacket(TcpConnection *con, const unsigned char *data, int dataLen) +#else //default to UDP_LIBRARY +void GenericConnection::OnRoutePacket(UdpConnection *con, const unsigned char *data, int dataLen) +#endif +{ + short type; + unsigned track; + + +#ifdef USE_SERIALIZE_LIB + unsigned bytes = 0; + unsigned fieldLen = soe::Read(data, dataLen, type); + if (fieldLen == 0) + return;//invalid message + bytes += fieldLen; + + fieldLen = soe::Read(data+bytes, dataLen-bytes, track); + if (fieldLen == 0) + return;//invalid message + bytes += fieldLen; +#else + ByteStream msg(data, dataLen); + ByteStream::ReadIterator iter = msg.begin(); + + get(iter, type); + get(iter, track); +#endif + GenericResponse *res = NULL; + + // the following if block is a temporary fix that prevents + // a crash with a game team in which they occasionally find + // themselves receiving a dupe track in consecutive calls to + // OnRoutePacket (which then leads to a callback being called + // twice and data being invalid on the second call -> crash!). + if (track != 0 && + track == m_lastTrack) + { + printf("!!! ERROR !!! Got a duplicate track ID %u\n", track); + return; + } + m_lastTrack = track; + + // end temporary fix. + + if(track == 0) + { +#ifdef USE_SERIALIZE_LIB + m_apiCore->responseCallback(type, data+bytes, dataLen-bytes); +#else + m_apiCore->responseCallback(type, iter); +#endif + } + else + { + map::iterator mapIter = m_apiCore->m_pending.find(track); + + if(mapIter != m_apiCore->m_pending.end()) + { + res = (*mapIter).second; +#ifdef USE_SERIALIZE_LIB + res->unpack(data, dataLen); +#else + iter = msg.begin(); + res->unpack(iter); +#endif + m_apiCore->m_pending.erase(mapIter); + m_apiCore->m_pendingCount--; + m_apiCore->responseCallback(res); + delete res; + } + } +} + +void GenericConnection::process(bool giveTime) +{ + switch(m_conState) + { + case CON_DISCONNECT: + // if host/port was changed, it takes effect here + m_host = m_nextHost; + m_port = m_nextPort; + + // create connection object, attempting to connect and + // checking for connection in next state, CON_NEGOTIATE + m_con = m_manager->EstablishConnection(m_host.c_str(), m_port); + if(m_con) + { + m_con->SetHandler(this); + m_conState = CON_NEGOTIATE; + m_conTimeout = time(NULL) + m_reconnectTimeout; + } + break; + case CON_NEGOTIATE: + // check for connection + +#ifdef USE_TCP_LIBRARY + if(m_con->GetStatus() == TcpConnection::StatusConnected) +#else //default to UDP_LIBRARY + if(m_con->GetStatus() == UdpConnection::cStatusConnected) +#endif + { + // we're connected + m_conState = CON_CONNECT; + m_apiCore->OnConnect(m_host.c_str(), m_port); + m_bConnected = true; + } + else if(time(NULL) > m_conTimeout) + { + // we did not connect + m_con->Disconnect(); + //no need to release, since callback to onTerminated releases it, and callback is allways made m_con->Release(); + m_con = NULL; + m_conState = CON_DISCONNECT; + m_bConnected = false; + } + break; + case CON_CONNECT: + // do nothing + break; + default: + // this should not occur, but we revert to CON_DISCONNECT if it does + m_conState = CON_DISCONNECT; + m_bConnected = false; + if (m_con) + { + m_con->Disconnect(); + //no need to release, since callback to onTerminated releases it, and callback is allways made m_con->Release(); + m_con = NULL; + } + } + + if (giveTime) + { + m_manager->GiveTime(); + } + +} + +#ifdef USE_SERIALIZE_LIB + void GenericConnection::Send(const unsigned char *data, int dataLen) + { + #ifdef USE_TCP_LIBRARY + if(m_con && m_con->GetStatus() == TcpConnection::StatusConnected) + { + m_con->Send((const char *)data, dataLen); + } + #else//USE_TCP_LIBRARY + if(m_con && m_con->GetStatus() == UdpConnection::cStatusConnected) + { + m_con->Send(cUdpChannelReliable1, data, dataLen); + } + #endif//USE_TCP_LIBRARY + } +#else //USE_SERIALIZE_LIB + void GenericConnection::Send(Base::ByteStream &msg) + { + #ifdef USE_TCP_LIBRARY + if(m_con && m_con->GetStatus() == TcpConnection::StatusConnected) + { + m_con->Send((const char *)msg.getBuffer(), msg.getSize()); + } + #else //USE_TCP_LIBRARY + if(m_con && m_con->GetStatus() == UdpConnection::cStatusConnected) + { + m_con->Send(cUdpChannelReliable1, msg.getBuffer(), msg.getSize()); + } + #endif//USE_TCP_LIBRARY + } +#endif //USE_SERIALIZE_LIB + + + +}; + +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericConnection.h b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericConnection.h new file mode 100644 index 00000000..fd14c3a3 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericConnection.h @@ -0,0 +1,99 @@ +#if !defined (GENERICCONNECTION_H_) +#define GENERICCONNECTION_H_ + +#include + +#ifdef USE_TCP_LIBRARY + #include + #include + #include +#else //default to UDP_LIBRARY + #include + #include +#endif + + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace GenericAPI +{ + + enum eConState + { + CON_DISCONNECT, + CON_NEGOTIATE, + CON_CONNECT + }; + +#ifdef USE_TCP_LIBRARY + class GenericConnection : public TcpConnectionHandler +#else //default to UDP_LIBRARY + class GenericConnection : public UdpLibrary::UdpConnectionHandler +#endif + { + public: + GenericConnection(const char *host, + short port, + GenericAPICore *apiCore, + unsigned reconnectTimeout, + unsigned noDataTimeoutSecs = 5, + unsigned noAckTimeoutSecs = 5, + unsigned incomingBufSizeInKB = 32, + unsigned outgoingBufSizeInKB = 32, + unsigned keepAlive = 1, + unsigned maxRecvMessageSizeInKB = 0, + unsigned holdTime = 0); + + virtual ~GenericConnection(); + +#ifdef USE_TCP_LIBRARY + virtual void OnRoutePacket(TcpConnection *con, const unsigned char *data, int dataLen); + virtual void OnTerminated(TcpConnection *con); +#else //default to UDP_LIBRARY + virtual void OnRoutePacket(UdpLibrary::UdpConnection *con, const unsigned char *data, int dataLen); + virtual void OnTerminated(UdpLibrary::UdpConnection *con); +#endif +#ifdef USE_SERIALIZE_LIB + void Send(const unsigned char *data, int dataLen); +#else + void Send(Base::ByteStream &msg); +#endif + + + void changeHostPort(const char *host, short port); + bool isConnected() { return m_bConnected; } + void disconnect(); + void process(bool giveTime = true); + + static unsigned ms_crcBytes; + private: + bool m_bConnected; + GenericAPICore *m_apiCore; +#ifdef USE_TCP_LIBRARY + TcpManager *m_manager; + TcpConnection *m_con; +#else //default to UDP_LIBRARY + UdpLibrary::UdpManager *m_manager; + UdpLibrary::UdpConnection *m_con; +#endif + std::string m_host; + std::string m_nextHost; + short m_port; + short m_nextPort; + + unsigned m_lastTrack; + + eConState m_conState; + time_t m_conTimeout; + unsigned m_reconnectTimeout; + }; + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericMessage.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericMessage.cpp new file mode 100644 index 00000000..05d08328 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericMessage.cpp @@ -0,0 +1,32 @@ +#include "GenericMessage.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace GenericAPI +{ + +GenericMessage::GenericMessage(short type) +: m_type(type) +{ +} + +GenericRequest::GenericRequest(short type) +: GenericMessage(type) +{ +} + +GenericResponse::GenericResponse(short type, unsigned result, void *user) +: GenericMessage(type), + m_result(result), + m_user(user) +{ +} + +}; + +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericMessage.h b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericMessage.h new file mode 100644 index 00000000..b50aa5a0 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/GenericAPI/GenericMessage.h @@ -0,0 +1,84 @@ +#if !defined (GENERICMESSAGE_H_) +#define GENERICMESSAGE_H_ + +#include +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace GenericAPI +{ + +// Basic request message, implements a type, and a timeout mechanism +class GenericMessage +{ +public: + GenericMessage(short type); + virtual ~GenericMessage() {}; + + short getType() const { return m_type; } +protected: + short m_type; +}; + +class GenericRequest : public GenericMessage +{ +public: + GenericRequest(short type); + virtual ~GenericRequest() {}; +#ifdef USE_SERIALIZE_LIB + virtual const unsigned char *pack(unsigned &msgSize) = 0; +#else + virtual void pack(Base::ByteStream &msg) = 0; +#endif + + const time_t &getTimeout() const { return m_timeout; } + void setTimeout(time_t t) { m_timeout = t; } + void setTrack(unsigned t) { m_track = t; } + unsigned getTrack() const { return m_track; } + + virtual bool isInputValid() const { return true; } + virtual unsigned getInputError() const { return 0; } + +protected: + unsigned m_track; + time_t m_timeout; +}; + +// Basic response message from server. In the case that this response to a request +// submitted from this API, the response would have been generated at request submission +// time, and the timeout value filled in appropriatly +class GenericResponse : public GenericMessage +{ +public: + GenericResponse(short type, unsigned result, void *user); + virtual ~GenericResponse() {}; +#ifdef USE_SERIALIZE_LIB + virtual void unpack(const unsigned char *data, unsigned dataLen) = 0; +#else + virtual void unpack(Base::ByteStream::ReadIterator &iter) = 0; +#endif + + time_t getTimeout() const { return m_timeout; } + void setTimeout(time_t t) { m_timeout = t; } + void setTrack(unsigned t) { m_track = t; } + unsigned getTrack() const { return m_track; } + unsigned getResult() const { return m_result; } + void setResult(unsigned res) { m_result = res; } + void *getUser() const { return m_user; } +protected: + unsigned m_track; + unsigned m_result; + void *m_user; + time_t m_timeout; +}; + +}; + +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpConnection.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpConnection.cpp new file mode 100644 index 00000000..6b2fce79 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpConnection.cpp @@ -0,0 +1,1852 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#if defined(WIN32) + #define _CRT_SECURE_NO_DEPRECATE // gets rid of deprecation warnings in VS 2005 (don't want to change to secure-versions as it hampers portability) +#endif + +#include +#include +#include +#include +#include + +#include "UdpLibrary.h" +#include "UdpReliableChannel.h" + +namespace UdpLibrary +{ + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpConnectionHandler default implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +void UdpConnectionHandler::OnConnectComplete(UdpConnection * /*con*/) +{ +} + +void UdpConnectionHandler::OnTerminated(UdpConnection * /*con*/) +{ +} + +void UdpConnectionHandler::OnCrcReject(UdpConnection * /*con*/, const udp_uchar * /*data*/, int /*dataLen*/) +{ +} + +void UdpConnectionHandler::OnPacketCorrupt(UdpConnection * /*con*/, const udp_uchar * /*data*/, int /*dataLen*/, UdpCorruptionReason /*reason*/) +{ +} + + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpConnection implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// + +UdpConnection::UdpConnection(UdpManager *udpManager, UdpPlatformAddress destIp, int destPort, int timeout) +{ + UdpRef ref(this); + UdpGuard myGuard(&mGuard); + + // client side initializations + Init(udpManager, destIp, destPort); + + mConnectAttemptTimeout = timeout; + mStatus = cStatusNegotiating; + mConnectCode = mUdpManager->Random(); + mUdpManager->AddConnection(this); + + GiveTime(false); +} + +UdpConnection::UdpConnection(UdpManager *udpManager, const UdpManager::PacketHistoryEntry *e) +{ + UdpRef ref(this); + UdpGuard myGuard(&mGuard); + + // server side initialization + Init(udpManager, e->mIp, e->mPort); + + mStatus = cStatusConnected; + for (int j = 0; j < cEncryptPasses; j++) + mConnectionConfig.encryptMethod[j] = mUdpManager->mParams.encryptMethod[j]; + mConnectionConfig.crcBytes = mUdpManager->mParams.crcBytes; + mConnectionConfig.maxRawPacketSize = mUdpManager->mParams.maxRawPacketSize; + mConnectionConfig.encryptCode = mUdpManager->Random(); + SetupEncryptModel(); + + // steal the connect code out of the packet early such that ProcessRawPacket will think it's a valid connect packet instead of ignoring it + // plus, the AddConnection function needs to know our connect code + mConnectCode = UdpMisc::GetValue32(e->mBuffer + 6); + mUdpManager->AddConnection(this); + + ProcessRawPacket(e); + GiveTime(false); +} + +void UdpConnection::Init(UdpManager *udpManager, UdpPlatformAddress destIp, int destPort) +{ + mUdpManager = udpManager; + mIp = destIp; + mPort = destPort; + + mFlaggedPortUnreachable = false; + + mLastPortAliveTime = mLastSendTime = 0; // makes it send out the first connect packet immediately (if we are in negotiating mode) + mLastReceiveTime = mUdpManager->CachedClock(); + mLastClockSyncTime = 0; + mDataHoldTime = 0; + mGettingTime = false; + mHandler = NULL; + mOtherSideProtocolVersion = 0; + + mNoDataTimeout = mUdpManager->mParams.noDataTimeout; + mKeepAliveDelay = mUdpManager->mParams.keepAliveDelay; + + mMultiBufferData = new udp_uchar[mUdpManager->mParams.maxRawPacketSize]; + mMultiBufferPtr = mMultiBufferData; + + mIcmpErrorRetryStartStamp = 0; // when the timer started for ICMP error retry delay (gets reset on a successful packet receive) + mPortRemapRequestStartStamp = 0; + + mEncryptXorBuffer = NULL; + mEncryptExpansionBytes = 0; + mOrderedCountOutgoing = 0; + mOrderedCountOutgoing2 = 0; + mOrderedStampLast = 0; + mOrderedStampLast2 = 0; + mDisconnectReason = cDisconnectReasonNone; + mOtherSideDisconnectReason = cDisconnectReasonNone; + + mConnectAttemptTimeout = 0; + mConnectionCreateTime = mUdpManager->CachedClock(); + mSimulateOutgoingQueueBytes = 0; + mPassThroughData = NULL; + mSilentDisconnect = false; + + mLastSendBin = 0; + mLastReceiveBin = 0; + mOutgoingBytesLastSecond = 0; + mIncomingBytesLastSecond = 0; + memset(mSendBin, 0, sizeof(mSendBin)); + memset(mReceiveBin, 0, sizeof(mReceiveBin)); + + PingStatReset(); + mSyncTimeDelta = 0; + memset(mChannel, 0, sizeof(mChannel)); + memset(&mConnectionStats, 0, sizeof(mConnectionStats)); +} + +UdpConnection::~UdpConnection() +{ + UdpGuard myGuard(&mGuard); + + assert(mUdpManager == NULL); // this should not be possible, since the UdpManager holds a reference to us until we are disconnected and disassociated from the manager. If you are hitting this, then odds are the application is releasing the UdpConnection object more times than it should + + for (int i = 0; i < cReliableChannelCount; i++) + delete mChannel[i]; + delete[] mMultiBufferData; + delete[] mEncryptXorBuffer; +} + +void UdpConnection::PortUnreachable() +{ + if (!mUdpManager->mParams.processIcmpErrors) + return; + + if (!mUdpManager->mParams.processIcmpErrorsDuringNegotiating) + { + if (mStatus == cStatusNegotiating) // during negotiating phase, ignore port unreachable errors, since it may be a case of the client starting up first + return; + } + + if (mUdpManager->mParams.icmpErrorRetryPeriod != 0) + { + if (mIcmpErrorRetryStartStamp == 0) + { + mIcmpErrorRetryStartStamp = mUdpManager->CachedClock(); // start timer on how long we will ignore ICMP errors + return; + } + + if (mUdpManager->CachedClockElapsed(mIcmpErrorRetryStartStamp) < mUdpManager->mParams.icmpErrorRetryPeriod) + { + return; // ignoring ICMP errors for a period of time + } + } + + InternalDisconnect(0, cDisconnectReasonIcmpError); +} + +void UdpConnection::InternalDisconnect(int flushTimeout, DisconnectReason reason) +{ + UdpGuard guard(&mGuard); // must guard this because the UdpManager can potentially call this in a worker thread while we are inside of a Send call from the main thread, causing us to be disconnected mid-processing on the Send call + + if (mDisconnectReason == cDisconnectReasonNone) + { + mDisconnectReason = reason; + } + + // if we are in a negotiating state, then you can't have a flushTimeout, any disconnect will occur immediately + if (mStatus == cStatusNegotiating) + flushTimeout = 0; + + if (mUdpManager != NULL) + { + if (flushTimeout > 0) + { + FlushMultiBuffer(); + mDisconnectFlushStamp = mUdpManager->CachedClock(); + mDisconnectFlushTimeout = flushTimeout; + ScheduleTimeNow(); + + if (mStatus != cStatusDisconnectPending) + { + mStatus = cStatusDisconnectPending; + mUdpManager->KeepUntilDisconnected(this); + } + return; + } + + // send a termination packet to the other side + // do not send a termination packet if we are still negotiating (we are not allowed to send any packets while negotiating) + // if you attempt to send a packet while negotiating, then it will potentially attempt to encrypt it before an encryption + // method is determined, resulting in a function call through an invalid pointer + if (!mSilentDisconnect) + { + if (mStatus == cStatusConnected || mStatus == cStatusDisconnectPending) + { + SendTerminatePacket(mConnectCode, mDisconnectReason); + } + } + + UdpManager *holdUdpManager = mUdpManager; + mUdpManager = NULL; + mStatus = cStatusDisconnected; + + // only hold a reference to the UdpManager if it is not currently being destructed. + // if it is currently being destructed, we obviously can't addref it. We know it + // is being destructed as our disconnect reason will be ManagerDeleted. Since we + // can only get this reason if we are called from the UdpManager destructor, it is + // safe to call the UdpManager without reffing it. The UdpManager is setup such + // that the RemoveConnection call is safe, even after the destuctor has started + // running. + if (reason != cDisconnectReasonManagerDeleted) + { + holdUdpManager->AddRef(); + } + + holdUdpManager->RemoveConnection(this); + + if (reason != cDisconnectReasonManagerDeleted) + { + holdUdpManager->CallbackTerminated(this); + holdUdpManager->Release(); + } + } +} + +void UdpConnection::SendTerminatePacket(int connectCode, DisconnectReason reason) +{ + udp_uchar buf[256]; + buf[0] = 0; + buf[1] = cUdpPacketTerminate; + UdpMisc::PutValue32(buf + 2, connectCode); + UdpMisc::PutValue16(buf + 6, (udp_ushort)reason); + PhysicalSend(buf, 8, true); +} + + +void UdpConnection::SetSilentDisconnect(bool silent) +{ + UdpGuard guard(&mGuard); + // this function tells the connection to disconnect silently, meaning that it should + // not send a packet to the other side telling it that the connection is being terminated + mSilentDisconnect = silent; +} + +bool UdpConnection::Send(UdpChannel channel, const void *data, int dataLen) +{ + UdpGuard myGuard(&mGuard); + + assert(dataLen >= 0); + + if (mStatus != cStatusConnected) // if we are no longer connected (not allowed to send more when we are pending disconnect either) + return(false); + if (dataLen == 0) // zero length packets are ignored + return(false); + + assert(data != NULL); // can't send a null packet + + // zero-escape application packets that start with 0 + if ((*(const udp_uchar *)data) == 0) + { + udp_uchar hold = 0; + return(InternalSend(channel, &hold, 1, (const udp_uchar *)data, dataLen)); + } + + return(InternalSend(channel, (const udp_uchar *)data, dataLen)); +} + +bool UdpConnection::Send(UdpChannel channel, const LogicalPacket *packet) +{ + UdpGuard myGuard(&mGuard); + + assert(packet != NULL); // can't send a null packet + + if (mStatus != cStatusConnected) // if we are no longer connected + return(false); + int dataLen = packet->GetDataLen(); + if (dataLen == 0) + return(false); + + // zero-escape application packets that start with 0 + const udp_uchar *data = (const udp_uchar *)packet->GetDataPtr(); + if (!packet->IsInternalPacket() && data[0] == 0) + { + udp_uchar hold = 0; + return(InternalSend(channel, &hold, 1, data, dataLen)); + } + + return(InternalSend(channel, data, dataLen)); +} + +bool UdpConnection::InternalSend(UdpChannel channel, const udp_uchar *data, int dataLen, const udp_uchar *data2, int dataLen2) +{ + assert(channel >= 0 && channel < cUdpChannelCount); + assert(mStatus != cStatusNegotiating); // you are not allowed to start sending data on a connection that is still in the process of negotiating (only applicable client-side obviously since servers never have connections in this state) + + mUdpManager->IncrementApplicationPacketsSent(); + mConnectionStats.applicationPacketsSent++; + + // promote unreliable packets that are larger than maxRawPacketSize to be reliable + int totalDataLen = dataLen + dataLen2; + + int rawDataBytesMax = (mConnectionConfig.maxRawPacketSize - mConnectionConfig.crcBytes - mEncryptExpansionBytes); + if ((channel == cUdpChannelUnreliable || channel == cUdpChannelUnreliableUnbuffered) && totalDataLen > rawDataBytesMax) + channel = cUdpChannelReliable1; + else if ((channel == cUdpChannelOrdered || channel == cUdpChannelOrderedUnbuffered) && totalDataLen > rawDataBytesMax - cUdpPacketOrderedSize) + channel = cUdpChannelReliable1; + + udp_uchar tempBuffer[UdpManager::cHardMaxRawPacketSize]; + switch(channel) + { + case cUdpChannelUnreliable: + BufferedSend(data, dataLen, data2, dataLen2, false); + return(true); + break; + case cUdpChannelUnreliableUnbuffered: + { + udp_uchar *bufPtr = tempBuffer; + memcpy(bufPtr, data, dataLen); + if (data2 != NULL) + memcpy(bufPtr + dataLen, data2, dataLen2); + PhysicalSend(bufPtr, totalDataLen, true); + return(true); + break; + } + case cUdpChannelOrdered: + { + udp_uchar *bufPtr = tempBuffer; + bufPtr[0] = 0; + bufPtr[1] = cUdpPacketOrdered; + UdpMisc::PutValue16(bufPtr + 2, (udp_ushort)(++mOrderedCountOutgoing & 0xffff)); + memcpy(bufPtr + 4, data, dataLen); + if (data2 != NULL) + memcpy(bufPtr + 4 + dataLen, data2, dataLen2); + BufferedSend(bufPtr, totalDataLen + 4, NULL, 0, true); + return(true); + break; + } + case cUdpChannelOrderedUnbuffered: + { + udp_uchar *bufPtr = tempBuffer; + bufPtr[0] = 0; + bufPtr[1] = cUdpPacketOrdered2; + UdpMisc::PutValue16(bufPtr + 2, (udp_ushort)(++mOrderedCountOutgoing2 & 0xffff)); + memcpy(bufPtr + 4, data, dataLen); + if (data2 != NULL) + memcpy(bufPtr + 4 + dataLen, data2, dataLen2); + PhysicalSend(bufPtr, totalDataLen + 4, true); + return(true); + break; + } + case cUdpChannelReliable1: + case cUdpChannelReliable2: + case cUdpChannelReliable3: + case cUdpChannelReliable4: + { + int num = channel - cUdpChannelReliable1; + if (mChannel[num] == NULL) + mChannel[num] = new UdpReliableChannel(num, this, &mUdpManager->mParams.reliable[num]); + mChannel[num]->Send(data, dataLen, data2, dataLen2); + return(true); + break; + } + default: + break; + } + return(false); +} + +void UdpConnection::PingStatReset() +{ + UdpGuard myGuard(&mGuard); + + mLastClockSyncTime = 0; // tells it to resync the clock pronto + mSyncStatMasterFixupTime = 0; + mSyncStatMasterRoundTime = 0; + mSyncStatLow = 0; + mSyncStatHigh = 0; + mSyncStatLast = 0; + mSyncStatTotal = 0; + mSyncStatCount = 0; + mConnectionStats.averagePingTime = 0; + mConnectionStats.highPingTime = 0; + mConnectionStats.lowPingTime = 0; + mConnectionStats.lastPingTime = 0; + mConnectionStats.masterPingTime = 0; +} + +void UdpConnection::GetStats(UdpConnectionStatistics *cs) +{ + UdpGuard myGuard(&mGuard); + + assert(cs != NULL); + + if (mUdpManager == NULL) + return; + *cs = mConnectionStats; + + if (mUdpManager->mParams.clockSyncDelay == 0) + cs->masterPingAge = -1; + else + cs->masterPingAge = mUdpManager->CachedClockElapsed(mSyncStatMasterFixupTime); + + cs->percentSentSuccess = 1.0; + cs->percentReceivedSuccess = 1.0; + if (cs->syncOurSent > 0) + cs->percentSentSuccess = (float)cs->syncTheirReceived / (float)cs->syncOurSent; + if (cs->syncTheirSent > 0) + cs->percentReceivedSuccess = (float)cs->syncOurReceived / (float)cs->syncTheirSent; + cs->reliableAveragePing = 0; + if (mChannel[0] != NULL) + cs->reliableAveragePing = mChannel[0]->GetAveragePing(); +} + +void UdpConnection::ProcessRawPacket(const UdpManager::PacketHistoryEntry *e) +{ + UdpRef ref(this); + UdpGuard guard(&mGuard); + + if (mUdpManager == NULL) + return; + + if (e->mLen == 0) + { + // length 0 packet indicates an ICMP dest-unreachable error packet on this connection (the driver puts these errors inline as 0 byte packets) + PortUnreachable(); + return; + } + + if (e->mBuffer[0] != 0 || e->mBuffer[1] != cUdpPacketUnreachableConnection) + { + // if we get any type of packet other than an unreachable-connection packet, then we can assume that our remapping + // request succeeded, and clear the timer for how long we should attempt to do the remapping. The reason we need + // to send requests for a certain amount of time, is the server may already have dozens of unreachable-connection packets + // on the wire on the way to us, before we manage to request that the remapping occur. + mPortRemapRequestStartStamp = 0; + } + + mIcmpErrorRetryStartStamp = 0; // we received a packet successfully, so assume we have recovered from any ICMP error state we may have been in, so we can reset the timer + mLastReceiveTime = mUdpManager->CachedClock(); + mConnectionStats.totalPacketsReceived++; + mConnectionStats.totalBytesReceived += e->mLen; + + // track incoming data rate + ExpireReceiveBin(); + mReceiveBin[mLastReceiveBin % cBinCount] += e->mLen; + mIncomingBytesLastSecond += e->mLen; + + if (e->mBuffer[0] == 0 && e->mBuffer[1] == cUdpPacketKeepAlive) + { + // encryption can't mess up the first two bytes of an internal packet, so this is safe to check + // if it is a keep alive packet, then we don't need to do any more processing beyond setting + // the mLastReceiveTime. We do this check here instead of letting it pass on through harmlessly + // like we used to do in order to avoid getting rescheduled in the priority queue. There is absolutely + // no reason to reschedule us due to an incoming keep alive packet since the keep-alive packet has the + // longest rescheduling of anything that needs time, so the worst thing that might happen is we might + // end up getting sheduled time sooner than we might otherwise need to. And obviously scheduling + // ourselves for immediate-time is even sooner than that, so there is no point. + // This turns out to be important for applications that have lots of connections (tens of thousands) + // that rarely talk but send keep alives...no reason to make the server do a lot work over these things. + return; + } + + // whenever we receive a packet, it could potentially change when we want time scheduled again + // so effectively we should reprioritize ourself to the top. By doing it this way instead of + // simply giving time and recalculating, we can effectively avoid giving ourself time and reprioritizing + // ourself over and over again as more and more packets arrive in rapid succession + // note: this cannot happen while we are in our UdpConnection::GiveTime function, so there is no need to squeltch check + // it like we do the others. + // note: this was moved to the top of the function from the bottom. This doesn't effect anything as it doesn't matter + // when we schedule ourself for future processing. Moving it to the top allowed us to get scheduled even if the packet + // we processed got rejected for some reason (crc mismatch or bad size). + ScheduleTimeNow(); + + if (e->mLen < 1) + { + CallbackCorruptPacket(e->mBuffer, e->mLen, cUdpCorruptionReasonZeroLengthPacket); + return; // invalid packet len + } + + // first see if we are a special connect/confirm/unreachable packet, if so, process us immediately + if (IsNonEncryptPacket(e->mBuffer)) + { + ProcessCookedPacket(e->mBuffer, e->mLen); + } + else + { + // if we are still awaiting confirmation packet, then we must ignore any other incoming data packets + // this can happen if the confirm packet is lost and the server has dumped a load of data on the newly created connection + if (mStatus == cStatusNegotiating) + return; + + udp_uchar *finalStart = e->mBuffer; + int finalLen = e->mLen; + + if (mConnectionConfig.crcBytes > 0) + { + if (finalLen < mConnectionConfig.crcBytes) + { + CallbackCorruptPacket(e->mBuffer, e->mLen, cUdpCorruptionReasonPacketShorterThanCrcBytes); + return; // invalid packet len + } + + udp_uchar *crcPtr = finalStart + (finalLen - mConnectionConfig.crcBytes); + int actualCrc = UdpMisc::Crc32(finalStart, finalLen - mConnectionConfig.crcBytes, mConnectionConfig.encryptCode); + int wantCrc = 0; + switch(mConnectionConfig.crcBytes) + { + case 1: + wantCrc = *crcPtr; + actualCrc &= 0xff; + break; + case 2: + wantCrc = UdpMisc::GetValue16(crcPtr); + actualCrc &= 0xffff; + break; + case 3: + wantCrc = UdpMisc::GetValue24(crcPtr); + actualCrc &= 0xffffff; + break; + case 4: + wantCrc = UdpMisc::GetValue32(crcPtr); + break; + } + if (wantCrc != actualCrc) + { + mConnectionStats.crcRejectedPackets++; + mUdpManager->IncrementCrcRejectedPackets(); + mUdpManager->CallbackCrcReject(this, e->mBuffer, e->mLen); + return; + } + finalLen -= mConnectionConfig.crcBytes; + } + + udp_uchar tempDecryptBuffer[2][UdpManager::cHardMaxRawPacketSize]; + + for (int j = cEncryptPasses - 1; j >= 0; j--) + { + if (mConnectionConfig.encryptMethod[j] != cEncryptMethodNone) + { + // connect/confirm/unreachable packets are not encrypted, other packets are encrypted from the second or third byte on as appropriate + udp_uchar *decryptPtr = tempDecryptBuffer[j % 2]; + *decryptPtr++ = finalStart[0]; + + if (finalStart[0] == 0) + { + if (finalLen < 2) + { + CallbackCorruptPacket(e->mBuffer, e->mLen, cUdpCorruptionReasonInternalPacketTooShort); + return; // invalid packet len + } + + *decryptPtr++ = finalStart[1]; + int len = (this->*(mDecryptFunction[j]))(decryptPtr, finalStart + 2, finalLen - 2); + if (mUdpManager == NULL) + return; + + if (len == -1) + { + CallbackCorruptPacket(e->mBuffer, e->mLen, cUdpCorruptionReasonDecryptFailed); + return; // decrypt failed, throw away packet + } + decryptPtr += len; + } + else + { + int len = (this->*(mDecryptFunction[j]))(decryptPtr, finalStart + 1, finalLen - 1); + if (len == -1) + { + CallbackCorruptPacket(e->mBuffer, e->mLen, cUdpCorruptionReasonDecryptFailed); + return; // decrypt failed, throw away packet + } + decryptPtr += len; + } + + finalStart = tempDecryptBuffer[j % 2]; + finalLen = (int)(decryptPtr - finalStart); + } + } + + ProcessCookedPacket(finalStart, finalLen); + } +} + +void UdpConnection::CallbackRoutePacket(const udp_uchar *data, int dataLen) +{ + if (mStatus == cStatusConnected) + { + mUdpManager->IncrementApplicationPacketsReceived(); + mConnectionStats.applicationPacketsReceived++; + mUdpManager->CallbackRoutePacket(this, data, dataLen); // callback through UdpManager in case it wants to queue the event + } +} + +void UdpConnection::CallbackCorruptPacket(const udp_uchar *data, int dataLen, UdpCorruptionReason reason) +{ + if (mStatus == cStatusConnected) + { + mConnectionStats.corruptPacketErrors++; + mUdpManager->IncrementCorruptPacketErrors(); + mUdpManager->CallbackPacketCorrupt(this, data, dataLen, reason); + InternalDisconnect(0, cDisconnectReasonCorruptPacket); + } +} + +void UdpConnection::ProcessCookedPacket(const udp_uchar *data, int dataLen) +{ + udp_uchar buf[256]; + udp_uchar *bufPtr; + if (mUdpManager == NULL) + return; + + if (data[0] == 0 && dataLen > 1) + { + // internal packet, so process it internally + switch(data[1]) + { + case cUdpPacketConnect: + { + int otherSideProtocolVersion = UdpMisc::GetValue32(data + 2); + int connectCode = UdpMisc::GetValue32(data + 6); + + if (mStatus == cStatusNegotiating) + { + // why are we receiving a connect-request coming from the guy we ourselves are currently + // in the process of trying to connect to? Odds are very high that what is actually + // happening is we are trying to connect to ourself. In either case, we should reply + // back telling them they are terminated. + if (connectCode == mConnectCode) + SendTerminatePacket(connectCode, cDisconnectReasonConnectingToSelf); + else + SendTerminatePacket(connectCode, cDisconnectReasonMutualConnectError); + return; + } + + if (connectCode == mConnectCode) + { + mOtherSideProtocolVersion = otherSideProtocolVersion; + mConnectionConfig.maxRawPacketSize = udpMin((int)UdpMisc::GetValue32(data + 10), mConnectionConfig.maxRawPacketSize); + + // send confirm packet (if our connect code matches up) + // prepare UdpPacketConnect packet + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = cUdpPacketConfirm; + bufPtr += UdpMisc::PutValue32(bufPtr, mConnectCode); + bufPtr += UdpMisc::PutValue32(bufPtr, mConnectionConfig.encryptCode); + *bufPtr++ = (udp_uchar)mConnectionConfig.crcBytes; + for (int j = 0; j < cEncryptPasses; j++) + *bufPtr++ = (udp_uchar)mConnectionConfig.encryptMethod[j]; + bufPtr += UdpMisc::PutValue32(bufPtr, mConnectionConfig.maxRawPacketSize); + bufPtr += UdpMisc::PutValue32(bufPtr, UdpManager::cProtocolVersion); + RawSend(buf, (int)(bufPtr - buf)); + } + else + { + // ok, we got a connect-request packet from the ip/port of something we thought we already had a connection to. + // Additionally, the connect-request packet has a different code, meaning it is not just a stragling connect-request + // packet that got sent after we accepted the connection. + // This means that the other side has probably terminated the connection and is attempting to connect again. + // if we just ignore the new connect-request, it will actually result in the new connection-attempt effectively + // keeping this connection object alive. So, instead, when we get this situation, we will terminate this connection + // and ignore the connect-request packet. The connect-request packet will be sent again 1 second later by the client + // at which time we won't exist and out UdpManager will establish a new connection object for it. + InternalDisconnect(0, cDisconnectReasonNewConnectionAttempt); + return; + } + break; + } + case cUdpPacketConfirm: + { + // unpack UdpPacketConfirm packet into stack variables + Configuration config; + int otherSideProtocolVersion = 0; + + int connectCode = UdpMisc::GetValue32(data + 2); + config.encryptCode = UdpMisc::GetValue32(data + 6); + config.crcBytes = *(data + 10); + for (int j = 0; j < cEncryptPasses; j++) + config.encryptMethod[j] = (EncryptMethod)*(data + 11 + j); + config.maxRawPacketSize = UdpMisc::GetValue32(data + 11 + cEncryptPasses); + if (dataLen > 15 + cEncryptPasses) + { + otherSideProtocolVersion = UdpMisc::GetValue32(data + 15 + cEncryptPasses); + } + + // only actually process the confirm if we are negotiating (expecting it) and the connect-code matches up + if (mStatus == cStatusNegotiating && mConnectCode == connectCode) + { + mConnectionConfig = config; + mOtherSideProtocolVersion = otherSideProtocolVersion; + SetupEncryptModel(); + mStatus = cStatusConnected; + mUdpManager->CallbackConnectComplete(this); + } + break; + } + case cUdpPacketRequestRemap: + { + // if a request remap packet managed to get routed to our connection, it is because + // the mapping is already correct, so we can just ignore this packet at this point + // this will happen when the client sends multiple remap-requests, the first one will + // cause the actual remapping to occur, and the subsequent ones will manage to make + // it into here + break; + } + case cUdpPacketZeroEscape: + { + CallbackRoutePacket(data + 1, dataLen - 1); + break; + } + case cUdpPacketOrdered: + { + udp_ushort orderedStamp = UdpMisc::GetValue16(data + 2); + int diff = (int)orderedStamp - (int)mOrderedStampLast; + if (diff <= 0) // equal here makes it strip dupes too + diff += 0x10000; + if (diff < 30000) + { + mOrderedStampLast = orderedStamp; + CallbackRoutePacket(data + cUdpPacketOrderedSize, dataLen - cUdpPacketOrderedSize); + } + else + { + mConnectionStats.orderRejectedPackets++; + mUdpManager->IncrementOrderRejectedPackets(); + } + break; + } + case cUdpPacketOrdered2: + { + udp_ushort orderedStamp = UdpMisc::GetValue16(data + 2); + int diff = (int)orderedStamp - (int)mOrderedStampLast2; + if (diff <= 0) // equal here makes it strip dupes too + diff += 0x10000; + if (diff < 30000) + { + mOrderedStampLast2 = orderedStamp; + CallbackRoutePacket(data + cUdpPacketOrderedSize, dataLen - cUdpPacketOrderedSize); + } + else + { + mConnectionStats.orderRejectedPackets++; + mUdpManager->IncrementOrderRejectedPackets(); + } + break; + } + case cUdpPacketTerminate: + { + int connectCode = UdpMisc::GetValue32(data + 2); + if (dataLen >= 8) // to remain protocol compatible with previous version, the other side disconnect reason is an optional field on this packet + { + mOtherSideDisconnectReason = (DisconnectReason)UdpMisc::GetValue16(data + 6); + } + + if (mConnectCode == connectCode) + { + // since other side explicitly told us they had terminated, there is no reason for us to send a terminate + // packet back to them as well (as it will almost always result in some for of unreachable-destination reply) + // so, put ourselves in silent-disconnect mode when this happens + SetSilentDisconnect(true); + InternalDisconnect(0, cDisconnectReasonOtherSideTerminated); + return; + } + break; + } + case cUdpPacketUnreachableConnection: + { + if (mUdpManager->mParams.allowPortRemapping) + { + if (mPortRemapRequestStartStamp == 0) + { + mPortRemapRequestStartStamp = mUdpManager->CachedClock(); + } + + enum { cMaximumTimeAllowedForPortRemapping = 5000 }; + if (mUdpManager->CachedClockElapsed(mPortRemapRequestStartStamp) < cMaximumTimeAllowedForPortRemapping) + { + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = cUdpPacketRequestRemap; + bufPtr += UdpMisc::PutValue32(bufPtr, mConnectCode); + bufPtr += UdpMisc::PutValue32(bufPtr, mConnectionConfig.encryptCode); + RawSend(buf, (int)(bufPtr - buf)); // since the destination doesn't have an associated connection for us to decrypt us, we must be sent unencrypted + break; + } + } + + InternalDisconnect(0, cDisconnectReasonUnreachableConnection); + return; + break; + } + case cUdpPacketMulti: + { + const udp_uchar *ptr = data + 2; + const udp_uchar *endPtr = data + dataLen; + while (ptr < endPtr) + { + int len = *(const udp_uchar *)ptr++; + const udp_uchar *nextPtr = ptr + len; + if (nextPtr > endPtr) + { + // multi-packet lengths didn't properly add up to total packet length + // meaning we likely got a corrupt packet. If you have CRC bytes enabled, it seems + // quite unlikely this could ever occur. Odds are it has happened because the application + // (while processing this packet) ended up touching the packet-data and corrupting the next + // packet in the multi-sequence. + CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonMultiPacket); + if (mUdpManager == NULL) + return; + } + else + { + ProcessCookedPacket(ptr, len); + } + ptr = nextPtr; + } + break; + } + case cUdpPacketClockSync: + { + // unpacket UdpPacketClockSync packet + UdpPacketClockSync pp; + pp.zeroByte = *data; + pp.packetType = *(data + 1); + pp.timeStamp = UdpMisc::GetValue16(data + 2); + pp.masterPingTime = UdpMisc::GetValue32(data + 4); + pp.averagePingTime = UdpMisc::GetValue32(data + 8); + pp.lowPingTime = UdpMisc::GetValue32(data + 12); + pp.highPingTime = UdpMisc::GetValue32(data + 16); + pp.lastPingTime = UdpMisc::GetValue32(data + 20); + pp.ourSent = UdpMisc::GetValue64(data + 24); + pp.ourReceived = UdpMisc::GetValue64(data + 32); + + mConnectionStats.averagePingTime = pp.averagePingTime; + mConnectionStats.highPingTime = pp.highPingTime; + mConnectionStats.lowPingTime = pp.lowPingTime; + mConnectionStats.lastPingTime = pp.lastPingTime; + mConnectionStats.masterPingTime = pp.masterPingTime; + mConnectionStats.syncOurReceived = mConnectionStats.totalPacketsReceived; + mConnectionStats.syncOurSent = mConnectionStats.totalPacketsSent; + mConnectionStats.syncTheirReceived = pp.ourReceived; + mConnectionStats.syncTheirSent = pp.ourSent; + + if (mUdpManager->mProcessingInducedLag > 1000) // if it has been over a second since our manager got processing time, then we should not reflect clock-sync packets as we will have introduced too much lag ourselves. + break; + + // prepare UdpPacketClockReflect packet + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = cUdpPacketClockReflect; + bufPtr += UdpMisc::PutValue16(bufPtr, pp.timeStamp); // timeStamp + bufPtr += UdpMisc::PutValue32(bufPtr, mUdpManager->LocalSyncStampLong()); // serverSyncStampLong + bufPtr += UdpMisc::PutValue64(bufPtr, pp.ourSent); // yourSent + bufPtr += UdpMisc::PutValue64(bufPtr, pp.ourReceived); // yourReceived + bufPtr += UdpMisc::PutValue64(bufPtr, mConnectionStats.totalPacketsSent); // ourSent + bufPtr += UdpMisc::PutValue64(bufPtr, mConnectionStats.totalPacketsReceived); // ourReceived + PhysicalSend(buf, (int)(bufPtr - buf), true); + break; + } + case cUdpPacketClockReflect: + { + UdpPacketClockReflect pp; + pp.zeroByte = *data; + pp.packetType = *(data + 1); + pp.timeStamp = UdpMisc::GetValue16(data + 2); + pp.serverSyncStampLong = UdpMisc::GetValue32(data + 4); + pp.yourSent = UdpMisc::GetValue64(data + 8); + pp.yourReceived = UdpMisc::GetValue64(data + 16); + pp.ourSent = UdpMisc::GetValue64(data + 24); + pp.ourReceived = UdpMisc::GetValue64(data + 32); + + mConnectionStats.syncOurReceived = pp.yourReceived; + mConnectionStats.syncOurSent = pp.yourSent; + mConnectionStats.syncTheirReceived = pp.ourReceived; + mConnectionStats.syncTheirSent = pp.ourSent; + + if (mUdpManager->mProcessingInducedLag > 1000) // if it has been over a second since our manager got processing time, then we should ignore the timing aspects of the clock-sync packets as we will have introduced too much lag ourselves. + break; + + udp_ushort curStamp = mUdpManager->LocalSyncStampShort(); + int roundTime = UdpMisc::SyncStampShortDeltaTime(pp.timeStamp, curStamp); + + mSyncStatCount++; + mSyncStatTotal += roundTime; + if (mSyncStatLow == 0 || roundTime < mSyncStatLow) + mSyncStatLow = roundTime; + if (roundTime > mSyncStatHigh) + mSyncStatHigh = roundTime; + mSyncStatLast = roundTime; + + // see if we should use this sync to reset the master sync time + // if have better (or close to better) round time or it has been a while + int elapsed = mUdpManager->CachedClockElapsed(mSyncStatMasterFixupTime); + if (roundTime <= mSyncStatMasterRoundTime + 20 || elapsed > 120000) + { + // resync on this packet unless this packet is a real loser (unless it just been a very long time, then sync up anyhow) + if (roundTime < mSyncStatMasterRoundTime * 2 || elapsed > 240000) + { + mSyncTimeDelta = (pp.serverSyncStampLong - mUdpManager->LocalSyncStampLong()) + (udp_uint)(roundTime / 2); + mSyncStatMasterFixupTime = mUdpManager->CachedClock(); + mSyncStatMasterRoundTime = roundTime; + } + } + + // update connection statistics + mConnectionStats.averagePingTime = (mSyncStatCount > 0) ? (mSyncStatTotal / mSyncStatCount) : 0; + mConnectionStats.highPingTime = mSyncStatHigh; + mConnectionStats.lowPingTime = mSyncStatLow; + mConnectionStats.lastPingTime = roundTime; + mConnectionStats.masterPingTime = mSyncStatMasterRoundTime; + break; + } + case cUdpPacketKeepAlive: + break; + case cUdpPacketReliable1: + case cUdpPacketReliable2: + case cUdpPacketReliable3: + case cUdpPacketReliable4: + case cUdpPacketFragment1: + case cUdpPacketFragment2: + case cUdpPacketFragment3: + case cUdpPacketFragment4: + { + int num = (data[1] - cUdpPacketReliable1) % cReliableChannelCount; + if (mChannel[num] == NULL) + mChannel[num] = new UdpReliableChannel(num, this, &mUdpManager->mParams.reliable[num]); + mChannel[num]->ReliablePacket(data, dataLen); + break; + } + case cUdpPacketAck1: + case cUdpPacketAck2: + case cUdpPacketAck3: + case cUdpPacketAck4: + { + int num = data[1] - cUdpPacketAck1; + if (mChannel[num] != NULL) + mChannel[num]->AckPacket(data, dataLen); + break; + } + case cUdpPacketAckAll1: + case cUdpPacketAckAll2: + case cUdpPacketAckAll3: + case cUdpPacketAckAll4: + { + int num = data[1] - cUdpPacketAckAll1; + if (mChannel[num] != NULL) + mChannel[num]->AckAllPacket(data, dataLen); + break; + } + case cUdpPacketGroup: + { + const udp_uchar *ptr = data + 2; + const udp_uchar *endPtr = data + dataLen; + while (ptr < endPtr) + { + udp_uint len; + ptr += UdpMisc::GetVariableValue(ptr, &len); + + if (ptr > endPtr || len > (udp_uint)(endPtr - ptr)) + { + // specified more data in this piece than is left in the entire packet + // this is either corruption, or more likely a hacker + CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonMisformattedGroup); + break; + } + + ProcessCookedPacket(ptr, len); + ptr += len; + } + break; + } + } + } + else + { + CallbackRoutePacket(data, dataLen); + } +} + +void UdpConnection::FlushChannels() +{ + UdpRef ref(this); // in case application tries to delete us during this give time (could only occur due to a ConnectComplete callback timeout) + UdpGuard myGuard(&mGuard); + + GiveTime(false); // gives our reliable channels time to send any data recently added to their queues. Reschedules us as well, which is ok. + FlushMultiBuffer(); +} + +void UdpConnection::FlagPortUnreachable() +{ + mFlaggedPortUnreachable = true; +} + +void UdpConnection::GiveTime(bool fromManager) +{ + UdpGuard myGuard(&mGuard); + if (mUdpManager == NULL) + return; + + if (fromManager && GetRefCount() == 2) + { + // if the manager's connection list and it's stack-variable are our only two references, then the application + // has forsaken us, so disconnect + InternalDisconnect(0, cDisconnectReasonApplicationReleased); + return; + } + + UdpRef manRef(mUdpManager); // hold a reference to the UdpManager so it doesn't disappear while we are inside our GiveTime + mGettingTime = true; // lets the internal code know we are in the process of getting time. We do this so when actual packets are sent while we are getting time, we don't reprioritize ourselves to 0 + InternalGiveTime(); + mGettingTime = false; +} + +void UdpConnection::InternalGiveTime() +{ + udp_uchar buf[256]; + udp_uchar *bufPtr; + + int nextSchedule = 10 * 60 * 1000; // give us time in 10 minutes (unless somebody wants it sooner) + mConnectionStats.iterations++; + + if (mFlaggedPortUnreachable) + { + mFlaggedPortUnreachable = false; + PortUnreachable(); + } + + switch(mStatus) + { + case cStatusNegotiating: + { + if (mConnectAttemptTimeout > 0 && ConnectionAge() > mConnectAttemptTimeout) + { + InternalDisconnect(0, cDisconnectReasonConnectFail); + return; + break; + } + + int elapsed = mUdpManager->CachedClockElapsed(mLastSendTime); + if (elapsed >= mUdpManager->mParams.connectAttemptDelay) + { + // prepare UdpPacketConnect packet + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = cUdpPacketConnect; + bufPtr += UdpMisc::PutValue32(bufPtr, UdpManager::cProtocolVersion); + bufPtr += UdpMisc::PutValue32(bufPtr, mConnectCode); + bufPtr += UdpMisc::PutValue32(bufPtr, mUdpManager->mParams.maxRawPacketSize); + RawSend(buf, (int)(bufPtr - buf)); + elapsed = 0; + } + + nextSchedule = udpMin(nextSchedule, mUdpManager->mParams.connectAttemptDelay - elapsed); + break; + } + case cStatusConnected: + case cStatusDisconnectPending: + { + // sync clock if required + if (mUdpManager->mParams.clockSyncDelay > 0) + { + // sync periodically. If our current master round time is very bad, then sync more frequently (this is important to quickly get a sync up and running) + int elapsed = mUdpManager->CachedClockElapsed(mLastClockSyncTime); + if (elapsed > mUdpManager->mParams.clockSyncDelay + || (mSyncStatMasterRoundTime > 3000 && elapsed > 2000) + || (mSyncStatMasterRoundTime > 1000 && elapsed > 5000) + || (mSyncStatCount < 2 && elapsed > 10000)) + { + // send a clock-sync packet + int averagePing = (mSyncStatCount > 0) ? (mSyncStatTotal / mSyncStatCount) : 0; + + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = cUdpPacketClockSync; + bufPtr += UdpMisc::PutValue16(bufPtr, mUdpManager->LocalSyncStampShort()); // timeStamp + bufPtr += UdpMisc::PutValue32(bufPtr, mSyncStatMasterRoundTime); // masterPingTime + bufPtr += UdpMisc::PutValue32(bufPtr, averagePing); // averagePingTime + bufPtr += UdpMisc::PutValue32(bufPtr, mSyncStatLow); // lowPingTime + bufPtr += UdpMisc::PutValue32(bufPtr, mSyncStatHigh); // highPingTime + bufPtr += UdpMisc::PutValue32(bufPtr, mSyncStatLast); // lastPingTime + bufPtr += UdpMisc::PutValue64(bufPtr, mConnectionStats.totalPacketsSent + 1); // ourSent (add 1 to include this packet we are about to send since other side will count it as received before getting it) + bufPtr += UdpMisc::PutValue64(bufPtr, mConnectionStats.totalPacketsReceived); // ourReceived + PhysicalSend(buf, (int)(bufPtr - buf), true); // don't buffer this, we need it to be as timely as possible, it still needs to be encrypted though, so don't raw send it. + + mLastClockSyncTime = mUdpManager->CachedClock(); + elapsed = 0; + } + + // schedule us next time for a clock-sync packet + nextSchedule = udpMin(nextSchedule, mUdpManager->mParams.clockSyncDelay - elapsed); + } + + // give reliable channels processing time and see when they want more time + int totalPendingBytes = 0; + for (int i = 0; i < cReliableChannelCount; i++) + { + if (mChannel[i] != NULL) + { + totalPendingBytes += mChannel[i]->TotalPendingBytes(); + int myNext = mChannel[i]->GiveTime(); + if (mUdpManager == NULL) + return; // giving the reliable channel time caused it to callback the application which may disconnect us + nextSchedule = udpMin(nextSchedule, myNext); + } + } + + if (mUdpManager->mParams.reliableOverflowBytes != 0 && totalPendingBytes >= mUdpManager->mParams.reliableOverflowBytes) + { + InternalDisconnect(0, cDisconnectReasonReliableOverflow); + return; + } + + // if we have multi-buffer data + if (mMultiBufferPtr - mMultiBufferData > 2) + { + int elapsed = mUdpManager->CachedClockElapsed(mDataHoldTime); + if (elapsed >= mUdpManager->mParams.maxDataHoldTime) + FlushMultiBuffer(); // having just sent it, there is no data in the buffer so no reason to adjust the schedule for when it may be needed again + else + nextSchedule = udpMin(nextSchedule, mUdpManager->mParams.maxDataHoldTime - elapsed); // schedule us processing time for when it does need to be sent + } + + // see if we need to keep connection alive + int elapsed = mUdpManager->CachedClockElapsed(mLastSendTime); + if (mKeepAliveDelay > 0) + { + if (elapsed >= mKeepAliveDelay) + { + // send keep-alive packet + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = cUdpPacketKeepAlive; + PhysicalSend(buf, (int)(bufPtr - buf), true); + elapsed = 0; + } + + // schedule us next time for a keep-alive packet + nextSchedule = udpMin(nextSchedule, mKeepAliveDelay - elapsed); + } + + // see if we need to keep the port alive + if (mUdpManager->mParams.portAliveDelay > 0) + { + int portElapsed = mUdpManager->CachedClockElapsed(mLastPortAliveTime); + if (portElapsed >= mUdpManager->mParams.portAliveDelay) + { + mLastPortAliveTime = mUdpManager->CachedClock(); + mUdpManager->SendPortAlive(mIp, mPort); + portElapsed = 0; + } + + // schedule us next time for a keep-alive packet + nextSchedule = udpMin(nextSchedule, mUdpManager->mParams.portAliveDelay - portElapsed); + } + + if (mStatus == cStatusDisconnectPending) + { + int timeLeft = mDisconnectFlushTimeout - mUdpManager->CachedClockElapsed(mDisconnectFlushStamp); + if (timeLeft < 0 || TotalPendingBytes() == 0) + { + InternalDisconnect(0, mDisconnectReason); + return; + } + else + { + nextSchedule = udpMin(nextSchedule, timeLeft); + } + } + + if (mNoDataTimeout > 0) + { + int lrt = LastReceive(); + if (lrt >= mNoDataTimeout) + { + InternalDisconnect(0, cDisconnectReasonTimeout); + return; + } + else + { + nextSchedule = udpMin(nextSchedule, mNoDataTimeout - lrt); + } + } + + break; + } + default: + break; + } + + if (mUdpManager != NULL) + { + // safety to prevent us for scheduling ourselves for a time period that has already passed, + // as doing so could result in infinite looping in the priority queue processing. + // in theory this cannot happen, I should likely assert here just to make sure... + if (nextSchedule < 0) + nextSchedule = 0; + + mUdpManager->SetPriority(this, mUdpManager->CachedClock() + nextSchedule + 5); // add 5ms to ensure that we are indeed slightly past the scheduled time + } +} + +int UdpConnection::TotalPendingBytes() const +{ + UdpGuard myGuard(&mGuard); + + int total = 0; + for (int i = 0; i < cReliableChannelCount; i++) + { + if (mChannel[i] != NULL) + total += mChannel[i]->TotalPendingBytes(); + } + return(total); +} + +void UdpConnection::RawSend(const udp_uchar *data, int dataLen) +{ + // raw send resets last send time, so we need to potentially recalculate when we need time again + // sends the actual physical packet (usually just after it has be prepped by PacketSend, but for connect/confirm/unreachable packets are bypass that step) + mUdpManager->ActualSend(data, dataLen, mIp, mPort); + mConnectionStats.totalPacketsSent++; + mConnectionStats.totalBytesSent += dataLen; + mLastPortAliveTime = mLastSendTime = mUdpManager->CachedClock(); + + // track data rate + ExpireSendBin(); + mSendBin[mLastSendBin % cBinCount] += dataLen; + mOutgoingBytesLastSecond += dataLen; + ScheduleTimeNow(); +} + +void UdpConnection::ExpireSendBin() +{ + udp_int64 curBin = mUdpManager->CachedClock() / cBinResolution; + udp_int64 binDiff = curBin - mLastSendBin; + if (binDiff > cBinCount) + { + memset(mSendBin, 0, sizeof(mSendBin)); + mOutgoingBytesLastSecond = 0; + } + else + { + for (udp_int64 i = 0; i < binDiff; i++) + { + int clearBin = (int)((curBin + i) % cBinCount); + mOutgoingBytesLastSecond -= mSendBin[clearBin]; + mSendBin[clearBin] = 0; + } + } + mLastSendBin = curBin; +} + +void UdpConnection::ExpireReceiveBin() +{ + udp_int64 curBin = mUdpManager->CachedClock() / cBinResolution; + udp_int64 binDiff = curBin - mLastReceiveBin; + if (binDiff > cBinCount) + { + memset(mReceiveBin, 0, sizeof(mReceiveBin)); + mIncomingBytesLastSecond = 0; + } + else + { + for (udp_int64 i = 0; i < binDiff; i++) + { + int clearBin = (int)((curBin + i) % cBinCount); + mIncomingBytesLastSecond -= mReceiveBin[clearBin]; + mReceiveBin[clearBin] = 0; + } + } + mLastReceiveBin = curBin; +} + +void UdpConnection::PhysicalSend(const udp_uchar *data, int dataLen, bool appendAllowed) +{ + if (mUdpManager == NULL) + return; + + // if we attempt to do a physical send (ie. encrypt/compress/crc a packet) while we are not connected + // (especially if we are cStatusNegotiating), then it will potentially crash, because in the case of + // cStatusNegotiating, we don't have the encryption method function pointer initialized yet, as the method + // is part of the negotiations + if (mStatus != cStatusConnected && mStatus != cStatusDisconnectPending) + return; + + // this is physical packet send routine that compressed, encrypts the packet, and adds crc bytes to it as appropriate + // no need to make sure we don't encrypt a connect/confirm/unreachable packet because those go directly to RawSend. + udp_uchar tempEncryptBuffer[2][UdpManager::cHardMaxRawPacketSize + sizeof(int)]; + const udp_uchar *finalStart = data; + int finalLen = dataLen; + for (int j = 0; j < cEncryptPasses; j++) + { + if (mConnectionConfig.encryptMethod[j] != cEncryptMethodNone) + { + udp_uchar *destStart = tempEncryptBuffer[j % 2]; + *(int *)(destStart + finalLen + mEncryptExpansionBytes) = (int)0xcececece; // overwrite debug signature + + udp_uchar *destPtr = destStart; + *destPtr++ = finalStart[0]; + if (finalStart[0] == 0) + { + // we know this internal packet will not be a connect or confirm packet since they are sent directly to RawSend to avoid getting encrypted + *destPtr++ = finalStart[1]; + int len = (this->*(mEncryptFunction[j]))(destPtr, finalStart + 2, finalLen - 2); + if (mUdpManager == NULL) + return; + + // if this assert triggers, it means the encryption pass expanded the size of the encrypted + // data more than was specified by the userSuppliedEncryptExpansionBytes setting, or at least + // tampered with the destination buffer past that length. This is considered a buffer overwrite + // and will potentially cause bugs. + assert(*(int *)(destStart + finalLen + mEncryptExpansionBytes) == (int)0xcececece); + + if (len == -1) + return; // would be really odd for encryption to return an error, but if it does, throw it away + destPtr += len; + } + else + { + int len = (this->*(mEncryptFunction[j]))(destPtr, finalStart + 1, finalLen - 1); + + // if this assert triggers, it means the encryption pass expanded the size of the encrypted + // data more than was specified by the userSuppliedEncryptExpansionBytes setting, or at least + // tampered with the destination buffer past that length. This is considered a buffer overwrite + // and will potentially cause bugs. + assert(*(int *)(destStart + finalLen + mEncryptExpansionBytes) == (int)0xcececece); + + if (len == -1) + return; // would be really odd for encryption to return an error, but if it does, throw it away + destPtr += len; + } + + finalStart = destStart; + finalLen = (int)(destPtr - finalStart); + appendAllowed = true; + } + } + + if (mConnectionConfig.crcBytes > 0) + { + if (!appendAllowed) + { + // if the buffer we are going to append onto was our original (ie. no encryption took place) + // then we have to copy it all over to a temp buffer since we can't modify the original + memcpy(tempEncryptBuffer[0], finalStart, finalLen); + finalStart = tempEncryptBuffer[0]; + } + + int crc = UdpMisc::Crc32(finalStart, finalLen, mConnectionConfig.encryptCode); + udp_uchar *crcPtr = const_cast(finalStart) + finalLen; // safe cast, since we make a copy of the data above if we would have ended up appending to the original + switch(mConnectionConfig.crcBytes) + { + case 1: + *crcPtr = (udp_uchar)(crc & 0xff); + break; + case 2: + UdpMisc::PutValue16(crcPtr, (udp_ushort)(crc & 0xffff)); + break; + case 3: + UdpMisc::PutValue24(crcPtr, crc & 0xffffff); + break; + case 4: + UdpMisc::PutValue32(crcPtr, crc); + break; + } + finalLen += mConnectionConfig.crcBytes; + } + + RawSend(finalStart, finalLen); +} + + // returns where it placed the data in the buffer (if it ended up in the buffer), such that the reliable channel + // can note where the ack was placed and replace it +udp_uchar *UdpConnection::BufferedSend(const udp_uchar *data, int dataLen, const udp_uchar *data2, int dataLen2, bool appendAllowed) +{ + if (mUdpManager == NULL) + return(NULL); + int used = (int)(mMultiBufferPtr - mMultiBufferData); + + int actualMaxDataHoldSize = udpMin(mUdpManager->mParams.maxDataHoldSize, mConnectionConfig.maxRawPacketSize); + + int totalDataLen = dataLen + dataLen2; + if (totalDataLen > 255 || (totalDataLen + 3) > actualMaxDataHoldSize) + { + // too long of data to even attempt a multi-buffer of this packet, so let's just send it unbuffered + // but first, to ensure the packet-order integrity is somewhat maintained, flush the multi-buffer + // if it currently has something in it + if (used > 2) + FlushMultiBuffer(); + + // now send it (the multi-buffer is empty if you need to use it temporarily to concatenate two data chunks -- it is large enough to hold the largest raw packet) + if (data2 != NULL) + { + memcpy(mMultiBufferData, data, dataLen); + memcpy(mMultiBufferData + dataLen, data2, dataLen2); + PhysicalSend(mMultiBufferData, totalDataLen, true); + } + else + PhysicalSend(data, dataLen, appendAllowed); + return(NULL); + } + + // if this data will not fit into buffer + // note: we allow the multi-packet to grow as large as maxRawPacketSize, but down below we will flush it + // as soon as it gets larger than maxDataHoldSize. + if (used + totalDataLen + 1 > (mConnectionConfig.maxRawPacketSize - mConnectionConfig.crcBytes - mEncryptExpansionBytes)) + { + FlushMultiBuffer(); + used = 0; + } + + // add data to buffer + if (used == 0) + { + // no buffered data yet, create multi-packet header + *mMultiBufferPtr++ = 0; + *mMultiBufferPtr++ = cUdpPacketMulti; + + // new multi-buffer started, so we need to potentially recalculate when we need time again + mDataHoldTime = mUdpManager->CachedClock(); // set data hold time to when the first piece of data is stuck in the multi-buffer + ScheduleTimeNow(); + } + + *(udp_uchar *)mMultiBufferPtr++ = (udp_uchar)totalDataLen; + udp_uchar *placementPtr = mMultiBufferPtr; + memcpy(mMultiBufferPtr, data, dataLen); + mMultiBufferPtr += dataLen; + if (data2 != NULL) + { + memcpy(mMultiBufferPtr, data2, dataLen2); + mMultiBufferPtr += dataLen2; + } + + if ((mMultiBufferPtr - mMultiBufferData) >= actualMaxDataHoldSize) + { + FlushMultiBuffer(); + placementPtr = NULL; // it got flushed + } + return(placementPtr); +} + +void UdpConnection::FlushMultiBuffer() +{ + UdpGuard myGuard(&mGuard); + + int len = (int)(mMultiBufferPtr - mMultiBufferData); + if (len > 2) + { + if ((int)((udp_uchar)mMultiBufferData[2]) + 3 == len) + PhysicalSend(mMultiBufferData + 3, len - 3, true); // only one packet so don't send it as a multi-packet + else + PhysicalSend(mMultiBufferData, len, true); + + // notify all the reliable channels to clear their buffered acks + for (int i = 0; i < cReliableChannelCount; i++) + { + if (mChannel[i] != NULL) + { + mChannel[i]->ClearBufferedAck(); + } + } + + } + mMultiBufferPtr = mMultiBufferData; +} + +int UdpConnection::EncryptNone(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + memcpy(destData, sourceData, sourceLen); + return(sourceLen); +} + +int UdpConnection::DecryptNone(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + memcpy(destData, sourceData, sourceLen); + return(sourceLen); +} + +int UdpConnection::EncryptUserSupplied(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + return(mUdpManager->EncryptUserSupplied(this, destData, sourceData, sourceLen)); +} + +int UdpConnection::DecryptUserSupplied(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + return(mUdpManager->DecryptUserSupplied(this, destData, sourceData, sourceLen)); +} + +int UdpConnection::EncryptUserSupplied2(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + return(mUdpManager->EncryptUserSupplied2(this, destData, sourceData, sourceLen)); +} + +int UdpConnection::DecryptUserSupplied2(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + return(mUdpManager->DecryptUserSupplied2(this, destData, sourceData, sourceLen)); +} + +int UdpConnection::EncryptXorBuffer(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + udp_uchar *destPtr = destData; + const udp_uchar *walkPtr = sourceData; + const udp_uchar *endPtr = sourceData + sourceLen; + udp_uchar *encryptPtr = mEncryptXorBuffer; + int prev = mConnectionConfig.encryptCode; + while ((walkPtr + sizeof(int)) <= endPtr) + { + *(int *)destPtr = *(const int *)walkPtr ^ *(int *)encryptPtr ^ prev; + prev = *(int *)destPtr; + walkPtr += sizeof(int); + destPtr += sizeof(int); + encryptPtr += sizeof(int); + } + + while (walkPtr != endPtr) + { + *destPtr = (udp_uchar)(*walkPtr ^ *encryptPtr); + destPtr++; + walkPtr++; + encryptPtr++; + } + return(sourceLen); +} + +int UdpConnection::DecryptXorBuffer(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + const udp_uchar *walkPtr = sourceData; + const udp_uchar *endPtr = sourceData + sourceLen; + udp_uchar *encryptPtr = mEncryptXorBuffer; + udp_uchar *destPtr = destData; + int hold; + int prev = mConnectionConfig.encryptCode; + while ((walkPtr + sizeof(int)) <= endPtr) + { + hold = *(const int *)walkPtr; + *(int *)destPtr = *(const int *)walkPtr ^ prev ^ *(int *)encryptPtr; + prev = hold; + walkPtr += sizeof(int); + destPtr += sizeof(int); + encryptPtr += sizeof(int); + } + + while (walkPtr != endPtr) + { + *destPtr = (udp_uchar)(*walkPtr ^ *encryptPtr); + walkPtr++; + destPtr++; + encryptPtr++; + } + return(sourceLen); +} + +int UdpConnection::EncryptXor(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + udp_uchar *destPtr = destData; + const udp_uchar *walkPtr = sourceData; + const udp_uchar *endPtr = sourceData + sourceLen; + int prev = mConnectionConfig.encryptCode; + + // this does nothing on intel boxes. This is bit of a hack to make the encryption on big-endian hardware match little-endian hardware + // this needs be done for performance reasons so we can xor 4 bytes at a time without the associated GetValue penalty, and to remain + // protocol compatible with previous versions of hte UdpLibrary that made a bad assumption + char buf[4]; + UdpMisc::PutValueLE32(buf, prev); + prev = *(int *)buf; + + while ((walkPtr + sizeof(int)) <= endPtr) + { + *(int *)destPtr = *(const int *)walkPtr ^ prev; + prev = *(int *)destPtr; + walkPtr += sizeof(int); + destPtr += sizeof(int); + } + + // need to do this fixup again when switching to single-byte comparisons + UdpMisc::PutValueLE32(buf, prev); + prev = *(int *)buf; + + while (walkPtr != endPtr) + { + *destPtr = (udp_uchar)(*walkPtr ^ prev); + destPtr++; + walkPtr++; + } + return(sourceLen); +} + +int UdpConnection::DecryptXor(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + const udp_uchar *walkPtr = sourceData; + const udp_uchar *endPtr = sourceData + sourceLen; + udp_uchar *destPtr = destData; + int hold; + int prev = mConnectionConfig.encryptCode; + + // this does nothing on intel boxes. This is bit of a hack to make the encryption on big-endian hardware match little-endian hardware + // this needs be done for performance reasons so we can xor 4 bytes at a time without the associated GetValue penalty, and to remain + // protocol compatible with previous versions of hte UdpLibrary that made a bad assumption + char buf[4]; + UdpMisc::PutValueLE32(buf, prev); + prev = *(int *)buf; + + while ((walkPtr + sizeof(int)) <= endPtr) + { + hold = *(const int *)walkPtr; + *(int *)destPtr = *(const int *)walkPtr ^ prev; + prev = hold; + walkPtr += sizeof(int); + destPtr += sizeof(int); + } + + // need to do this fixup again when switching to single-byte comparisons + UdpMisc::PutValueLE32(buf, prev); + prev = *(int *)buf; + + while (walkPtr != endPtr) + { + *destPtr = (udp_uchar)(*walkPtr ^ prev); + walkPtr++; + destPtr++; + } + return(sourceLen); +} + +void UdpConnection::SetupEncryptModel() +{ + mEncryptExpansionBytes = 0; + for (int j = 0; j < cEncryptPasses; j++) + { + switch(mConnectionConfig.encryptMethod[j]) + { + default: + assert(0); // unknown encryption method specified during in UdpManager construction + break; + case cEncryptMethodNone: + { + // point to method functions + mDecryptFunction[j] = &UdpConnection::DecryptNone; + mEncryptFunction[j] = &UdpConnection::EncryptNone; + mEncryptExpansionBytes += 0; + break; + } + case cEncryptMethodUserSupplied: + { + // point to method functions + mDecryptFunction[j] = &UdpConnection::DecryptUserSupplied; + mEncryptFunction[j] = &UdpConnection::EncryptUserSupplied; + mEncryptExpansionBytes += mUdpManager->mParams.userSuppliedEncryptExpansionBytes; + break; + } + case cEncryptMethodUserSupplied2: + { + // point to method functions + mDecryptFunction[j] = &UdpConnection::DecryptUserSupplied2; + mEncryptFunction[j] = &UdpConnection::EncryptUserSupplied2; + mEncryptExpansionBytes += mUdpManager->mParams.userSuppliedEncryptExpansionBytes2; + break; + } + case cEncryptMethodXorBuffer: + { + // point to method functions + mDecryptFunction[j] = &UdpConnection::DecryptXorBuffer; + mEncryptFunction[j] = &UdpConnection::EncryptXorBuffer; + mEncryptExpansionBytes += 0; + + // set up encrypt buffer (random numbers generated based on seed) + if (mEncryptXorBuffer == NULL) + { + int len = ((mUdpManager->mParams.maxRawPacketSize + 1) / 4) * 4; + mEncryptXorBuffer = new udp_uchar[len]; + int seed = mConnectionConfig.encryptCode; + udp_uchar *sptr = mEncryptXorBuffer; + for (int i = 0; i < len; i++) + *sptr++ = (udp_uchar)(UdpMisc::Random(&seed) & 0xff); + } + break; + } + case cEncryptMethodXor: + { + // point to method functions + mDecryptFunction[j] = &UdpConnection::DecryptXor; + mEncryptFunction[j] = &UdpConnection::EncryptXor; + mEncryptExpansionBytes += 0; + break; + } + } + } +} + +void UdpConnection::GetChannelStatus(UdpChannel channel, ChannelStatus *channelStatus) const +{ + UdpGuard myGuard(&mGuard); + + memset(channelStatus, 0, sizeof(*channelStatus)); + switch (channel) + { + case cUdpChannelReliable1: + case cUdpChannelReliable2: + case cUdpChannelReliable3: + case cUdpChannelReliable4: + if (mChannel[channel - cUdpChannelReliable1] != NULL) + { + mChannel[channel - cUdpChannelReliable1]->GetChannelStatus(channelStatus); + } + break; + default: + break; + } +} + +const char *UdpConnection::DisconnectReasonText(DisconnectReason reason) +{ + static bool sInitialized = false; + static char *sDisconnectReason[cDisconnectReasonCount]; + + if (!sInitialized) + { + sInitialized = true; + memset(sDisconnectReason, 0, sizeof(sDisconnectReason)); + sDisconnectReason[cDisconnectReasonNone] = "DisconnectReasonNone"; + sDisconnectReason[cDisconnectReasonIcmpError] = "DisconnectReasonIcmpError"; + sDisconnectReason[cDisconnectReasonTimeout] = "DisconnectReasonTimeout"; + sDisconnectReason[cDisconnectReasonOtherSideTerminated] = "DisconnectReasonOtherSideTerminated"; + sDisconnectReason[cDisconnectReasonManagerDeleted] = "DisconnectReasonManagerDeleted"; + sDisconnectReason[cDisconnectReasonConnectFail] = "DisconnectReasonConnectFail"; + sDisconnectReason[cDisconnectReasonApplication] = "DisconnectReasonApplication"; + sDisconnectReason[cDisconnectReasonUnreachableConnection] = "DisconnectReasonUnreachableConnection"; + sDisconnectReason[cDisconnectReasonUnacknowledgedTimeout] = "DisconnectReasonUnacknowledgedTimeout"; + sDisconnectReason[cDisconnectReasonNewConnectionAttempt] = "DisconnectReasonNewConnectionAttempt"; + sDisconnectReason[cDisconnectReasonConnectionRefused] = "DisconnectReasonConnectionRefused"; + sDisconnectReason[cDisconnectReasonMutualConnectError] = "DisconnectReasonConnectError"; + sDisconnectReason[cDisconnectReasonConnectingToSelf] = "DisconnectReasonConnectingToSelf"; + sDisconnectReason[cDisconnectReasonReliableOverflow] = "DisconnectReasonReliableOverflow"; + sDisconnectReason[cDisconnectReasonApplicationReleased] = "DisconnectReasonApplicationReleased"; + sDisconnectReason[cDisconnectReasonCorruptPacket] = "DisconnectReasonCorruptPacket"; + } + + return(sDisconnectReason[reason]); +} + +char *UdpConnection::GetDestinationString(char *buf, int bufLen) const +{ + UdpGuard myGuard(&mGuard); + + if (bufLen < 22) + return(NULL); + UdpPlatformAddress ip = GetDestinationIp(); + int port = GetDestinationPort(); + char hold[256]; + sprintf(buf, "%s:%d", ip.GetAddress(hold, sizeof(hold)), port); + return(buf); +} + +char *UdpConnection::GetDisconnectReasonText(char *buf, int bufLen) const +{ + bufLen--; // leave room for terminating zero + DisconnectReason reason = GetDisconnectReason(); + const char *reasonText = DisconnectReasonText(reason); + if (reason != cDisconnectReasonOtherSideTerminated) + { + UdpMisc::Strncpy(buf, reasonText, bufLen); + return(buf); + } + + DisconnectReason otherReason = GetOtherSideDisconnectReason(); + const char *otherText = DisconnectReasonText(otherReason); + UdpMisc::Strncpy(buf, reasonText, bufLen); + UdpMisc::Strncat(buf, ",", bufLen); + UdpMisc::Strncat(buf, otherText, bufLen); + return(buf); +} + +void UdpConnection::OnRoutePacket(const udp_uchar *data, int dataLen) +{ + UdpGuard myGuard(&mHandlerGuard); + + if (mHandler != NULL) + { + mHandler->OnRoutePacket(this, data, dataLen); + } + else + { + // no handler at time of actually delivery to application of data, means the application must + // have released us, so disconnect for that reason. + // this is a bit screwy. The problem is, if the application releases the connection while the + // event queue has pending data, the connection will not know that it is not longer being + // referenced by the application, so we will disconnect here. + // this (along with the check just after OnConnectRequest) effectively requires that the application + // always have a handler installed or else the connection will potentially get disconnected + InternalDisconnect(0, UdpConnection::cDisconnectReasonApplicationReleased); + } +} + +void UdpConnection::OnConnectComplete() +{ + UdpGuard myGuard(&mHandlerGuard); + if (mHandler != NULL) + { + mHandler->OnConnectComplete(this); + } +} + +void UdpConnection::OnTerminated() +{ + UdpGuard myGuard(&mHandlerGuard); + if (mHandler != NULL) + { + mHandler->OnTerminated(this); + } +} + +void UdpConnection::OnCrcReject(const udp_uchar *data, int dataLen) +{ + UdpGuard myGuard(&mHandlerGuard); + if (mHandler != NULL) + { + mHandler->OnCrcReject(this, data, dataLen); + } +} + +void UdpConnection::OnPacketCorrupt(const udp_uchar *data, int dataLen, UdpCorruptionReason reason) +{ + UdpGuard myGuard(&mHandlerGuard); + if (mHandler != NULL) + { + mHandler->OnPacketCorrupt(this, data, dataLen, reason); + } +} + + + +} // namespace diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpConnection.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpConnection.h new file mode 100644 index 00000000..9d64e460 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpConnection.h @@ -0,0 +1,726 @@ +#ifndef UDPLIBRARY_UDPCONNECTION_H +#define UDPLIBRARY_UDPCONNECTION_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +namespace UdpLibrary +{ + +class UdpReliableChannel; + +struct UdpConnectionStatistics +{ + ///////////////////////////////////////////////////////////////////////// + // these statistics are valid even if clock-sync is not used + // these statistics are never reset and should not be as the negotiated + // packetloss stats would get messed up if they were + // as such, use UdpConnection::ConnectionAge to determine how long they have been accumulating + ///////////////////////////////////////////////////////////////////////// + udp_int64 totalBytesSent; + udp_int64 totalBytesReceived; + udp_int64 totalPacketsSent; // total packets we have sent + udp_int64 totalPacketsReceived; // total packets we have received + udp_int64 crcRejectedPackets; // total packets on our connection that have been rejected due to a crc error + udp_int64 orderRejectedPackets; // total packets on our connection that have been rejected due to an order error (only applicable for ordered channel) + udp_int64 duplicatePacketsReceived; // total reliable packets that we received where we had already received it before and threw it away + udp_int64 resentPacketsAccelerated; // number of times we have resent a packet due to receiving a later packet in the series + udp_int64 resentPacketsTimedOut; // number of times we have resent a packet due to the ack-timeout expiring + udp_int64 applicationPacketsSent; + udp_int64 applicationPacketsReceived; + udp_int64 iterations; // number of times this connection has been given processing time + udp_int64 corruptPacketErrors; // number of misformed/corrupt packets + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // these statistics are only valid if clock-sync'ing is enabled (highly recommended) (will be valid on both client and server side) + // these statistics are reset by PingStatReset and are negotiated periodically by the clock-sync stuff (Params::clockSyncDelay) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + int masterPingAge; // only valid (and applicable) on client side + int masterPingTime; + int averagePingTime; + int lowPingTime; + int highPingTime; + int lastPingTime; + int reliableAveragePing; // the average time (over last 3 acks) for a reliable packet to get acked (when packet is not lost) + udp_int64 syncOurSent; // total packets we have sent at time they reported their numbers + udp_int64 syncOurReceived; // total packets we have received at time they reported their numbers + udp_int64 syncTheirSent; // total packets they have sent + udp_int64 syncTheirReceived; // total packets they have received + float percentSentSuccess; + float percentReceivedSuccess; +}; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // The purpose of the UdpConnection is to manage a single logical connection + //////////////////////////////////////////////////////////////////////////////////////////////////////////// +class UdpConnection : public UdpGuardedRefCount, public PriorityQueueMember, public HashTableMember1, public HashTableMember2 +{ + public: + enum Status { cStatusNegotiating, cStatusConnected, cStatusDisconnected, cStatusDisconnectPending, cStatusCount }; + + enum DisconnectReason { cDisconnectReasonNone, cDisconnectReasonIcmpError, cDisconnectReasonTimeout + , cDisconnectReasonOtherSideTerminated, cDisconnectReasonManagerDeleted + , cDisconnectReasonConnectFail, cDisconnectReasonApplication + , cDisconnectReasonUnreachableConnection, cDisconnectReasonUnacknowledgedTimeout + , cDisconnectReasonNewConnectionAttempt, cDisconnectReasonConnectionRefused + , cDisconnectReasonMutualConnectError, cDisconnectReasonConnectingToSelf + , cDisconnectReasonReliableOverflow, cDisconnectReasonApplicationReleased + , cDisconnectReasonCorruptPacket + , cDisconnectReasonCount }; + + // returns the current status of this connection + Status GetStatus() const; + + // returns the reason that a connection was disconnected. See the enum above for a list of all the reasons + DisconnectReason GetDisconnectReason() const; + char *GetDisconnectReasonText(char *buf, int bufLen) const; + DisconnectReason GetOtherSideDisconnectReason() const; + static const char *DisconnectReasonText(DisconnectReason reason); // text-description of disconnect reason to aid in logging + + // sets the handler object for this connection. If a handler object is specified, then the callback functions specified + // in UdpManager::Params are ignored for this connection and the handler is used for the callback instead. + // by default there is no handler. + void SetHandler(UdpConnectionHandler *handler); + UdpConnectionHandler *GetHandler() const; + + // set and get the pass-through data value. Typically the application will set the pass through data + // in the callback function for establishing a connection, then it will use the pass through data + // in the callback function for routing packets. + void SetPassThroughData(void *passThroughData); + void *GetPassThroughData() const; + + // when called this connection is marked as terminated. It is the responsibility of the application + // to explicitly destroy connections that are no longer connected. When this object is disconnected + // it calls the UdpManager and has itself removed from the list of active connections, at which point + // the only person having a pointer to this object is the application itself (which owns it) + // (if the UdpManager is deleted before all UdpConnections are destroyed, the UdpManager loops through + // all of the connections it has calling Disconnect on them such that they know that they no longer + // have a udp manager that they can send data through) + // + // setting a flushTimeout tells the connection to stay alive for that amount of time trying to send any pending + // reliable data before shutting down. Once the application calls Disconnect even with a flushTimeout, the application + // should not attempt to use the connection in any significant way (see docs and release notes for details) + // note: the notifyApplication parameter was removed from this function and the functionality of the library + // was changed such that ANYTIME the connection objects state changes to cStatusDisconnected, the OnTerminated callback + // function gets called. + void Disconnect(int flushTimeout = 0); + + // sends a logical packet on the specified channel, returns FALSE if packet could not be queued for sending (should never happen) + // Internally, a packet that starts with a 0 byte is considered an internal control packet. If a logical packet starts with a 0 + // byte, then there will an extra control byte of overhead in order to facilitate it. It is recommended that if packet size + // is critical, that you don't start the packet with a 0 byte. Typically an application will have a packet-type byte on the front + // of application packets; the application packet types should simply start at 1. + bool Send(UdpChannel channel, const void *data, int dataLen); + + // same as the regular Send only it takes a LogicalPacket instead. There are two huge advantages to having it take a + // LogicalPacket. First, we can send the same LogicalPacket to multiple locations and each connection will not necessarily + // have to make its own copy of the data at the time it is put into the send queue (instead each connection just increments + // the buffer ref-count). Second, it allows the application to pre-generate very large packets (like file update packets potentially) + // and hold onto them for the entire length of the application, then, whenever any player needs that chunk of data, it can send them + // the already formatted LogicalPacket. + bool Send(UdpChannel channel, const LogicalPacket *packet); + + // manually forces all channels to send-off any data they have queued up waiting for processing time to send + // this mainly applies to reliable channels. When you send a reliable packet, it actually only adds it to the reliable + // queue until the connection is given processing time by the manager object. This call forces it to attempt to + // send that queued data immediately (subject to normal flow control restrictions). This also flushes the multi-buffer + // for the channel. If you send reliable data and want to ensure that it goes out immediately after the send, this is the + // best call to make. + void FlushChannels(); + + // manually forces buffered data to be sent immediately + void FlushMultiBuffer(); + + // returns the number of bytes sent/received in the last second to this connection (accurate to within cBinResolution(25) milliseconds) + // these functions are not const as they expire the older bin data internally in order to calculate the number + int OutgoingBytesLastSecond(); + int IncomingBytesLastSecond(); + + // returns the total number of bytes outstanding in all reliable channels. When this is zero, you know for sure + // that all sent reliable data has arrived at destination and is confirmed. + int TotalPendingBytes() const; + + // returns how long has elapsed since this connection received data (in milliseconds) + int LastReceive() const; + + // returns how long has elapsed since this connection received data (in milliseconds), using useStamp as the current time (optimization) + int LastReceive(UdpClockStamp useStamp) const; + + // returns how long has elapsed since this connection sent data (in milliseconds) + int LastSend() const; + + // returns how long this connection has been in existence (in milliseconds) + int ConnectionAge() const; + + // returns the UdpManager object that is managing this connection + // will return NULL if the connection has been disconnected for some reason (because disconnecting severes the link to UdpManager) + UdpManager *GetUdpManager() const; + + // returns the 32-bit encryption-code that was negotiated as part of the connection-establishment process. + // this is a randomly generated number that both the client and the server have in common. It is exposed + // via this interface primarily to allow user-supplied encrypt routines access to it. + // this code is generated by the server side in response to a connect request. + int GetEncryptCode() const; + + // this returns the connection-code. This is very similar to the encrypt-code in that it is randomly + // generated and both ends of the connection will report the same value. The difference is that this + // code's purpose is part of the internal protocol to ensure that old connections don't try to process + // new connection request packets. Unlike the encrypt-code, this value is generated by the client + // and is part of the connect-request packet. Nevertheless, since this number will be the same random + // number on both ends of the connection, it too can be used as a potential encryption key for the user + // supplied encrypt routines. It's not quite as secure as the encrypt code since this value in theory + // could be hacked to be something predictable on the client side. + int GetConnectCode() const; + + // returns a sync-stamp that can be compared to other ServerSyncStamp's generated on other machines + // in order to calculate the one-way travel time for a packet. It can only accurate calculate + // packet travel times under 32 seconds, would should be completely safe. You must use the + // UdpManager::SyncStampDeltaTime function in order to calculate the elapsed time between + // the two stamps. + udp_ushort ServerSyncStampShort() const; + udp_uint ServerSyncStampLong() const; + int ServerSyncStampShortElapsed(udp_ushort syncStamp) const; + int ServerSyncStampLongElapsed(udp_uint syncStamp) const; + + // returns the IP address/port this connection is linked to + UdpPlatformAddress GetDestinationIp() const; + int GetDestinationPort() const; + char *GetDestinationString(char *buf, int bufLen) const; + + // statistical functions + void GetStats(UdpConnectionStatistics *cs); + void PingStatReset(); // resets the ping-stat information, causing it to resync the clock etc (if in clock-sync mode). Generally this is not done, it was added for backward compatibility + + + // functions for manipulating the automatic no-data-disconnect stuff on a per-connection basis + void SetNoDataTimeout(int noDataTimeout); // 0=never timeout, otherwise in milliseconds (overrides UdpManager::Params::noDataTimeout setting, which is the default) + int GetNoDataTimeout() const; + + // functions for manipulating the keep-alive packet sending on a per-connection basis + void SetKeepAliveDelay(int keepAliveDelay); + int GetKeepAliveDelay() const; + + // configures whether this connection is in silent-disconnect mode or not. By default, the connection is not in silent + // disconnect mode, which means that when this connection is terminated, it will send a final terminate-packet to the + // other side telling them that we are disconnected, allowing them to quickly realize that the connection is now dead. + // In some circumstances, it may be desireable to not do this, and this can be accomplished by calling this function + // passing in 'true' to put it in silent mode. This may be desireable in cases where you are disconnecting a cheater + // and don't want them to have immediate notification that they did something bad. Or, if you are attempting to test + // timeout functionality on the other end and want to simulate a truly dead connection. Normally, you will not want + // to mess with this. It was added to the API to support some internal functionality, see its use in the source-code + // or release-notes for details. + void SetSilentDisconnect(bool silent); + + + // returns the current queue-status of the reliable channel specified. Unreliable channels will always report zero. + struct ChannelStatus + { + int totalPendingBytes; // total bytes of data in channel that have yet to be acknowledged (includes queuedBytes plus physical-packet bytes that have yet to be acknowledged) + int queuedPackets; // number of logical packets in the queue + int queuedBytes; // number of bytes in the logical queue (the logical queue does NOT include pending physical packets) + int incomingLargeTotal; // total number of bytes in the currently incoming logical packet (only meaningful obviously if a fragmented file is in tranist) + int incomingLargeSoFar; // number of bytes received so far in the currently incoming logical packet + int oldestUnacknowledgedAge; // age of the oldest unacknowledged (but sent) packet (in milliseconds) + int duplicatePacketsReceived; // number of times we received a packet that we had already received + int resentPacketsAccelerated; // number of times we have resent a packet due to receiving a later packet in the series + int resentPacketsTimedOut; // number of times we have resent a packet due to the ack-timeout expiring + int congestionSlowStartThreshhold; // current threshhold for slow-start algorithm + int congestionWindowSize; // current sliding window size + int ackAveragePing; // average time for a packet to be acknowledged (used in calculating optimal resend timeouts) + }; + void GetChannelStatus(UdpChannel channel, ChannelStatus *channelStatus) const; + + protected: + friend class UdpManager; + friend class UdpReliableChannel; + + // note: if connectPacket is NULL, that means this connection object is being created to establish + // a new connection to the specified ip/port (ie. the connection starts out in cStatusNegotiating mode) + // if connectPacket is non-NULL, that menas this connection object is being created to handle an + // incoming connect request and it will start out in cStatusConnected mode. + UdpConnection(UdpManager *udpManager, UdpPlatformAddress destIp, int destPort, int timeout); // starts connection-establishment protocol + UdpConnection(UdpManager *udpManager, const UdpManager::PacketHistoryEntry *e); // starts already connected, replying to connection request + + // gives this connection processing time (only given processing time by the manager object and then + // only when the connection has scheduled itself to receive processing time) + void GiveTime(bool fromManager); + void ProcessRawPacket(const UdpManager::PacketHistoryEntry *e); + void PortUnreachable(); + void FlagPortUnreachable(); + + // these functions are called by the manager to forward these events to this connection + // all events get sent to the UdpManager for potential event-queuing, then forwarded back + // to the connection for actual deliver, since the connection object needs to hold a + // guard such that the handler doesn't get deleted during event delivery + void OnRoutePacket(const udp_uchar *data, int dataLen); + void OnConnectComplete(); + void OnTerminated(); + void OnCrcReject(const udp_uchar *data, int dataLen); + void OnPacketCorrupt(const udp_uchar *data, int dataLen, UdpCorruptionReason reason); + + protected: + typedef int (UdpConnection::* IEncryptFunction)(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + typedef int (UdpConnection::* IDecryptFunction)(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + IDecryptFunction mDecryptFunction[cEncryptPasses]; + IEncryptFunction mEncryptFunction[cEncryptPasses]; + + UdpPlatformAddress mIp; + int mPort; + int mSimulateOutgoingQueueBytes; // used by UdpManager to track how many bytes are in it's simulation queue headed to each destination + + private: + ~UdpConnection(); + void Init(UdpManager *udpManager, UdpPlatformAddress destIp, int destPort); + + // note: BufferedSend is capable of optionally taking two chunks of data at once, which are then concatenated together as if they were one chunk of data + // into the multi-buffer. Providing this facility prevents the UdpReliableChannel object from having to make a copy of all the data it sends + // in order to stick a realiable header on it. + // we don't bother extending this down to the PhysicalSend (in case the BufferedSend does a pass through due to size) because the encryption code + // is incapable of sourcing from two different chunks and outputting to one chunk. It's not possible to change that either, since the encyption + // takes place 32 bits at a time and you could end up straddling boundaries between chunks. + void RawSend(const udp_uchar *data, int dataLen); // nothing happens to the data here, it is given to the udpmanager and sent out the port + void PhysicalSend(const udp_uchar *data, int dataLen, bool appendAllowed); // sends a physical packet (encrypts and adds crc bytes) + udp_uchar *BufferedSend(const udp_uchar *data, int dataLen, const udp_uchar *data2, int dataLen2, bool appendAllowed); // buffers logical packets waiting til we have more data (makes multi-packets) + bool InternalSend(UdpChannel channel, const udp_uchar *data, int dataLen, const udp_uchar *data2 = NULL, int dataLen2 = 0); + + void InternalGiveTime(); + void InternalDisconnect(int flushTimeout, DisconnectReason reason); + void ProcessCookedPacket(const udp_uchar *data, int dataLen); + void DecryptIt(const udp_uchar *data, int dataLen); + void ScheduleTimeNow(); + void ExpireSendBin(); + void ExpireReceiveBin(); + void SendTerminatePacket(int connectCode, DisconnectReason reason); + void CallbackRoutePacket(const udp_uchar *data, int dataLen); + void CallbackCorruptPacket(const udp_uchar *data, int dataLen, UdpCorruptionReason reason); + bool IsNonEncryptPacket(const udp_uchar *data) const; + + // these encrypt-method functions return the length of the encrypted/decrypted data + // new methods of encryption/compression can be easily added by simply creating the + // functions for them and changing the SetupEncryptModel function as appropriate + // since raw packets are encrypted in the first place and have a limited size + // the decrypted data will never be larger than a maxRawPacketSize. Both of encrypt + // and decrypt are guaranteed to have enough room in dest buffers to hold the results. + // Encryption function is allowed to expand the data at most the number of bytes + // it reserves for this purpose in the SetupEncryptModel function. + int EncryptNone(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptNone(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int EncryptXor(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptXor(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int EncryptXorBuffer(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptXorBuffer(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int EncryptUserSupplied(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptUserSupplied(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int EncryptUserSupplied2(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptUserSupplied2(udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + void SetupEncryptModel(); + + + UdpLinkedListMember mConnectionLink; + UdpLinkedListMember mDisconnectPendingLink; + + Status mStatus; + void *mPassThroughData; + UdpManager *mUdpManager; + int mConnectCode; + UdpConnectionStatistics mConnectionStats; + UdpClockStamp mConnectionCreateTime; + int mConnectAttemptTimeout; + int mNoDataTimeout; + DisconnectReason mDisconnectReason; + DisconnectReason mOtherSideDisconnectReason; + bool mFlaggedPortUnreachable; + bool mSilentDisconnect; + + UdpReliableChannel *mChannel[cReliableChannelCount]; + + struct Configuration + { + int encryptCode; + int crcBytes; + EncryptMethod encryptMethod[cEncryptPasses]; + int maxRawPacketSize; // negotiated maxRawPacketSize (ie. smaller of what two sides are set to) + }; + + Configuration mConnectionConfig; + int mOtherSideProtocolVersion; + + UdpClockStamp mLastClockSyncTime; + UdpClockStamp mDataHoldTime; + UdpClockStamp mLastSendTime; + UdpClockStamp mLastReceiveTime; + UdpClockStamp mLastPortAliveTime; + udp_uchar *mMultiBufferData; + udp_uchar *mMultiBufferPtr; + + int mOrderedCountOutgoing; + int mOrderedCountOutgoing2; + udp_ushort mOrderedStampLast; + udp_ushort mOrderedStampLast2; + + udp_uchar *mEncryptXorBuffer; + int mEncryptExpansionBytes; + + udp_uint mSyncTimeDelta; + int mSyncStatTotal; + int mSyncStatCount; + int mSyncStatLow; + int mSyncStatHigh; + int mSyncStatLast; + int mSyncStatMasterRoundTime; + UdpClockStamp mSyncStatMasterFixupTime; + + bool mGettingTime; + UdpConnectionHandler *mHandler; + + int mKeepAliveDelay; + + UdpClockStamp mIcmpErrorRetryStartStamp; + UdpClockStamp mPortRemapRequestStartStamp; + + UdpClockStamp mDisconnectFlushStamp; + int mDisconnectFlushTimeout; + mutable UdpPlatformGuardObject mGuard; + mutable UdpPlatformGuardObject mHandlerGuard; + + + // data rate management functions + enum { cBinResolution = 25, cBinCount = 1000 / cBinResolution }; + udp_int64 mLastSendBin; + udp_int64 mLastReceiveBin; + int mOutgoingBytesLastSecond; + int mIncomingBytesLastSecond; + int mSendBin[cBinCount]; + int mReceiveBin[cBinCount]; + + + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // The following structs represent what the internal packets look like. In practice, most of these + // structs are never used and exist only for documentation clarity. Internally packets are + // manually assembled such that struct packing and byte-ordering issues won't be an issue. + ////////////////////////////////////////////////////////////////////////////////////////////////////// + struct UdpPacketConnect + { + udp_uchar zeroByte; + udp_uchar packetType; + int protocolVersion; + int connectCode; + int maxRawPacketSize; + }; + + struct UdpPacketConfirm + { + udp_uchar zeroByte; + udp_uchar packetType; + int connectCode; + Configuration config; + int maxRawPacketSize; + }; + + struct UdpPacketTerminate + { + udp_uchar zeroByte; + udp_uchar packetType; + int connectCode; + }; + + struct UdpPacketKeepAlive + { + udp_uchar zeroByte; + udp_uchar packetType; + }; + + struct UdpPacketGroup + { + // this format is prepped by the GroupLogicalPacket object, which reports itself to the UdpConnection object as an internal packet + // type such that it doesn't get treated as an application-packet even though the application is the one sending it + udp_uchar zeroByte; + udp_uchar packetType; + // variableValue/data, repeated... + }; + + struct UdpPacketClockSync + { + udp_uchar zeroByte; + udp_uchar packetType; + udp_ushort timeStamp; + int masterPingTime; + int averagePingTime; + int lowPingTime; + int highPingTime; + int lastPingTime; + udp_int64 ourSent; + udp_int64 ourReceived; + }; + + struct UdpPacketClockReflect + { + udp_uchar zeroByte; + udp_uchar packetType; + udp_ushort timeStamp; + udp_uint serverSyncStampLong; + udp_int64 yourSent; + udp_int64 yourReceived; + udp_int64 ourSent; + udp_int64 ourReceived; + }; + + struct UdpPacketReliable + { + udp_uchar zeroByte; + udp_uchar packetType; + udp_ushort reliableStamp; + }; + + struct UdpPacketReliableFragmentStart + { + UdpPacketReliable reliable; + int length; + }; + + struct UdpPacketAck + { + udp_uchar zeroByte; + udp_uchar packetType; + udp_ushort reliableStamp; + }; + + struct UdpPacketOrdered + { + udp_uchar zeroByte; + udp_uchar packetType; + udp_ushort orderStamp; + }; + + + enum { cUdpPacketReliableSize = 4 }; + enum { cUdpPacketOrderedSize = 4 }; + + protected: + friend class GroupLogicalPacket; // so it can see cUdpPacketGroup enum + + // note: cUdpPacketReliable, cUdpPacketFragment both indicate a reliable-packet header. They are marked + // differently such that we can support large packets without any additional header overhead, a fragment marked packet means + // that the packet is part of a larger packet being assembled. The first fragment has an additional 4 bytes on the header specifying + // the length to follow. The order of those entries is important + enum UdpPacketType { cUdpPacketZeroEscape, cUdpPacketConnect, cUdpPacketConfirm, cUdpPacketMulti, cUdpPacketBig + , cUdpPacketTerminate, cUdpPacketKeepAlive + , cUdpPacketClockSync, cUdpPacketClockReflect + , cUdpPacketReliable1, cUdpPacketReliable2, cUdpPacketReliable3, cUdpPacketReliable4 + , cUdpPacketFragment1, cUdpPacketFragment2, cUdpPacketFragment3, cUdpPacketFragment4 + , cUdpPacketAck1, cUdpPacketAck2, cUdpPacketAck3, cUdpPacketAck4 + , cUdpPacketAckAll1, cUdpPacketAckAll2, cUdpPacketAckAll3, cUdpPacketAckAll4 + , cUdpPacketGroup, cUdpPacketOrdered, cUdpPacketOrdered2, cUdpPacketPortAlive + , cUdpPacketUnreachableConnection, cUdpPacketRequestRemap }; + +}; + + + ///////////////////////////////////////////////////////////////////////// + // inline implementations + ///////////////////////////////////////////////////////////////////////// + // UdpConnection +inline void UdpConnection::ScheduleTimeNow() +{ + // if we are current in our GiveTime function getting time, then there is no need to reprioritize to 0 when we send a raw packet, since + // the last thing we do in out GiveTime is do a scheduling calculation based on the last time a packet was sent. This little check + // prevents us from reprioritizing to 0, only to shortly thereafter be reprioritized to where we actually belong. + if (!mGettingTime) + { + if (mUdpManager != NULL) + mUdpManager->SetPriority(this, 0); + } +} + +inline void UdpConnection::SetHandler(UdpConnectionHandler *handler) +{ + UdpGuard guard(&mHandlerGuard); + mHandler = handler; +} + +inline UdpConnectionHandler *UdpConnection::GetHandler() const +{ + UdpGuard guard(&mHandlerGuard); + return(mHandler); +} + +inline bool UdpConnection::IsNonEncryptPacket(const udp_uchar *data) const +{ + if (data[0] == 0) + { + if (data[1] == cUdpPacketConnect || data[1] == cUdpPacketConfirm || data[1] == cUdpPacketUnreachableConnection || data[1] == cUdpPacketRequestRemap) + return(true); + } + return(false); +} + +inline int UdpConnection::GetEncryptCode() const +{ + UdpGuard guard(&mGuard); + return(mConnectionConfig.encryptCode); +} + +inline int UdpConnection::GetConnectCode() const +{ + UdpGuard guard(&mGuard); + return(mConnectCode); +} + +inline int UdpConnection::LastReceive(UdpClockStamp useStamp) const +{ + UdpGuard guard(&mGuard); + return(UdpMisc::ClockDiff(mLastReceiveTime, useStamp)); +} + +inline int UdpConnection::LastReceive() const +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + return(mUdpManager->CachedClockElapsed(mLastReceiveTime)); +} + +inline int UdpConnection::ConnectionAge() const +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + return(mUdpManager->CachedClockElapsed(mConnectionCreateTime)); +} + +inline int UdpConnection::LastSend() const +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + return(mUdpManager->CachedClockElapsed(mLastSendTime)); +} + +inline udp_ushort UdpConnection::ServerSyncStampShort() const +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + return((udp_ushort)(mUdpManager->LocalSyncStampShort() + (mSyncTimeDelta & 0xffff))); +} + +inline udp_uint UdpConnection::ServerSyncStampLong() const +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + return(mUdpManager->LocalSyncStampLong() + mSyncTimeDelta); +} + +inline int UdpConnection::ServerSyncStampShortElapsed(udp_ushort syncStamp) const +{ + return(UdpMisc::SyncStampShortDeltaTime(syncStamp, ServerSyncStampShort())); +} + +inline int UdpConnection::ServerSyncStampLongElapsed(udp_uint syncStamp) const +{ + return(UdpMisc::SyncStampLongDeltaTime(syncStamp, ServerSyncStampLong())); +} + +inline UdpManager *UdpConnection::GetUdpManager() const +{ + UdpGuard guard(&mGuard); + return(mUdpManager); +} + +inline UdpConnection::Status UdpConnection::GetStatus() const +{ + UdpGuard guard(&mGuard); + return(mStatus); +} + +inline UdpConnection::DisconnectReason UdpConnection::GetDisconnectReason() const +{ + UdpGuard guard(&mGuard); + return(mDisconnectReason); +} + +inline UdpConnection::DisconnectReason UdpConnection::GetOtherSideDisconnectReason() const +{ + UdpGuard guard(&mGuard); + return(mOtherSideDisconnectReason); +} + +inline int UdpConnection::OutgoingBytesLastSecond() +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + + ExpireSendBin(); + return(mOutgoingBytesLastSecond); +} + +inline int UdpConnection::IncomingBytesLastSecond() +{ + UdpGuard guard(&mGuard); + if (mUdpManager == NULL) + return(0); + + ExpireReceiveBin(); + return(mIncomingBytesLastSecond); +} + +inline void UdpConnection::SetPassThroughData(void *passThroughData) +{ + UdpGuard guard(&mGuard); + mPassThroughData = passThroughData; +} + +inline void *UdpConnection::GetPassThroughData() const +{ + UdpGuard guard(&mGuard); + return(mPassThroughData); +} + +inline UdpPlatformAddress UdpConnection::GetDestinationIp() const +{ + UdpGuard guard(&mGuard); + return(mIp); +} + +inline int UdpConnection::GetDestinationPort() const +{ + UdpGuard guard(&mGuard); + return(mPort); +} + +inline void UdpConnection::SetNoDataTimeout(int noDataTimeout) +{ + UdpGuard guard(&mGuard); + mNoDataTimeout = noDataTimeout; +} + +inline int UdpConnection::GetNoDataTimeout() const +{ + UdpGuard guard(&mGuard); + return(mNoDataTimeout); +} + +inline void UdpConnection::Disconnect(int flushTimeout) +{ + UdpRef ref(this); // in case application releases us during the disconnect, we need to hold this reference so our guard object can be destroyed first + UdpGuard guard(&mGuard); + InternalDisconnect(flushTimeout, cDisconnectReasonApplication); +} + +inline void UdpConnection::SetKeepAliveDelay(int keepAliveDelay) +{ + UdpGuard guard(&mGuard); + mKeepAliveDelay = keepAliveDelay; +} + +inline int UdpConnection::GetKeepAliveDelay() const +{ + UdpGuard guard(&mGuard); + return(mKeepAliveDelay); +} + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriver.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriver.h new file mode 100644 index 00000000..47ceeffc --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriver.h @@ -0,0 +1,124 @@ +#ifndef UDPLIBRARY_UDPDRIVER_H +#define UDPLIBRARY_UDPDRIVER_H + +#include "UdpTypes.h" + +namespace UdpLibrary +{ + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +class UdpDriver +{ + public: + virtual ~UdpDriver() {} + + // socket related functions + virtual bool SocketOpen(int port, int incomingBufferSize, int outgoingBufferSize, const char *bindIpAddress) = 0; // returns true if successful, false if it could not allocate/bind the socket to specified port + virtual void SocketClose() = 0; + virtual int SocketReceive(char *buffer, int bufferSize, UdpPlatformAddress *ipAddress, int *port) = 0; // returns bytes read, -1 if no data, 0 for ICMP errors (from ip/port is filled in with who got the error) + virtual bool SocketSend(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port) = 0; + virtual void SocketSendPortAlive(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port) = 0; + virtual bool SocketGetLocalIp(UdpPlatformAddress *ipAddress) = 0; + virtual int SocketGetLocalPort() = 0; + + // non-socket related functions + virtual bool GetHostByName(UdpPlatformAddress *ipAddress, const char *hostName) = 0; + virtual bool GetSelfAddress(UdpPlatformAddress *ipAddress, bool preferNoRoute) = 0; + virtual void Sleep(int milliseconds) = 0; + virtual UdpClockStamp Clock() = 0; +}; + +class UdpPlatformData; +class UdpPlatformDriver : public UdpDriver +{ + public: + UdpPlatformDriver(); + virtual ~UdpPlatformDriver(); + + // socket related functions + virtual bool SocketOpen(int port, int incomingBufferSize, int outgoingBufferSize, const char *bindIpAddress); + virtual void SocketClose(); + virtual int SocketReceive(char *buffer, int bufferSize, UdpPlatformAddress *ipAddress, int *port); + virtual bool SocketSend(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port); + virtual void SocketSendPortAlive(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port); + virtual bool SocketGetLocalIp(UdpPlatformAddress *ipAddress); + virtual int SocketGetLocalPort(); + + // non-socket related functions that only the platform driver has + virtual bool GetHostByName(UdpPlatformAddress *ipAddress, const char *hostName); + virtual bool GetSelfAddress(UdpPlatformAddress *ipAddress, bool preferNoRoute); + virtual void Sleep(int milliseconds); + virtual UdpClockStamp Clock(); + + private: + UdpPlatformData *mData; +}; + +class UdpPlatformGuardData; +class UdpPlatformGuardObject +{ + public: + UdpPlatformGuardObject(); + ~UdpPlatformGuardObject(); + void Enter(); + void Leave(); + + private: + UdpPlatformGuardData *mData; +}; + +class UdpGuardedRefCount : public UdpRefCount +{ + // portable: implemented in UdpLibrary.cpp + public: + virtual void AddRef() const; + virtual void Release() const; + + protected: + mutable UdpPlatformGuardObject mGuard; +}; + +class UdpPlatformThreadData; +class UdpPlatformThreadObject : public UdpGuardedRefCount +{ + public: + UdpPlatformThreadObject(); + + virtual void Start(); // starts thread running (can't do this in constructor because we need to give derived classes time to finish constructing) + virtual bool IsRunning(); + virtual void Run() = 0; + + protected: + virtual ~UdpPlatformThreadObject(); + + public: + UdpPlatformThreadData *mThreadData; +}; + +class UdpPlatformAddress +{ + public: + UdpPlatformAddress(); + UdpPlatformAddress(const UdpPlatformAddress &source); + bool operator==(const UdpPlatformAddress &e) const; + UdpPlatformAddress &operator=(const UdpPlatformAddress &e); + char *GetAddress(char *buffer, int bufferLen) const; + void SetAddress(const char *address); + int GetHash(); + + protected: + friend class UdpPlatformDriver; + // note: platforms are required to be able to store their representation of the address in these 4 bytes + // if we come across a platform that needs more space than this (or when we start doing IPv6), then we will + // increase this space a bit. This is sufficient for every platform so far and it avoids us having to + // do an allocation, particularly since these things are passed around by-value a lot. + unsigned char mData[4]; +}; + + + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriverLinux.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriverLinux.cpp new file mode 100644 index 00000000..da7bcc5c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriverLinux.cpp @@ -0,0 +1,467 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include "UdpDriver.h" +#include "UdpHelper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // needed by gcc 3.1 for linux +#include + + +namespace UdpLibrary +{ + +typedef int SOCKET; +const int INVALID_SOCKET = 0xFFFFFFFF; +const int SOCKET_ERROR = 0xFFFFFFFF; + +int IcmpReceive(SOCKET socket, unsigned *ipAddress, int *port); + + + //////////////////////////////////////////////////////////// + // internal data definition + //////////////////////////////////////////////////////////// +class UdpPlatformData +{ + public: + SOCKET socket; + unsigned startTtl; + UdpPlatformGuardObject clockGuard; + UdpClockStamp lastStamp; + UdpClockStamp currentCorrection; +}; + +class UdpPlatformGuardData +{ + public: + pthread_mutex_t mutex; +}; + +class UdpPlatformThreadData +{ + public: + pthread_t handle; + bool running; +}; + + + //////////////////////////////////////////////////////////// + // platform specific implementation + //////////////////////////////////////////////////////////// +UdpPlatformDriver::UdpPlatformDriver() +{ + mData = new UdpPlatformData; + mData->socket = INVALID_SOCKET; + mData->startTtl = 32; + mData->currentCorrection = 0; + mData->lastStamp = 0; +} + +UdpPlatformDriver::~UdpPlatformDriver() +{ + delete mData; +} + +bool UdpPlatformDriver::SocketOpen(int port, int incomingBufferSize, int outgoingBufferSize, const char *bindIpAddress) +{ + mData->socket = socket(PF_INET, SOCK_DGRAM, 0); + if (mData->socket != INVALID_SOCKET) + { + // open socket stuff + unsigned long nb = 1; + int err = ioctl(mData->socket, FIONBIO, &nb); + assert(err != -1); + nb = outgoingBufferSize; + err = setsockopt(mData->socket, SOL_SOCKET, SO_SNDBUF, &nb, sizeof(nb)); + assert(err == 0); + nb = incomingBufferSize; + err = setsockopt(mData->socket, SOL_SOCKET, SO_RCVBUF, &nb, sizeof(nb)); + assert(err == 0); + nb = 0; + err = setsockopt(mData->socket, SOL_SOCKET, SO_BSDCOMPAT, &nb, sizeof(nb)); + assert(err == 0); + nb = 1; + err = setsockopt(mData->socket, SOL_IP, IP_RECVERR, &nb, sizeof(nb)); + assert(err == 0); + int optLen = sizeof(mData->startTtl); + getsockopt(mData->socket, IPPROTO_IP, IP_TTL, &mData->startTtl, (socklen_t *)&optLen); + + // bind it to any address + struct sockaddr_in addr_loc; + addr_loc.sin_family = PF_INET; + addr_loc.sin_port = htons((unsigned short)port); + addr_loc.sin_addr.s_addr = htonl(INADDR_ANY); + if (bindIpAddress != NULL && bindIpAddress[0] != 0) + { + unsigned long address = inet_addr(bindIpAddress); + if (address != INADDR_NONE) + { + addr_loc.sin_addr.s_addr = address; // this is already in network order from the call above + } + } + + if (bind(mData->socket, (struct sockaddr *)&addr_loc, sizeof(addr_loc)) != 0) + { + SocketClose(); + return(false); + } + } + else + { + return(false); + } + return(true); +} + +void UdpPlatformDriver::SocketClose() +{ + if (mData->socket != INVALID_SOCKET) + { + close(mData->socket); + mData->socket = INVALID_SOCKET; + } +} + +int UdpPlatformDriver::SocketReceive(char *buffer, int bufferSize, UdpPlatformAddress *ipAddress, int *port) +{ + // check for standard packets + struct sockaddr_in addr_from; + socklen_t sf = sizeof(addr_from); + int res = recvfrom(mData->socket, buffer, bufferSize, 0, (struct sockaddr *)&addr_from, &sf); + if (res != SOCKET_ERROR) + { + memcpy(ipAddress->mData, &addr_from.sin_addr.s_addr, 4); + *port = (int)ntohs(addr_from.sin_port); + return(res); + } + + // out of standard packets, check for ICMP error packets + unsigned address; + int ret = IcmpReceive(mData->socket, &address, port); + memcpy(ipAddress->mData, &address, 4); + return(ret); +} + +bool UdpPlatformDriver::SocketSend(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port) +{ + struct sockaddr_in addr_dest; + addr_dest.sin_family = PF_INET; + memcpy(&addr_dest.sin_addr.s_addr, ipAddress->mData, 4); + addr_dest.sin_port = htons((unsigned short)port); + if (SOCKET_ERROR == sendto(mData->socket, data, dataLen, 0, (struct sockaddr *)&addr_dest, sizeof(addr_dest))) + { + return(false); + } + return(true); +} + +void UdpPlatformDriver::SocketSendPortAlive(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port) +{ + // port alive packet send + unsigned long val = 5; + setsockopt(mData->socket, IPPROTO_IP, IP_TTL, &val, sizeof(val)); + SocketSend(data, dataLen, ipAddress, port); + val = mData->startTtl; + setsockopt(mData->socket, IPPROTO_IP, IP_TTL, &val, sizeof(val)); +} + +bool UdpPlatformDriver::SocketGetLocalIp(UdpPlatformAddress *ipAddress) +{ + struct sockaddr_in addr_self; + memset(&addr_self, 0, sizeof(addr_self)); + socklen_t len = sizeof(addr_self); + getsockname(mData->socket, (struct sockaddr *)&addr_self, &len); + memcpy(ipAddress->mData, &addr_self.sin_addr.s_addr, 4); + return(true); +} + +int UdpPlatformDriver::SocketGetLocalPort() +{ + struct sockaddr_in addr_self; + memset(&addr_self, 0, sizeof(addr_self)); + socklen_t len = sizeof(addr_self); + getsockname(mData->socket, (struct sockaddr *)&addr_self, &len); + return(ntohs(addr_self.sin_port)); +} + +bool UdpPlatformDriver::GetHostByName(UdpPlatformAddress *ipAddress, const char *hostName) +{ + unsigned long address = inet_addr(hostName); + if (address == INADDR_NONE) + { + struct hostent *lphp; + lphp = gethostbyname(hostName); + if (lphp == NULL) + { + address = 0; + } + else + { + address = ((struct in_addr *)(lphp->h_addr))->s_addr; + } + } + + memcpy(ipAddress->mData, &address, 4); + return(address != 0); +} + +bool UdpPlatformDriver::GetSelfAddress(UdpPlatformAddress *ipAddress, bool preferNoRoute) +{ + unsigned long address = 0; + + char hostname[1024]; + if (gethostname(hostname, sizeof(hostname)) == 0) + { + struct hostent *entry = gethostbyname(hostname); + if (entry != NULL) + { + for (int i = 0; entry->h_addr_list[i] != 0; i++) + { + in_addr *sin = (in_addr *)entry->h_addr_list[i]; + int s_net = (sin->s_addr >> 24); + int s_host = ((sin->s_addr >> 16) & 0xff); + + if (address == 0) + { + address = sin->s_addr; + } + else if (s_net != 127) // never return 127.0.0.1 as self address if there is another option + { + bool routeable = true; + if (s_net == 10 || (s_net == 172 && s_host == 16) || (s_net == 192 && s_host == 168)) + { + routeable = false; + } + + if (preferNoRoute && !routeable) + { + address = sin->s_addr; + } + else if (!preferNoRoute && routeable) + { + address = sin->s_addr; + } + } + } + } + } + + memcpy(ipAddress->mData, &address, 4); + return(address != 0); +} + +void UdpPlatformDriver::Sleep(int milliseconds) +{ + struct timeval tv; + tv.tv_sec = milliseconds / 1000; + tv.tv_usec = (milliseconds % 1000) * 1000; + select(0, 0, 0, 0, &tv); +} + +UdpClockStamp UdpPlatformDriver::Clock() +{ + UdpGuard guard(&mData->clockGuard); + + struct timeval tv; + gettimeofday(&tv, NULL); + UdpClockStamp cs = static_cast(tv.tv_sec) * 1000 + static_cast(tv.tv_usec / 1000); + cs += mData->currentCorrection; + if (cs < mData->lastStamp) + { + // clock moved backwards (somebody changed it), don't ever let this happen + // if clock moves forward, there is no way we can recognize it, code will just + // have to deal with it. In the case of the UdpLibrary, it will likely result + // in a ton of pending packets thinking they have gotten lost and being sent, fairly harmless. + mData->currentCorrection += (mData->lastStamp - cs); + cs = mData->lastStamp; + } + mData->lastStamp = cs; + return(cs); +} + +int IcmpReceive(SOCKET socket, unsigned *address, int *port) +{ + // we can use some ICMP errors to our advantage to more quickly realize that the connection on the other end has disappeared + struct sock_extended_err + { + unsigned ee_errno; + unsigned char ee_origin; + unsigned char ee_type; + unsigned char ee_code; + unsigned char ee_pad; + unsigned ee_info; + unsigned ee_data; + }; + + unsigned char msg_control[1024]; + struct msghdr msgh = {0}; + struct sockaddr_in msg_name; + socklen_t sf = sizeof(msg_name); + msgh.msg_name = &msg_name; + msgh.msg_namelen = sf; + msgh.msg_iov = 0; + msgh.msg_iovlen = 0; + msgh.msg_control = msg_control; + msgh.msg_controllen = sizeof(msg_control); + + int err = recvmsg(socket, &msgh, MSG_ERRQUEUE); + if (err == -1) + return(-1); + + struct cmsghdr *cmsg; + for(cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) + { + if(cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) + { + sock_extended_err *ee = (sock_extended_err *)CMSG_DATA(cmsg); + if (ee->ee_origin == 2 && ee->ee_type == ICMP_DEST_UNREACH) // ICMP origin, destination-unreachable error // note: process all code types: && ee->ee_code == ICMP_PORT_UNREACH + { + memcpy(address, &msg_name.sin_addr.s_addr, 4); + *port = (int)ntohs(msg_name.sin_port); + return(0); // ICMP error return + } + } + } + + return(-1); +} + + + //////////////////////////////////////////////////////////// + // UdpPlatformGuardObject object implementation + //////////////////////////////////////////////////////////// +UdpPlatformGuardObject::UdpPlatformGuardObject() +{ + mData = new UdpPlatformGuardData; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mData->mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + +UdpPlatformGuardObject::~UdpPlatformGuardObject() +{ + pthread_mutex_destroy(&mData->mutex); + delete mData; +} + +void UdpPlatformGuardObject::Enter() +{ + pthread_mutex_lock(&mData->mutex); +} + +void UdpPlatformGuardObject::Leave() +{ + pthread_mutex_unlock(&mData->mutex); +} + + + /////////////////////////////////////////////////////////////// + // UdpPlatformThreadObject implementation + /////////////////////////////////////////////////////////////// +void *GoThread(void *param) +{ + UdpPlatformThreadObject *thread = (UdpPlatformThreadObject *)param; + thread->mThreadData->running = true; + thread->Run(); + thread->mThreadData->running = false; + thread->mThreadData->handle = 0; + thread->Release(); + return(NULL); +} + +UdpPlatformThreadObject::~UdpPlatformThreadObject() +{ + delete mThreadData; +} + +void UdpPlatformThreadObject::Start() +{ + AddRef(); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&mThreadData->handle, &attr, &GoThread, (void *)this); + pthread_attr_destroy(&attr); +} + +UdpPlatformThreadObject::UdpPlatformThreadObject() +{ + mThreadData = new UdpPlatformThreadData; + mThreadData->handle = 0; + mThreadData->running = false; +} + +bool UdpPlatformThreadObject::IsRunning() +{ + return(mThreadData->running); +} + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpPlatformAddress implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpPlatformAddress::UdpPlatformAddress() +{ + memset(mData, 0, sizeof(mData)); +} + +UdpPlatformAddress::UdpPlatformAddress(const UdpPlatformAddress &source) +{ + memcpy(mData, source.mData, sizeof(mData)); +} + +UdpPlatformAddress &UdpPlatformAddress::operator=(const UdpPlatformAddress &e) +{ + memcpy(mData, e.mData, sizeof(mData)); + return(*this); +} + +char *UdpPlatformAddress::GetAddress(char *buffer, int bufferLen) const +{ + if (bufferLen < 16) + { + *buffer = 0; + return(buffer); + } + assert(buffer != NULL); + sprintf(buffer, "%d.%d.%d.%d", mData[0], mData[1], mData[2], mData[3]); + return(buffer); +} + +void UdpPlatformAddress::SetAddress(const char *address) +{ + for (int i = 0; i < 4; i++) + { + mData[i] = (unsigned char)strtol(address, NULL, 10); + while (*address >= '0' && *address <= '9') + address++; + if (*address != 0) + address++; + } +} + +bool UdpPlatformAddress::operator==(const UdpPlatformAddress &e) const +{ + return(memcmp(mData, e.mData, sizeof(mData)) == 0); +} + + +int UdpPlatformAddress::GetHash() +{ + return(*(int *)mData); +} + + +} // namespace diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriverWindows.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriverWindows.cpp new file mode 100644 index 00000000..cc47e705 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpDriverWindows.cpp @@ -0,0 +1,421 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#if defined(WIN32) + #define _CRT_SECURE_NO_DEPRECATE // gets rid of deprecation warnings in VS 2005 (don't want to change to secure-versions as it hampers portability) +#endif + +#include "UdpDriver.h" +#include "UdpHelper.h" + +#ifdef WIN32 + +#pragma warning(push, 3) +#pragma warning(disable:4706) +#include +#include +#include + +#ifndef UDPLIBRARY_SINGLE_THREAD + #include +#endif + +#pragma warning(pop) + + +namespace UdpLibrary +{ + +typedef int socklen_t; + + //////////////////////////////////////////////////////////// + // internal data definition + //////////////////////////////////////////////////////////// +class UdpPlatformData +{ + public: + SOCKET socket; + unsigned startTtl; + UdpPlatformGuardObject clockGuard; + unsigned globalLow; + int globalHigh; +}; + +class UdpPlatformGuardData +{ + public: + CRITICAL_SECTION mCriticalSection; +}; + +class UdpPlatformThreadData +{ + public: + HANDLE handle; + bool running; +}; + + + //////////////////////////////////////////////////////////// + // platform specific implementation + //////////////////////////////////////////////////////////// +UdpPlatformDriver::UdpPlatformDriver() +{ + mData = new UdpPlatformData; + mData->socket = INVALID_SOCKET; + mData->startTtl = 32; + mData->globalLow = 0; + mData->globalHigh = 0; + + WSADATA wsaData; + #if defined(UDPLIBRARY_WINSOCK2) + WSAStartup(MAKEWORD(2,0), &wsaData); + #else + WSAStartup(MAKEWORD(1,1), &wsaData); + #endif +} + +UdpPlatformDriver::~UdpPlatformDriver() +{ + WSACleanup(); + + delete mData; +} + +bool UdpPlatformDriver::SocketOpen(int port, int incomingBufferSize, int outgoingBufferSize, const char *bindIpAddress) +{ + mData->socket = socket(PF_INET, SOCK_DGRAM, 0); + if (mData->socket != INVALID_SOCKET) + { + unsigned long lb = 1; + int err = ioctlsocket(mData->socket, FIONBIO, &lb); + int nb = outgoingBufferSize; + err = setsockopt(mData->socket, SOL_SOCKET, SO_SNDBUF, (char *)&nb, sizeof(nb)); + nb = incomingBufferSize; + err = setsockopt(mData->socket, SOL_SOCKET, SO_RCVBUF, (char *)&nb, sizeof(nb)); + int optLen = sizeof(mData->startTtl); + getsockopt(mData->socket, IPPROTO_IP, IP_TTL, (char *)&mData->startTtl, &optLen); + + // bind it to any address + struct sockaddr_in addr_loc; + addr_loc.sin_family = PF_INET; + addr_loc.sin_port = htons((unsigned short)port); + addr_loc.sin_addr.s_addr = htonl(INADDR_ANY); + if (bindIpAddress != NULL && bindIpAddress[0] != 0) + { + unsigned long address = inet_addr(bindIpAddress); + if (address != INADDR_NONE) + { + addr_loc.sin_addr.s_addr = address; // this is already in network order from the call above + } + } + + if (bind(mData->socket, (struct sockaddr *)&addr_loc, sizeof(addr_loc)) != 0) + { + SocketClose(); + return(false); + } + } + else + { + return(false); + } + return(true); +} + +void UdpPlatformDriver::SocketClose() +{ + if (mData->socket != INVALID_SOCKET) + { + closesocket(mData->socket); + mData->socket = INVALID_SOCKET; + } +} + +int UdpPlatformDriver::SocketReceive(char *buffer, int bufferSize, UdpPlatformAddress *ipAddress, int *port) +{ + struct sockaddr_in addr_from; + socklen_t sf = sizeof(addr_from); + int res = recvfrom(mData->socket, buffer, bufferSize, 0, (struct sockaddr *)&addr_from, &sf); + + if (res != SOCKET_ERROR) + { + memcpy(ipAddress->mData, &addr_from.sin_addr.s_addr, 4); + *port = (int)ntohs(addr_from.sin_port); + return(res); + } + + // windows is kind enough to put ICMP error packets inline within the stream as errors, so we + // can easily see the errors indicating that the destination address is unreachable for some reason + if (WSAGetLastError() == WSAECONNRESET) + { + memcpy(ipAddress->mData, &addr_from.sin_addr.s_addr, 4); + *port = (int)ntohs(addr_from.sin_port); + return(0); + } + + return(-1); // no more packets found +} + +bool UdpPlatformDriver::SocketSend(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port) +{ + struct sockaddr_in addr_dest; + addr_dest.sin_family = PF_INET; + memcpy(&addr_dest.sin_addr.s_addr, ipAddress->mData, 4); + addr_dest.sin_port = htons((unsigned short)port); + if (SOCKET_ERROR == sendto(mData->socket, data, dataLen, 0, (struct sockaddr *)&addr_dest, sizeof(addr_dest))) + { + return(false); + } + return(true); +} + +void UdpPlatformDriver::SocketSendPortAlive(const char *data, int dataLen, const UdpPlatformAddress *ipAddress, int port) +{ + int val = 5; + setsockopt(mData->socket, IPPROTO_IP, IP_TTL, (char *)&val, sizeof(val)); + SocketSend(data, dataLen, ipAddress, port); + setsockopt(mData->socket, IPPROTO_IP, IP_TTL, (char *)&mData->startTtl, sizeof(mData->startTtl)); +} + +bool UdpPlatformDriver::SocketGetLocalIp(UdpPlatformAddress *ipAddress) +{ + struct sockaddr_in addr_self; + memset(&addr_self, 0, sizeof(addr_self)); + socklen_t len = sizeof(addr_self); + getsockname(mData->socket, (struct sockaddr *)&addr_self, &len); + memcpy(ipAddress->mData, &addr_self.sin_addr.s_addr, 4); + return(true); +} + +int UdpPlatformDriver::SocketGetLocalPort() +{ + struct sockaddr_in addr_self; + memset(&addr_self, 0, sizeof(addr_self)); + socklen_t len = sizeof(addr_self); + getsockname(mData->socket, (struct sockaddr *)&addr_self, &len); + return(ntohs(addr_self.sin_port)); +} + +bool UdpPlatformDriver::GetHostByName(UdpPlatformAddress *ipAddress, const char *hostName) +{ + unsigned long address = inet_addr(hostName); + if (address == INADDR_NONE) + { + struct hostent *lphp; + lphp = gethostbyname(hostName); + if (lphp == NULL) + { + address = 0; + } + else + { + address = ((struct in_addr *)(lphp->h_addr))->s_addr; + } + } + + memcpy(ipAddress->mData, &address, 4); + return(address != 0); +} + +bool UdpPlatformDriver::GetSelfAddress(UdpPlatformAddress *ipAddress, bool preferNoRoute) +{ + unsigned long address = 0; + + char hostname[1024]; + if (gethostname(hostname, sizeof(hostname)) == 0) + { + struct hostent *entry = gethostbyname(hostname); + if (entry != NULL) + { + for (int i = 0; entry->h_addr_list[i] != 0; i++) + { + in_addr *sin = (in_addr *)entry->h_addr_list[i]; + + if (address == 0) + { + address = sin->s_addr; + } + else if (sin->s_net != 127) // never return 127.0.0.1 as self address if there is another option + { + bool routeable = true; + if (sin->s_net == 10 || (sin->s_net == 172 && sin->s_host == 16) || (sin->s_net == 192 && sin->s_host == 168)) + { + routeable = false; + } + + if (preferNoRoute && !routeable) + { + address = sin->s_addr; + } + else if (!preferNoRoute && routeable) + { + address = sin->s_addr; + } + } + } + } + } + + memcpy(ipAddress->mData, &address, 4); + return(address != 0); +} + +void UdpPlatformDriver::Sleep(int milliseconds) +{ + ::Sleep((DWORD)milliseconds); +} + +UdpClockStamp UdpPlatformDriver::Clock() +{ + UdpGuard guard(&mData->clockGuard); + unsigned low = GetTickCount(); + if (low < mData->globalLow) + { + mData->globalHigh++; + } + mData->globalLow = low; + return(((UdpClockStamp)mData->globalHigh << 32) | low); +} + + //////////////////////////////////////////////////////////// + // UdpPlatformGuardObject object implementation + //////////////////////////////////////////////////////////// +UdpPlatformGuardObject::UdpPlatformGuardObject() +{ +#ifndef UDPLIBRARY_SINGLE_THREAD + mData = new UdpPlatformGuardData; + InitializeCriticalSection(&mData->mCriticalSection); +#endif +} + +UdpPlatformGuardObject::~UdpPlatformGuardObject() +{ +#ifndef UDPLIBRARY_SINGLE_THREAD + DeleteCriticalSection(&mData->mCriticalSection); + delete mData; +#endif +} + +void UdpPlatformGuardObject::Enter() +{ +#ifndef UDPLIBRARY_SINGLE_THREAD + EnterCriticalSection(&mData->mCriticalSection); +#endif +} + +void UdpPlatformGuardObject::Leave() +{ +#ifndef UDPLIBRARY_SINGLE_THREAD + LeaveCriticalSection(&mData->mCriticalSection); +#endif +} + + + /////////////////////////////////////////////////////////////// + // UdpPlatformThreadObject implementation + /////////////////////////////////////////////////////////////// +unsigned __stdcall GoThread(void *param) +{ + UdpPlatformThreadObject *thread = (UdpPlatformThreadObject *)param; + thread->mThreadData->running = true; + thread->Run(); + thread->mThreadData->running = false; + thread->Release(); + return(0); +} + +UdpPlatformThreadObject::~UdpPlatformThreadObject() +{ +#ifndef UDPLIBRARY_SINGLE_THREAD + if (mThreadData->handle != NULL) + { + CloseHandle(mThreadData->handle); + mThreadData->handle = NULL; + } +#endif + delete mThreadData; +} + +void UdpPlatformThreadObject::Start() +{ + AddRef(); +#ifndef UDPLIBRARY_SINGLE_THREAD + unsigned threadId; + mThreadData->handle = (HANDLE)_beginthreadex(NULL, 0, &GoThread, this, 0, &threadId); +#else + GoThread(this); // run it inline in main thread (blocks til it's finished, so odds are it won't work, but they shouldn't be using it anyhow in this mode) +#endif +} + +UdpPlatformThreadObject::UdpPlatformThreadObject() +{ + mThreadData = new UdpPlatformThreadData; + mThreadData->handle = NULL; + mThreadData->running = false; +} + +bool UdpPlatformThreadObject::IsRunning() +{ + return(mThreadData->running); +} + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpPlatformAddress implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpPlatformAddress::UdpPlatformAddress() +{ + memset(mData, 0, sizeof(mData)); +} + +UdpPlatformAddress::UdpPlatformAddress(const UdpPlatformAddress &source) +{ + memcpy(mData, source.mData, sizeof(mData)); +} + +UdpPlatformAddress &UdpPlatformAddress::operator=(const UdpPlatformAddress &e) +{ + memcpy(mData, e.mData, sizeof(mData)); + return(*this); +} + +char *UdpPlatformAddress::GetAddress(char *buffer, int bufferLen) const +{ + if (bufferLen < 16) + { + *buffer = 0; + return(buffer); + } + assert(buffer != NULL); + sprintf(buffer, "%d.%d.%d.%d", mData[0], mData[1], mData[2], mData[3]); + return(buffer); +} + +void UdpPlatformAddress::SetAddress(const char *address) +{ + for (int i = 0; i < 4; i++) + { + mData[i] = (unsigned char)atoi(address); + while (*address >= '0' && *address <= '9') + address++; + if (*address != 0) + address++; + } +} + +bool UdpPlatformAddress::operator==(const UdpPlatformAddress &e) const +{ + return(memcmp(mData, e.mData, sizeof(mData)) == 0); +} + + +int UdpPlatformAddress::GetHash() +{ + return(*(int *)mData); +} + +} // namespace + +#endif // WIN32 + + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHandler.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHandler.h new file mode 100644 index 00000000..cb3ad45b --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHandler.h @@ -0,0 +1,70 @@ +#ifndef UDPLIBRARY_UDPHANDLER_H +#define UDPLIBRARY_UDPHANDLER_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include "UdpTypes.h" + +namespace UdpLibrary +{ + +class UdpManagerHandler +{ + public: + // This function is called when a listening UdpManager receives a new connection request. If the application wishes to + // accept this connection, it is the responsibility of the application to AddRef the UdpConnection object such that it + // doesn't get destroyed upon returning from the callback. Additionally, the application should set the handler object + // for the connection. See sample code in the UdpLibrary.doc file for an example. + virtual void OnConnectRequest(UdpConnection *con); + + // The following functions are called when user-supplied encryption is specified. In particular, the functions may wish + // to query the connection object for the encryption-code it is using. The encryption code is simply a randomly generated + // 32-bit value that the client and server negotiated during the connection-establishment. It can be used as a key + // of sorts for encrypting data uniquely on a per-connection basis. (see UdpConnection::GetEncryptCode()) + // For the encrypt-functions, the destination buffer will be (sourceLen + userSuppliedEncryptExpansionBytes1) long, + // do not overflow it, the debug version has an assert check that ensures that you do not. + // For the decrypt-functions, the destination buffer is guaranteed to be large enough to hold what the original + // data used to be before it was encrypted. + virtual int OnUserSuppliedEncrypt(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + virtual int OnUserSuppliedDecrypt(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + virtual int OnUserSuppliedEncrypt2(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + virtual int OnUserSuppliedDecrypt2(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); +}; + +class UdpConnectionHandler +{ + public: + // This function is called whenever an application-packet is ready to be delivered to the application. + // Packets will only ever be delivered to the application during UdpManager::GiveTime calls, so the application + // has complete control of when it willing/able to receive packets. + virtual void OnRoutePacket(UdpConnection *con, const udp_uchar *data, int dataLen) = 0; + + // This function is called whenever a UdpManager::EstablishConnection call succeeds in establishing the connection. + // Generally on client-side establishment of a connection, I prefer to sit in a tight loop polling the connection + // to see if it has connected yet or not, rather than using this callback (see sample code) + // note: If it is unable to establish the connection, the OnTerminated callback will be called. + // note: this is a change from previous behavior, see release notes for details. + virtual void OnConnectComplete(UdpConnection *con); + + // This function is called anytime the UdpConnection object changes to a cStatusDisconnected state. Every UdpConnection + // object is guaranteed to eventually call this once and only once, even connections that never successfully established. + // note: this is a change from previous behavior, see release notes for details + virtual void OnTerminated(UdpConnection *con); + + // This function is called anytime an incoming packet fails the CRC check. Normally these packets are just ignored, as + // corruption does occur from time to time; however, some applications may wish to log these events as often times, they + // are an indication of somebody attempting to hack the data stream. + virtual void OnCrcReject(UdpConnection *con, const udp_uchar *data, int dataLen); + + // This function is called anytime a corrupt packet is sensed for some reason. + // The reason we give a callback for it is because you may wish to log it as it could be an early indicator of + // somebody trying to hack the protocol. + + virtual void OnPacketCorrupt(UdpConnection *con, const udp_uchar *data, int dataLen, UdpCorruptionReason reason); +}; + +} // namespace + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h new file mode 100644 index 00000000..ba9f1748 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h @@ -0,0 +1,625 @@ +#ifndef UDPLIBRARY_UDPHASHTABLE_H +#define UDPLIBRARY_UDPHASHTABLE_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include +#include + +namespace UdpLibrary +{ + + +int NextPrime(int value); + + + // This is a simple hash table template. Any type of object can be stored in this hash table + // provided it can be copied. Resizing the table while in use is generally not recommended. + // putting the same object in the table twice is generally not recommended as it makes the find ambiguous +struct HashTableStatistics +{ + int tableSize; + int usedSlots; + int totalEntries; +}; + + + ////////////////////////////////////////////////////////////////////////// + // HashTable + ////////////////////////////////////////////////////////////////////////// +template class HashTable +{ + public: + HashTable(int hashSize); + ~HashTable(); + + void Insert(T& obj, int hashValue); + bool Remove(T& obj, int hashValue); + void Reset(); // removes all entries from the table + + T *FindFirst(int hashValue) const; // returns NULL if not found + T *FindNext(T *prevResult) const; // returns NULL if not found + + T *WalkFirst() const; // returns NULL if not found + T *WalkNext(T *prevResult) const; // returns NULL if not found + + void Resize(int hashSize); // the actual hash size will be rounded up to the next larger prime number (very slow, not recommended) + void GetStatistics(HashTableStatistics *stats) const; + + protected: + struct HashEntry + { + T obj; + int hashValue; + HashEntry *nextEntry; + }; + + HashEntry **mTable; + int mTableSize; + int mEntryCount; + int mStatUsedSlots; +}; + + +template HashTable::HashTable(int hashSize) +{ + mTable = NULL; + mTableSize = 0; + mEntryCount = 0; + mStatUsedSlots = 0; + Resize(hashSize); +} + +template HashTable::~HashTable() +{ + Reset(); // deletes everything + delete[] mTable; +} + +template void HashTable::Insert(T& obj, int hashValue) +{ + HashEntry *entry = new HashEntry; + entry->obj = obj; + entry->hashValue = hashValue; + + int spot = ((unsigned)hashValue) % mTableSize; + if (mTable[spot] == NULL) + { + entry->nextEntry = NULL; + mTable[spot] = entry; + mStatUsedSlots++; + } + else + { + entry->nextEntry = mTable[spot]; + mTable[spot] = entry; + } + mEntryCount++; +} + +template bool HashTable::Remove(T& obj, int hashValue) +{ + int spot = ((unsigned)hashValue) % mTableSize; + HashEntry* next = mTable[spot]; + HashEntry** prev = &mTable[spot]; + while (next != NULL) + { + if (next->obj == obj && next->hashValue == hashValue) + { + *prev = next->nextEntry; + delete next; + mEntryCount--; + if (mTable[spot] == NULL) + mStatUsedSlots--; + return(true); + break; + + } + prev = &next->nextEntry; + next = next->nextEntry; + } + return(false); +} + +template void HashTable::Reset() +{ + for (int spot = 0; spot < mTableSize; spot++) + { + HashEntry *curr = mTable[spot]; + if (curr != NULL) + { + mStatUsedSlots--; + while (curr != NULL) + { + HashEntry *next = curr->nextEntry; + delete curr; + mEntryCount--; + curr = next; + } + mTable[spot] = NULL; + } + } +} + +template T *HashTable::FindFirst(int hashValue) const +{ + HashEntry *entry = mTable[((unsigned)hashValue) % mTableSize]; + while (entry != NULL) + { + if (entry->hashValue == hashValue) + return(&entry->obj); + entry = entry->nextEntry; + } + return(NULL); +} + +template T *HashTable::FindNext(T *prevResult) const +{ + HashEntry *entry = (HashEntry *)(((char *)prevResult) - offsetof(HashEntry, obj)); + int hashValue = entry->hashValue; + entry = entry->nextEntry; + while (entry != NULL) + { + if (entry->hashValue == hashValue) + return(&entry->obj); + entry = entry->nextEntry; + } + return(NULL); +} + +template T *HashTable::WalkFirst() const +{ + for (int bucket = 0; bucket < mTableSize; bucket++) + { + HashEntry *entry = mTable[bucket]; + if (entry != NULL) + return(&entry->obj); + } + return(NULL); +} + +template T *HashTable::WalkNext(T *prevResult) const +{ + HashEntry *entry = (HashEntry *)(((char *)prevResult) - offsetof(HashEntry, obj)); + int bucket = ((unsigned)entry->hashValue) % mTableSize; + + entry = entry->nextEntry; + if (entry != NULL) + return(&entry->obj); + + bucket++; // go onto next bucket + for (; bucket < mTableSize; bucket++) + { + HashEntry *entry = mTable[bucket]; + if (entry != NULL) + return(&entry->obj); + } + return(NULL); +} + +template void HashTable::Resize(int hashSize) +{ + HashEntry **oldTable = mTable; + int oldSize = mTableSize; + + // calculate next prime number greater than hashSize. + mTableSize = NextPrime(hashSize); + mTable = new HashEntry*[mTableSize]; + memset(mTable, 0, sizeof(HashEntry *) * mTableSize); + + mStatUsedSlots = 0; + + if (mEntryCount > 0) + { + for (int i = 0; i < oldSize; i++) + { + HashEntry* next = oldTable[i]; + while (next != NULL) + { + HashEntry* hold = next; + next = next->nextEntry; + + // insert hold into new table + int spot = ((unsigned)hold->hashValue) % mTableSize; + if (mTable[spot] == NULL) + { + hold->nextEntry = NULL; + mTable[spot] = hold; + mStatUsedSlots++; + } + else + { + hold->nextEntry = mTable[spot]; + mTable[spot] = hold; + } + } + } + } + + delete[] oldTable; +} + +template void HashTable::GetStatistics(HashTableStatistics *stats) const +{ + stats->totalEntries = mEntryCount; + stats->usedSlots = mStatUsedSlots; + stats->tableSize = mTableSize; +} + + + ////////////////////////////////////////////////////////////////////////////// + // ObjectHashTable + // + // similar to basic HashTable object, only this version requires the contents + // be pointers to objects derived from class HashTableMember. If you can use + // this version, it avoids allocations of HashEntry objects. + // making the cost of object inserts/deletes dirt-cheap + ////////////////////////////////////////////////////////////////////////////// +template class HashTableMember +{ +#if defined(_MSC_VER) && (_MSC_VER < 1300) // MSVC 7.0 is the first version to support friend templates + public: +#else + protected: + template friend class ObjectHashTable; +#endif + int mHashValue; + M *mHashNextEntry; +}; + +template class HashTableMember1 : public HashTableMember {}; +template class HashTableMember2 : public HashTableMember {}; +template class HashTableMember3 : public HashTableMember {}; +template class HashTableMember4 : public HashTableMember {}; + + +template class ObjectHashTable +{ + public: + ObjectHashTable(int hashSize); + ~ObjectHashTable(); + + void Insert(T *obj, int hashValue); + bool Remove(T *obj); + void Reset(); // removes all entries from the table + + T *FindFirst(int hashValue) const; // returns NULL if not found + T *FindNext(T *prevResult) const; // returns NULL if not found + + T *WalkFirst() const; // returns NULL if not found + T *WalkNext(T *prevResult) const; // returns NULL if not found + + void Resize(int hashSize); // the actual hash size will be rounded up to the next larger prime number (very slow, not recommended) + void GetStatistics(HashTableStatistics *stats) const; + + protected: + T **mTable; + int mTableSize; + int mEntryCount; + int mStatUsedSlots; +}; + + +template ObjectHashTable::ObjectHashTable(int hashSize) +{ + mTable = NULL; + mTableSize = 0; + mEntryCount = 0; + mStatUsedSlots = 0; + Resize(hashSize); +} + +template ObjectHashTable::~ObjectHashTable() +{ + delete[] mTable; +} + +template void ObjectHashTable::Insert(T *obj, int hashValue) +{ + static_cast(obj)->mHashValue = hashValue; + + int spot = ((unsigned)hashValue) % mTableSize; + if (mTable[spot] == NULL) + { + static_cast(obj)->mHashNextEntry = NULL; + mTable[spot] = obj; + mStatUsedSlots++; + } + else + { + static_cast(obj)->mHashNextEntry = mTable[spot]; + mTable[spot] = obj; + } + mEntryCount++; +} + +template bool ObjectHashTable::Remove(T *obj) +{ + int spot = ((unsigned)static_cast(obj)->mHashValue) % mTableSize; + T *cur = mTable[spot]; + T **prev = &mTable[spot]; + while (cur != NULL) + { + if (cur == obj) + { + *prev = static_cast(cur)->mHashNextEntry; + static_cast(cur)->mHashNextEntry = NULL; + mEntryCount--; + if (mTable[spot] == NULL) + mStatUsedSlots--; + return(true); + break; + + } + prev = &static_cast(cur)->mHashNextEntry; + cur = static_cast(cur)->mHashNextEntry; + } + return(false); +} + +template void ObjectHashTable::Reset() +{ + memset(mTable, 0, sizeof(T *) * mTableSize); + mStatUsedSlots = 0; + mEntryCount = 0; +} + +template T *ObjectHashTable::FindFirst(int hashValue) const +{ + T *entry = mTable[((unsigned)hashValue) % mTableSize]; + while (entry != NULL) + { + if (static_cast(entry)->mHashValue == hashValue) + return(entry); + entry = static_cast(entry)->mHashNextEntry; + } + return(NULL); +} + +template T *ObjectHashTable::FindNext(T *prevResult) const +{ + T *entry = prevResult; + int hashValue = static_cast(entry)->mHashValue; + entry = static_cast(entry)->mHashNextEntry; + while (entry != NULL) + { + if (static_cast(entry)->mHashValue == hashValue) + return(entry); + entry = static_cast(entry)->mHashNextEntry; + } + return(NULL); +} + +template T *ObjectHashTable::WalkFirst() const +{ + for (int bucket = 0; bucket < mTableSize; bucket++) + { + T *entry = mTable[bucket]; + if (entry != NULL) + return(entry); + } + return(NULL); +} + +template T *ObjectHashTable::WalkNext(T *prevResult) const +{ + T *entry = prevResult; + int bucket = ((unsigned)static_cast(entry)->mHashValue) % mTableSize; + + entry = static_cast(entry)->mHashNextEntry; + if (entry != NULL) + return(entry); + + bucket++; // go onto next bucket + for (; bucket < mTableSize; bucket++) + { + entry = mTable[bucket]; + if (entry != NULL) + return(entry); + } + return(NULL); +} + +template void ObjectHashTable::Resize(int hashSize) +{ + T **oldTable = mTable; + int oldSize = mTableSize; + + // calculate next prime number greater than hashSize. + mTableSize = NextPrime(hashSize); + mTable = new T*[mTableSize]; + memset(mTable, 0, sizeof(T *) * mTableSize); + + mStatUsedSlots = 0; + + if (mEntryCount > 0) + { + for (int i = 0; i < oldSize; i++) + { + T *cur = oldTable[i]; + while (cur != NULL) + { + T *hold = cur; + cur = static_cast(cur)->mHashNextEntry; + + // insert hold into new table + int spot = ((unsigned)static_cast(hold)->mHashValue) % mTableSize; + if (mTable[spot] == NULL) + { + static_cast(hold)->mHashNextEntry = NULL; + mTable[spot] = hold; + mStatUsedSlots++; + } + else + { + static_cast(hold)->mHashNextEntry = mTable[spot]; + mTable[spot] = hold; + } + } + } + } + + delete[] oldTable; +} + +template void ObjectHashTable::GetStatistics(HashTableStatistics *stats) const +{ + stats->totalEntries = mEntryCount; + stats->usedSlots = mStatUsedSlots; + stats->tableSize = mTableSize; +} + + + + + + + //////////////////////////////////////////////////////// + // helper functions for the above hash table classes + //////////////////////////////////////////////////////// + +inline bool IsPrime(int value) // works on positive numbers up 62,710,561 +{ + static int sPrimeTab[] = + { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, + 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, + 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, + 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, + 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, + 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, + 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, + 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, + 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, + 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, + 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, + 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, + 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, + 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, + 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, + 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, + 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, + 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, + 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, + 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, + 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, + 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, + 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, + 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, + 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, + 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, + 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, + 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, + 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, + 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, + 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, + 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, + 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, + 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, + 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, + 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, + 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, + 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, + 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, + 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, + 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, + 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, + 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, + 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, + 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, + 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, + 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, + 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, + 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919 + }; + + for (unsigned int j = 0; j < sizeof(sPrimeTab) / sizeof(int) && sPrimeTab[j] * sPrimeTab[j] < value; j++) + { + if (value % sPrimeTab[j] == 0) + return(false); + } + return(true); +} + +inline int NextPrime(int value) +{ + if (value % 2 == 0) + value++; + while (!IsPrime(value)) + value += 2; + return(value); +} + +inline int HashString(const char *string) +{ + int h = 0; + while (*string != 0) + h = ((31 * h) + *string++) ^ (h >> 26); + return(h); +} + +inline int UpperHashString(const char *string) +{ + int h = 0; + while (*string != 0) + { + h = ((31 * h) + (*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26); + string++; + } + return(h); +} + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHelper.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHelper.h new file mode 100644 index 00000000..beb2ee4c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHelper.h @@ -0,0 +1,31 @@ +#ifndef UDPLIBRARY_UDPHELPER_H +#define UDPLIBRARY_UDPHELPER_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +namespace UdpLibrary +{ + +class UdpGuard +{ + public: + UdpGuard(UdpPlatformGuardObject *obj) { mObj = obj; mObj->Enter(); } + ~UdpGuard() { mObj->Leave(); } + protected: + UdpPlatformGuardObject *mObj; +}; + +class UdpRef +{ + public: + UdpRef(UdpRefCount *obj) { mObj = obj; mObj->AddRef(); } + ~UdpRef() { mObj->Release(); } + + private: + UdpRefCount *mObj; +}; + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLibrary.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLibrary.cpp new file mode 100644 index 00000000..ed40944f --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLibrary.cpp @@ -0,0 +1,42 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include +#include +#include +#include +#include + +#include "UdpLibrary.h" + +namespace UdpLibrary +{ + + //////////////////////////////////////////////////////// + // UdpGuardedRefCount + //////////////////////////////////////////////////////// +void UdpGuardedRefCount::AddRef() const +{ + UdpGuard guard(&mGuard); + UdpRefCount::AddRef(); +} + +void UdpGuardedRefCount::Release() const +{ + mGuard.Enter(); + assert(!mNoRef); + assert(mRefCount > 0); + bool done = (--mRefCount == 0); + mGuard.Leave(); + + if (done) + { + delete this; + } +} + + + + + +} // namespace diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLibrary.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLibrary.h new file mode 100644 index 00000000..57e8db19 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLibrary.h @@ -0,0 +1,18 @@ +#ifndef UDPLIBRARY_UDPLIBRARY_H +#define UDPLIBRARY_UDPLIBRARY_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include +#include "UdpHandler.h" +#include "UdpDriver.h" +#include "UdpHelper.h" +#include "UdpLogicalPacket.h" +#include "UdpMisc.h" +#include "UdpManager.h" +#include "UdpConnection.h" + + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLinkedList.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLinkedList.h new file mode 100644 index 00000000..6fab2d03 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLinkedList.h @@ -0,0 +1,244 @@ +#ifndef UDPLIBRARY_UDPLINKEDLIST_H +#define UDPLIBRARY_UDPLINKEDLIST_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +namespace UdpLibrary +{ + +template class UdpLinkedListMember; +template class UdpLinkedList; + + +template class UdpLinkedListMember +{ + public: + UdpLinkedListMember() { mPrev = NULL; mNext = NULL; } + UdpLinkedListMember(const UdpLinkedListMember &) { mPrev = NULL; mNext = NULL; } + ~UdpLinkedListMember() {} + +#if defined(_MSC_VER) && (_MSC_VER < 1300) // MSVC 7.0 is the first version to support friend templates + public: +#else + protected: + template friend class UdpLinkedList; +#endif + M *mPrev; + M *mNext; +}; + + +template class UdpLinkedList +{ + public: + UdpLinkedList(UdpLinkedListMember T::*node); + virtual ~UdpLinkedList(); + + T *First() const; + T *Last() const; + T *Next(const T *cur) const; + T *Prev(const T *cur) const; + T *Position(int index) const; + T *Remove(T *cur); + T *RemoveHead(); + T *RemoveTail(); + T *InsertHead(T *cur); + T *InsertTail(T *cur); + T *InsertAfter(T *cur, T *prev); + int Count() const; + + void DeleteAll(); // calls delete on all contents + void ReleaseAll(); // calls Release on all contents + + protected: + T *mHead; + T *mTail; + UdpLinkedListMember T::*mNode; + int mCount; +}; + +template UdpLinkedList::UdpLinkedList(UdpLinkedListMember T::*node) +{ + mHead = NULL; + mTail = NULL; + mNode = node; + mCount = 0; +} + +template UdpLinkedList::~UdpLinkedList() +{ +} + +template T *UdpLinkedList::First() const +{ + return(mHead); +} + +template T *UdpLinkedList::Next(const T *cur) const +{ + return((cur->*mNode).mNext); +} + +template T *UdpLinkedList::Prev(const T *cur) const +{ + return((cur->*mNode).mPrev); +} + +template T *UdpLinkedList::Last() const +{ + return(mTail); +} + +template int UdpLinkedList::Count() const +{ + return(mCount); +} + +template T *UdpLinkedList::Position(int index) const +{ + T *cur = mHead; + while (cur != NULL && index > 0) + { + cur = Next(cur); + index--; + } + return(cur); +} + +template T *UdpLinkedList::Remove(T *cur) +{ + UdpLinkedListMember *node = &(cur->*mNode); + if (node->mPrev == NULL) + mHead = node->mNext; + else + ((node->mPrev)->*mNode).mNext = node->mNext; + + if (node->mNext == NULL) + mTail = node->mPrev; + else + ((node->mNext)->*mNode).mPrev = node->mPrev; + + node->mNext = NULL; + node->mPrev = NULL; + mCount--; + return(cur); +} + +template T *UdpLinkedList::RemoveHead() +{ + if (mHead == NULL) + return(NULL); + return(Remove(mHead)); +} + +template T *UdpLinkedList::RemoveTail() +{ + if (mTail == NULL) + return(NULL); + return(Remove(mTail)); +} + +template T *UdpLinkedList::InsertHead(T *cur) +{ + assert((cur->*mNode).mPrev == NULL); + assert((cur->*mNode).mNext == NULL); + (cur->*mNode).mNext = mHead; + + if (mHead != NULL) + { + (mHead->*mNode).mPrev = cur; + mHead = cur; + } + else + { + mTail = mHead = cur; + } + + mCount++; + return(cur); +} + +template T *UdpLinkedList::InsertTail(T *cur) +{ + assert((cur->*mNode).mPrev == NULL); + assert((cur->*mNode).mNext == NULL); + + (cur->*mNode).mPrev = mTail; + + if (mTail != NULL) + { + (mTail->*mNode).mNext = cur; + mTail = cur; + } + else + { + mTail = mHead = cur; + } + + mCount++; + return(cur); +} + +template T *UdpLinkedList::InsertAfter(T *cur, T *prev) +{ + assert((cur->*mNode).mPrev == NULL); + assert((cur->*mNode).mNext == NULL); + + if (prev == NULL) + return(InsertHead(cur)); + + (cur->*mNode).mPrev = prev; + (cur->*mNode).mNext = (prev->*mNode).mNext; + (prev->*mNode).mNext = cur; + + if ((cur->*mNode).mNext != NULL) + (((cur->*mNode).mNext)->*mNode).mPrev = cur; + else + mTail = cur; + + mCount++; + return(cur); +} + +template void UdpLinkedList::DeleteAll() +{ + T *cur = First(); + while (cur != NULL) + { + T *next = Next(cur); + Remove(cur); + delete cur; + cur = next; + } +} + +template void UdpLinkedList::ReleaseAll() +{ + T *cur = First(); + while (cur != NULL) + { + T *next = Next(cur); + Remove(cur); + cur->Release(); + cur = next; + } +} + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +template class UdpLinkedListOwn : public UdpLinkedList +{ + public: + virtual ~UdpLinkedListOwn() + { + this->DeleteAll(); + } +}; + + +} // namespace + + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLogicalPacket.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLogicalPacket.cpp new file mode 100644 index 00000000..5ecce2fb --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLogicalPacket.cpp @@ -0,0 +1,218 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include + +#include "UdpLibrary.h" + +namespace UdpLibrary +{ + + ///////////////////////////////////////////////////// + // LogicalPacket implementation + ///////////////////////////////////////////////////// +LogicalPacket::LogicalPacket() +{ +} + +LogicalPacket::~LogicalPacket() +{ +} + +bool LogicalPacket::IsInternalPacket() const +{ + return(false); +} + + ///////////////////////////////////////////////////// + // SimpleLogicalPacket implementation + ///////////////////////////////////////////////////// +SimpleLogicalPacket::SimpleLogicalPacket(const void *data, int dataLen) +{ + mDataLen = dataLen; + mData = new udp_uchar[mDataLen]; + if (data != NULL) + memcpy(mData, data, mDataLen); +} + +SimpleLogicalPacket::~SimpleLogicalPacket() +{ + delete[] mData; +} + +void *SimpleLogicalPacket::GetDataPtr() +{ + return(mData); +} + +const void *SimpleLogicalPacket::GetDataPtr() const +{ + return(mData); +} + +int SimpleLogicalPacket::GetDataLen() const +{ + return(mDataLen); +} + +void SimpleLogicalPacket::SetDataLen(int len) +{ + assert(len <= mDataLen); + mDataLen = len; +} + ///////////////////////////////////////////////////// + // GroupLogicalPacket implementation + ///////////////////////////////////////////////////// +GroupLogicalPacket::GroupLogicalPacket() : LogicalPacket() +{ + mDataLen = 0; + mData = NULL; +} + +GroupLogicalPacket::~GroupLogicalPacket() +{ + UdpMisc::SmartResize(mData, 0); // free it +} + +void GroupLogicalPacket::AddPacket(const LogicalPacket *packet) +{ + assert(packet != NULL); + AddPacketInternal(packet->GetDataPtr(), packet->GetDataLen(), packet->IsInternalPacket()); +} + +void GroupLogicalPacket::AddPacket(const void *data, int dataLen) +{ + assert(data != NULL); + assert(dataLen >= 0); + AddPacketInternal(data, dataLen, false); +} + +void GroupLogicalPacket::AddPacketInternal(const void *data, int dataLen, bool isInternalPacket) +{ + if (dataLen == 0) + return; + mData = (udp_uchar *)UdpMisc::SmartResize(mData, mDataLen + dataLen + 10, 512); // 7 is the most bytes that could be needed to specify the length of the data to follow, 2 is for internal header-bytes, 1 is for zero-escape if needed (if they need to be added on) + if (mDataLen == 0) + { + mData[0] = 0; + mData[1] = UdpConnection::cUdpPacketGroup; + mDataLen = 2; + } + + udp_uchar *ptr = mData + mDataLen; + if (!isInternalPacket && *(const udp_uchar *)data == 0) + { + ptr += UdpMisc::PutVariableValue(ptr, dataLen + 1); + *ptr++ = 0; // packet is not internal and starts with 0, so we need to zero-escape it so it knows it's an application packet + } + else + ptr += UdpMisc::PutVariableValue(ptr, dataLen); + + memcpy(ptr, data, dataLen); + ptr += dataLen; + mDataLen = (int)(ptr - mData); +} + +void *GroupLogicalPacket::GetDataPtr() +{ + return(mData); +} + +const void *GroupLogicalPacket::GetDataPtr() const +{ + return(mData); +} + +int GroupLogicalPacket::GetDataLen() const +{ + return(mDataLen); +} + +void GroupLogicalPacket::SetDataLen(int /*len*/) +{ + assert(0); // not allowed to set the len of a group logical packet +} + +bool GroupLogicalPacket::IsInternalPacket() const +{ + return(true); +} + + /////////////////////////////////////////////////////////////////////////////////////////// + // PooledLogicalPacket implementation + /////////////////////////////////////////////////////////////////////////////////////////// +PooledLogicalPacket::PooledLogicalPacket(UdpManager *manager, int len) +{ + mMaxDataLen = len; + mData = new udp_uchar[mMaxDataLen]; + mDataLen = 0; + mUdpManager = manager; + mUdpManager->PoolCreated(this); +} + +PooledLogicalPacket::~PooledLogicalPacket() +{ + if (mUdpManager != NULL) + { + mUdpManager->PoolDestroyed(this); + mUdpManager = NULL; + } + + delete[] mData; +} + +void PooledLogicalPacket::AddRef() const +{ + LogicalPacket::AddRef(); +} + +void PooledLogicalPacket::Release() const +{ + if (GetRefCount() == 1 && mUdpManager != NULL) + { + // the PoolReturn function steals our reference (ie, we don't release, they don't addref), this is for thread safety reasons + mUdpManager->PoolReturn(const_cast(this)); + return; // it would be non-thread-safe for us to touch this object in any way after is is added back to the pool, since some other thread might steal it before we get back to here (or if the pool didn't want us, we are potentially deleted at this point) + } + LogicalPacket::Release(); +} + +void PooledLogicalPacket::TrueRelease() const +{ + // this function is used by the UdpManager to delete this object in situations where it has decided that it does + // not want the object returned to the pool (pool is full) + LogicalPacket::Release(); +} + +void *PooledLogicalPacket::GetDataPtr() +{ + return(mData); +} + +const void *PooledLogicalPacket::GetDataPtr() const +{ + return(mData); +} + +int PooledLogicalPacket::GetDataLen() const +{ + return(mDataLen); +} + +void PooledLogicalPacket::SetDataLen(int len) +{ + assert(len <= mMaxDataLen); + mDataLen = len; +} + +void PooledLogicalPacket::SetData(const void *data, int dataLen, const void *data2, int dataLen2) +{ + mDataLen = dataLen + dataLen2; + if (data != NULL) + memcpy(mData, data, dataLen); + if (data2 != NULL) + memcpy(mData + dataLen, data2, dataLen2); +} + + +} // namespace diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLogicalPacket.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLogicalPacket.h new file mode 100644 index 00000000..6a5962c4 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpLogicalPacket.h @@ -0,0 +1,299 @@ +#ifndef UDPLIBRARY_UDPLOGICALPACKET_H +#define UDPLIBRARY_UDPLOGICALPACKET_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include "UdpHandler.h" +#include "UdpLinkedList.h" + +namespace UdpLibrary +{ + +class SimpleLogicalPacket; +class GroupLogicalPacket; + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // The purpose of the LogicalPacket class is to provide means whereby multiple connections can share + // a queued packet to save having each connection make its own copy. It is highly recommended that + // logical packets be used for optimal performance when sending reliable data as well, since internally + // it will just end up creating one for you anyhow (LogicalPackets are used by the reliable layer to + // hold onto the data until it is acknowledged) + // + // Logical packets passed in are never modified by the udp library. + // After calling Send, application should immediately Release the logical packet if they don't need it for + // something else (like sending to another connection). The udp library will addref it if it decided it + // wants to keep it around past the Send call (for reliable data, it will always hang onto it, for unreliable + // data, it will only hang onto it if it gets promoted to reliable due to size.) + // + // Application is encouraged to derive their own application-specific packet classes from the LogicalPacket + // The object is required to be able to provide a pointer to the raw packet data that will remain valid + // for as long as the LogicalPacket object exists. + // + // for example: + // class PlayerLoginPacket : public LogicalPacket + // { + // public: + // PlayerLoginPacket(char *userName, char *password) { mData.packetType = cPacketTypePlayerLogin; strcpy(mData.userName, userName); strcpy(mData.password, password); } + // virtual const void *GetDataPtr() const { return(&mData); } + // virtual int GetDataLen() const { return(sizeof(mData)); } + // protected: + // virtual ~PlayerLoginPacket() {}; + // struct + // { + // udp_uchar packetType; + // char userName[32]; + // char password[32]; + // } mData; + // }; + //////////////////////////////////////////////////////////////////////////////////////////////////////////// +class LogicalPacket : public UdpRefCount +{ + public: + LogicalPacket(); + + virtual void *GetDataPtr() = 0; + virtual const void *GetDataPtr() const = 0; + virtual int GetDataLen() const = 0; + virtual void SetDataLen(int len) = 0; + + // returns true if this logical packet is an internal packet + // by default this returns false, and applications should not override this function to do + // otherwise. Basically, if this returns true, it tells the udp library that the packet has + // an internal-packet header (starts with a zero byte) on it that should not be escaped when sent. + // The packet will ultimately be processed by the internal udp library code on the other side. + // The purpose of this is to support features such as GroupLogicalPacket, such that the application + // can prep grouped packets and then send them via traditional means (it's how the udp library + // knows that the packet is a group packet instead of just a application-packet that happens to start with 0) + virtual bool IsInternalPacket() const; + protected: + virtual ~LogicalPacket(); // protected since the class should only be deleted by Releasing it + + private: + friend class UdpReliableChannel; + UdpLinkedListMember mReliableLink; // used by reliable channel object to hold a list of these packets +}; + +class SimpleLogicalPacket : public LogicalPacket +{ + // this class is a simply dynamically allocated packet. Applications are welcome to use it, but + // it was originally created to allow the internal code to handle reliable data that was sent + // via the Send(char *, int) api call. + public: + SimpleLogicalPacket(const void *data, int dataLen); // data can be NULL if you want to populate it after it is allocated (get the pointer and write to it) + virtual void *GetDataPtr(); + virtual const void *GetDataPtr() const; + virtual int GetDataLen() const; + virtual void SetDataLen(int len); + protected: + virtual ~SimpleLogicalPacket(); + udp_uchar *mData; + int mDataLen; +}; + +class WrappedLogicalPacket : public LogicalPacket +{ + // this class is used internally by the library such that it can get a free and clear mNext pointer + // in cases where a logical packet is being shared by multiple connections (such that the packet + // can reside in the linked-list for the reliable channel queue) + public: + WrappedLogicalPacket(UdpManager *manager); // lives in a pool + + virtual void AddRef() const; + virtual void Release() const; + virtual void *GetDataPtr(); + virtual const void *GetDataPtr() const; + virtual int GetDataLen() const; + virtual void SetDataLen(int len); + protected: + virtual ~WrappedLogicalPacket(); + const LogicalPacket *mPacket; + + protected: + friend class UdpManager; + friend class UdpReliableChannel; + void TrueRelease() const; + void SetLogicalPacket(const LogicalPacket *packet); + UdpManager *mUdpManager; + UdpLinkedListMember mAvailableLink; // for available linked list in manager (used by reliable channel object as well while it is borrowed) + UdpLinkedListMember mCreatedLink; // for created linked list in manager +}; + +template class FixedLogicalPacket : public LogicalPacket +{ + // this class is similar to the SimpleLogicalPacket in that it is designed to just store raw + // data of various sizes. The difference here is that this class may be created at compile + // time to be any size desired (via template parameters), and is more efficient than the + // SimpleLogicalPacket when used (it avoid the internal alloc as the data is inline). The + // UdpMisc::CreateQuickLogicalPacket function automatically attempts to use this for small + // packets and will fall back and use SimpleLogicalPackets for larger packets. + public: + FixedLogicalPacket(const void *data, int dataLen); + virtual void *GetDataPtr(); + virtual const void *GetDataPtr() const; + virtual int GetDataLen() const; + virtual void SetDataLen(int len); + protected: + udp_uchar mData[t_quickSize]; + int mDataLen; +}; + +template class StructLogicalPacket : public LogicalPacket +{ + // this class is designed to turn any raw struct into a logical packet. The application + // can then access the struct through thisLogicalPacket->mStruct.structMember. The template + // will take care of all the wrappings necessary to turn the struct into a fully functional + // logical packet that can be sent to a connection. As a word of caution, sending struct's + // across the wire is not considered very portable. There are byte-ordering and structure-packing + // issues that are platform dependent. At a minimum, you will probably want to make sure that + // struct's you use in this way are packed to 1-byte boundaries, such that you are not sending + // wasteful information. Do not attempt to send the member-content of classes (particularly classes + // with virtual functions) via this method as they may contain hidden data-members (such as pointers + // to vtables). + public: + StructLogicalPacket(T *initData = NULL); + virtual void *GetDataPtr(); + virtual const void *GetDataPtr() const; + virtual int GetDataLen() const; + virtual void SetDataLen(int len); + protected: + T mStruct; +}; + +class GroupLogicalPacket : public LogicalPacket +{ + // this class is a helper object intended for use by the application (it is not used internally) + // It allows you to add multiple application-packets and them send them all as an autonomous unit. + // The receiving end will automatically split the packet up and send them to the application callback function + // as if the individual packets had all been sent one at at time. + // + // This facility is primarily intended for reliable data, though it can be used to group unreliable data as well. + // Grouping unreliable data together would effectively give you an all-or-nothing type of delivery system. Be + // mindful that if the group of packets gets larger than max-raw-packet-size, it will end up getting + // promoted to being a reliable-packet with the associated overhead involved in that. + // + // You might be wondering what the advantage would be of grouping packets together at the application level as opposed to + // just letting the internal multi-buffer take care of the problem for you. For starters, the internal multi-buffer + // is incapable of combining partial-packets, so you end up sending less than maximum-size packets if you let the + // internal layer take care of it. Additionally, there is additional overhead in that if you send 100 tiny logical + // packets, each one will need to be ack'ed by the receiving end (even though they are getting combined down at the physical-packet + // level in order to reduce UDP overhead). Finally, grouping them together at the higher level will allow the + // logical-packet compression helper routines to operate on larger chunks of data at a time, which tends to improve + // compression efficiency. The downside to combining is that none of the application packets get delivered until the + // entire group arrives, then all are delivered in one fell swoop...the net effect being that in order to gain these efficeincies, + // the first-packet takes longer to be delivered to the application than it otherwise would have (while the last packet will in theory + // get there is less time as there will be less overhead). + // + // Internal packets can be added to the group (though that is somewhat unlikely), which means you can add a group to a group + public: + GroupLogicalPacket(); + void AddPacket(const LogicalPacket *packet); // cannot add internal logical packets to the group + void AddPacket(const void *data, int dataLen); + virtual void *GetDataPtr(); + virtual const void *GetDataPtr() const; + virtual int GetDataLen() const; + virtual void SetDataLen(int len); + virtual bool IsInternalPacket() const; // returns true if this is considering an internal logical packet type + + protected: + virtual ~GroupLogicalPacket(); + void AddPacketInternal(const void *data, int dataLen, bool isInternalPacket); + + udp_uchar *mData; + int mDataLen; +}; + +class PooledLogicalPacket : public LogicalPacket +{ + // a pooled logical packet is like other logical packets, only when it's refCount gets down to 1, it notifies + // its manager to add it back to the pool. (The manager keeps the last ref count on the packet) + public: + PooledLogicalPacket(UdpManager *manager, int len); + + virtual void AddRef() const; + virtual void Release() const; + virtual void *GetDataPtr(); + virtual const void *GetDataPtr() const; + virtual int GetDataLen() const; + virtual void SetDataLen(int len); + protected: + virtual ~PooledLogicalPacket(); + + udp_uchar *mData; + int mDataLen; + int mMaxDataLen; + protected: + friend class UdpManager; + void TrueRelease() const; + void SetData(const void *data, int dataLen, const void *data2 = NULL, int dataLen2 = 0); + UdpManager *mUdpManager; + UdpLinkedListMember mAvailableLink; // for available linked list in manager + UdpLinkedListMember mCreatedLink; // for created linked list in manager +}; + + + + ///////////////////////////////////////////////////////////////////////// + // FixedLogicalPacket implementation + ///////////////////////////////////////////////////////////////////////// +template FixedLogicalPacket::FixedLogicalPacket(const void *data, int dataLen) +{ + mDataLen = dataLen; + if (data != NULL) + memcpy(mData, data, mDataLen); +} + +template void *FixedLogicalPacket::GetDataPtr() +{ + return(mData); +} + +template const void *FixedLogicalPacket::GetDataPtr() const +{ + return(mData); +} + +template int FixedLogicalPacket::GetDataLen() const +{ + return(mDataLen); +} + +template void FixedLogicalPacket::SetDataLen(int len) +{ + mDataLen = len; +} + + + ///////////////////////////////////////////////////////////////////////// + // StructLogicalPacket implementation + ///////////////////////////////////////////////////////////////////////// +template StructLogicalPacket::StructLogicalPacket(T *initData) +{ + if (initData != NULL) + mStruct = *initData; +} + +template void *StructLogicalPacket::GetDataPtr() +{ + return(&mStruct); +} + +template const void *StructLogicalPacket::GetDataPtr() const +{ + return(&mStruct); +} + +template int StructLogicalPacket::GetDataLen() const +{ + return(sizeof(mStruct)); +} + +template void StructLogicalPacket::SetDataLen(int len) +{ +} + +} // namespace + + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpManager.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpManager.cpp new file mode 100644 index 00000000..5a63f361 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpManager.cpp @@ -0,0 +1,1394 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#if defined(WIN32) + #define _CRT_SECURE_NO_DEPRECATE // gets rid of deprecation warnings in VS 2005 (don't want to change to secure-versions as it hampers portability) +#endif + +#include +#include +#include +#include +#include + +#include "UdpLibrary.h" + +namespace UdpLibrary +{ + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpManagerHandler default implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +void UdpManagerHandler::OnConnectRequest(UdpConnection * /*con*/) +{ +} + +int UdpManagerHandler::OnUserSuppliedEncrypt(UdpConnection * /*con*/, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + memcpy(destData, sourceData, sourceLen); + return(sourceLen); +} + +int UdpManagerHandler::OnUserSuppliedEncrypt2(UdpConnection * /*con*/, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + memcpy(destData, sourceData, sourceLen); + return(sourceLen); +} + +int UdpManagerHandler::OnUserSuppliedDecrypt(UdpConnection * /*con*/, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + memcpy(destData, sourceData, sourceLen); + return(sourceLen); +} + +int UdpManagerHandler::OnUserSuppliedDecrypt2(UdpConnection * /*con*/, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + memcpy(destData, sourceData, sourceLen); + return(sourceLen); +} + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // SimulationParameters implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpSimulationParameters::UdpSimulationParameters() +{ + simulateIncomingByteRate = 0; + simulateIncomingLossPercent = 0.0f; + simulateOutgoingByteRate = 0; + simulateOutgoingLossPercent = 0.0f; + simulateDestinationOverloadLevel = 0; + simulateOutgoingOverloadLevel = 0; + simulateOutgoingLatency = 0; + simulateIncomingLatency = 0; +} + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpManager implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpManager::UdpManager(const UdpParams *params) : mConnectionList(&UdpConnection::mConnectionLink) + , mDisconnectPendingList(&UdpConnection::mDisconnectPendingLink) + , mSimulateIncomingList(&SimulateQueueEntry::mLink) + , mSimulateOutgoingList(&SimulateQueueEntry::mLink) + , mPoolCreatedList(&PooledLogicalPacket::mCreatedLink) + , mPoolAvailableList(&PooledLogicalPacket::mAvailableLink) + , mAvailableEventList(&CallbackEvent::mLink) + , mEventList(&CallbackEvent::mLink) +{ + assert(params->clockSyncDelay >= 0); // negative clockSyncDelay is not allowed (makes no sense) + assert(params->crcBytes >= 0 && params->crcBytes <= 4); // crc bytes must be between 0 and 4 + assert(params->encryptMethod[0] >= 0 && params->encryptMethod[0] < cEncryptMethodCount); // illegal encryption method specified + assert(params->encryptMethod[1] >= 0 && params->encryptMethod[1] < cEncryptMethodCount); // illegal encryption method specified + assert(params->hashTableSize > 0); // a hash table size greater than zero is required + assert(params->maxRawPacketSize >= 64); // raw packet size must be at least 64 bytes + assert(params->incomingBufferSize >= params->maxRawPacketSize); // incoming socket buffer size must be at least as big as one raw packet + assert(params->keepAliveDelay >= 0); // keep alive delay can't be negative + assert(params->portAliveDelay >= 0); // port alive delay can't be negative + assert(params->maxConnections > 0); // must have at least 1 connection allowed + assert(params->outgoingBufferSize >= params->maxRawPacketSize); // outgoing socket buffer must larger than a raw packet size + assert(params->packetHistoryMax > 0); // packet history must be at least 1 + assert(params->port >= 0); // port cannot be negative + assert(params->userSuppliedEncryptExpansionBytes + params->userSuppliedEncryptExpansionBytes2 < params->maxRawPacketSize); // if encryption expansion is larger than raw packet size, we are screwed + assert(params->reliable[0].maxOutstandingBytes >= params->maxRawPacketSize); + assert(params->reliable[1].maxOutstandingBytes >= params->maxRawPacketSize); + assert(params->reliable[2].maxOutstandingBytes >= params->maxRawPacketSize); + assert(params->reliable[3].maxOutstandingBytes >= params->maxRawPacketSize); + assert(params->port != 0 || params->portRange == 0); + + mParams = *params; + mParams.maxRawPacketSize = udpMin(mParams.maxRawPacketSize, (int)cHardMaxRawPacketSize); + if (mParams.maxDataHoldSize == -1) + { + mParams.maxDataHoldSize = mParams.maxRawPacketSize; + } + if (mParams.pooledPacketSize == -1) + { + mParams.pooledPacketSize = mParams.maxRawPacketSize; + } + + mParams.maxDataHoldSize = udpMin(mParams.maxDataHoldSize, mParams.maxRawPacketSize); + mParams.packetHistoryMax = udpMax(1, mParams.packetHistoryMax); + mPacketHistoryPosition = 0; + mPassThroughData = NULL; + mBackgroundThread = NULL; + + if (mParams.udpDriver != NULL) + { + mDriver = mParams.udpDriver; + } + else + { + mDriver = new UdpPlatformDriver(); + } + + typedef PacketHistoryEntry *PacketHistoryEntryPtr; + mPacketHistory = new PacketHistoryEntryPtr[mParams.packetHistoryMax]; + + int i; + for (i = 0; i < mParams.packetHistoryMax; i++) + { + mPacketHistory[i] = new PacketHistoryEntry(mParams.maxRawPacketSize); + } + + Clock(); // call Clock to initialize mCachedClock + ResetStats(); + mRandomSeed = (int)CachedClock(); + mLastReceiveTime = 0; + mLastSendTime = 0; + mLastEmptySocketBufferStamp = 0; + mProcessingInducedLag = 0; + mMinimumScheduledStamp = 0; + mInsideGiveTime = false; + mEventListBytes = 0; + + for (i = 0; i < mParams.pooledPacketInitial && i < mParams.pooledPacketMax; i++) + { + PooledLogicalPacket *lp = new PooledLogicalPacket(this, mParams.pooledPacketSize); + PoolReturn(lp); // steals our reference + } + + mSimulateNextOutgoingTime = 0; + mSimulateNextIncomingTime = 0; + mSimulateOutgoingQueueBytes = 0; + + if (mParams.avoidPriorityQueue) + mPriorityQueue = NULL; + else + mPriorityQueue = new PriorityQueue(mParams.maxConnections); + + mAddressHashTable = new ObjectHashTable >(mParams.hashTableSize); + mConnectCodeHashTable = new ObjectHashTable >(udpMax(mParams.hashTableSize / 5, 10)); // rarely used, so make it a fraction of the main tables size + + if (mParams.portRange == 0) + { + CreateAndBindSocket(mParams.port); + } + else + { + int r = Random() % mParams.portRange; + for (int i = 0; i < mParams.portRange; i++) + { + CreateAndBindSocket(mParams.port + ((r + i) % mParams.portRange)); + if (mErrorCondition != cErrorConditionCouldNotBindSocket) + break; + } + } +} + +UdpManager::~UdpManager() +{ + // Since the background thread holds a reference to the UdpManager while it is running, this should + // not be possible. The only way it could happen is if somebody released the manager who should not have. + assert(mBackgroundThread == NULL); + + // next thing we must do is tell all the connections to disconnect (which severs their link to this dying manager) + // this has to be done first since they will call back into us and have themselves removed from our connection-list/priority-queue/etc + // additionally, they may try sending packets to other connections that are not yet disconnected, so we need to make sure that as a + // managed we are in a fully operational state until everybody is disconnected from us. + { + UdpGuard cg(&mConnectionGuard); + + UdpConnection *cur = mConnectionList.First(); + while (cur != NULL) + { + cur->AddRef(); + cur->InternalDisconnect(0, UdpConnection::cDisconnectReasonManagerDeleted); // this will cause it to remove us from the mConnectionList + cur->Release(); + + // the above call ended up calling us back and removing them from our connection list, so now mConnectionList is pointing to the next entry + cur = mConnectionList.First(); + } + } + + + { + // release any objects that were pending disconnection + UdpGuard guard(&mDisconnectPendingGuard); + mDisconnectPendingList.ReleaseAll(); + } + + + { + // next we need to tell all the pooled packets we have created that they can no longer check themselves back into use + // when they are released + UdpGuard guard(&mPoolGuard); + + PooledLogicalPacket *walk = mPoolCreatedList.RemoveHead(); + while (walk != NULL) + { + walk->mUdpManager = NULL; + walk = mPoolCreatedList.RemoveHead(); + } + // next release the ones we have in our available pool + mPoolAvailableList.ReleaseAll(); + } + + if (mParams.lingerDelay != 0) + { + mDriver->Sleep(mParams.lingerDelay); // sleep momentarily before closing socket to give it a chance to empty the socket buffer if there is something in it + } + + CloseSocket(); + + if (mParams.udpDriver == NULL) + { + delete mDriver; // we were not given a driver to use, so we must own this driver we have, so destroy it + } + mDriver = NULL; + + delete mAddressHashTable; + delete mConnectCodeHashTable; + delete mPriorityQueue; + for (int i = 0; i < mParams.packetHistoryMax; i++) + { + delete mPacketHistory[i]; + } + delete[] mPacketHistory; + + // delete simulation queues + mSimulateOutgoingList.DeleteAll(); + mSimulateIncomingList.DeleteAll(); + + // delete event queues + mAvailableEventList.DeleteAll(); + mEventList.DeleteAll(); +} + +void UdpManager::GetSimulation(UdpSimulationParameters *simulationParameters) const +{ + UdpGuard guard(&mGiveTimeGuard); + *simulationParameters = mSimulation; +} + +void UdpManager::SetSimulation(const UdpSimulationParameters *simulationParameters) +{ + UdpGuard guard(&mGiveTimeGuard); + mSimulation = *simulationParameters; +} + +void UdpManager::CreateAndBindSocket(int usePort) +{ + CloseSocket(); + mErrorCondition = cErrorConditionNone; + if (!mDriver->SocketOpen(usePort, mParams.incomingBufferSize, mParams.outgoingBufferSize, mParams.bindIpAddress)) + { + mErrorCondition = cErrorConditionCouldNotBindSocket; + } +} + +void UdpManager::CloseSocket() +{ + mDriver->SocketClose(); +} + + +UdpManager::ErrorCondition UdpManager::GetErrorCondition() const +{ + return(mErrorCondition); +} + + +void UdpManager::ProcessDisconnectPending() +{ + UdpGuard guard(&mDisconnectPendingGuard); + + UdpConnection *entry = mDisconnectPendingList.First(); + while (entry != NULL) + { + UdpConnection *next = mDisconnectPendingList.Next(entry); + if (entry->GetStatus() == UdpConnection::cStatusDisconnected) + { + mDisconnectPendingList.Remove(entry); + entry->Release(); + } + entry = next; + } +} + +void UdpManager::RemoveConnection(UdpConnection *con) +{ + assert(con != NULL); // attemped to remove a NULL connection object + + // note: it's a bug to Remove a connection object that is already removed...should never be able to happen. + UdpGuard cg(&mConnectionGuard); + + if (mPriorityQueue != NULL) + { + mPriorityQueue->Remove(con); + } + mConnectionList.Remove(con); + mAddressHashTable->Remove(con); + mConnectCodeHashTable->Remove(con); + con->Release(); +} + +void UdpManager::AddConnection(UdpConnection *con) +{ + assert(con != NULL); // attemped to add a NULL connection object + + UdpGuard cg(&mConnectionGuard); + con->AddRef(); // UdpManager keeps a soft reference to the connection (ie. if it sees it is the only one holding a reference, it releases it) + mConnectionList.InsertHead(con); + mAddressHashTable->Insert(con, AddressHashValue(con->mIp, con->mPort)); + mConnectCodeHashTable->Insert(con, con->mConnectCode); +} + +void UdpManager::FlushAllMultiBuffer() +{ + UdpRef ref(this); // hold reference to ourselves for duration of call (must be before guard object, since guard object references us). In this way, if the application releases us during a callback, we don't disappear until the stack is unwound + + mConnectionGuard.Enter(); + UdpConnection *cur = mConnectionList.First(); + if (cur != NULL) + cur->AddRef(); + mConnectionGuard.Leave(); + + while (cur != NULL) + { + cur->FlushMultiBuffer(); + + mConnectionGuard.Enter(); + UdpConnection *next = mConnectionList.Next(cur); + if (next != NULL) + next->AddRef(); + mConnectionGuard.Leave(); + + cur->Release(); + cur = next; + } +} + +void UdpManager::DisconnectAll() +{ + UdpRef ref(this); // hold reference to ourselves for duration of call (must be before guard object, since guard object references us). In this way, if the application releases us during a callback, we don't disappear until the stack is unwound + + mConnectionGuard.Enter(); + UdpConnection *cur = mConnectionList.First(); + if (cur != NULL) + cur->AddRef(); + mConnectionGuard.Leave(); + + while (cur != NULL) + { + mConnectionGuard.Enter(); + UdpConnection *next = mConnectionList.Next(cur); + if (next != NULL) + next->AddRef(); + mConnectionGuard.Leave(); + + cur->Disconnect(); + cur->Release(); + cur = next; + } +} + +void UdpManager::DeliverEvents(int maxProcessingTime) +{ + UdpRef ref(this); // hold reference to ourselves for duration of call (must be before guard object, since guard object references us). In this way, if the application releases us during a callback, we don't disappear until the stack is unwound + + UdpClockStamp start = Clock(); + for (;;) + { + CallbackEvent *ce = EventListPop(); + if (ce == NULL) + break; + + switch(ce->mEventType) + { + case CallbackEvent::cCallbackEventRoutePacket: + { + ce->mSource->OnRoutePacket((const udp_uchar *)ce->mPayload->GetDataPtr(), ce->mPayload->GetDataLen()); + break; + } + case CallbackEvent::cCallbackEventConnectComplete: + { + ce->mSource->OnConnectComplete(); + break; + } + case CallbackEvent::cCallbackEventTerminated: + { + ce->mSource->OnTerminated(); + break; + } + case CallbackEvent::cCallbackEventCrcReject: + { + ce->mSource->OnCrcReject((const udp_uchar *)ce->mPayload->GetDataPtr(), ce->mPayload->GetDataLen()); + break; + } + case CallbackEvent::cCallbackEventPacketCorrupt: + { + ce->mSource->OnPacketCorrupt((const udp_uchar *)ce->mPayload->GetDataPtr(), ce->mPayload->GetDataLen(), ce->mReason); + break; + } + case CallbackEvent::cCallbackEventConnectRequest: + { + { // guard block + UdpGuard hguard(&mHandlerGuard); + if (mParams.handler != NULL) + { + mParams.handler->OnConnectRequest(ce->mSource); + } + } + + if (ce->mSource->GetHandler() == NULL) // if application did not set a handler, then the connection is considered refused + { + ce->mSource->InternalDisconnect(0, UdpConnection::cDisconnectReasonConnectionRefused); + } + break; + } + case CallbackEvent::cCallbackEventNone: + default: + break; + } + + ce->ClearEventData(); + AvailableEventReturn(ce); + + if (ClockElapsed(start) >= maxProcessingTime) + { + UdpGuard sg(&mStatsGuard); + mManagerStats.maxDeliveryTimeExceeded++; + break; + } + } +} + +void UdpManager::SetEventQueuing(bool on) +{ + UdpGuard guard(&mGiveTimeGuard); // don't allow changing of queuing mode while inside GiveTime from another thread + mParams.eventQueuing = on; +} + +bool UdpManager::GetEventQueuing() const +{ + UdpGuard guard(&mGiveTimeGuard); + return(mParams.eventQueuing); +} + +bool UdpManager::GiveTime(int maxPollingTime, bool giveConnectionsTime) +{ + UdpRef ref(this); // hold reference to ourselves for duration of call (must be before guard object, since guard object references us). In this way, if the application releases us during a callback, we don't disappear until the stack is unwound + UdpGuard guard(&mGiveTimeGuard); + + Clock(); // update cached clock + + if (!mParams.eventQueuing && mEventList.Count() > 0) + { + // if we have events queued and we are not in queuing mode, we must deliver those events + // before we can actually do a give time (this should only happen when the queuing mode is changed on the fly) + DeliverEvents(maxPollingTime); + return(true); + } + + ////////////////////////////////////////////// + // do the work (prevent re-entry) + ////////////////////////////////////////////// + if (mInsideGiveTime) + { + assert(0); // odds are this an application bug, so we want them to see this fairly quickly when it happens + return(false); // prevent re-entrancy of GiveTime function, since that will cause all sorts of problems + } + mInsideGiveTime = true; + + // process incoming raw packets from the port + { + UdpGuard sg(&mStatsGuard); + mManagerStats.iterations++; + } + + // if we are currently not queuing, yet we have stuff remaining in the queue, then + // we must deliver everything in the queue before we can do more processing of the socket + // note: this would only happen in theory if the queuing mode were being changed on the fly + bool found = false; + if (maxPollingTime != 0) + { + UdpClockStamp start = CachedClock(); + for (;;) + { +#ifdef UDPLIBRARY_NO_SIMULATION + PacketHistoryEntry *e = ActualReceive(); +#else + PacketHistoryEntry *e = SimulationReceive(); +#endif + + if (e == NULL) + { + mLastEmptySocketBufferStamp = CachedClock(); + break; + } + + // if the application takes too long to process packets, or doesn't give the UdpManager frequent enough time via GiveTime + // then it's possible that we will have a clock-sync packet that is sitting in the socket buffer waiting to be processed + // we don't want the applications inability to give us frequent processing time to totally whack up the clock sync stuff + // so we have the clock-sync code ignore clock-sync packets that get stalled in the socket buffer for too long because our + // application is busy processing other packets that were queued before it, or because the application paused for a long + // time before calling GiveTime. + // note: this is intended to prevent cpu induced stalls from causing a sync packet to appear to take longer. For example + // if the player is on a modem, it's possible for the socket-buffer to fill up while the application is stalled and cause the + // the sync-packet to actually get stalled at the terminal buffer on the other end up of the modem. When the application starts + // processing again, it will empty the socket-buffer, but then the get an empty-socket-buffer briefly until the terminal server + // can send the rest of the buffered packets on over. A large client side receive socket buffer may help in this regard. + mProcessingInducedLag = CachedClockElapsed(mLastEmptySocketBufferStamp); + found = true; + ProcessRawPacket(e); + + if (ClockElapsed(start) >= maxPollingTime) + { + UdpGuard sg(&mStatsGuard); + mManagerStats.maxPollingTimeExceeded++; + break; + } + } + } + + if (giveConnectionsTime) + { + if (mPriorityQueue != NULL) + { + // give time to everybody in the priority-queue that needs it + UdpClockStamp curPriority = CachedClock(); + + // at the time we start processing the priority queue, we should effectively be taking a snap-shot + // of everybody who needs time, before we give anybody time. Otherwise, it is possible that in the + // process of giving one connection time, another connection could get bumped up the queue to the point + // where it needs time now as well (for example, one connection sending another connection data during the + // give time phase). Although very rare, in theory this could result in an infinite loop situation. + // To solve this, we simply set the earliest time period that somebody can schedule for to 1 ms after + // the current time stamp that we are processing, effectively making it impossible for any connection + // to be given time twice in the same interation of the loop below + + mConnectionGuard.Enter(); + mMinimumScheduledStamp = curPriority + 1; + mConnectionGuard.Leave(); + + int processed = 0; + for (;;) + { + UdpConnection *top; + + mConnectionGuard.Enter(); + top = mPriorityQueue->TopRemove(curPriority); + if (top != NULL) + top->AddRef(); // must always addref connections while inside the connection guard + mConnectionGuard.Leave(); + if (top == NULL) + break; + + top->GiveTime(true); + top->Release(); + + processed++; + } + + { + UdpGuard sg(&mStatsGuard); + mManagerStats.priorityQueueProcessed += processed; + mManagerStats.priorityQueuePossible += mConnectionList.Count(); + } + } + else + { + // give time to everybody + mConnectionGuard.Enter(); + UdpConnection *cur = mConnectionList.First(); + if (cur != NULL) + cur->AddRef(); + mConnectionGuard.Leave(); + + while (cur != NULL) + { + cur->GiveTime(true); + + mConnectionGuard.Enter(); + UdpConnection *next = mConnectionList.Next(cur); + if (next != NULL) + next->AddRef(); + mConnectionGuard.Leave(); + + cur->Release(); + cur = next; + } + } + + ProcessDisconnectPending(); + } + + + { + UdpGuard guard(&mSimulateGuard); + UdpClockStamp curStamp = CachedClock(); + + SimulateQueueEntry *entry = mSimulateOutgoingList.First(); + while (entry != NULL && curStamp >= mSimulateNextOutgoingTime) + { + mSimulateOutgoingList.Remove(entry); + SimulateQueueEntry *next = mSimulateOutgoingList.First(); + + // simulate a delay before next packet is considered (ie. simple lag) + if (next != NULL) + { + int latencyDelay = (mSimulation.simulateOutgoingLatency - CachedClockElapsed(next->mQueueTime)); + mSimulateNextOutgoingTime = curStamp + latencyDelay; + } + + // simulate a max data rate + UdpClockStamp nextRateTime = curStamp; + if (mSimulation.simulateOutgoingByteRate > 0) + { + nextRateTime += (entry->mDataLen * 1000 / mSimulation.simulateOutgoingByteRate); + mSimulateNextOutgoingTime = udpMax(mSimulateNextOutgoingTime, nextRateTime); + } + + ActualSendHelper(entry->mData, entry->mDataLen, entry->mIp, entry->mPort); + + UdpConnection *con = AddressGetConnection(entry->mIp, entry->mPort); + if (con != NULL) + { + con->mSimulateOutgoingQueueBytes -= entry->mDataLen; + con->Release(); + } + mSimulateOutgoingQueueBytes -= entry->mDataLen; + delete entry; + + entry = next; + } + } + + mInsideGiveTime = false; + return(found); +} + +UdpConnection *UdpManager::EstablishConnection(const char *serverAddress, int serverPort, int timeout) +{ + UdpGuard guard(&mGiveTimeGuard); // probably not needed, I don't see any reason we can't do this while GiveTime is happening in the background...the connection list is protected independently...still, better safe than sorry + + assert(serverAddress != NULL); + + char useServerAddress[512]; + UdpLibrary::UdpMisc::Strncpy(useServerAddress, serverAddress, sizeof(useServerAddress)); + char *portPtr = strchr(useServerAddress, ':'); + if (portPtr != NULL) + { + *portPtr++ = 0; + serverPort = atoi(portPtr); + } + + assert(useServerAddress[0] != 0); + assert(serverPort != 0); // can't connect to no port + + if (mConnectionList.Count() >= mParams.maxConnections) + return(NULL); + + // get server address + UdpPlatformAddress destIp; + if (!mDriver->GetHostByName(&destIp, useServerAddress)) + { + return(NULL); // could not resolve name + } + + // first, see if we already have a connection object managing this ip/port, if we do, then fail + UdpConnection *con = AddressGetConnection(destIp, serverPort); + if (con != NULL) + { + con->Release(); + return(NULL); // already connected to this address/port + } + return(new UdpConnection(this, destIp, serverPort, timeout)); +} + +void UdpManager::KeepUntilDisconnected(UdpConnection *con) +{ + UdpGuard guard(&mDisconnectPendingGuard); + con->AddRef(); + mDisconnectPendingList.InsertTail(con); +} + +void UdpManager::GetStats(UdpManagerStatistics *stats) +{ + UdpGuard sg(&mStatsGuard); + + assert(stats != NULL); + *stats = mManagerStats; + stats->poolAvailable = mPoolAvailableList.Count(); + stats->poolCreated = mPoolCreatedList.Count(); + + { + UdpGuard guard(&mDisconnectPendingGuard); + stats->disconnectPendingCount = mDisconnectPendingList.Count(); + } + + stats->connectionCount = mConnectionList.Count(); + stats->eventListCount = mEventList.Count(); + stats->eventListBytes = mEventListBytes; + stats->elapsedTime = CachedClockElapsed(mManagerStatsResetTime); +} + +void UdpManager::ResetStats() +{ + UdpGuard guard(&mStatsGuard); + + mManagerStatsResetTime = CachedClock(); + memset(&mManagerStats, 0, sizeof(mManagerStats)); +} + +void UdpManager::DumpPacketHistory(const char *filename) const +{ + UdpGuard guard(&mGiveTimeGuard); + + assert(filename != NULL); + assert(filename[0] != 0); + FILE *file = fopen(filename, "wt"); + if (file != NULL) + { + // dump history of packets... + for (int i = 0; i < mParams.packetHistoryMax; i++) + { + int pos = (mPacketHistoryPosition + i) % mParams.packetHistoryMax; + + if (mPacketHistory[pos]->mLen > 0) + { + char hold[256]; + udp_uchar *ptr = mPacketHistory[pos]->mBuffer; + fprintf(file, "%16s,%5d %3d: ", mPacketHistory[pos]->mIp.GetAddress(hold, sizeof(hold)), mPacketHistory[pos]->mPort, mPacketHistory[pos]->mLen); + int len = mPacketHistory[pos]->mLen; + while (len-- > 0) + { + fprintf(file, "%02x ", *ptr); + ptr++; + } + fprintf(file, "\n"); + } + } + fclose(file); + } +} + +UdpPlatformAddress UdpManager::GetLocalIp() const +{ + UdpPlatformAddress ip; + mDriver->SocketGetLocalIp(&ip); + return(ip); +} + +int UdpManager::GetLocalPort() const +{ + return(mDriver->SocketGetLocalPort()); +} + +UdpManager::PacketHistoryEntry *UdpManager::SimulationReceive() +{ + if (mSimulateIncomingList.Count() == 0 && mSimulation.simulateIncomingLatency == 0) + { + return(ActualReceive()); + } + + // pull packets from wire and queue them + UdpClockStamp curStamp = CachedClock(); + for (;;) + { + PacketHistoryEntry *entry = ActualReceive(); + if (entry == NULL) + break; + + SimulateQueueEntry *qe = new SimulateQueueEntry(entry->mBuffer, entry->mLen, entry->mIp, entry->mPort, curStamp); + mSimulateIncomingList.InsertTail(qe); + } + + SimulateQueueEntry *winner = mSimulateIncomingList.First(); + if (winner != NULL && CachedClockElapsed(winner->mQueueTime) >= mSimulation.simulateIncomingLatency) + { + mSimulateIncomingList.Remove(winner); + int pos = mPacketHistoryPosition; + memcpy(mPacketHistory[pos]->mBuffer, winner->mData, winner->mDataLen); + mPacketHistory[pos]->mLen = winner->mDataLen; + mPacketHistory[pos]->mIp = winner->mIp; + mPacketHistory[pos]->mPort = winner->mPort; + mPacketHistoryPosition = (mPacketHistoryPosition + 1) % mParams.packetHistoryMax; + delete winner; + return(mPacketHistory[pos]); + } + return(NULL); +} + +UdpManager::PacketHistoryEntry *UdpManager::ActualReceive() +{ + UdpClockStamp curStamp = CachedClock(); + if (mSimulation.simulateIncomingByteRate > 0 && curStamp < mSimulateNextIncomingTime) + return(NULL); + + UdpPlatformAddress fromAddress; + int fromPort = 0; + + for (;;) + { + int pos = mPacketHistoryPosition; + int res = mDriver->SocketReceive((char *)mPacketHistory[pos]->mBuffer, mParams.maxRawPacketSize, &fromAddress, &fromPort); + if (res < 0) + { + break; + } + + // found data + // note: this will simulate loss of ICMP errors packets too, since ICMP error packets are return from the driver as inline 0-byte packets + if (mSimulation.simulateIncomingLossPercent > 0.0f && ((Random() % 10000) < (mSimulation.simulateIncomingLossPercent * 100))) + { + continue; // packet, what packet? + } + + if (mSimulation.simulateIncomingByteRate > 0) + { + mSimulateNextIncomingTime = curStamp + (res * 1000 / mSimulation.simulateIncomingByteRate); + } + + mPacketHistory[pos]->mLen = res; + mPacketHistory[pos]->mIp = fromAddress; + mPacketHistory[pos]->mPort = fromPort; + mPacketHistoryPosition = (mPacketHistoryPosition + 1) % mParams.packetHistoryMax; + + { + UdpGuard sg(&mStatsGuard); + mLastReceiveTime = curStamp; + mManagerStats.bytesReceived += res; + mManagerStats.packetsReceived++; + } + return(mPacketHistory[pos]); + } + return(NULL); +} + +void UdpManager::ActualSend(const udp_uchar *data, int dataLen, UdpPlatformAddress ip, int port) +{ + { + UdpGuard sg(&mStatsGuard); + mLastSendTime = CachedClock(); + mManagerStats.bytesSent += dataLen; + mManagerStats.packetsSent++; + } + + if (mSimulation.simulateOutgoingByteRate != 0 || mSimulation.simulateOutgoingLatency != 0) + { + UdpGuard guard(&mSimulateGuard); + + // simulating outgoing byte-rate, so queue it up for sending later + if (mSimulation.simulateOutgoingOverloadLevel > 0 && mSimulateOutgoingQueueBytes + dataLen > mSimulation.simulateOutgoingOverloadLevel) + return; // no room, packet gets lost + + UdpConnection *con = AddressGetConnection(ip, port); + if (con != NULL) + { + if (mSimulation.simulateDestinationOverloadLevel > 0 && con->mSimulateOutgoingQueueBytes + dataLen > mSimulation.simulateDestinationOverloadLevel) + { + con->Release(); + return; // no room, packet gets lost + } + con->mSimulateOutgoingQueueBytes += dataLen; + con->Release(); + } + mSimulateOutgoingQueueBytes += dataLen; + SimulateQueueEntry *entry = new SimulateQueueEntry(data, dataLen, ip, port, LastSendTime()); + + mSimulateOutgoingList.InsertTail(entry); + + if (mSimulateOutgoingList.Count() == 1) + { + mSimulateNextOutgoingTime = udpMax(LastSendTime() + mSimulation.simulateOutgoingLatency, mSimulateNextOutgoingTime); + } + return; + } + ActualSendHelper(data, dataLen, ip, port); +} + +void UdpManager::ActualSendHelper(const udp_uchar *data, int dataLen, UdpPlatformAddress ip, int port) +{ + if (mSimulation.simulateOutgoingLossPercent > 0.0f && ((Random() % 10000) < (mSimulation.simulateOutgoingLossPercent * 100))) + return; + + if (!mDriver->SocketSend((const char *)data, dataLen, &ip, port)) + { + // assume a send error is a socket overflow, which we track only for statistical purposes + UdpGuard sg(&mStatsGuard); + mManagerStats.socketOverflowErrors++; + } +} + +void UdpManager::SendPortAlive(UdpPlatformAddress ip, int port) +{ + char buf[2]; + buf[0] = 0; + buf[1] = UdpConnection::cUdpPacketPortAlive; + mDriver->SocketSendPortAlive(buf, 2, &ip, port); +} + +void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e) +{ + if (e->mLen == 2 && e->mBuffer[0] == 0 && e->mBuffer[1] == UdpConnection::cUdpPacketPortAlive) + return; // port-alive packets are not supposed to reach the destination machine, but on the odd chance they do, pretend like they never existed + + UdpConnection *con = AddressGetConnection(e->mIp, e->mPort); + + if (con == NULL) + { + if (e->mLen == 0) // len = 0 = ICMP error + { + // we received an ICMP error packet for an unknown connection, so simply ignore it + // if we attempt to process it, it will send a destination-unreachable packet to the ip/port in question + // and create an infinite ICMP reply loop + return; + } + + // packet coming from an unknown ip/port + // if it is a connection request packet, then establish a new connection object to reply to it + // connection establish packet must always be at least 6 bytes long as we must have a version number, no matter how it changes + if (e->mBuffer[0] == 0 && e->mBuffer[1] == UdpConnection::cUdpPacketConnect) + { + if (mConnectionList.Count() >= mParams.maxConnections) + return; // can't handle any more connections, so ignore this request entirely + + if (mParams.handler != NULL) + { + UdpConnection *newcon = new UdpConnection(this, e); + CallbackConnectRequest(newcon); + newcon->Release(); + } + } + else + { + if (mParams.allowPortRemapping) + { + if (e->mBuffer[0] == 0 && e->mBuffer[1] == UdpConnection::cUdpPacketRequestRemap) + { + // ok, we got a packet from somebody, that we don't know who they are, but, it appears they are asking + // for their address/port to be remapped. If we allow port (and/or address) remapping, then go ahead + // an honor their request if possible + udp_uchar *ptr = e->mBuffer + 2; + int connectCode = UdpMisc::GetValue32(ptr); + ptr += 4; + int encryptCode = UdpMisc::GetValue32(ptr); + + UdpConnection *con = ConnectCodeGetConnection(connectCode); + if (con != NULL) + { + if (mParams.allowAddressRemapping || con->mIp == e->mIp) + { + // one final security check to ensure these are really the same connection, compare encryption codes + if (con->mConnectionConfig.encryptCode == encryptCode) + { + // remapping is allowed, remap ourselves to the address of the incoming request + UdpGuard guard(&mConnectionGuard); + + mAddressHashTable->Remove(con); + con->mIp = e->mIp; + con->mPort = e->mPort; + mAddressHashTable->Insert(con, AddressHashValue(con->mIp, con->mPort)); + + con->Release(); + return; + } + } + + con->Release(); + } + } + } + + + // got a packet from somebody and we don't know who they are and the packet we got was not a connection request + // just in case they are a previous client who thinks they are still connected, we will send them an internal + // packet telling them that we don't know who they are + if (mParams.replyUnreachableConnection) + { + // do not reply back with unreachable if the packet coming in is a terminate or unreachable packet itself + if (e->mBuffer[0] != 0 || (e->mBuffer[0] == 0 && e->mBuffer[1] != UdpConnection::cUdpPacketUnreachableConnection && e->mBuffer[1] != UdpConnection::cUdpPacketTerminate)) + { + // since we do not have a connection-object associated with this incoming packet, there is no way we could + // encrypt it or add CRC bytes to it, since we have no idea what the other end of the connection is expecting + // in this regard. As such, the UnreachableConnection packet (like the connect and confirm packets) is one + // of those internal packet types that is designated as not being encrypted or CRC'ed. + unsigned char buf[8]; + buf[0] = 0; + buf[1] = UdpConnection::cUdpPacketUnreachableConnection; + ActualSend(buf, 2, e->mIp, e->mPort); + } + } + } + return; + } + + con->ProcessRawPacket(e); + con->Release(); +} + +UdpConnection *UdpManager::AddressGetConnection(UdpPlatformAddress ip, int port) const +{ + UdpGuard guard(&mConnectionGuard); + + UdpConnection *found = mAddressHashTable->FindFirst(AddressHashValue(ip, port)); + while (found != NULL) + { + if (found->mIp == ip && found->mPort == port) + { + found->AddRef(); + return(found); + } + found = mAddressHashTable->FindNext(found); + } + return(NULL); +} + +UdpConnection *UdpManager::ConnectCodeGetConnection(int connectCode) const +{ + UdpGuard guard(&mConnectionGuard); + + UdpConnection *found = mConnectCodeHashTable->FindFirst(connectCode); + while (found != NULL) + { + if (found->mConnectCode == connectCode) + { + found->AddRef(); + return(found); + } + found = mConnectCodeHashTable->FindNext(found); + } + return(NULL); +} + +LogicalPacket *UdpManager::CreatePacket(const void *data, int dataLen, const void *data2, int dataLen2) +{ + if (mParams.pooledPacketMax > 0) + { + int totalLen = dataLen + dataLen2; + if (totalLen <= mParams.pooledPacketSize) + { + UdpGuard guard(&mPoolGuard); + PooledLogicalPacket *lp = mPoolAvailableList.RemoveHead(); + if (lp == NULL) + { + // create a new pooled packet to fulfil request + lp = new PooledLogicalPacket(this, mParams.pooledPacketSize); + } + lp->SetData(data, dataLen, data2, dataLen2); + return(lp); + } + } + + return(UdpMisc::CreateQuickLogicalPacket(data, dataLen, data2, dataLen2)); +} + +void UdpManager::PoolCreated(PooledLogicalPacket *packet) +{ + UdpGuard guard(&mPoolGuard); + mPoolCreatedList.InsertHead(packet); +} + +void UdpManager::PoolDestroyed(PooledLogicalPacket *packet) +{ + UdpGuard guard(&mPoolGuard); + mPoolCreatedList.Remove(packet); +} + +char *UdpManager::GetLocalString(char *buf, int bufLen) const +{ + if (bufLen < 22) + return(NULL); + UdpPlatformAddress ip = GetLocalIp(); + int port = GetLocalPort(); + char hold[256]; + sprintf(buf, "%s:%d", ip.GetAddress(hold, sizeof(hold)), port); + return(buf); +} + +UdpManager::CallbackEvent *UdpManager::AvailableEventBorrow() +{ + UdpGuard guard(&mAvailableEventGuard); + CallbackEvent *ce = mAvailableEventList.RemoveHead(); + if (ce == NULL) + { + ce = new CallbackEvent(); + } + return(ce); +} + +void UdpManager::AvailableEventReturn(CallbackEvent *ce) +{ + if (mAvailableEventList.Count() < mParams.callbackEventPoolMax) + { + UdpGuard guard(&mAvailableEventGuard); + mAvailableEventList.InsertHead(ce); + } + else + { + delete ce; + } +} + +void UdpManager::EventListAppend(CallbackEvent *ce) +{ + UdpGuard guard(&mEventListGuard); + mEventList.InsertTail(ce); + if (ce->mPayload != NULL) + { + mEventListBytes += ce->mPayload->GetDataLen(); + } +} + +UdpManager::CallbackEvent *UdpManager::EventListPop() +{ + UdpGuard guard(&mEventListGuard); + CallbackEvent *event = mEventList.RemoveHead(); + if (event != NULL && event->mPayload != NULL) + { + mEventListBytes -= event->mPayload->GetDataLen(); + } + return(event); +} + + +void UdpManager::ThreadStart() +{ + UdpGuard guard(&mThreadGuard); + if (mBackgroundThread == NULL) + { + mBackgroundThread = new UdpManagerThread(this, mParams.threadSleepTime); + mBackgroundThread->Start(); + } +} + +void UdpManager::ThreadStop() +{ + UdpGuard guard(&mThreadGuard); + if (mBackgroundThread != NULL) + { + assert(mRefCount > 1); // caller must hold a reference, and thread must hold a reference, so this should be true. If it asserts, it means the caller is using a UdpManager that it does not hold a reference to. + mBackgroundThread->Stop(true); + mBackgroundThread->Release(); + mBackgroundThread = NULL; + } +} + +void UdpManager::CallbackRoutePacket(UdpConnection *con, const udp_uchar *data, int dataLen) +{ + if (mParams.eventQueuing) + { + CallbackEvent *ce = AvailableEventBorrow(); + LogicalPacket *packet = CreatePacket(data, dataLen); + ce->SetEventData(CallbackEvent::cCallbackEventRoutePacket, con, packet); + packet->Release(); + EventListAppend(ce); + } + else + { + con->OnRoutePacket(data, dataLen); + } +} + +void UdpManager::CallbackConnectComplete(UdpConnection *con) +{ + if (mParams.eventQueuing) + { + CallbackEvent *ce = AvailableEventBorrow(); + ce->SetEventData(CallbackEvent::cCallbackEventConnectComplete, con); + EventListAppend(ce); + } + else + { + con->OnConnectComplete(); + } +} + +void UdpManager::CallbackTerminated(UdpConnection *con) +{ + if (mParams.eventQueuing) + { + CallbackEvent *ce = AvailableEventBorrow(); + ce->SetEventData(CallbackEvent::cCallbackEventTerminated, con); + EventListAppend(ce); + } + else + { + con->OnTerminated(); + } +} + +void UdpManager::CallbackCrcReject(UdpConnection *con, const udp_uchar *data, int dataLen) +{ + if (mParams.eventQueuing) + { + CallbackEvent *ce = AvailableEventBorrow(); + LogicalPacket *packet = CreatePacket(data, dataLen); + ce->SetEventData(CallbackEvent::cCallbackEventCrcReject, con, packet); + packet->Release(); + EventListAppend(ce); + } + else + { + con->OnCrcReject(data, dataLen); + } +} + +void UdpManager::CallbackPacketCorrupt(UdpConnection *con, const udp_uchar *data, int dataLen, UdpCorruptionReason reason) +{ + if (mParams.eventQueuing) + { + CallbackEvent *ce = AvailableEventBorrow(); + LogicalPacket *packet = CreatePacket(data, dataLen); + ce->SetEventData(CallbackEvent::cCallbackEventPacketCorrupt, con, packet); + ce->mReason = reason; + packet->Release(); + EventListAppend(ce); + } + else + { + con->OnPacketCorrupt(data, dataLen, reason); + } +} + +void UdpManager::CallbackConnectRequest(UdpConnection *con) +{ + if (mParams.eventQueuing) + { + CallbackEvent *ce = AvailableEventBorrow(); + ce->SetEventData(CallbackEvent::cCallbackEventConnectRequest, con); + EventListAppend(ce); + } + else + { + { // guard block + UdpGuard hguard(&mHandlerGuard); + if (mParams.handler != NULL) + { + mParams.handler->OnConnectRequest(con); + } + } + + if (con->GetHandler() == NULL) // if application did not set a handler, then the connection is considered refused + { + con->InternalDisconnect(0, UdpConnection::cDisconnectReasonConnectionRefused); + } + } +} + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // CallbackEvent implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpManager::CallbackEvent::CallbackEvent() +{ + mEventType = cCallbackEventNone; + mSource = NULL; + mPayload = NULL; + mReason = cUdpCorruptionReasonNone; +} + +UdpManager::CallbackEvent::~CallbackEvent() +{ + ClearEventData(); +} + +void UdpManager::CallbackEvent::SetEventData(CallbackEventType eventType, UdpConnection *con, const LogicalPacket *payload) +{ + mEventType = eventType; + mSource = con; + mSource->AddRef(); + if (payload != NULL) + { + mPayload = payload; + mPayload->AddRef(); + } +} + +void UdpManager::CallbackEvent::ClearEventData() +{ + if (mSource != NULL) + { + mSource->Release(); + mSource = NULL; + } + + if (mPayload != NULL) + { + mPayload->Release(); + mPayload = NULL; + } +} + + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // PacketHistory implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpManager::PacketHistoryEntry::PacketHistoryEntry(int maxRawPacketSize) +{ + mBuffer = new udp_uchar[maxRawPacketSize]; + mPort = 0; + mLen = 0; +} + +UdpManager::PacketHistoryEntry::~PacketHistoryEntry() +{ + delete[] mBuffer; +} + + + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // SimulateQueueEntry functions + //////////////////////////////////////////////////////////////////////////////////////////////////// +UdpManager::SimulateQueueEntry::SimulateQueueEntry(const udp_uchar *data, int dataLen, UdpPlatformAddress ip, int port, UdpClockStamp queueTime) +{ + mData = new udp_uchar[dataLen]; + mDataLen = dataLen; + memcpy(mData, data, dataLen); + mIp = ip; + mPort = port; + mQueueTime = queueTime; +} + +UdpManager::SimulateQueueEntry::~SimulateQueueEntry() +{ + delete[] mData; +} + + + /////////////////////////////////////////////////////////// + // UdpManagerThread + /////////////////////////////////////////////////////////// +UdpManagerThread::UdpManagerThread(UdpManager *manager, int sleepTime) +{ + mUdpManager = manager; + mUdpManager->AddRef(); + mStop = false; + mSleepTime = sleepTime; +} + +UdpManagerThread::~UdpManagerThread() +{ + Stop(true); + mUdpManager->Release(); +} + +void UdpManagerThread::Run() +{ + while (!mStop) + { + mUdpManager->GiveTime(); + mUdpManager->Sleep(mSleepTime); + } +} + +void UdpManagerThread::Stop(bool waitUntilStopped) +{ + mStop = true; + if (waitUntilStopped) + { + while (IsRunning()) + { + mUdpManager->Sleep(10); + } + } +} + + +} // namespace + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpManager.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpManager.h new file mode 100644 index 00000000..3715a0b2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpManager.h @@ -0,0 +1,1224 @@ +#ifndef UDPLIBRARY_UDPMANAGER_H +#define UDPLIBRARY_UDPMANAGER_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include "UdpPriority.h" +#include "UdpHashTable.h" +#include "UdpHelper.h" + +namespace UdpLibrary +{ + +enum { cReliableChannelCount = 4 }; +enum { cEncryptPasses = 2 }; + + // encryption methods are allowed to change the packet-size, so raw packet level compression + // would actually be implemented as a new encryption-method if needed + // the user-supplied method requires that the both ends of the connection have the user-supplied + // encrypt handler functions setup to correspond to each other. +enum EncryptMethod { cEncryptMethodNone + , cEncryptMethodUserSupplied // use the UdpConnectionHandler::OnUserSuppliedEncrypt function + , cEncryptMethodUserSupplied2 // use the UdpConnectionHandler::OnUserSuppliedEncrypt2 function + , cEncryptMethodXorBuffer // slower xor method, but slightly more encrypted + , cEncryptMethodXor // faster using less memory, slightly less well encrypted, use this one as first choice typically + , cEncryptMethodCount }; + +enum ManagerRole { cManagerRoleDefault // original default UdpLibrary settings + , cManagerRoleInternalServer // server process that is servicing multiple internal/local/high-bandwidth connections + , cManagerRoleInternalClient // client process that is connecting to internal servers (ie. local high-bandwidth connections) + , cManagerRoleExternalServer // server process that is servicing multiple external/relative-low-bandwidth connections + , cManagerRoleExternalClient // client process that is connection to an external server (ie. a typical end-user client setup, relatively low bandwidth) + , cManagerRoleLfn // highly specialized role for talking on a long-fat-network (super-high bandwidth, high-latency, slight packetloss, semi-dedicated pipe) + }; + + + + +class UdpManagerThread; + +struct UdpManagerStatistics +{ + udp_int64 bytesSent; + udp_int64 packetsSent; + udp_int64 bytesReceived; + udp_int64 packetsReceived; + udp_int64 connectionRequests; + udp_int64 crcRejectedPackets; + udp_int64 orderRejectedPackets; + udp_int64 duplicatePacketsReceived; + udp_int64 resentPacketsAccelerated; // number of times we have resent a packet due to receiving a later packet in the series + udp_int64 resentPacketsTimedOut; // number of times we have resent a packet due to the ack-timeout expiring + udp_int64 priorityQueueProcessed; // cumulative number of times a priority-queue entry has received processing time + udp_int64 priorityQueuePossible; // cumalative number of priority-queue entries that could have received processing time + udp_int64 applicationPacketsSent; + udp_int64 applicationPacketsReceived; + udp_int64 iterations; // number of times GiveTime has been called + udp_int64 corruptPacketErrors; // number of misformed/corrupt packets + udp_int64 socketOverflowErrors; // number of times the socket buffer was full when a send was attempted. + udp_int64 maxPollingTimeExceeded; // number of times GiveTime has aborted due to time, before exhausting all data in the socket buffer + udp_int64 maxDeliveryTimeExceeded; // number of times DeliverEvents has aborted due to time, before exhausting all data in the event queue + int connectionCount; // number of connections currently being managed + int disconnectPendingCount; // number of connections that are pending disconnection + int eventListCount; // number of events that are in the callback event queue + int eventListBytes; // number of bytes of packet data that are in the callback event queue + int poolCreated; // number of packets created in the pool + int poolAvailable; // number of packets available in the pool + int elapsedTime; // how long these statistics have been gathered (in milliseconds), useful for figuring out averages +}; + + +struct UdpReliableConfig +{ + int maxOutstandingBytes; // maximum number of bytes that are allowed to be outstanding without an acknowledgement before more are sent (default=200k) + int maxOutstandingPackets; // maximum number of physical reliable packets that are allowed to be outstanding (default=400) + int maxInstandingPackets; // maximum number of incoming reliable packets it will queue for ordered delivery while waiting for the missing packet to arrive (should generally be same as maxOutstandingPackets setting on other side) (default=400) + int fragmentSize; // this is the size it should fragment large logical packets into (default=0=max allowed=maxRawPacketSize) + int trickleSize; // maximum number of bytes to send per trickleRate period of time (default=0=max allowed=fragmentSize) + int trickleRate; // how often trickleSize bytes are sent on the channel. (default=0=no trickle control) + int resendDelayAdjust; // amount of additional time (in ms) above the average ack-time before a packet should be deemed lost and resent (default=300) + int resendDelayPercent; // percent average ack-time it should use in calculating the resend delay (default = 125 or 125%) + int resendDelayCap; // maximum length of resend-delay that will ever be assigned to an outstanding packet. (default=5000) + int congestionWindowMinimum; // the minimum size to allow the congestion-window to shrink. This defaults to 0, though internally it the implementation will never let the window get smaller than a single raw packet (512 bytes by default). + // This setting is more intended to allow the application to set a higher minimum than that, effectively allowing the application to tell the connection to refuse to slow itself + // down as much. See release notes for more details. + + int toleranceLossCount; // the number of resend-accellerated packets in a frame that is severe enough to constitute a resetting of the flow control window. + // typically this number is set in extremely high bandwidth (LFN) situations where some small amount of packetloss should not + // reset the flow-control window. (default = 0, which means that even is a single lost packet will reset the window, which matches previously UdpLibrary and TCP like behavior) + // note: setting this too high can cause it to be unfriendly to other connections sharing the network. + + bool outOfOrder; // whether incoming packets on this channel should be allowed to be delivered out of order (default=false) + bool coalesce; // whether the reliable-channel should attempt to coalesce data to reduce ack's needed (note: rarely change this to false)(default=true) + bool ackDeduping; // whether ack-packets stuck into the low-level multi-buffer should be deduped (note: rarely change this to false)(default=true) +}; + + // these functions allow you to manipulate the line-simulation parameters on the fly +struct UdpSimulationParameters +{ + UdpSimulationParameters(); + + + // the following parameters are used to simulate various line conditions that may occur. This allows the application + // program to test how well it performs under various conditions + // simulating an incoming byte-rate is simply done by internally not polling the port for a certain period of time + // after receiving a packet based on the amount of data in the last packet received + // simulating outgoing byte-rate is a bit more difficult as it requires queuing the data to be sent and slowly trickling + // it out to the socket. Simulating is very much akin to simulating lag; however, it is not exactly the same thing. It's + // possible to have low-bandwidth, yet good or bad ping times depending on how many hops away you are, but this should good + // enough for most testing. + // default = 0 + float simulateOutgoingLossPercent; // 0=no loss, 100=100% loss + float simulateIncomingLossPercent; // 0=no loss, 100=100% loss + int simulateIncomingByteRate; // simulates the incoming bandwidth specified (in bytes/second) (0=off) + + + // simulates the outgoing bandwidth specified (in bytes/second) (0=off) + // an interesting side-note of the outgoing byte-rate limit. In order to accomplish + // this we to queue stuff on the client and then pace the sending of it. When the client + // terminates the connection, the last thing it does is send a terminate packet to the other side + // The UdpManager is playing the role of the operating system when byte-limiting is on insofar as it + // is the UdpManager that is managing the virutal socket buffer. Most of the time when the client + // terminates, it also terminates the UdpManager. When you are using the outgoing byte rate simulator, + // terminating the UdpManager is akin to rebooting the box. The net effect is that any outgong packets + // in the queue are lost. This includes the ever important 'terminate-packet' that is sent to the server + // at the last moment. This means that when you are simulating an outgoing byte rate, that the server + // will never see the client properly terminate, UNLESS the client gives the UdpManager processing time + // for several seconds (long enough to flush the queue at the specified byte-rate) after the connection + // is destroyed, but before the UdpManager is destroyed. + // note: when using this setting, it is critical that you also set the simulateOutgoingOverloadLevel as + // well in order to simulate the limited-size socket buffer that the OS would have. + int simulateOutgoingByteRate; + + + // this is the number of bytes in the outgoing queue total before packets are simply lost + // this number is used to simulate the condition where you can't simply throw tons of data at a modem + // and expect it to not lose any of it. Normally this data would queue up in the socket buffer for however + // big your outgoing socket buffer is; however, if you are simulating limited outgoing bandwidth, then + // the socket buffer never actually has any data in it, instead all the queuing is taking place in the + // simulation queue. In order to handle this properly, we have to cap the outgoing simulation queue size + // total for all connection. + int simulateOutgoingOverloadLevel; + + + // this is the number of bytes in the outgoing queue/connection before packets are simply lost (0=infinite) + // this number is used to simulate the condition where some router or terminal-server down + // the line has a limited buffer size and once it gets overloaded it just throws away new incoming + // packets. The reason we have to do this is because otherwise our internal simulation queue + // would grow forever. The loss of packets is necessary for the flow control stuff to do its + // job. The incoming side uses the socket-buffer for this purpose and as such can simply + // set the incoming socket buffer to the desired size and the OS will throw away stuff that comes + // in yet doesn't fit. Since this parameter is supposed to simulate a line condition downward + // toward the destination and we may have multiple destinations in our queue, this handles it properly + // by tracking the amount of data queued for each destination ip/port address (it does this by actually + // back-link up to the UdpConnection object). + int simulateDestinationOverloadLevel; + + + // this simulates outgoing packet latency. That is, if you set this value to 100, it will act as if every + // packet sent lived on the wire for 100ms longer than it actually did. That is, the library will hold the raw + // packet for 100ms before putting it on the wire, such that it simulates the packet having been on the wire for + // 100ms longer than it actually was. + int simulateOutgoingLatency; + + // this simulates incoming packet latency. That is, if you set this value to 100, it will act as if every + // packet received off the wire took 100ms longer than it actually did. That is, the library will hold the raw + // packet for 100ms before processing it in any way. + int simulateIncomingLatency; +}; + +struct UdpParams +{ + UdpParams(ManagerRole role = cManagerRoleDefault); // constructor merely sets default values for the structure members + + // instead of specifying a callbackConnectRequest pointer, you can also specify a handler object to receive + // the callback directly. To have the UdpManager call your object directly when connection requests come in, you + // simply need to derive your class (multiply if necessary) from UdpManagerHandler, then you can set this + // pointer equal to your object and the UdpManager will call it as appropriate. The UdpConnection object + // also has a handler mechanism that replaces the other callback functions below, see UdpConnection::SetHandler + // if a handler is specified, the callback function is ignored, even if specified. + // default = NULL (not used) + UdpManagerHandler *handler; + + // this is the maximum number of connections that can be established by this manager, any incoming/outgoing connections + // over this limit will be refused. On the client side, this typically only needs to be set to 1, though there + // is little harm in setting this number larger. + // default = 10 + int maxConnections; + + // this is the port number that this manager will use for all incoming and outgoing data. On the client side + // this is typically set to 0, which causes the manager object to randomly pick an available port. On the server + // side, this port should be set to a specific value as it will represent the port number that clients will use + // to connect to the server (ie. the listening port). It's generally a good idea to give the user on the client + // side the option of fixing this port number at a specific value as well as it is often necessary for them to + // do so in order to navigate company firewalls which may have specific port numbers open to them for this purpose. + // default = 0 + int port; + + // if port is not zero, setting this to a value greater than zero causes it to randomly pick a port in the range + // (port to port+portRange). This is desireable when you wish to have the manager bind to a random port within + // a specified range. If you specify a portRange to use, then port must not be 0 (since 0 means to let the OS + // pick the port to use). 0=don't use a range, bind only to the port specified in 'port' setting. + // default = 0 + int portRange; + + // the size of the outgoing socket buffer. The client will want to set this fairly small (32k or so), but the server + // will want to set this fairly large (512k) + // default = 64k + int outgoingBufferSize; + + // the size of the incoming socket buffer. The client will want to set this fairly small (32k or so), but the server + // will want to set this fairly large (512k) + // default = 64k + int incomingBufferSize; + + // the purpose of the packet history is to make debugging easier. Sometimes a processed packet will cause the server + // to crash (due to a bug or possibly just corruption). Typically the application will put an exception handler around + // the main loop and call UdpManager::DumpPacketHistory when it is triggered. This will dump a history of the last + // packets received such that they can be analyzed by hand to determine if one of them caused the problem and why. + // The packet history is done at the raw packet level (before logical packet re-assembly). This is the number of raw + // packets to buffer in the history. Typically this can be set fairly small (maybe 1000) since packets older than + // that have little debug value. (uses maxRawPacketSize * thisValue of memory) + // default = 4 + int packetHistoryMax; + + // how long a connection will wait before sending a keep-alive packet to the other side of the connection + // set this to 0 to never send keep-alive packets (typically the server will set this to 0 and never keep alive + // the client, but the client will typically set this some value that will ensure that the server will not kick them + // for inactivity. Keep alive packets are only sent if no other data is being sent. + // default = 0 + int keepAliveDelay; + + // this is very similar to the keep alive delay, but serves a completely different purpose and may not have the desired + // effect on all platforms. The purpose of the keepAliveDelay above is generally to keep data flowing to the server + // so it knows that the client is still there. In this manner if the server doesn't get data within a certain period + // of time, it can know that the connection is probably dead. Sometimes it is the case that the server does not need + // to be kept alive, or at least kept alive very often (like for a chat server perhaps where nobody is talking much). + // For some people, it may be necessary to send data more frequently in order to keep their NAT mapping fresh, or their + // firewall software happy. However, we don't want to be in a situation where our server is receiving a lot more data + // than it needs to just so these people can keep their port open. I have seen NAT's that lose mappings in as short + // as 20 seconds. What this feature does is a bit tricky. It changes the time-to-live (TTL) for a special keep-alive + // packet to some small value (4) which is enough for the packet to get past firewalls and NAT's, but not make it all + // the way to our server. In this manner, the port gets kept alive, but we don't waste bandwidth with these packets. + // These special packets are not counted statistically in any way and they do not reset any timers of any kind. Their + // sole purpose is to keep the port alive on the client side. Any other data (include standard keepAlive packets will + // reset the timer for this packet, so obviously the portAliveDelay must be smaller than the keepAliveDelay in order + // to be meaningful. + // default = 0 = off + int portAliveDelay; + + // whether this UdpManager should send back an unreachable-connection packet when it receives incoming data from + // a destination it does not have a UdpConnection object representing. This is the equivalent of a port-unreachable + // ICMP error packet, only taken up one level further to the virtual-connection object (UdpConnection). Imagine a + // server that has terminated a client's connection, but the client didn't get notice that such termination had occurred. + // The client would still think the connection was good and continue to try and send data to the server, but the data + // would simply be getting lost and queued up indefinately on the client. The client doesn't get port unreachable errors + // since the server is using the same port for lots of people. Having this true causes the server to notify the client + // that its connection is dead. If a client finds out it is terminated in this manner, it will set its disconnect reason + // to cDisconnectReasonUnreachableConnection. + // default = true + bool replyUnreachableConnection; + + // the UdpLibrary supports a feature whereby a connection can remap its ip/port on-the-fly. How it works is, if a client + // gets back a connection-unreachable error, it will send out a request for the server to remap its connection to the + // new port that it is coming from. This will happen if a NAT expires and the next outgoing packet causes a different + // port-mapping to be selected. The UdpLibrary can recover from this situation. The icmpErrorRetryPeriod must be + // set to a reasonably high value, such that the client has time to send data and request the remapping before icmp + // errors are processed. This value determines not only whether a server will honor a remapping request, but also + // whether the client will attempt a remapping request. The terms client as server are used loosely here, as it is + // possible for the server to request the remapping (though it is extremely unlikely that the server end + // of a connection will have its port changed on-the-fly). + // default = true + bool allowPortRemapping; + + // this is the same as allowPortRemapping, only it allows the full IP address to be remapped on-the-fly. I + // recommend that you do NOT enable this, as it represents a fairly serious security loophole, whereby a hacker could + // cause random people to be disconnected, and in theory possibly even hi-jack their connection. The odds of this + // actually being able to happen are incredibly rare unless the hacker has been snooping your packet stream, as they + // would effectively have to guess two 32-bit random numbers (one generated by the client and one generated by the server) + // default = false + bool allowAddressRemapping; + + + // how long (in milliseconds) the manager will ignore ICMP errors to a particular connection before it will act upon + // them and terminate the connection. When a packet is successfully received into the connection in question, the + // retry period is reset, such that the next time an ICMP error comes in, it has another period of time for it + // to resolve the issue. This servers a couple purpose, 1) it can allow for momentary outages that can be recovered + // from in short order, and 2) it is necessary for the port-remapping feature to work properly in situations where + // the server may send data to the old-port before the remapping negotiations are completed. In order for the + // remapping feature to work properly, this value should be set to larger than the longest time a connection typically + // goes without receiving data from the other side. (0=no grace period) + // default = 5000 + int icmpErrorRetryPeriod; + + // how long a connection will go without receiving any data before it will terminate the connection + // set this to 0 to never have the connection terminated automatically for receiving no data. + // the application will receive an OnTerminated callback when the connection is terminated due to this timeout + // this setting can be overridden on a per-connection basis by calling UdpConnection::SetNoDataTimeout + // default = 0 + int noDataTimeout; + + // when reliable data is sent, it remains in the queue until it is acknowledged by the other side. When you query + // the reliable channel status, you can find out the age of the oldest piece of data in the queue that has been sent + // yet has not been acknowledged yet. As a general rule, if things are operating correctly, it should be very rare + // for something that has been sent to not be acknowledged within a few seconds, even if resending had to occur. + // Eventually, the sender could use this statistic to determine that the other side is no longer talking and terminate + // the connection. In past version of the UdpLibrary, the sending-application has checked this statistic itself. This + // parameter will cause the UdpLibrary to monitor this for you and automatically change the connection to a disconnected + // state when the value goes over this setting (in milliseconds) (0 means do not perform this check at all) + // The default is set fairly liberally, on client-side connections, you could safely set this to as low as 30 seconds + // allowing for quicker realization of lost connections. Often times the connection will realize it is dead much quicker + // for other reasons. When disconnected due to this, the disconnect reason is set to cDisconnectReasonUnacknowledgedTimeout + // default = 90000 + int oldestUnacknowledgedTimeout; + + // maximum number of bytes that are allowed to be pending in all the reliable channels combined + // before it will terminate the connection with a cDisconnectReasonReliableOverflow. If this value is set to + // zero, then it will never overflow (it will run out of memory and crash first). If your application wants + // to do something other than disconnect on this condition, then the application will have to periodically check the status + // itself using UdpConnection::TotalPendingBytes and act as appropriate. + // default = 0 + int reliableOverflowBytes; + + // how long a connection will hold onto outgoing data in hopes of bundling together future outgoing data in the same + // raw packet (specified in milliseconds) + // setting this to 0 will cause it to effectively flush at the end of every frame. This is generally desireable in + // cases where frame-rates are slow (less than 10 fps), or for internal LAN connections. + // default = 50 + int maxDataHoldTime; + + // how much data a connection will hold onto before sending out a raw packet + // (0=no multi-packet buffering, all application sends result in immediate raw packet sends) + // (-1=use same value as maxRawPacketSize) + // this value will be effectively ignored if it is larger than the maxRawPacketSize specified below) + // default = -1 + int maxDataHoldSize; + + // this is the maximum raw physical packet size that the UdpLibrary will attempt to send or can receive. + // In very old versions of the UdpLibrary, both sides needed to have this value configured identically. In the + // newer versions, this value is negotiated during connection negotiation and the actual size used is the smaller + // value of what the client has configured and what the server has configured. As a general rule, any connection + // that talks off of the local-area-network should leave this at the default value of 512. Internal server to server + // connections should set this number to 1460 bytes, as that represents the maximum size that can fit in a normal + // ethernet frame. If you are unsure, set it to 512, since this value is guaranteed to work on any IP based network. + // Larger values will make more efficient use of internal network resources if you know that all connectionsn are + // going to be on our internal network. + // default = 512, minimum = 64 + int maxRawPacketSize; + + // how large the hash-table is for looking up connections. It takes 4*hashTableSize memory and it is recommended + // you set it fairly large to prevent collisions (10 times maximum number of connections should be fine) + // default = 100 + int hashTableSize; + + // whether a priority queue should be used. If a priority queue is not used, then everytime + // UdpManager::GiveTime is called, every UdpConnection object gets processing time as well. + // It is thought that if traffic is heavy enough, that managing the priority queue may end up being more + // cpu time than giving everybody time (as it is possible everybody would end up getting time anyways) + // if not using a priority queue, it is recommended that you GiveTime only periodically (every 50ms for example) + // the more often you GiveTime, the more critical the priority-queue is at reducing load compared to not using it + // default = false + bool avoidPriorityQueue; + + // how often the client synchronizes its timing-clock to the servers (0=never)(specified in ms). + // the server-side MUST specify this as 0, or else the server will attempt to synchronize it's clock with + // the client as well (which would just be a waste of packets generally, though would work) + // the client should generally always set this feature on by setting it to something like 45000 ms. + // the clock-sync is used to negotiate statistics as well, so if you are not using clock sync, then you + // will not be able to get packetloss/lag statistics for the connection. If you are using it, then you will + // be able to get these statistics from either end of the connection. + // default = 0 + int clockSyncDelay; + + // when the UdpManager is destroyed and the socket is closed, all pending data in the socket is destroyed + // (because we are UDP and non-blocking, there is no lingering time). The problem is, on the client side it + // is often the case that connection and manager are destroyed simultaneously. This can often result in the + // final terminate-packet not making it to the server since the terminate packet will often get thrown away + // when the socket buffer is destroyed. This delay will cause the UdpManager to sleep momentarily (for however + // long is specified in this option) in order to give the OS time to flush out that socket buffer before it + // destroys it. I wish there were a way to select on whether a socket buffer was empty, but there isn't, and there + // is no way to query how full an outgoing socket buffer is. As such, the only way to have a fair-chance of deliver + // of this final packet is to simply give up our time-slice momentarily and hope the OS pumps out that final message + // to the network before we wake up and destroy the socket. By default we will have it sleep for 10ms, which does + // little more than give up our time-slice, but should be enough to get the job done in most cases. Setting this + // value to 0 will cause it to not linger at all. Again, however long you set this value to is how long the + // UdpManager destructor will block. + // default=10 + int lingerDelay; + + + // these two values control the number of packets that the UdpManager will create in its packet pool. The packet pool + // is a means by which the UdpManager avoid allocating logical packets for every send, by instead using them from the pool. + // you need to specify the size of the packets that are in the pool. Then, when somebody calls UdpManager::CreatePacket, + // if the packet being created is small enough and there is room available, it grabs one from the pool, otherwise it + // creates a new non-pooled one. The largest the pool will ever grow is pooledPacketMax, and the memory used will be roughly + // pooledPacketMax * pooledPacketSize. You should be generous with the pool packet size and the pool max in order + // to avoid having to do allocations as much as possible + // pooledPacketMax default = 1000, (0 = don't use memory pooling at all) + int pooledPacketMax; + // pooledPacketInitial is the number of packets to allocate in the initial pool. The only reason to set this to + // something other than the default, which is 0, is to avoid having your memory fragmented as the pool grows on demand. + int pooledPacketInitial; + // as a general rule, ou should leave this at -1. This is critical. If the pooledPacketSize is smaller than the + // maxRawPacketSize, then all the coalescing that occurs in the reliable channel will result in allocations. You + // would just as well not have a pool if you don't set this at least as large as the maxRawPacketSize. If your application + // tends to send largish packets (larger than maxRawPacketSize), setting this large enough to cover those might buy you + // some speed as well. + // pooledPacketSize defaults to -1, which means use the same as maxRawPacketSize + int pooledPacketSize; + + // the maximum number of entries to allow in the callback event pool. The callback event pool is only used + // if the application is queuing callback events for later delivery in the main thread. This pool serves as + // an optimization by providing a pool of these objects to use. Generally, this number should be set as large + // as the highest number of callback events that might come in between calls to have the events delivered. + // We do not pre-create these things, they are just created on demand. + // default = 5000 + int callbackEventPoolMax; + + // whether ICMP error packets should be used to determine if a connection has gone dead. + // when the destination machine is not available, or there is no process on the destination machine + // talking on the port, then a ICMP error packet will sometimes be returned to the client when a packet is sent. + // Processing ICMP errors will often allow the client machine to quickly determine that the other end of the + // connection is no longer reachable, allowing it to quickly change to a disconnected state. The downside + // of having this feature enabled is that it is possible that if there is a network problem along the route, that + // the connection will be terminated, even though the hardware along the route may correct the problem by re-routing + // within a couple seconds. If you are having problems with clients getting disconnected for ICMP errors (see + // disconnect reason), and you know the server should have remained reachable the entire time, then you might + // want to set this setting to false. The only downside of setting this to false is that it might take the + // client a bit longer to realize when a server goes down. + // default = true + bool processIcmpErrors; + + // whether ICMP errors should be used to terminate connection negotiations. By default, this is set to + // false, since generally when you are trying to establish a new connection (ie. negotiating), you are + // are willing to wait for timeout specified in the EstablishConnection call, since it may be a case + // that the client process gets started slightly sooner than the server process. + // default = false + bool processIcmpErrorsDuringNegotiating; + + + // during connection negotiation, the client sends connect-attempt packets on a periodic basis until the + // server responds acknowledging the connection. This value represents how often the client sends those packets. + // By default this is set to 1000 or 1 second and generally should not be messed with. + int connectAttemptDelay; + + // if you call UdpManager::ThreadStart to start a background thread going calling GiveTime, it will sleep for + // this amount of time each iteration. Generally there is no reason to change this value as going much faster + // doesn't buy you much, and going much slower doesn't save you much either. + // default = 20 + int threadSleepTime; + + + // This settings allows you to bind the socket used by the library to a specific IP address on the machine. + // Normally, and by default, the library will bind the socket to any address in the machine. This setting should + // not be messed with unless you really know what you are doing. In multi-homed machines it is generally NOT + // necessary to bind to a particular address, even if there are firewall issues involved, and even if you want + // to limit traffic to a particular network (firewalls do a better job of serving that purpose). If you are having + // problems communicating with a server on a multi-homed machine and think this might solve the problem, think again. + // You most likely need to configure the OS to route data appropriately, or make sure that internal network clients + // are connecting to the machine via the machines internal IP address (or vice versa). + // by default this string is empty meaning the socket is bound to any address. To bind to specific IP address, it + // should be entered in a.b.c.d form (DNS names are not allowed). Figuring out what IP addresses are in the machine + // and which one should be bound to is left as an exercise for the user. + char bindIpAddress[32]; + + // you need to specify the characteristics of the various reliable channels here, generally you will want + // to make sure the client and server sides set these characteristics the same, though it is technically not + // required. Each channel decides locally whether it will accept out of order delivery on a particular channel or not. + // (note: out of order delivery is a tiny optimization that simply lets the channel deliver the packet the moment it + // arrives, even if previous packets have not yet arrived). Likewise trickle-rates are for outgoing data only obviously. + // reliable channel managers are not actually created internally until data is actually sent on the channel, so there + // is no overhead associated with channels that are not used, and you need not specify characteristics for channels + // that you know you will not be using. + // default = 400 packets in&out/200k outstanding, ordered, no trickle (all channels) + UdpReliableConfig reliable[cReliableChannelCount]; + + + // when user supplied encrypt and decrypt routines are specified, it becomes necessary to tell the UdpManager + // how many bytes the encryption process could possibly expand the chunk of data it was given. Often times this + // will simply be 0, but if the user supplied routines attempt compression, then it's possible that expansion could + // could actually occur. Typically I would have the compression routines put a leader-byte on the chunk of data + // specifying whether it was compressed or not. Then if the compression didn't pan out, it could alway abort and just + // prepend the byte in question and the rest of the data. In that sort of algorithm, you would set this value to 1 + // since the most it could ever expand beyond the original is the 1-byte indicator on the front. It's possible that + // a particular encryption routine might want to append a 4-byte encryption key on the end of the chunk of data, in + // which case you would need to reserve 4 bytes. This is necessary as it allows the udp library to guarantee that + // no packet will be larger than maxRawPacketSize, and at the same time ensures that the destination buffers supplied + // to the encrypt/decrypt functions will have enough room. Obviously this value is ignored if the encryptMethod + // is not set to cEncryptMethodUserSupplied. + // default = 0 + int userSuppliedEncryptExpansionBytes; + int userSuppliedEncryptExpansionBytes2; + + + // pointer to driver-object to use for this manager. Typically, this driver object will create + // the UdpPlatformDriver object itself and chain the calls on through, plus do whatever else it wants; + // however, that is not required. The application maintains ownership of this object and the object must + // not be destroyed by the application until the UdpManager using it is destroyed. + // default = NULL, meaning the UdpManager it will create it's own UdpPlatformDriver for use. + UdpDriver *udpDriver; + + + // whether the UdpManager should be operating in event-queuing mode. This setting can be changed on the fly + // by the application through the SetEventQueuing function call. When in event queuing mode, all callbacks + // to the application via either the UdpConnectionHandler or the UdpManagerHandler are queued and only sent + // when the application makes a DeliverEvents call (or turns queuing mode off). Queuing these events is not + // quite as efficient as processing them inline, so should generally only be done when the threading benefits + // are needed. The main purpose of this feature is such that a background thread can GiveTime to the UdpManager + // on a regulard basis, yet the applications main thread can call DeliverEvents only at times it is capable of + // processing the packets. If your application's main loop consistently spins fast enough (say 10 fps), then I + // recommend not spinning a thread to give time to the UdpManager, and instead giving time in the main thread + // and operating in non-queuing mode. See SetEventQueuing function call for more details. + // default = false + bool eventQueuing; + + + // largest application packet to expect incoming on the wire. This should generally be set liberally as it will + // disconnect any connection that tries to send a larger packet than this. The purpose of this setting it to + // prevent hackers from fiddling with the packet-stream and make the server think it has an enomous (gigabytes) + // packet coming in, as it will allocate a buffer to hold the incoming packet, which could lead to a server crash. + // Since extremely large applications packets are rare, I have set the default limit to somewhat low, since most + // applications won't bother to mess with this setting. If you legitimately send super-big packets, you may need + // to increase this number + // default = 10mb + int incomingLogicalPacketMax; + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // the following values are ignored by connections initiated by this manager (ie. client side) since the server will tell + // the client the values that are in effect during the connection initialization process. + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + // how many additional bytes of CRC data is added to raw packets to ensure integrity (0 through 4 allowed) + // default = 0 + int crcBytes; + + // which encryption method is to be used (see enumeration) (this occurs at the raw packet level) + // default = cEncryptMethodNone + EncryptMethod encryptMethod[cEncryptPasses]; +}; + + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // The purpose of the UdpManager is to manage a set of connections that are coming in on a particular port. + // Typically an application will only have one UdpManager taking care of all incoming connections. The + // exception is if the application is talking to two distinct sets of individuals. For example, the leaf + // server application might have a UdpManager to manage the connections to all the users/players who will + // be connecting. It may then have a second UdpManager to manage its connection to a master server + // someplace (though in theory it could use one UdpManager for everything). + // + // The UdpManager owns the solitary socket that all data being sent/received by any of the managed connections uses. + // When the UdpManager is created, it is given a port-number that it uses for this purpose. The UdpManager is capable + // of establishing new connections to other UdpManager, or it is also capable of accepting new connections. + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + +class UdpManager : public UdpGuardedRefCount +{ + public: + enum ErrorCondition { cErrorConditionNone, cErrorConditionCouldNotAllocateSocket, cErrorConditionCouldNotBindSocket }; + + typedef UdpParams Params; // DEPRECATED: in here for backwards compatibility + + enum { cProtocolVersion = 2 }; // protocol version must match on both ends, or connect packets are simply ignored by the server + enum { cHardMaxRawPacketSize = 8192 }; + enum { cHardMaxOutstandingPackets = 30000 }; // don't change this + + UdpManager(const UdpParams *params); + + void SetHandler(UdpManagerHandler *handler); + UdpManagerHandler *GetHandler() const; + void SetPassThroughData(void *passThroughData); + void *GetPassThroughData() const; + ErrorCondition GetErrorCondition() const; + + // previous UdpMisc stuff that now needs driver + udp_ushort LocalSyncStampShort(); // gets a local-clock based sync-stamp. (only good for timings up to 32 seconds) + udp_uint LocalSyncStampLong(); // gets a local-clock based sync-stamp. (good for timings up to 23 days) + int ClockElapsed(UdpClockStamp stamp); // returns a elapsed time since stamp in milliseconds (if elapsed is over 23 days, it returns 23 days) + UdpClockStamp Clock(); + int Random(); + void Sleep(int milliseconds); // chains on through to the driver object + + + // this function MUST be called on a regular basis in order to give the manager object time to service the socket + // and give time to various connection objects that may need processing time to send/resend packets, etc. + // + // If you set maxPollingTime to 0, it will not attempt to receive any packets out of the socket. If no + // packets are gotten from the socket, then it is impossible for any packets to be forwarded to the application; + // hence, this is a good way to give the manager processing time for outgoing packets in situations + // where the application does not want to have to worry about processing incoming packets. + // + // If you set maxPollingTime to -1, it will poll at most 1 packet out of the socket at a time and process it. You + // should know that a single packet on the socket can possibly result in multiple data-packets being delivered to the application. + // For example, the incoming packet could be a previous lost reliable packet, which would cause all the stalled reliable packets to be + // delivered. Multi-buffering could also result in multiple route-packet callbacks from one physical packet coming off the socket. + // The purpose of this 1-packet feature is primarily to support the EstablishConnection process. By processing only one packet at a + // time, it gives the application a chance to check the status of a negotiating connection before any data is possibly delivered to + // that connection. This allows the client-app to loop on GetStatus checking for the connection to get established, then create all + // the infrastructure necessary to support that connection once it is established, without fear of packets being delivered before said + // infrastructure is in place. This is safe since connection-confirmation packets do not multi-buffer up. + // + // The only reason you might want to avoid giving the connections time is if you are a fairly non-packet-time critical application + // and are using the avoidPriorityQueue setting (and want to avoid using up too much CPU time while at the same + // time you don't want to avoid processing the socket). + // returns true if any incoming packets were processed during this time slice, otherwise returns false + bool GiveTime(int maxPollingTime = 500, bool giveConnectionsTime = true); + + + // when in event queuing mode, callback events are all queued by the GiveTime function for later deliver. The application + // must call DeliverEvents in order to get these events deliver. If there are events queued and you turn off queuing mode, + // the next call to GiveTime will cause the queued events to actually be delivered. + // note: specifying 0 for maxProcessingTime causes it to deliver at most one event during that call. This can be + // used in situations where the application wants to get control back after each event processed. + void DeliverEvents(int maxProcessingTime = 500); + + // gets/sets the event queuing mode. By default the event queuing mode is off. The application must explicity + // call SetEventQueuing(true) to turn on event queuing. Generally, event queuing is used if the application sets up + // a worker thread to give the UdpManager processing time, but doesn't want events delivered during that GiveTime call. + // The main application thread that does want to receive deliver of the packets then calls DeliverEvents explicitly when + // it wants the events delivered. The main loop need not ever call GiveTime if they have a worker-thread doing it. + void SetEventQueuing(bool on); + bool GetEventQueuing() const; + + // changes the UdpParams::maxDataHoldTime setting on the fly + void SetMaxDataHoldTime(int milliseconds); + int GetMaxDataHoldTime() const; + + // start/stop a thread from automatically calling GiveTime in the background. + // you will generally want to make sure you are in event queuing mode if you enable threads, otherwise + // you will receive callbacks asynchronously from the other thread. Normally you will want to call + // DeliverEvents instead of GiveTime to cause the queued events to be delivered. + void ThreadStart(); + void ThreadStop(); + + // used to establish a connection to a server that is listening at the specified address and port. + // the serverAddress will do a DNS lookup as appropriate. This call will block long enough to resolve + // the DNS lookup, but then will return a UdpConnection object that will be in a cStatusNegotiating + // state until the connection is actually established. The application must give the manager + // object time after calling EstablishConnection or else the negotiation process to establish the + // connection will never have time to actually occur. Typically the client establishing the connection + // will call EstablishConnection, then sit in a loop calling UdpManager::GiveTime and checking to see + // if the status of the returned UdpConnection object is changed from cStatusNegotiating. This allows + // the application to look for the ESC key or timeout an attempted connection. + // This function will return NULL if the manager object has exceeded its maximum number of connections + // or if the serverAddress cannot be resolved to an IP address + // as is noted in the declaration, it is the responsibility of the application establishing the connection to delete it + // setting the timeout value (in milliseconds) to something greater than 0 will cause the UdpConnection object to change + // from a cStatusNegotiating state to a cStatusDisconnected state after the timeout has expired. It will also cause + // the connect-complete callback to be called. + // note: if serverPort is 0, then serverAddress MUST contain the port-number appended to the address in the form ":port" + // for example: myserver.com:5000 or 127.0.0.1:5000 + UdpConnection *EstablishConnection(const char *serverAddress, int serverPort = 0, int timeout = 0); + + // gets statistical information about this manager, which covers all connections going through this manager + // (useful for getting server-wide statistics) + void GetStats(UdpManagerStatistics *stats); + void ResetStats(); + + // this function will dump the packet history out to the specified filename. If no packet history is being kept (see UdmManagerParams::packetHistoryMax) + // then this function does nothing. + void DumpPacketHistory(const char *filename) const; + + // returns the ip address of this machine. If the machine is multi-homed, this value may be blank. + UdpPlatformAddress GetLocalIp() const; + + // returns the port the manager is actually using. This value will be the same as is specified in Params::port (or if Params::port was set to 0, this will be the dynamically assigned port number) + int GetLocalPort() const; + + // return a string representing the local ip and port the manager is actually using + char *GetLocalString(char *buf, int bufLen) const; + + // returns how long it has been (in milliseconds) since this manager last received data + int LastReceive(); + + // returns how long it has been (in milliseconds) since this manager last sent data + int LastSend(); + + // manually forces all live connections to flush their multi buffers immediately + void FlushAllMultiBuffer(); + + // forces all connections to disconnect. If an application is not sure that all connections are disconnected + // before destroying the UdpManager, it is recommended that they call this first, as it will generally clean + // up the connections better by increasing the chances that the other side of the connection will receive a + // a terminated packet. + void DisconnectAll(); + + // creates a logical packet and populates it with data. data can be NULL, in which case it gives you logical packet + // of the size specified, but copies no data into it. If you are using pool management (see Params::poolPacketMax), + // it will give you a packet out of the pool if possible, otherwise it will create a packet for you. When logical + // are packets are needed internally for various things (like reliable channel sends that use the (void *, int) interface) + // they are gotten from this function, so your application can likely take advantage of pooling, even if it never bothers + // to explicitly call this function. + LogicalPacket *CreatePacket(const void *data, int dataLen, const void *data2 = NULL, int dataLen2 = 0); + + void GetSimulation(UdpSimulationParameters *simulationParameters) const; + void SetSimulation(const UdpSimulationParameters *simulationParameters); + + protected: + friend class PooledLogicalPacket; + void PoolReturn(/*gift*/ PooledLogicalPacket *packet); // so pooled packets can add themselves back to the pool. Note: this steals the reference for thread-safety reasons. + void PoolCreated(PooledLogicalPacket *packet); + void PoolDestroyed(PooledLogicalPacket *packet); + + protected: + friend class UdpReliableChannel; + + class PacketHistoryEntry + { + public: + PacketHistoryEntry(int maxRawPacketSize); + ~PacketHistoryEntry(); + + public: + udp_uchar *mBuffer; + UdpPlatformAddress mIp; + int mPort; + int mLen; + }; + + UdpParams mParams; + UdpSimulationParameters mSimulation; + PacketHistoryEntry **mPacketHistory; + int mPacketHistoryPosition; + int mRandomSeed; + int mEventListBytes; + UdpManagerThread *mBackgroundThread; + + void *mPassThroughData; + + UdpLinkedList mConnectionList; + UdpLinkedList mDisconnectPendingList; // linked list of connections to be released when they go to cStatusDisconnected + + ObjectHashTable > *mAddressHashTable; + ObjectHashTable > *mConnectCodeHashTable; + PriorityQueue *mPriorityQueue; + UdpClockStamp mMinimumScheduledStamp; // soonest anybody is allowed to schedule themselves for more processing time + + UdpDriver *mDriver; + bool mInsideGiveTime; + UdpClockStamp mLastReceiveTime; + UdpClockStamp mLastSendTime; + UdpClockStamp mLastEmptySocketBufferStamp; + int mProcessingInducedLag; // how long the currently being processed packet could have possibly been sitting in the socket-buffer waiting for processing (which is effectively how long it has been since we last quit polling packets from the socket queue) + ErrorCondition mErrorCondition; + UdpClockStamp mCachedClock; + + UdpPlatformGuardObject mCachedClockGuard; + UdpPlatformGuardObject mThreadGuard; + UdpPlatformGuardObject mPoolGuard; + UdpPlatformGuardObject mEventListGuard; + UdpPlatformGuardObject mAvailableEventGuard; + UdpPlatformGuardObject mStatsGuard; + UdpPlatformGuardObject mDisconnectPendingGuard; + UdpPlatformGuardObject mSimulateGuard; + mutable UdpPlatformGuardObject mGiveTimeGuard; + mutable UdpPlatformGuardObject mConnectionGuard; + mutable UdpPlatformGuardObject mHandlerGuard; + + UdpManagerStatistics mManagerStats; + UdpClockStamp mManagerStatsResetTime; + + // stuff for managing the outgoing packet-rate simulation + class SimulateQueueEntry + { + public: + SimulateQueueEntry(const udp_uchar *data, int dataLen, UdpPlatformAddress ip, int port, UdpClockStamp queueTime); + ~SimulateQueueEntry(); + public: + UdpLinkedListMember mLink; + udp_uchar *mData; + int mDataLen; + UdpPlatformAddress mIp; + int mPort; + UdpClockStamp mQueueTime; + }; + friend class SimulateQueueEntry; + int mSimulateOutgoingQueueBytes; + UdpClockStamp mSimulateNextIncomingTime; + UdpClockStamp mSimulateNextOutgoingTime; + + UdpLinkedList mSimulateIncomingList; + UdpLinkedList mSimulateOutgoingList; + + // pool management + UdpLinkedList mPoolCreatedList; + UdpLinkedList mPoolAvailableList; + + protected: + class CallbackEvent + { + public: + enum CallbackEventType { cCallbackEventNone, cCallbackEventRoutePacket, cCallbackEventConnectComplete + , cCallbackEventTerminated, cCallbackEventCrcReject, cCallbackEventPacketCorrupt + , cCallbackEventConnectRequest }; + + CallbackEvent(); + ~CallbackEvent(); + void SetEventData(CallbackEventType eventType, UdpConnection *con, const LogicalPacket *payload = NULL); + void ClearEventData(); + + CallbackEventType mEventType; + UdpConnection *mSource; + const LogicalPacket *mPayload; + UdpCorruptionReason mReason; // only used by CorruptPacket event + UdpLinkedListMember mLink; + }; + + // event queuing + CallbackEvent *AvailableEventBorrow(); + void AvailableEventReturn(CallbackEvent *ce); + void EventListAppend(CallbackEvent *ce); + CallbackEvent *EventListPop(); + + UdpLinkedList mAvailableEventList; + UdpLinkedList mEventList; + + + protected: // internal functions + int AddressHashValue(UdpPlatformAddress ip, int port) const; + UdpConnection *AddressGetConnection(UdpPlatformAddress ip, int port) const; // NOTE: returns an AddRef'ed connection, caller must release it + UdpConnection *ConnectCodeGetConnection(int connectCode) const; // NOTE: returns an AddRef'ed connection, caller must release it + + PacketHistoryEntry *SimulationReceive(); + PacketHistoryEntry *ActualReceive(); + void ActualSendHelper(const udp_uchar *data, int dataLen, UdpPlatformAddress ip, int port); + void ProcessRawPacket(const PacketHistoryEntry *e); + void ProcessDisconnectPending(); + void CloseSocket(); + void CreateAndBindSocket(int usePort); + void CallbackConnectRequest(UdpConnection *con); + UdpClockStamp LastSendTime(); + + protected: // functions called by the UdpConnection + friend class UdpConnection; + + void KeepUntilDisconnected(UdpConnection *con); + void AddConnection(UdpConnection *con); + void RemoveConnection(UdpConnection *con); + void ActualSend(const udp_uchar *data, int dataLen, UdpPlatformAddress ip, int port); + void SendPortAlive(UdpPlatformAddress ip, int port); + void SetPriority(UdpConnection *con, UdpClockStamp stamp); + void CallbackRoutePacket(UdpConnection *con, const udp_uchar *data, int dataLen); + void CallbackConnectComplete(UdpConnection *con); + void CallbackTerminated(UdpConnection *con); + void CallbackCrcReject(UdpConnection *con, const udp_uchar *data, int dataLen); + void CallbackPacketCorrupt(UdpConnection *con, const udp_uchar *data, int dataLen, UdpCorruptionReason reason); + + void IncrementCrcRejectedPackets() { UdpGuard sg(&mStatsGuard); mManagerStats.crcRejectedPackets++; } + void IncrementOrderRejectedPackets() { UdpGuard sg(&mStatsGuard); mManagerStats.orderRejectedPackets++; } + void IncrementDuplicatePacketsReceived() { UdpGuard sg(&mStatsGuard); mManagerStats.duplicatePacketsReceived++; } + void IncrementResentPacketsAccelerated() { UdpGuard sg(&mStatsGuard); mManagerStats.resentPacketsAccelerated++; } + void IncrementResentPacketsTimedOut() { UdpGuard sg(&mStatsGuard); mManagerStats.resentPacketsTimedOut++; } + void IncrementApplicationPacketsSent() { UdpGuard sg(&mStatsGuard); mManagerStats.applicationPacketsSent++; } + void IncrementApplicationPacketsReceived() { UdpGuard sg(&mStatsGuard); mManagerStats.applicationPacketsReceived++; } + void IncrementCorruptPacketErrors() { UdpGuard sg(&mStatsGuard); mManagerStats.corruptPacketErrors++; } + + int EncryptUserSupplied(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int EncryptUserSupplied2(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptUserSupplied(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + int DecryptUserSupplied2(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen); + + // CachedClock is only updated once when a real Clock call is made, but is faster than a regular Clock call since it does + // not have to call out to the driver. The UdpLibrary implementation makes use of the cached clock whenever possible so as to + // reduce the number of calls to the driver. The main motivation for this was to reduce the amount of data that needed + // to be stored by the UdpDriverRecord driver. + UdpClockStamp CachedClock(); + int CachedClockElapsed(UdpClockStamp start); + private: + ~UdpManager(); // does not destroy UdpConnection objects since it does not own them; however, it has a pointer to all the active + // ones and it will notify them that it no longer exists and set their state to cStatusDisconnected + // typically it is recommended that all UdpConnection objects be destroyed before destroying this manager object +}; + + +class UdpManagerThread : public UdpPlatformThreadObject +{ + public: + UdpManagerThread(UdpManager *manager, int sleepTime); + ~UdpManagerThread(); + virtual void Run(); + void Stop(bool waitUntilStopped); + + private: + UdpManager *mUdpManager; + bool mStop; + int mSleepTime; +}; + + + ///////////////////////////////////////////////////////////////////////// + // inline implementations + ///////////////////////////////////////////////////////////////////////// + + // UdpManager +inline int UdpManager::LastReceive() +{ + UdpGuard guard(&mStatsGuard); + return(CachedClockElapsed(mLastReceiveTime)); +} + +inline int UdpManager::LastSend() +{ + UdpGuard guard(&mStatsGuard); + return(CachedClockElapsed(mLastSendTime)); +} + +inline UdpClockStamp UdpManager::LastSendTime() +{ + UdpGuard guard(&mStatsGuard); + return(mLastSendTime); +} + +inline int UdpManager::AddressHashValue(UdpPlatformAddress ip, int port) const +{ + return((int)((ip.GetHash() ^ port) & 0x7fffffff)); +} + +inline void UdpManager::SetPriority(UdpConnection *con, UdpClockStamp stamp) +{ + UdpGuard myGuard(&mConnectionGuard); + + // do not ever let anybody schedule themselves for processing time sooner then mMinimumScheduledStamp + // otherwise, they could end up getting processing time multiple times in a single UdpManager::GiveTime iteration + // of the priority queue, which under odd circumstances could result in an infinite loop + if (stamp < mMinimumScheduledStamp) + stamp = mMinimumScheduledStamp; + + if (mPriorityQueue != NULL) + { + mPriorityQueue->Add(con, stamp); + } +} + +inline void UdpManager::SetHandler(UdpManagerHandler *handler) +{ + UdpGuard guard(&mHandlerGuard); + mParams.handler = handler; +} + +inline UdpManagerHandler *UdpManager::GetHandler() const +{ + UdpGuard guard(&mHandlerGuard); + return(mParams.handler); +} + +inline void UdpManager::PoolReturn(/*gift*/ PooledLogicalPacket *packet) +{ + UdpGuard guard(&mPoolGuard); + if (mPoolAvailableList.Count() < mParams.pooledPacketMax) + { + mPoolAvailableList.InsertHead(packet); + } + else + { + packet->TrueRelease(); + } +} + +inline void UdpManager::SetPassThroughData(void *passThroughData) +{ + UdpGuard guard(&mGiveTimeGuard); // probably no reason we couldn't change this during a GiveTime, but it is so rarely called it won't matter + mPassThroughData = passThroughData; +} + +inline void *UdpManager::GetPassThroughData() const +{ + UdpGuard guard(&mGiveTimeGuard); + return(mPassThroughData); +} + +inline void UdpManager::SetMaxDataHoldTime(int milliseconds) +{ + // not need to thread-protect this, it can't really screw anything up no matter how it is set + mParams.maxDataHoldTime = milliseconds; +} + +inline int UdpManager::GetMaxDataHoldTime() const +{ + return(mParams.maxDataHoldTime); +} + +inline UdpClockStamp UdpManager::Clock() +{ + UdpGuard guard(&mCachedClockGuard); + return(mCachedClock = mDriver->Clock()); +} + +inline int UdpManager::ClockElapsed(UdpClockStamp stamp) +{ + return(UdpMisc::ClockDiff(stamp, Clock())); +} + +inline udp_ushort UdpManager::LocalSyncStampShort() +{ + return((udp_ushort)(Clock() & 0xffff)); +} + +inline udp_uint UdpManager::LocalSyncStampLong() +{ + return((udp_uint)(Clock() & 0xffffffff)); +} + +inline int UdpManager::Random() +{ + return(UdpMisc::Random(&mRandomSeed)); +} + +inline void UdpManager::Sleep(int milliseconds) +{ + mDriver->Sleep(milliseconds); +} + +inline UdpClockStamp UdpManager::CachedClock() +{ + UdpGuard guard(&mCachedClockGuard); + return(mCachedClock); +} + +inline int UdpManager::CachedClockElapsed(UdpClockStamp start) +{ + return(UdpMisc::ClockDiff(start, CachedClock())); +} + +inline int UdpManager::EncryptUserSupplied(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + UdpGuard guard(&mHandlerGuard); + if (mParams.handler != NULL) + { + return(mParams.handler->OnUserSuppliedEncrypt(con, destData, sourceData, sourceLen)); + } + return(0); +} + +inline int UdpManager::EncryptUserSupplied2(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + UdpGuard guard(&mHandlerGuard); + if (mParams.handler != NULL) + { + return(mParams.handler->OnUserSuppliedEncrypt2(con, destData, sourceData, sourceLen)); + } + return(0); +} + +inline int UdpManager::DecryptUserSupplied(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + UdpGuard guard(&mHandlerGuard); + if (mParams.handler != NULL) + { + return(mParams.handler->OnUserSuppliedDecrypt(con, destData, sourceData, sourceLen)); + } + return(0); +} + +inline int UdpManager::DecryptUserSupplied2(UdpConnection *con, udp_uchar *destData, const udp_uchar *sourceData, int sourceLen) +{ + UdpGuard guard(&mHandlerGuard); + if (mParams.handler != NULL) + { + return(mParams.handler->OnUserSuppliedDecrypt2(con, destData, sourceData, sourceLen)); + } + return(0); +} + + + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpManager::Params initializations constructor (ie. default values) + ///////////////////////////////////////////////////////////////////////////////////////////////////// +inline UdpParams::UdpParams(ManagerRole role) +{ + handler = NULL; + outgoingBufferSize = 64 * 1024; + incomingBufferSize = 64 * 1024; + packetHistoryMax = 4; + maxDataHoldTime = 50; + maxDataHoldSize = -1; + maxRawPacketSize = 512; + hashTableSize = 100; + avoidPriorityQueue = false; + clockSyncDelay = 0; + crcBytes = 0; + encryptMethod[0] = cEncryptMethodNone; + encryptMethod[1] = cEncryptMethodNone; + keepAliveDelay = 0; + portAliveDelay = 0; + noDataTimeout = 0; + maxConnections = 10; + port = 0; + portRange = 0; + pooledPacketMax = 1000; + pooledPacketSize = -1; + pooledPacketInitial = 0; + replyUnreachableConnection = true; + allowPortRemapping = true; + allowAddressRemapping = false; + icmpErrorRetryPeriod = 5000; + oldestUnacknowledgedTimeout = 90000; + processIcmpErrors = true; + processIcmpErrorsDuringNegotiating = false; + connectAttemptDelay = 1000; + reliableOverflowBytes = 0; + lingerDelay = 10; + bindIpAddress[0] = 0; + udpDriver = NULL; + callbackEventPoolMax = 5000; + eventQueuing = false; + threadSleepTime = 20; + incomingLogicalPacketMax = 20 * 1024 * 1024; + + userSuppliedEncryptExpansionBytes = 0; + userSuppliedEncryptExpansionBytes2 = 0; + + reliable[0].maxInstandingPackets = 400; + reliable[0].maxOutstandingBytes = 200 * 1024; + reliable[0].maxOutstandingPackets = 400; + reliable[0].outOfOrder = false; + reliable[0].coalesce = true; + reliable[0].ackDeduping = true; + reliable[0].fragmentSize = 0; + reliable[0].resendDelayAdjust = 300; + reliable[0].resendDelayPercent = 125; + reliable[0].resendDelayCap = 8000; + reliable[0].toleranceLossCount = 0; + reliable[0].congestionWindowMinimum = 0; + reliable[0].trickleRate = 0; + reliable[0].trickleSize = 0; + + switch (role) + { + case cManagerRoleInternalServer: + outgoingBufferSize = 4 * 1024 * 1024; + incomingBufferSize = 4 * 1024 * 1024; + crcBytes = 2; + icmpErrorRetryPeriod = 500; + maxRawPacketSize = 1460; + hashTableSize = 10000; + keepAliveDelay = 30000; + noDataTimeout = 90000; + maxConnections = 2000; + pooledPacketMax = 20000; + pooledPacketInitial = 1000; + allowPortRemapping = false; + reliable[0].maxInstandingPackets = 1000; + reliable[0].maxOutstandingBytes = 1024 * 1024; + reliable[0].maxOutstandingPackets = 1000; + reliable[0].congestionWindowMinimum = 8192; + reliable[0].resendDelayAdjust = 150; + break; + case cManagerRoleInternalClient: + outgoingBufferSize = 1024 * 1024; + incomingBufferSize = 1024 * 1024; + crcBytes = 2; + icmpErrorRetryPeriod = 500; + maxRawPacketSize = 1460; + hashTableSize = 10; + keepAliveDelay = 30000; + noDataTimeout = 90000; + maxConnections = 2; + pooledPacketMax = 2000; + pooledPacketInitial = 100; + allowPortRemapping = false; + reliable[0].maxInstandingPackets = 1000; + reliable[0].maxOutstandingBytes = 1024 * 1024; + reliable[0].maxOutstandingPackets = 1000; + reliable[0].congestionWindowMinimum = 8192; + reliable[0].resendDelayAdjust = 150; + break; + case cManagerRoleExternalServer: + outgoingBufferSize = 2 * 1024 * 1024; + incomingBufferSize = 2 * 1024 * 1024; + crcBytes = 2; + icmpErrorRetryPeriod = 2500; + hashTableSize = 10000; + keepAliveDelay = 30000; + noDataTimeout = 90000; + maxConnections = 2000; + pooledPacketMax = 20000; + pooledPacketInitial = 1000; + break; + case cManagerRoleExternalClient: + crcBytes = 2; + icmpErrorRetryPeriod = 2500; + hashTableSize = 10; + keepAliveDelay = 30000; + noDataTimeout = 90000; + maxConnections = 2; + pooledPacketMax = 2000; + pooledPacketInitial = 10; + break; + case cManagerRoleLfn: + outgoingBufferSize = 16 * 1024 * 1024; + incomingBufferSize = 16 * 1024 * 1024; + crcBytes = 2; + icmpErrorRetryPeriod = 1500; + maxRawPacketSize = 1460; + keepAliveDelay = 30000; + noDataTimeout = 90000; + maxConnections = 2; + pooledPacketMax = 50000; + pooledPacketInitial = 5000; + allowPortRemapping = false; + incomingLogicalPacketMax = 200 * 1024 * 1024; + callbackEventPoolMax = 50000; + reliable[0].maxInstandingPackets = 32000; + reliable[0].maxOutstandingBytes = 50 * 1024 * 1024; + reliable[0].maxOutstandingPackets = 32000; + reliable[0].congestionWindowMinimum = 300000; + reliable[0].toleranceLossCount = 100; + break; + case cManagerRoleDefault: + default: + break; + } + + // all reliable channels should match main channel + for (int j = 1; j < cReliableChannelCount; j++) + reliable[j] = reliable[0]; +} + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpMisc.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpMisc.cpp new file mode 100644 index 00000000..15718755 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpMisc.cpp @@ -0,0 +1,253 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include + +#include "UdpMisc.h" +#include "UdpLogicalPacket.h" + + +namespace UdpLibrary +{ + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // UdpMisc functions + //////////////////////////////////////////////////////////////////////////////////////////////////// + +int UdpMisc::SyncStampShortDeltaTime(udp_ushort stamp1, udp_ushort stamp2) +{ + udp_ushort delta = (udp_ushort)(stamp1 - stamp2); + if (delta > 0x7fff) + return((int)(0xffff - delta)); + return((int)delta); +} + +int UdpMisc::SyncStampLongDeltaTime(udp_uint stamp1, udp_uint stamp2) +{ + udp_uint delta = stamp1 - stamp2; + if (delta > 0x7fffffff) + return((int)(0xffffffff - delta)); + return((int)delta); +} + +int UdpMisc::Random(int *seed) +{ + int hi = *seed / 127773; + int lo = *seed % 127773; + int t = lo * 16807 - hi * 2836 + 123; + *seed = (t > 0) ? t : (t + 2147483647); + return(*seed); +} + +int UdpMisc::Crc32(const void *buffer, int bufferLen, int encryptValue) +{ + static unsigned crc32_table[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 crc = 0xffffffff; + crc = ((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[(crc ^ (encryptValue & 0xff)) & 0x000000FFL]; + crc = ((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[(crc ^ ((encryptValue >> 8) & 0xff)) & 0x000000FFL]; + crc = ((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[(crc ^ ((encryptValue >> 16) & 0xff)) & 0x000000FFL]; + crc = ((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[(crc ^ ((encryptValue >> 24) & 0xff)) & 0x000000FFL]; + + const udp_uchar *bufPtr = (const udp_uchar *)buffer; + const udp_uchar *endPtr = (const udp_uchar *)buffer + bufferLen; + while (bufPtr < endPtr) + { + crc = ((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[(crc ^ *bufPtr) & 0x000000FFL]; + bufPtr++; + } + crc = ~crc; + + return(crc); +} + +void *UdpMisc::SmartResize(void *ptr, int bytes, int round) +{ + enum { cAlignment = sizeof(int) }; + + // rounding stuff for speed + bytes = ((bytes + round - 1) / round) * round; + + if (bytes == 0) + { + if (ptr != NULL) + { + free((udp_uchar *)ptr - cAlignment); + } + return(NULL); + } + + udp_uchar *ptr2; + if (ptr == NULL) + { + ptr2 = (udp_uchar *)malloc(bytes + cAlignment); + if (ptr2 == NULL) + return(NULL); + *(int *)ptr2 = bytes; + return(ptr2 + cAlignment); + } + + int oldBytes = *((int *)((udp_uchar *)ptr - cAlignment)); + if (bytes == oldBytes) + return(ptr); + + ptr2 = (udp_uchar *)realloc((udp_uchar *)ptr - cAlignment, bytes + cAlignment); + if (ptr2 == NULL) + return(NULL); + + *(int *)ptr2 = bytes; + return(ptr2 + cAlignment); +} + +udp_uint UdpMisc::PutVariableValue(void *buffer, udp_uint value) +{ + udp_uchar *bufptr = (udp_uchar *)buffer; + udp_uint store = (udp_uint)value; + if (store < 254) + { + *bufptr = (udp_uchar)store; + return(1); + } + else if (store < 0xffff) + { + *bufptr = 0xff; + *(bufptr + 1) = (udp_uchar)(store >> 8); + *(bufptr + 2) = (udp_uchar)(store & 0xff); + return(3); + } + else + { + *bufptr = 0xff; + *(bufptr + 1) = 0xff; + *(bufptr + 2) = 0xff; + *(bufptr + 3) = (udp_uchar)(store >> 24); + *(bufptr + 4) = (udp_uchar)((store >> 16) & 0xff); + *(bufptr + 5) = (udp_uchar)((store >> 8) & 0xff); + *(bufptr + 6) = (udp_uchar)(store & 0xff); + return(7); + } +} + +udp_uint UdpMisc::GetVariableValue(const void *buffer, udp_uint *value) +{ + const udp_uchar *bufptr = (const udp_uchar *)buffer; + if (*bufptr == 0xff) + { + if (*(bufptr + 1) == 0xff && *(bufptr + 2) == 0xff) + { + *value = (udp_uint)((*(bufptr + 3) << 24) | (*(bufptr + 4) << 16) | (*(bufptr + 5) << 8) | *(bufptr + 6)); + return(7); + } + + *value = (udp_uint)((*(bufptr + 1) << 8) | *(bufptr + 2)); + return(3); + } + + *value = (udp_uint)*bufptr; + return(1); +} + +LogicalPacket *UdpMisc::CreateQuickLogicalPacket(const void *data, int dataLen, const void *data2, int dataLen2) +{ + enum { cQuickFactor = 128 }; + int totalDataLen = dataLen + dataLen2; + int q = (totalDataLen - 1) / cQuickFactor; + LogicalPacket *tlp; + switch(q) + { + case 0: + tlp = new FixedLogicalPacket(NULL, totalDataLen); + break; + case 1: + tlp = new FixedLogicalPacket(NULL, totalDataLen); + break; + case 2: + case 3: + tlp = new FixedLogicalPacket(NULL, totalDataLen); + break; + case 4: + case 5: + case 6: + case 7: + tlp = new FixedLogicalPacket(NULL, totalDataLen); + break; + default: + tlp = new SimpleLogicalPacket(NULL, totalDataLen); + break; + } + + udp_uchar *dest = (udp_uchar *)tlp->GetDataPtr(); + if (data != NULL) + memcpy(dest, data, dataLen); + if (data2 != NULL) + memcpy(dest + dataLen, data2, dataLen2); + return(tlp); +} + +UdpPlatformAddress UdpMisc::GetHostByName(const char *hostName) +{ + static UdpPlatformDriver sDriver; + UdpPlatformAddress ip; + sDriver.GetHostByName(&ip, hostName); + return(ip); +} + +void UdpMisc::Sleep(int milliseconds) +{ + static UdpPlatformDriver sDriver; + sDriver.Sleep(milliseconds); +} + +UdpPlatformAddress UdpMisc::GetSelfAddress(bool preferNoRoute) +{ + static UdpPlatformDriver sDriver; + UdpPlatformAddress ip; + sDriver.GetSelfAddress(&ip, preferNoRoute); + return(ip); +} + + +} // namespace diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpMisc.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpMisc.h new file mode 100644 index 00000000..82e309e7 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpMisc.h @@ -0,0 +1,237 @@ +#ifndef UDPLIBRARY_UDPMISC_H +#define UDPLIBRARY_UDPMISC_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include +#include +#include "UdpDriver.h" + +namespace UdpLibrary +{ + +class LogicalPacket; + +class UdpMisc +{ + //////////////////////////////////////////////////////////////////////////////////////////// + // This is a group of miscellaneous function used as part of the implementation + // The application is free to use these helper functions as well if finds them useful. + // they are stuck into this class so as to avoid conflicts with the application + //////////////////////////////////////////////////////////////////////////////////////////// + public: + + +#if 1 // DEPRECATED (here for backwards compatibility only. Not used by UdpLibrary, it uses the UdpPlatformDriver version) + // Internally these create a static UdpPlatformDriver and chain the call through. If you have a UdpManager, I recommend + // simply call UdpManager::Clock and UdpManager::ClockElapsed, which chain on through to the driver created by the UdpManager + // values returned by this clock function should not be compared to values return from the UdpManager clock function as + // they go through two different drivers to get the answer and may not return the same number (though in practice it + // likely always will). + typedef UdpClockStamp ClockStamp; + static ClockStamp Clock(); // returns a timestamp (most likely in milliseconds) + static int ClockElapsed(ClockStamp stamp); // returns a elapsed time since stamp in milliseconds (if elapsed is over 23 days, it returns 23 days) +#endif + + + static int ClockDiff(UdpClockStamp start, UdpClockStamp stop); // returns a time difference in milliseconds (if difference is over 23 days, it returns 23 days) + static int Crc32(const void *buffer, int bufferLen, int encryptValue = 0); // calculate a 32-bit crc for a buffer (encrypt value simple scrambles the crc at the beginning so the same packet doesn't produce the same crc on different connections) + static int Random(int *seed); // random number generator + static void Sleep(int milliseconds); + + // returns the time difference between two sync-stamps that are based on the same clock + // for example, two LocalSyncStampShort stamps can be compared. Only differences up to + // 32 seconds can be timed. There is also a UdpConnect::ServerSyncStampShort function that returns + // you a sync-stamp that you can compare with ServerSyncStampShort values generated on other + // machines that are synchronized against the same server. This ServerSyncStampShort function and + // this delta time function serve as the basis for calculating one-way travel times for packets. + static int SyncStampShortDeltaTime(udp_ushort stamp1, udp_ushort stamp2); + static int SyncStampLongDeltaTime(udp_uint stamp1, udp_uint stamp2); // same as Short version only no limit + + // used to alloc/resize/free an allocation previously created with this function + // rounding causes that it pre-allocates additional space up to the rounded buffer size + // this allows the function to be called over and over again as tiny members are added, yet + // only do an actual realloc periodically. A 4-byte header is invisibly prepended on the + // allocated block such that it can keep track of the actual size of the block. The built-in + // memory manager does a little bit of this, but if you know you have an allocation that is likely + // to grow quite a bit, you can set the round'ing size up to a fairly large number and avoid + // unnecessary reallocs at the cost of a little potentially wasted space + // initial allocations are done by passing in ptr==NULL, freeing is done by passing in bytes==0 + static void *SmartResize(void *ptr, int bytes, int round = 1); + + // the following two functions store values in the buffer as a variable length (B1, 0xffB2B1, 0xffffffB4B3B2B1) + // such that values under 254 take one byte, values under 65535 take three bytes, and larger values take seven bytes + static udp_uint PutVariableValue(void *buffer, udp_uint value); // returns the number of bytes it took to store the value in the buffer + static udp_uint GetVariableValue(const void *buffer, udp_uint *value); // returns the number of bytes it took to get the value from the buffer + + // these functions are used to aid in portability and serve to ensure that the packet-headers are interpretted in the same + // manner on all platforms + static int PutValue64(void *buffer, udp_int64 value); // puts a 64-bit value into the buffer in big-endian format, returns number of bytes used(8) + static int PutValue32(void *buffer, udp_uint value); // puts a 32-bit value into the buffer in big-endian format, returns number of bytes used(4) + static int PutValue24(void *buffer, udp_uint value); // puts a 24-bit value into the buffer in big-endian format, returns number of bytes used(4) + static int PutValue16(void *buffer, udp_ushort value); // puts a 16-bit value into the buffer in big-endian format, returns number of bytes used(2) + static int PutValueLE32(void *buffer, udp_uint value); // puts a 32-bit value in little-endian format + + static udp_int64 GetValue64(const void *buffer); // gets a 64-bit value from the buffer in big-endian format + static udp_uint GetValue32(const void *buffer); // gets a 32-bit value from the buffer in big-endian format + static udp_uint GetValue24(const void *buffer); // gets a 24-bit value from the buffer in big-endian format + static udp_ushort GetValue16(const void *buffer); // gets a 16-bit value from the buffer in big-endian format + + static LogicalPacket *CreateQuickLogicalPacket(const void *data, int dataLen, const void *data2 = NULL, int dataLen2 = 0); + + // looks up the specified name and translates it to an IP address + // this is a blocking call that can at times take a significant amount of time, but will generally be fast (less than 300ms) + static UdpPlatformAddress GetHostByName(const char *hostName); + static UdpPlatformAddress GetSelfAddress(bool preferNoRoute); + + static char *Strncpy(char *dest, const char *source, int len); + static char *Strncat(char *dest, const char *source, int len); +}; + + + + //////////////////////////////////////////////////////////////////////////// + // inline implementations + //////////////////////////////////////////////////////////////////////////// + + // UdpMisc +#if 1 // DEPRECATED (see declaration) + inline UdpMisc::ClockStamp UdpMisc::Clock() + { + static UdpPlatformDriver sClockDriver; + return(sClockDriver.Clock()); + } + + inline int UdpMisc::ClockElapsed(ClockStamp stamp) + { + return(UdpMisc::ClockDiff(stamp, Clock())); + } +#endif + +inline int UdpMisc::ClockDiff(UdpClockStamp start, UdpClockStamp stop) +{ + UdpClockStamp t = (stop - start); + if (t > 0x7fffffff) // only time differences up to about 23 days can be measured with this function + return(0x7fffffff); + return((int)t); +} + +inline int UdpMisc::PutValue64(void *buffer, udp_int64 value) +{ + udp_uchar *bufptr = (udp_uchar *)buffer; + *bufptr++ = (udp_uchar)(value >> 56); + *bufptr++ = (udp_uchar)((value >> 48) & 0xff); + *bufptr++ = (udp_uchar)((value >> 40) & 0xff); + *bufptr++ = (udp_uchar)((value >> 32) & 0xff); + *bufptr++ = (udp_uchar)((value >> 24) & 0xff); + *bufptr++ = (udp_uchar)((value >> 16) & 0xff); + *bufptr++ = (udp_uchar)((value >> 8) & 0xff); + *bufptr = (udp_uchar)(value & 0xff); + return(8); +} + +inline udp_int64 UdpMisc::GetValue64(const void *buffer) +{ + const udp_uchar *bufptr = (const udp_uchar *)buffer; + return(((udp_int64)*bufptr << 56) | ((udp_int64)*(bufptr + 1) << 48) | ((udp_int64)*(bufptr + 2) << 40) | ((udp_int64)*(bufptr + 3) << 32) | ((udp_int64)*(bufptr + 4) << 24) | ((udp_int64)*(bufptr + 5) << 16) | ((udp_int64)*(bufptr + 6) << 8) | (udp_int64)*(bufptr + 7)); +} + +inline int UdpMisc::PutValue32(void *buffer, udp_uint value) +{ + udp_uchar *bufptr = (udp_uchar *)buffer; + *bufptr++ = (udp_uchar)(value >> 24); + *bufptr++ = (udp_uchar)((value >> 16) & 0xff); + *bufptr++ = (udp_uchar)((value >> 8) & 0xff); + *bufptr = (udp_uchar)(value & 0xff); + return(4); +} + +inline int UdpMisc::PutValueLE32(void *buffer, udp_uint value) +{ + udp_uchar *bufptr = (udp_uchar *)buffer; + *bufptr++ = (udp_uchar)(value & 0xff); + *bufptr++ = (udp_uchar)((value >> 8) & 0xff); + *bufptr++ = (udp_uchar)((value >> 16) & 0xff); + *bufptr = (udp_uchar)(value >> 24); + return(4); +} + +inline udp_uint UdpMisc::GetValue32(const void *buffer) +{ + const udp_uchar *bufptr = (const udp_uchar *)buffer; + return((*bufptr << 24) | (*(bufptr + 1) << 16) | (*(bufptr + 2) << 8) | *(bufptr + 3)); +} + +inline int UdpMisc::PutValue24(void *buffer, udp_uint value) +{ + udp_uchar *bufptr = (udp_uchar *)buffer; + *bufptr++ = (udp_uchar)((value >> 16) & 0xff); + *bufptr++ = (udp_uchar)((value >> 8) & 0xff); + *bufptr = (udp_uchar)(value & 0xff); + return(3); +} + +inline udp_uint UdpMisc::GetValue24(const void *buffer) +{ + const udp_uchar *bufptr = (const udp_uchar *)buffer; + return((*bufptr << 16) | (*(bufptr + 1) << 8) | *(bufptr + 2)); +} + +inline int UdpMisc::PutValue16(void *buffer, udp_ushort value) +{ + udp_uchar *bufptr = (udp_uchar *)buffer; + *bufptr++ = (udp_uchar)((value >> 8) & 0xff); + *bufptr = (udp_uchar)(value & 0xff); + return(2); +} + +inline udp_ushort UdpMisc::GetValue16(const void *buffer) +{ + const udp_uchar *bufptr = (const udp_uchar *)buffer; + return((udp_ushort)((*bufptr << 8) | *(bufptr + 1))); +} + +inline char *UdpMisc::Strncpy(char *dest, const char *source, int len) +{ + if (len > 0) + { + char *walk = dest; + char *end = dest + len - 1; + while (*source != 0 && walk < end) + { + *walk++ = *source++; + } + *walk = 0; + } + return(dest); +} + +inline char *UdpMisc::Strncat(char *dest, const char *source, int len) +{ + int clen = (int)strlen(dest); + len -= clen; + if (len > 1) + { + Strncpy(dest + clen, source, len); + } + return(dest); +} + +template const ValueType &udpMax(const ValueType &a, const ValueType &b) +{ + if (a < b) + return b; + return a; +} + +template const ValueType &udpMin(const ValueType &a, const ValueType &b) +{ + if (b < a) + return b; + return a; +} + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h new file mode 100644 index 00000000..6b4f5968 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h @@ -0,0 +1,233 @@ +#ifndef UDPLIBRARY_UDPPRIORITY_H +#define UDPLIBRARY_UDPPRIORITY_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +namespace UdpLibrary +{ + + +template class PriorityQueue; + + // classes that wish to be members of the priority queue below must derive themselves from this class + // in order to pull in the two member variables. Unlike normal priority queue classes which don't + // have this restriction, it is required in order to support Remove and reprioritize functionality + // in a timely manner (otherwise, in order to remove an entry that is not at the top, you would have + // to linearly scan the entire queue). This is accomplished by having the member itself contain + // a pointer to it's position in the queue (mPriorityQueuePosition). + // note: a restriction of this ability is that an object cannot participate in more than one priority + // queue at a time. +class PriorityQueueMember +{ + public: + PriorityQueueMember(); + +#if defined(_MSC_VER) && (_MSC_VER < 1300) // MSVC 7.0 is the first version to support friend templates + public: +#else + protected: + template friend class PriorityQueue; +#endif + int mPriorityQueuePosition; // -1=not in queue +}; + + // this class provides a priority queue that is capable of reprioritizing/removing entries. The + // compiler will ensure that objects stored in this class are derived from PriorityQueueMember. + // We don't really need this to be a template class, since we could just treat everything as a + // PriorityQueueMember, but then the application would lose some type checking. We don't use references + // in the api as most priority queue templates do as we can't support non pointer types anyways. +template class PriorityQueue +{ + public: + PriorityQueue(int queueSize); + ~PriorityQueue(); + + T* Top(); // returns NULL if queue is empty + T* TopRemove(); // returns NULL if queue is empty + T* TopRemove(P priority); // removes item from queue if it has a lower priority value, otherwise return NULL + T* Add(T* entry, P priority); // reprioritizes if already in queue, returns entry always + T* Remove(T* entry); // returns entry always (even if it was not in the queue) + P *GetPriority(T* entry); // returns NULL if entry is not in the queue + int QueueUsed(); // returns how many entries are in the queue + protected: + struct QueueEntry + { + T* entry; + P priority; + }; + + QueueEntry* mQueue; + int mQueueSize; + int mQueueEnd; + + void Refloat(T* entry); +}; + + + + ////////////////////////////////////////////////////////////////////////// + // PriorityQueueMember implementation + ////////////////////////////////////////////////////////////////////////// +inline PriorityQueueMember::PriorityQueueMember() +{ + mPriorityQueuePosition = -1; +} + + + ////////////////////////////////////////////////////////////////////////// + // PriorityQueue implementation + ////////////////////////////////////////////////////////////////////////// +template PriorityQueue::PriorityQueue(int queueSize) +{ + mQueueEnd = 0; + mQueueSize = queueSize; + mQueue = new QueueEntry[mQueueSize]; + memset(mQueue, 0, sizeof(mQueue)); +} + +template PriorityQueue::~PriorityQueue() +{ + delete[] mQueue; +} + +template T* PriorityQueue::Top() +{ + if (mQueueEnd == 0) + return(NULL); + return(mQueue[0].entry); +} + +template T* PriorityQueue::TopRemove() +{ + if (mQueueEnd == 0) + return(NULL); + T* top = mQueue[0].entry; + Remove(top); + return(top); +} + +template T* PriorityQueue::TopRemove(P priority) +{ + if (mQueueEnd > 0 && mQueue[0].priority <= priority) + return(Remove(mQueue[0].entry)); + return(NULL); +} + +template P* PriorityQueue::GetPriority(T* entry) +{ + if (entry->mPriorityQueuePosition >= 0) + return(&mQueue[entry->mPriorityQueuePosition].priority); + return(NULL); +} + +template T* PriorityQueue::Add(T* entry, P priority) +{ + if (entry->mPriorityQueuePosition == -1) + { + // not in queue, so add it to the bottom + if (mQueueEnd >= mQueueSize) + return(NULL); + mQueue[mQueueEnd].entry = entry; + mQueue[mQueueEnd].priority = priority; + mQueue[mQueueEnd].entry->mPriorityQueuePosition = mQueueEnd; + mQueueEnd++; + } + else + { + // see if priority has actually changed, if not, just return, otherwise change priority and fall through to refloat it + if (mQueue[entry->mPriorityQueuePosition].priority == priority) + return(entry); + mQueue[entry->mPriorityQueuePosition].priority = priority; + } + + Refloat(entry); + return(entry); +} + +template T* PriorityQueue::Remove(T* entry) +{ + if (entry->mPriorityQueuePosition == -1) + return(entry); + + // move end entry into place of one being removed + mQueueEnd--; + int spot = entry->mPriorityQueuePosition; + if (spot != mQueueEnd) // don't remove last item in queue (bottom of tree), so no need to copy bottom one up and refloat it (we would be refloating our own removed entry) + { + mQueue[spot] = mQueue[mQueueEnd]; + mQueue[spot].entry->mPriorityQueuePosition = spot; + Refloat(mQueue[spot].entry); + } + entry->mPriorityQueuePosition = -1; + return(entry); +} + +template void PriorityQueue::Refloat(T* entry) +{ + // float upward + int spot = entry->mPriorityQueuePosition; + bool tryDown = true; + while (spot > 0 && mQueue[spot].priority < mQueue[(spot - 1) / 2].priority) + { + int newSpot = (spot - 1) / 2; + QueueEntry hold = mQueue[spot]; + mQueue[spot] = mQueue[newSpot]; + mQueue[newSpot] = hold; + mQueue[spot].entry->mPriorityQueuePosition = spot; + mQueue[newSpot].entry->mPriorityQueuePosition = newSpot; + spot = newSpot; + tryDown = false; + } + + if (tryDown) + { + // if we didn't manage to float up at all, then we need to try floating down + for (;;) + { + // pick smallest child + int downSpot1 = (spot * 2) + 1; + if (downSpot1 >= mQueueEnd) + break; + int downSpot2 = (spot * 2) + 2; + + if (downSpot2 >= mQueueEnd || mQueue[downSpot1].priority < mQueue[downSpot2].priority) + { + if (mQueue[downSpot1].priority < mQueue[spot].priority) + { + QueueEntry hold = mQueue[spot]; + mQueue[spot] = mQueue[downSpot1]; + mQueue[downSpot1] = hold; + mQueue[spot].entry->mPriorityQueuePosition = spot; + mQueue[downSpot1].entry->mPriorityQueuePosition = downSpot1; + spot = downSpot1; + } + else + break; + } + else + { + if (mQueue[downSpot2].priority < mQueue[spot].priority) + { + QueueEntry hold = mQueue[spot]; + mQueue[spot] = mQueue[downSpot2]; + mQueue[downSpot2] = hold; + mQueue[spot].entry->mPriorityQueuePosition = spot; + mQueue[downSpot2].entry->mPriorityQueuePosition = downSpot2; + spot = downSpot2; + } + else + break; + } + } + } +} + +template int PriorityQueue::QueueUsed() +{ + return(mQueueEnd); +} + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpReliableChannel.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpReliableChannel.cpp new file mode 100644 index 00000000..d31de9b4 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpReliableChannel.cpp @@ -0,0 +1,881 @@ +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include +#include +#include +#include +#include + +#include "UdpLibrary.h" +#include "UdpReliableChannel.h" + + +namespace UdpLibrary +{ + + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // ReliableChannel implementation + ///////////////////////////////////////////////////////////////////////////////////////////////////// +UdpReliableChannel::UdpReliableChannel(int channelNumber, UdpConnection *con, UdpReliableConfig *config) : mLogicalPacketList(&LogicalPacket::mReliableLink) +{ + mUdpConnection = con; + mChannelNumber = channelNumber; + mConfig = *config; + mConfig.maxOutstandingPackets = udpMin(mConfig.maxOutstandingPackets, (int)UdpManager::cHardMaxOutstandingPackets); + + mAveragePingTime = 800; // start out fairly high so we don't do a lot of resends on a bad connection to start out with + mTrickleLastSend = 0; + + int fragmentSize = mConfig.fragmentSize; + if (fragmentSize == 0 || fragmentSize > mUdpConnection->mConnectionConfig.maxRawPacketSize) + fragmentSize = mUdpConnection->mConnectionConfig.maxRawPacketSize; + mMaxDataBytes = (fragmentSize - UdpConnection::cUdpPacketReliableSize - mUdpConnection->mConnectionConfig.crcBytes - mUdpConnection->mEncryptExpansionBytes); + assert(mMaxDataBytes > 0); // fragment size/max-raw-packet-size set too small to allow for reliable deliver + if (mConfig.trickleSize != 0) + mMaxDataBytes = udpMin(mMaxDataBytes, mConfig.trickleSize); + + mMaxCoalesceAttemptBytes = -1; + if (mConfig.coalesce) + { + mMaxCoalesceAttemptBytes = mMaxDataBytes - 5; // 2 bytes for group-header, 3 bytes for length of packet + } + + mReliableIncomingId = 0; + mReliableOutgoingId = 0; + mReliableOutgoingPendingId = 0; + mReliableOutgoingBytes = 0; + mLogicalBytesQueued = 0; + + mCoalescePacket = NULL; + mCoalesceStartPtr = NULL; + mCoalesceEndPtr = NULL; + mCoalesceCount = 0; + + mBufferedAckPtr = NULL; + + mStatDuplicatePacketsReceived = 0; + mStatResentPacketsAccelerated = 0; + mStatResentPacketsTimedOut = 0; + + mWindowResetTime = 0; + + mCongestionWindowMinimum = udpMax(mMaxDataBytes, mConfig.congestionWindowMinimum); + mCongestionWindowStart = udpMin(4 * mMaxDataBytes, udpMax(2 * mMaxDataBytes, 4380)); + mCongestionWindowStart = udpMax(mCongestionWindowStart, mCongestionWindowMinimum); + mCongestionSlowStartThreshhold = udpMin(mConfig.maxOutstandingPackets * mMaxDataBytes, mConfig.maxOutstandingBytes); + mCongestionWindowSize = mCongestionWindowStart; + + mBigDataLen = 0; + mBigDataTargetLen = 0; + mBigDataPtr = NULL; + mFragmentNextPos = 0; + mLastTimeStampAcknowledged = 0; + mMaxxedOutCurrentWindow = false; + mNextNeedTime = 0; + + mPhysicalPackets = new PhysicalPacket[mConfig.maxOutstandingPackets]; + mReliableIncoming = new IncomingQueueEntry[mConfig.maxInstandingPackets]; +} + +UdpReliableChannel::~UdpReliableChannel() +{ + if (mCoalescePacket != NULL) + { + mCoalescePacket->Release(); + mCoalescePacket = NULL; + } + + const LogicalPacket *cur = mLogicalPacketList.RemoveHead(); + while (cur != NULL) + { + cur->Release(); + cur = mLogicalPacketList.RemoveHead(); + } + + delete[] mPhysicalPackets; // destructor will release any logical packets as appropriate + delete[] mReliableIncoming; // destructor will delete any data as appropriate + + // delete any big packet that might be under construction + delete[] mBigDataPtr; +} + +void UdpReliableChannel::Send(const udp_uchar *data, int dataLen, const udp_uchar *data2, int dataLen2) +{ + if (mLogicalPacketList.Count() == 0 && mCoalescePacket == NULL) + { + // if we are adding something to a previously empty logical queue, then it is possible that + // we may be able to send it, so mark ourselves to take time the next time it is offered + mNextNeedTime = 0; + mUdpConnection->ScheduleTimeNow(); + } + + if (dataLen + dataLen2 <= mMaxCoalesceAttemptBytes) + { + SendCoalesce(data, dataLen, data2, dataLen2); + } + else + { + FlushCoalesce(); + LogicalPacket *packet = mUdpConnection->mUdpManager->CreatePacket(data, dataLen, data2, dataLen2); + QueueLogicalPacket(packet); + packet->Release(); + } +} + +void UdpReliableChannel::FlushCoalesce() +{ + if (mCoalescePacket != NULL) + { + if (mCoalesceCount == 1) + { + // only one packet in coalesce, so remove the coalesce/group header and make it just a simple raw packet + int firstLen; + int skipLen = UdpMisc::GetVariableValue(mCoalesceStartPtr + 2, (udp_uint *)&firstLen); + memmove(mCoalesceStartPtr, mCoalesceStartPtr + 2 + skipLen, firstLen); + mCoalesceEndPtr = mCoalesceStartPtr + firstLen; + } + + mCoalescePacket->SetDataLen((int)(mCoalesceEndPtr - mCoalesceStartPtr)); + QueueLogicalPacket(mCoalescePacket); + mCoalescePacket->Release(); + mCoalescePacket = NULL; + } +} + +void UdpReliableChannel::SendCoalesce(const udp_uchar *data, int dataLen, const udp_uchar *data2, int dataLen2) +{ + int totalLen = dataLen + dataLen2; + if (mCoalescePacket == NULL) + { + mCoalescePacket = mUdpConnection->mUdpManager->CreatePacket(NULL, mMaxDataBytes); + mCoalesceEndPtr = mCoalesceStartPtr = (udp_uchar *)mCoalescePacket->GetDataPtr(); + *mCoalesceEndPtr++ = 0; + *mCoalesceEndPtr++ = UdpConnection::cUdpPacketGroup; + mCoalesceCount = 0; + } + else + { + int spaceLeft = mMaxDataBytes - (int)(mCoalesceEndPtr - mCoalesceStartPtr); + if (totalLen + 3 > spaceLeft) // 3 bytes to ensure PutVariableValue has room for the length indicator (this limits us to 64k coalescing, which is ok, since fragments can't get that big) + { + FlushCoalesce(); + SendCoalesce(data, dataLen, data2, dataLen2); + return; + } + } + + // append on end of coalesce + mCoalesceCount++; + mCoalesceEndPtr += UdpMisc::PutVariableValue(mCoalesceEndPtr, totalLen); + if (data != NULL) + memcpy(mCoalesceEndPtr, data, dataLen); + mCoalesceEndPtr += dataLen; + if (data2 != NULL) + memcpy(mCoalesceEndPtr, data2, dataLen2); + mCoalesceEndPtr += dataLen2; +} + +void UdpReliableChannel::QueueLogicalPacket(LogicalPacket *packet) +{ + packet->AddRef(); + mLogicalBytesQueued += packet->GetDataLen(); + mLogicalPacketList.InsertTail(packet); +} + +bool UdpReliableChannel::PullDown(int windowSpaceLeft) +{ + // the pull-down on-demand method will give us the opportunity to late-combine as many tiny logical packets as we can, + // reducing the number of tracked-packets that are required. This effectively reduces the number of acks that we are + // going to get back, which can be substantial in situations where there are a LOT of tiny reliable packets being sent. + // operating with fewer outstanding physical-packets to track is more CPU efficient as well. + + // (NOTE: as of this writing, the below implementation does not do the late-combine techique yet) + // (NOTE: we currently combine on send instead, which generally accomplishes the same thing) + + bool pulledDown = false; + int physicalCount = (int)(mReliableOutgoingId - mReliableOutgoingPendingId); + while (windowSpaceLeft > 0 && physicalCount < mConfig.maxOutstandingPackets) + { + if (mLogicalPacketList.Count() == 0) + { + FlushCoalesce(); // this is guaranteed to stick + if (mLogicalPacketList.Count() == 0) + break; // nothing flushed, so we are done + } + + int nextSpot = (int)(mReliableOutgoingId % mConfig.maxOutstandingPackets); + + // ok, we can move something down, even if it is only a fragment of the logical packet + PhysicalPacket *entry = &mPhysicalPackets[nextSpot]; + entry->mParent = mLogicalPacketList.First(); + entry->mParent->AddRef(); // add ref from physical packet + entry->mFirstTimeStamp = 0; + entry->mLastTimeStamp = 0; + + // calculate how much we can send based on our starting position (mFragmentNextPos) in the logical packet. + // if we can't send it the rest of data to end of packet, then send the fragment portion and addref, otherwise send the whole thing and pop the logical packet + int dataLen = entry->mParent->GetDataLen(); + const udp_uchar *data = (const udp_uchar *)entry->mParent->GetDataPtr(); + int bytesLeft = dataLen - mFragmentNextPos; + int bytesToSend = udpMin(bytesLeft, mMaxDataBytes); + + entry->mDataPtr = data + mFragmentNextPos; + + // if not sending entire packet + if (bytesToSend != dataLen) + { + // mark it as a fragment + if (mFragmentNextPos == 0) + bytesToSend -= 4; // fragment start has a 4 byte header specifying size of following large data, so make room for it so we don't exceed max raw packet size + } + entry->mDataLen = bytesToSend; + mReliableOutgoingBytes += bytesToSend; + + if (bytesToSend == bytesLeft) + { + mFragmentNextPos = 0; + const LogicalPacket *lp = mLogicalPacketList.RemoveHead(); + lp->Release(); // release from logical queue + } + else + { + mFragmentNextPos += bytesToSend; + } + + mLogicalBytesQueued -= bytesToSend; // as fragments are sent, decrease the number of logical bytes queued + mReliableOutgoingId++; + physicalCount++; + windowSpaceLeft -= bytesToSend; + pulledDown = true; + } + return(pulledDown); +} + +int UdpReliableChannel::GiveTime() +{ + udp_uchar buf[256]; + udp_uchar *bufPtr; + + UdpClockStamp hotClock = mUdpConnection->GetUdpManager()->CachedClock(); + + if (hotClock < mNextNeedTime) + return(UdpMisc::ClockDiff(hotClock, mNextNeedTime)); + + // if we are a trickle channel, then don't try sending more until trickleRate has expired. We are only allowed + // to send up to trickleBytes at a time every trickleRate milliseconds; however, if we don't send the full trickleBytes + // in one GiveTime call, then it won't get to try sending more bytes until this timer has expired, even if we had not used + // up the entire trickleBytes allotment the last time we were in here...this should not cause any significant problems + if (mConfig.trickleRate > 0) + { + int nextAllowedSendTime = mConfig.trickleRate - UdpMisc::ClockDiff(mTrickleLastSend, hotClock); + if (nextAllowedSendTime > 0) + return(nextAllowedSendTime); + } + + + // lot a tweaking goes into calculating the optimal resend time. Set it too large and you can stall the pipe + // at the beginning of the connection fairly easily + int optimalResendDelay = (mAveragePingTime * mConfig.resendDelayPercent / 100) + mConfig.resendDelayAdjust; // percentage of average ping plus a fixed amount + optimalResendDelay = udpMin(mConfig.resendDelayCap, optimalResendDelay); // never let the resend delay get over max + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // see if any of the physical packets can actually be sent (either resends, or initial sends, whatever + // if not, calculate when exactly somebody is expected to need sending + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + mMaxxedOutCurrentWindow = false; + int outstandingNextSendTime = 10 * 60000; + // if we have something to do + if (mReliableOutgoingPendingId < mReliableOutgoingId || mLogicalPacketList.Count() != 0 || mCoalescePacket != NULL) + { + // first, let's calculate how many bytes we figure is outstanding based on who is still waiting for an ack-packet + UdpClockStamp oldestResendTime = udpMax(hotClock - optimalResendDelay, mLastTimeStampAcknowledged); // anything older than this, we need to resend + + bool readyQueueOverflow; + do + { + readyQueueOverflow = false; + int useMaxOutstandingBytes = udpMin(mConfig.maxOutstandingBytes, mCongestionWindowSize); + int outstandingBytes = 0; + enum { cReadyQueueSize = 1000 }; + PhysicalPacket *readyQueue[cReadyQueueSize]; + PhysicalPacket **readyEnd = readyQueue + (sizeof(readyQueue) / sizeof(PhysicalPacket *)); + PhysicalPacket **readyPtr = readyQueue; + + int windowSpaceLeft = useMaxOutstandingBytes; + for (udp_int64 i = mReliableOutgoingPendingId; i <= mReliableOutgoingId; i++) + { + if (i == mReliableOutgoingId) + { + // this packet is not really here yet, we need to pull it down if possible + // if not possible, we need to break out of the loop as we are done + if (!PullDown(windowSpaceLeft)) + break; + } + + // if this packet has not been acked and it is NOT ready to be sent (was recently sent) then we consider it outstanding + // note: packets needing re-sending probably got lost and are therefore not outstanding + PhysicalPacket *entry = &mPhysicalPackets[i % mConfig.maxOutstandingPackets]; + if (entry->mDataPtr != NULL) // acked packets set the dataPtr to NULL + { + // if this packet is ready to be sent (ie: needs time now, or some later packet has already been ack'ed) + windowSpaceLeft -= entry->mDataLen; // window-space is effectively taken whether we have sent it yet or not + if (entry->mLastTimeStamp < oldestResendTime) + { + if (readyPtr < readyEnd) // if we have queue space + { + *readyPtr++ = entry; + } + else + { + // we ran out of space in the ready-queue, so we are going to have to do this whole process + // over again. Normally we would just want to make sure the readyQueue was really big to save + // us doing all this stuff twice; however, that uses up a ton of stack space we may not have + // and really only happens in situations where there is a ton of stuff waiting to be sent + // (ie, super high bandwidth situations really). So I don't mind taking a performance hit + // for those situations to keep the stack size small for the vast majority of normal situations. + // note: this was initially added in support of the tiny stack the PS3 had. + readyQueueOverflow = true; + } + } + else + { + outstandingBytes += entry->mDataLen; + outstandingNextSendTime = udpMin(outstandingNextSendTime, optimalResendDelay - UdpMisc::ClockDiff(entry->mLastTimeStamp, hotClock)); + } + + // if we have reached a point in the queue where there are no sent packets + // and our outstanding bytes plus how much we intend to send is greater than the window we have + // then we can quit step-2, since there is nothing else to be gained by continuing. + if (entry->mFirstTimeStamp == 0 && (windowSpaceLeft <= 0)) + break; + } + } + + // second, send ready entries until the max outstanding is reached + int toleranceLossCount = 0; + bool allowWindowReset = (UdpMisc::ClockDiff(mWindowResetTime, hotClock) > mAveragePingTime); // only allow it to reset the window again if it has been longer than the average ping time + int trickleSent = 0; + PhysicalPacket **readyWalk = readyQueue; + PhysicalPacket *pendingReliableBasePtr = &mPhysicalPackets[mReliableOutgoingPendingId % mConfig.maxOutstandingPackets]; + while (readyWalk < readyPtr && outstandingBytes < useMaxOutstandingBytes) + { + // prepare packet and send it + PhysicalPacket *entry = *readyWalk++; + + // prepare reliable header and send it with data + const udp_uchar *parentBase = (const udp_uchar *)entry->mParent->GetDataPtr(); + + bool fragment = false; + if (entry->mDataPtr != parentBase || entry->mDataLen != entry->mParent->GetDataLen()) + fragment = true; + + // we can calculate what our reliableId should be based on our position in the array + // need to handle the case where we wrap around the end of the array + udp_int64 reliableId; + if (entry >= pendingReliableBasePtr) + { + reliableId = mReliableOutgoingPendingId + (entry - pendingReliableBasePtr); + } + else + { + reliableId = mReliableOutgoingPendingId + (&mPhysicalPackets[mConfig.maxOutstandingPackets] - pendingReliableBasePtr) + (entry - &mPhysicalPackets[0]); + } + + // prep the actual packet and send it + bufPtr = buf; + *bufPtr++ = 0; + *bufPtr++ = (udp_uchar)(((fragment) ? UdpConnection::cUdpPacketFragment1 : UdpConnection::cUdpPacketReliable1) + mChannelNumber); // mark us as a fragment if we are one + bufPtr += UdpMisc::PutValue16(bufPtr, (udp_ushort)(reliableId & 0xffff)); + if (fragment && entry->mDataPtr == parentBase) + bufPtr += UdpMisc::PutValue32(bufPtr, entry->mParent->GetDataLen()); // first fragment has a total-length byte after the reliable header + mUdpConnection->BufferedSend(buf, (int)(bufPtr - buf), entry->mDataPtr, entry->mDataLen, false); + + // update state information + if (entry->mFirstTimeStamp == 0) + { + entry->mFirstTimeStamp = hotClock; + } + else + { + // trying to send the packet again, let's see how long we have been trying to send this packet. If we + // have an unacknowledged timeout set and it is older than that, then terminate the connection. + // note: we only check for the oldest unacknowledged age against the timeout at the point in time + // that we are considering sending the packet again. This can technically cause it to wait slightly + // longer than the specified timeout setting before disconnecting the connection, but should be + // close enough for all practical purposes and allows for more efficient processing of this setting internally. + if (mUdpConnection->mUdpManager->mParams.oldestUnacknowledgedTimeout > 0) + { + int age = UdpMisc::ClockDiff(entry->mFirstTimeStamp, hotClock); + if (age > mUdpConnection->mUdpManager->mParams.oldestUnacknowledgedTimeout) + { + mUdpConnection->InternalDisconnect(0, UdpConnection::cDisconnectReasonUnacknowledgedTimeout); + return(0); + } + } + + // were we resent because of a later ack came in? or because we timed out? + if (entry->mLastTimeStamp < mLastTimeStampAcknowledged) + { + // we are resending this packet due to an accelleration (receiving a later packet ack) + // so recalc slow start threshhold and congestion window size as per Reno fast-recovery algorithm + if (allowWindowReset && toleranceLossCount > mConfig.toleranceLossCount) + { + allowWindowReset = false; + mWindowResetTime = hotClock; + mCongestionWindowSize = mCongestionWindowSize * 3 / 4; + mCongestionWindowSize = udpMax(mCongestionWindowMinimum, mCongestionWindowSize); // never let congestion window get smaller than a single packet + mCongestionSlowStartThreshhold = mCongestionWindowSize; + useMaxOutstandingBytes = udpMin(mConfig.maxOutstandingBytes, mCongestionWindowSize); + } + + // when resends are caused by a selective ack, that means later data is making it, so we may not be overloading + // the connection after all. Reno fast recovery calls for less shrinking of the window in this circumstance + // already. This tolerance code allows us to do even better, by allowing us to experience some small amount + // of packetloss without immediately considering such loss to be indicative that the connection is being overloaded. + // It does this by only allowing the window to get reset in cases where teh selective-ack forces a certain number + // of packets to be accellerated. If the application sets the tolerance at something like 10, then isolated packet + // losses will have no effect on the flow control window, yet a burst of loss of 10 would more strongly indicate + // a overloaded condition. Typically an application will only set this tolerance if they need extremely high + // bandwidth (ie, can't afford the window getting reset), and are known to be on a connection that may experience + // random packetloss. This is typical of a LFN type network. + toleranceLossCount++; + + mStatResentPacketsAccelerated++; + mUdpConnection->mConnectionStats.resentPacketsAccelerated++; + mUdpConnection->mUdpManager->IncrementResentPacketsAccelerated(); + } + else + { + // we are resending this packet due to a timeout, so we are seriously overloading things probably + // so recalc slow start threshhold and congestion window size as per Reno algorithm + // no tolerance on timed-out window resets, since by definition you have not received later acks + // or this would be an accellerated timeout, which means that either your volume is really low + // anyways (so resetting the window is fine), or you seriously overloaded the other side as nothing + // later made it either. + if (allowWindowReset) + { + allowWindowReset = false; + mWindowResetTime = hotClock; + + mCongestionSlowStartThreshhold = udpMax(mMaxDataBytes * 2, mCongestionWindowSize / 2); + mCongestionWindowSize = mCongestionWindowStart; + useMaxOutstandingBytes = udpMin(mConfig.maxOutstandingBytes, mCongestionWindowSize); + + // because a resend has occurred due to a timeout, slow down the resend times slightly + // when things start flowing again, it will fix itself up quickly anyways + mAveragePingTime += 100; + + // When a connection goes temporarily dead, everything that is in the current + // window will end up getting timedout. If the window were large, this could result in the + // mAveragePingTime growing quite large and creating very long stalls in the pipe once it does + // start moving again. To prevent this, we cap mAveragePingTime when these events occur to prevent + // long stalls when the pipe finally reopens. + mAveragePingTime = udpMin(mConfig.resendDelayCap, mAveragePingTime); + } + + mStatResentPacketsTimedOut++; + mUdpConnection->mConnectionStats.resentPacketsTimedOut++; + mUdpConnection->mUdpManager->IncrementResentPacketsTimedOut(); + } + } + + entry->mLastTimeStamp = hotClock; + + outstandingNextSendTime = udpMin(outstandingNextSendTime, optimalResendDelay); // this packet is now outstanding, so factor it into the outstandingNextSendTime calculation + outstandingBytes += entry->mDataLen; + mTrickleLastSend = hotClock; + trickleSent += entry->mDataLen; + + if (mConfig.trickleSize != 0 && trickleSent >= mConfig.trickleSize) + break; + } + + if (outstandingBytes >= useMaxOutstandingBytes) + { + mMaxxedOutCurrentWindow = true; + } + + // if we filled up the ready queue (ie, if we may still have data to send) + // and we still have space left in the flow window, then repeat the process. + // this should only happen when the flow-control window is enormous. + } while (readyQueueOverflow && !mMaxxedOutCurrentWindow); + } + else + { + // we have nothing in the pipe at all, reset the congestion window (this means everything has been acked, so the pipe is totally empty + // we need to reset the window back to prevent a sudden flood next time a large chunk of data is sent. + // we also need to avoid having the slowly sent reliable packets constantly increase the window size (since none will ever get lost) + // such that when it does come time to send a big chunk of data, it thinks the window-size is enormous. + // resetting the window back to small will only have an effect if a large chunk of data is then sent, at which time it will quickly + // ramp up with the slow-start method. + mCongestionWindowSize = mCongestionWindowStart; + } + + // printf("%d,%d\n", mCongestionWindowSize, mCongestionSlowStartThreshhold); // useful debug output for graphing congestion window + + int nextAllowedSendTime = mConfig.trickleRate - UdpMisc::ClockDiff(mTrickleLastSend, hotClock); + nextAllowedSendTime = udpMax(0, udpMax(nextAllowedSendTime, outstandingNextSendTime)); + mNextNeedTime = hotClock + nextAllowedSendTime; + return(nextAllowedSendTime); +} + +void UdpReliableChannel::GetChannelStatus(UdpConnection::ChannelStatus *channelStatus) const +{ + int coalesceBytes = 0; + if (mCoalescePacket != NULL) + coalesceBytes = (int)(mCoalesceEndPtr - mCoalesceStartPtr); + + channelStatus->totalPendingBytes = mLogicalBytesQueued + mReliableOutgoingBytes + coalesceBytes; + channelStatus->queuedPackets = mLogicalPacketList.Count(); + channelStatus->queuedBytes = mLogicalBytesQueued; + channelStatus->incomingLargeTotal = mBigDataTargetLen; + channelStatus->incomingLargeSoFar = mBigDataLen; + channelStatus->duplicatePacketsReceived = mStatDuplicatePacketsReceived; + channelStatus->resentPacketsAccelerated = mStatResentPacketsAccelerated; + channelStatus->resentPacketsTimedOut = mStatResentPacketsTimedOut; + channelStatus->congestionSlowStartThreshhold = mCongestionSlowStartThreshhold; + channelStatus->congestionWindowSize = mCongestionWindowSize; + channelStatus->ackAveragePing = mAveragePingTime; + channelStatus->oldestUnacknowledgedAge = 0; + + if (mReliableOutgoingPendingId < mReliableOutgoingId) + { + // oldest pending packet will be definition be the oldestUnacknowledged, since it is impossible + // for any packet after it to have possibly been sent before it was sent for its first time + // since queue is effectively in first-send order. It is also impossible for this packet to have + // been acknowledged, since the pending id advances the moment the oldest is acknowledged, meaning + // that the pendingId is always pointing to something that has either been sent (or not sent at all) + PhysicalPacket *entry = &mPhysicalPackets[mReliableOutgoingPendingId % mConfig.maxOutstandingPackets]; + if (entry->mFirstTimeStamp != 0) // if has been sent (we know it hasn't been acknowledged or we couldn't possibly be pointing at it as pending) + { + if (mUdpConnection->GetUdpManager() != NULL) + { + channelStatus->oldestUnacknowledgedAge = mUdpConnection->GetUdpManager()->CachedClockElapsed(entry->mFirstTimeStamp); + } + } + } +} + +void UdpReliableChannel::ReliablePacket(const udp_uchar *data, int dataLen) +{ + udp_uchar buf[256]; + udp_uchar *bufPtr; + + if (dataLen <= UdpConnection::cUdpPacketReliableSize) + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonReliablePacketTooShort); + return; + } + + int packetType = data[1]; + udp_ushort reliableStamp = UdpMisc::GetValue16(data + 2); + udp_int64 reliableId = GetReliableIncomingId(reliableStamp); + + if (reliableId >= mReliableIncomingId + mConfig.maxInstandingPackets) + return; // if we do not have buffer space to hold onto this packet, then we simply must pretend like it was lost + + if (reliableId >= mReliableIncomingId) + { + ReliablePacketMode mode = (ReliablePacketMode)((packetType - UdpConnection::cUdpPacketReliable1) / cReliableChannelCount); + + // is this the packet we are waiting for + if (mReliableIncomingId == reliableId) + { + // if so, process it immediately + ProcessPacket(mode, data + UdpConnection::cUdpPacketReliableSize, dataLen - UdpConnection::cUdpPacketReliableSize); + mReliableIncomingId++; + + // process other packets that have arrived + while (mReliableIncoming[mReliableIncomingId % mConfig.maxInstandingPackets].mPacket != NULL) + { + int spot = (int)(mReliableIncomingId % mConfig.maxInstandingPackets); + if (mReliableIncoming[spot].mMode != cReliablePacketModeDelivered) + { + ProcessPacket(mReliableIncoming[spot].mMode, (udp_uchar *)mReliableIncoming[spot].mPacket->GetDataPtr(), mReliableIncoming[spot].mPacket->GetDataLen()); + } + + mReliableIncoming[spot].mPacket->Release(); + mReliableIncoming[spot].mPacket = NULL; + mReliableIncomingId++; + } + } + else + { + // not the one we need next, but it is later than the one we need , so store it in our buffer until it's turn comes up + int spot = (int)(reliableId % mConfig.maxInstandingPackets); + if (mReliableIncoming[spot].mPacket == NULL) // only make the copy of it if we don't already have it in our buffer (in cases where it was sent twice, there would be no harm in the copy again since it must be the same packet, it's just inefficient) + { + mReliableIncoming[spot].mMode = mode; + mReliableIncoming[spot].mPacket = mUdpConnection->mUdpManager->CreatePacket(data + UdpConnection::cUdpPacketReliableSize, dataLen - UdpConnection::cUdpPacketReliableSize); + + // on out of order deliver, we need to keep a copy of it as if we were doing ordered-delivery in order to prevent duplicates + // we will mark the packet in the queue as already delivered to prevent it from getting delivered a second time when the stalled packet + // arrives and unwinds the queue + if (mode == cReliablePacketModeReliable && mConfig.outOfOrder) + { + ProcessPacket(cReliablePacketModeReliable, (udp_uchar *)mReliableIncoming[spot].mPacket->GetDataPtr(), mReliableIncoming[spot].mPacket->GetDataLen()); + mReliableIncoming[spot].mMode = cReliablePacketModeDelivered; + } + } + else + { + mStatDuplicatePacketsReceived++; + mUdpConnection->mConnectionStats.duplicatePacketsReceived++; + mUdpConnection->mUdpManager->IncrementDuplicatePacketsReceived(); + } + } + } + else + { + mStatDuplicatePacketsReceived++; + mUdpConnection->mConnectionStats.duplicatePacketsReceived++; + mUdpConnection->mUdpManager->IncrementDuplicatePacketsReceived(); + } + + bool ackAll = false; + bufPtr = buf; + *bufPtr++ = 0; + if (mReliableIncomingId > reliableId) + { + // ack everything up to the current head of our chain (minus one since the stamp represents the next one we want to get) + *bufPtr++ = (udp_uchar)(UdpConnection::cUdpPacketAckAll1 + mChannelNumber); + bufPtr += UdpMisc::PutValue16(bufPtr, (udp_ushort)((mReliableIncomingId - 1) & 0xffff)); + ackAll = true; + } + else + { + // a simple ack for us only + *bufPtr++ = (udp_uchar)(UdpConnection::cUdpPacketAck1 + mChannelNumber); + bufPtr += UdpMisc::PutValue16(bufPtr, (udp_ushort)(reliableId & 0xffff)); + } + + if (mBufferedAckPtr != NULL && mConfig.ackDeduping && ackAll) + { + memcpy(mBufferedAckPtr, buf, bufPtr - buf); + } + else + { + udp_uchar *ptr = mUdpConnection->BufferedSend(buf, (int)(bufPtr - buf), NULL, 0, true); // safe to append on our data, it is stack data + if (mBufferedAckPtr == NULL) + { + // the buffered-ack ptr should always point to the earliest ack in the buffer, such that + // a replacement ack-all will be processed by the receiver before any selective acks that may + // have been buffered up. Thus, only repoint the buffered ack ptr if it was previously unset. + mBufferedAckPtr = ptr; + } + } +} + +void UdpReliableChannel::ProcessPacket(ReliablePacketMode mode, const udp_uchar *data, int dataLen) +{ + assert(dataLen > 0); + + // if we have a big packet under construction already, or we are a fragment and thus need to be constructing one, then append this on the end (will create new if it is the first fragment) + if (mode == cReliablePacketModeReliable) + { + // we are not a fragment, nor was there a fragment in progress, so we are a simple reliable packet, just send it to the app + if (mBigDataPtr != NULL) + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonFragmentExpected); + return; + } + + mUdpConnection->ProcessCookedPacket(data, dataLen); + } + else if (mode == cReliablePacketModeFragment) + { + // append onto end of big packet (or create new big packet if not existing already) + if (mBigDataPtr == NULL) + { + if (dataLen < 4) + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonFragmentBad); + return; + } + + mBigDataTargetLen = UdpMisc::GetValue32(data); // first fragment has a total-length int header on it. + + if (mBigDataTargetLen <= 0) // negative or zero sized chunk to follow means packet corruption or tampering for sure + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonFragmentBad); + return; + } + + if (mBigDataTargetLen > mUdpConnection->mUdpManager->mParams.incomingLogicalPacketMax) + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonFragmentOversized); + return; + } + + mBigDataPtr = new udp_uchar[mBigDataTargetLen]; + mBigDataLen = 0; + data += 4; + dataLen -= 4; + } + + int safetyMax = udpMin(mBigDataTargetLen - mBigDataLen, dataLen); // can't happen in theory since they should add up exact, but protect against it if it does + assert(safetyMax == dataLen); + memcpy(mBigDataPtr + mBigDataLen, data, safetyMax); + mBigDataLen += safetyMax; + + if (mBigDataTargetLen == mBigDataLen) + { + // send big-packet off to application + mUdpConnection->ProcessCookedPacket(mBigDataPtr, mBigDataLen); + + // delete big packet, and reset + delete[] mBigDataPtr; + mBigDataLen = 0; + mBigDataTargetLen = 0; + mBigDataPtr = NULL; + } + } +} + +void UdpReliableChannel::AckAllPacket(const udp_uchar *data, int dataLen) +{ + if (dataLen < 4) + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonAckBad); + return; + } + + udp_int64 reliableId = GetReliableOutgoingId((udp_ushort)UdpMisc::GetValue16(data + 2)); + + if (mReliableOutgoingPendingId > reliableId) + { + // if we ackall'ed a packet and everything before the ackall address had already been acked, then we know + // for certainty that we sent a packet over again that did not need to be sent over again (ie. wasn't lost, just slow) + // so adjust the mAveragePingTime upward to slow down future resends + mAveragePingTime += 400; + mAveragePingTime = udpMin(mConfig.resendDelayCap, mAveragePingTime); + } + + for (udp_int64 i = mReliableOutgoingPendingId; i <= reliableId; i++) + { + Ack(i); + } +} + +void UdpReliableChannel::Ack(udp_int64 reliableId) +{ + // if packet being acknowledged is possibly in our resend queue, then check for it + if (reliableId >= mReliableOutgoingPendingId && reliableId < mReliableOutgoingId) + { + int pos = (int)(reliableId % mConfig.maxOutstandingPackets); + PhysicalPacket *entry = &mPhysicalPackets[pos]; + + if (entry->mDataPtr != NULL) // if this packet has not been acknowledged yet (sometimes we get back two acks for the same packet) + { + mNextNeedTime = 0; // something got acked, so we actually need to take the time next time it is offered + + // if the last time we gave this reliable channel processing time, it filled up the entire sliding window + // then go ahead and increase the window-size when incoming acks come in. However, if the window wasn't full + // then don't increase the window size. The problem is, a game application is likely to send reliable data + // at a relatively slow rate (2k/second for example), never filling the window. The net result would be that + // every acknowledged packet would increase the window size, giving the reliable channel the impression that + // it's window can be very very large, when in fact, it is only not losing packets because the application is pacing + // itself. The window could grow enormous, even 200k for a modem. Then, if the application were to dump a load + // of data onto us all at once, it would flush it all out at once thinking it had a big window. By only increasing + // the window size when we have high enough volume to fill the window, we ensure this does not happen. TCP does a similar + // thing, but what they do is reset the window if there has been a long stall. We do that too, but because we are a game + // application that is likely to pace the data at the application level, we have a unique circumstances that need addressing. + if (mMaxxedOutCurrentWindow) + { + if (mCongestionWindowSize < mCongestionSlowStartThreshhold) + { + mCongestionWindowSize += mMaxDataBytes; // slow-start mode + } + else + { + int increase = (mMaxDataBytes * mMaxDataBytes / mCongestionWindowSize); + mCongestionWindowSize += udpMax(1, increase); // congestion mode + + } + } + + if (entry->mLastTimeStamp == entry->mFirstTimeStamp) + { + + + // if the packet that is being acknowledged was only sent once, then we can safely use + // the round-trip time as an accurate measure of ping time. By knowing ping time, we can + // better (more agressively) schedule resends of lost packets. We will use a moving average + // that weights the current packet as 1/4 the average. + int thisPingTime = mUdpConnection->GetUdpManager()->CachedClockElapsed(entry->mFirstTimeStamp); + mAveragePingTime = (mAveragePingTime * 3 + thisPingTime) / 4; + } + + // what this is doing is if we receive an ACK for a packet that was sent at TIME_X + // we can assume that all packets sent before TIME_X that are not yet acknowledge were lost + // and we can resend them immediately + // since we do not know whether this ack is for last packet we sent, we have to assume it is for the first time this packet was sent (if sent multiple times) + // otherwise, we could resend it, then receive the ack from the first packet, and think our last-ack time is the time of the second outgoing packet + // which would cause about every packet in the queue to resend, even if they had just been sent + // in situations where the first packet truely was lost and this is an ACK of the second packet, then the only + // harm done is that the we may not resend some of the earlier sent packets quite as quickly. This will only + // happen in situations where a packet that was truely lost gets acked on it's second attempt...we just + // won't be using that ack for the purposes of accelerating other resends...since odds are a non-lost packet + // will accelerate those other resends shortly anyhow, there really is no loss + // (note: we used to only set this value forward for packets that were never lost (one time sends); however, if this stamp + // ever got set way high for some reason (in theory it can't happen), then we would get into a situation where it would + // rapidly resend and possibly never get reset, causing infinite rapid resends, so we now set it every time to the first-stamp) + // which will be safe, even if the packet were resent.) + mLastTimeStampAcknowledged = entry->mFirstTimeStamp; + + + // this packet we have queued has been acknowledged, so delete it from queue + mReliableOutgoingBytes -= entry->mDataLen; + entry->mDataLen = 0; + entry->mDataPtr = NULL; + entry->mParent->Release(); + entry->mParent = NULL; + + // advance the pending ptr until it reaches outgoingId or an entry that has yet to acknowledged + while (mReliableOutgoingPendingId < mReliableOutgoingId) + { + if (mPhysicalPackets[mReliableOutgoingPendingId % mConfig.maxOutstandingPackets].mDataPtr != NULL) + break; + mReliableOutgoingPendingId++; + } + } + else + { + // we got an ack for a packet that has already been acked. This could be due to an ack-all packet that covered us so statistically + // we can't do much with this information. + } + } + + // we don't need to try rescheduling ourself here, since our connection object reschedules to go immediately whenever any type + // of packet arrives (including ack packets) +} + + +UdpReliableChannel::IncomingQueueEntry::IncomingQueueEntry() +{ + mPacket = NULL; + mMode = UdpReliableChannel::cReliablePacketModeReliable; +} + +UdpReliableChannel::IncomingQueueEntry::~IncomingQueueEntry() +{ + if (mPacket != NULL) + mPacket->Release(); +} + + +UdpReliableChannel::PhysicalPacket::PhysicalPacket() +{ + mParent = NULL; +} + +UdpReliableChannel::PhysicalPacket::~PhysicalPacket() +{ + if (mParent != NULL) + mParent->Release(); +} + + +} // namespace diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpReliableChannel.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpReliableChannel.h new file mode 100644 index 00000000..fab02474 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpReliableChannel.h @@ -0,0 +1,177 @@ +#ifndef UDPLIBRARY_UDPRELIABLECHANNEL_H +#define UDPLIBRARY_UDPRELIABLECHANNEL_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +namespace UdpLibrary +{ + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // The purpose of this class is to manage the reliable transmission of packets on top of the inherently + // unreliable UDP layer. This is an internal object and should not be manually created or talked to by the user. + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class UdpReliableChannel +{ + protected: + friend class UdpConnection; + + UdpReliableChannel(int channelNumber, UdpConnection *connection, UdpReliableConfig *config); + ~UdpReliableChannel(); + void GetChannelStatus(UdpConnection::ChannelStatus *channelStatus) const; + int GetAveragePing() const; + int TotalPendingBytes() const; // returns total bytes outstanding + + void ReliablePacket(const udp_uchar *data, int dataLen); + void Send(const udp_uchar *data, int dataLen, const udp_uchar *data2, int dataLen2); + void AckPacket(const udp_uchar *data, int dataLen); + void AckAllPacket(const udp_uchar *data, int dataLen); + void ClearBufferedAck(); + int GiveTime(); + + protected: + enum ReliablePacketMode { cReliablePacketModeReliable, cReliablePacketModeFragment, cReliablePacketModeDelivered }; + + class PhysicalPacket + { + public: + PhysicalPacket(); + ~PhysicalPacket(); + + public: + UdpClockStamp mFirstTimeStamp; + UdpClockStamp mLastTimeStamp; + const LogicalPacket *mParent; // physical packets hold an addref on the logical packet. Once all of the logical packet data has been divied out to physical packets, the logical queue releases it + const udp_uchar *mDataPtr; // within parent's data (it's possible it is not pointing to the beginning in the case of large packets) + int mDataLen; + }; + + class IncomingQueueEntry + { + public: + IncomingQueueEntry(); + ~IncomingQueueEntry(); + + public: + LogicalPacket *mPacket; + ReliablePacketMode mMode; + }; + friend class IncomingQueueEntry; + + udp_int64 GetReliableOutgoingId(int reliableStamp) const; + udp_int64 GetReliableIncomingId(int reliableStamp) const; + void Ack(udp_int64 reliableId); + void ProcessPacket(ReliablePacketMode mode, const udp_uchar *data, int dataLen); + bool PullDown(int windowSpaceLeft); + void FlushCoalesce(); + void SendCoalesce(const udp_uchar *data, int dataLen, const udp_uchar *data2 = NULL, int dataLen2 = 0); + void QueueLogicalPacket(LogicalPacket *packet); + + UdpReliableConfig mConfig; + UdpConnection *mUdpConnection; + UdpClockStamp mLastTimeStampAcknowledged; + UdpClockStamp mTrickleLastSend; + UdpClockStamp mNextNeedTime; + UdpClockStamp mWindowResetTime; + int mChannelNumber; + udp_int64 mReliableOutgoingId; + udp_int64 mReliableOutgoingPendingId; + int mReliableOutgoingBytes; + int mLogicalBytesQueued; + udp_uchar *mBigDataPtr; + int mBigDataLen; + int mBigDataTargetLen; + int mAveragePingTime; + int mMaxDataBytes; + int mFragmentNextPos; + PhysicalPacket *mPhysicalPackets; + UdpLinkedList mLogicalPacketList; + + int mCongestionWindowStart; + int mCongestionWindowSize; + int mCongestionSlowStartThreshhold; + int mCongestionWindowMinimum; + bool mMaxxedOutCurrentWindow; + + udp_int64 mReliableIncomingId; + IncomingQueueEntry *mReliableIncoming; + + LogicalPacket *mCoalescePacket; + udp_uchar *mCoalesceStartPtr; + udp_uchar *mCoalesceEndPtr; + int mCoalesceCount; + int mMaxCoalesceAttemptBytes; + + udp_uchar *mBufferedAckPtr; + + int mStatDuplicatePacketsReceived; + int mStatResentPacketsAccelerated; + int mStatResentPacketsTimedOut; +}; + + + ///////////////////////////////////////////////////////////////////////// + // inline implementations + ///////////////////////////////////////////////////////////////////////// + + // UdpReliableChannel +inline void UdpReliableChannel::AckPacket(const udp_uchar *data, int dataLen) +{ + if (dataLen < 4) + { + mUdpConnection->CallbackCorruptPacket(data, dataLen, cUdpCorruptionReasonAckBad); + return; + } + + Ack(GetReliableOutgoingId((udp_ushort)UdpMisc::GetValue16(data + 2))); +} + +inline int UdpReliableChannel::GetAveragePing() const +{ + return(mAveragePingTime); +} + +inline int UdpReliableChannel::TotalPendingBytes() const +{ + return(mLogicalBytesQueued + mReliableOutgoingBytes); +} + +inline void UdpReliableChannel::ClearBufferedAck() +{ + mBufferedAckPtr = NULL; +} + +inline udp_int64 UdpReliableChannel::GetReliableOutgoingId(int reliableStamp) const +{ + // since we can never have anywhere close to 65000 packets outstanding, we only need to + // to send the low order word of the reliableId in the UdpPacketReliable and UdpPacketAck + // packets, because we can reconstruct the full id from that, we just need to take + // into account the wrap around issue. We calculate it based of the high-word of the + // next packet we are going to send. If it ends up being larger then we know + // we wrapped and can fix it up by simply subtracting 1 from the high-order word. + udp_int64 reliableId = reliableStamp | (mReliableOutgoingId & (~(udp_int64)0xffff)); + if (reliableId > mReliableOutgoingId) + reliableId -= 0x10000; + return(reliableId); +} + +inline udp_int64 UdpReliableChannel::GetReliableIncomingId(int reliableStamp) const +{ + // since we can never have anywhere close to 65000 packets outstanding, we only need to + // to send the low order word of the reliableId in the UdpPacketReliable and UdpPacketAck + // packets, because we can reconstruct the full id from that, we just need to take + // into account the wrap around issue. We basically prepend the last-known + // high-order word. If we end up significantly below the head of our chain, then we + // know we need to pick the entry 0x10000 higher. If we fall significantly above + // our previous high-end, then we know we need to go the other way. + udp_int64 reliableId = reliableStamp | (mReliableIncomingId & (~(udp_int64)0xffff)); + if (reliableId < mReliableIncomingId - UdpManager::cHardMaxOutstandingPackets) + reliableId += 0x10000; + if (reliableId > mReliableIncomingId + UdpManager::cHardMaxOutstandingPackets) + reliableId -= 0x10000; + return(reliableId); +} + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpTypes.h b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpTypes.h new file mode 100644 index 00000000..5296a0ec --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpTypes.h @@ -0,0 +1,119 @@ +#ifndef UDPLIBRARY_UDPTYPES_H +#define UDPLIBRARY_UDPTYPES_H + +// Copyright 2004 Sony Online Entertainment, all rights reserved. +// Author: Jeff Petersen + +#include + +namespace UdpLibrary +{ + +class UdpManager; +class UdpConnection; +class LogicalPacket; +class UdpPlatformAddress; + +#if defined(WIN32) + typedef __int64 udp_int64; + #pragma warning(disable:4121) // an error in microsofts compiler makes it think that pointers-to-members require 12 byte alignment, and since we are only doing 8 byte alignment by default, we get this warning. Turns out that alignment is actually a non-issue for pointers-to-members since they are accessed only 4 bytes at a time. (found this info on the internet) +#else + typedef long long udp_int64; +#endif + +typedef unsigned char udp_uchar; +typedef unsigned short udp_ushort; +typedef unsigned int udp_uint; +typedef unsigned long udp_ulong; +typedef udp_int64 UdpClockStamp; +typedef UdpPlatformAddress UdpIpAddress; // deprecated, use UdpPlatformAddress directly instead + +enum UdpCorruptionReason { cUdpCorruptionReasonNone + , cUdpCorruptionReasonMultiPacket + , cUdpCorruptionReasonReliablePacketTooShort + , cUdpCorruptionReasonInternalPacketTooShort + , cUdpCorruptionReasonDecryptFailed + , cUdpCorruptionReasonZeroLengthPacket + , cUdpCorruptionReasonPacketShorterThanCrcBytes + , cUdpCorruptionReasonMisformattedGroup + , cUdpCorruptionReasonFragmentOversized + , cUdpCorruptionReasonFragmentBad + , cUdpCorruptionReasonFragmentExpected + , cUdpCorruptionReasonAckBad + }; + + +enum UdpChannel { cUdpChannelUnreliable // unreliable/unordered/buffered + , cUdpChannelUnreliableUnbuffered // unreliable/unordered/unbuffered + , cUdpChannelOrdered // unreliable/ordered/buffered + , cUdpChannelOrderedUnbuffered // unreliable/ordered/unbuffered + , cUdpChannelReliable1 // reliable (as per channel config) + , cUdpChannelReliable2 // reliable (as per channel config) + , cUdpChannelReliable3 // reliable (as per channel config) + , cUdpChannelReliable4 // reliable (as per channel config) + , cUdpChannelCount // count of number of channels + }; + +class UdpRefCount +{ + public: + UdpRefCount(); + virtual void AddRef() const; + virtual void Release() const; + virtual void NoRef() const; + virtual int GetRefCount() const; + + protected: + virtual ~UdpRefCount(); + + mutable int mRefCount; + mutable bool mNoRef; +}; + + ///////////////////////////////////////////////////////////////////////////////// + // UdpRefCount implementation (entirely inline) + ///////////////////////////////////////////////////////////////////////////////// + +inline UdpRefCount::UdpRefCount() +{ + mRefCount = 1; + mNoRef = false; +} + +inline UdpRefCount::~UdpRefCount() +{ + assert(mRefCount == 0 || mNoRef); +} + +inline void UdpRefCount::AddRef() const +{ + assert(!mNoRef); + assert(mRefCount > 0); + ++mRefCount; +} + +inline void UdpRefCount::Release() const +{ + assert(!mNoRef); + assert(mRefCount > 0); + if (--mRefCount == 0) + { + delete this; + } +} + +inline void UdpRefCount::NoRef() const +{ + assert(mRefCount == 1); + mNoRef = true; +} + +inline int UdpRefCount::GetRefCount() const +{ + return(mRefCount); +} + + +} // namespace + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/FirstUnicode.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/FirstUnicode.cpp new file mode 100644 index 00000000..5d166f7c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/FirstUnicode.cpp @@ -0,0 +1,9 @@ +// ====================================================================== +// +// FirstUnicode.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstUnicode.h" + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/FirstUnicode.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/FirstUnicode.h new file mode 100644 index 00000000..70125beb --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/FirstUnicode.h @@ -0,0 +1,26 @@ +// ====================================================================== +// +// FirstUnicode.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_PlatFirstUnicode_H +#define INCLUDED_PlatFirstUnicode_H + +// ====================================================================== +// stl unref inline func removed + +#ifdef WIN32 + +// C4514 unreferenced inline/local function has been removed +// C4786 'identifier' : identifier was truncated to 'number' characters in the debug information + +#pragma warning (disable:4514 4786) + +#endif + +// ====================================================================== + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/Unicode.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/Unicode.cpp new file mode 100644 index 00000000..5aa7aae2 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/Unicode.cpp @@ -0,0 +1,26 @@ +// ====================================================================== +// +// Unicode.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstUnicode.h" +#include "Unicode.h" + +// ====================================================================== + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +// ====================================================================== diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/Unicode.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/Unicode.h new file mode 100644 index 00000000..3c31835c --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/Unicode.h @@ -0,0 +1,62 @@ +// ====================================================================== +// Unicode.h +// copyright (c) 2001 Sony Online Entertainment +// +// jwatson +// +// Basic Unicode primitives and string handling/manipulating functions +// ====================================================================== + +#ifndef INCLUDED_PlatUnicode_H +#define INCLUDED_PlatUnicode_H + +#if WIN32 +#pragma warning (disable:4710) +#pragma warning (disable:4786) +// stl warning func not inlined +#pragma warning (disable:4514) +#endif + +#include + +//----------------------------------------------------------------- + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + + typedef unsigned short unicode_char_t; + + /** + * Standard Unicode string is UTF-16 + */ + typedef std::basic_string String; + + /** + * NarrowString is a ascii string. + */ + + typedef std::string NarrowString; + + const unicode_char_t whitespace [] = { ' ', '\n', '\r', '\t', 0 }; + const unicode_char_t endlines [] = { '\r', '\n', 0 }; + const char ascii_whitespace [] = { ' ', '\n', '\r', '\t', 0 }; + const char ascii_endlines [] = { '\r', '\n', 0 }; + + const unicode_char_t cyrillic_lower_first = 0x0410; + const unicode_char_t cyrillic_lower_last = 0x042F; + const unicode_char_t cyrillic_upper_first = 0x0430; + const unicode_char_t cyrillic_upper_last = 0x044F; +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +//----------------------------------------------------------------- + +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeBlocks.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeBlocks.cpp new file mode 100644 index 00000000..0b8194b1 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeBlocks.cpp @@ -0,0 +1,267 @@ +// ====================================================================== +// +// UnicodeBlocks.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// This contains Unicode 3.0 compliant Blocks. +// +// ====================================================================== + +#include "FirstUnicode.h" +#include "UnicodeBlocks.h" + +// ====================================================================== +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif +using namespace Plat_Unicode::Blocks; +using Plat_Unicode::unicode_char_t; + +//----------------------------------------------------------------- + +const Plat_Unicode::Blocks::RawData Plat_Unicode::Blocks::Mapping::ms_defaultBlockData [] = +{ + { Basic_Latin, "Basic Latin",0x0000,0x007F }, + { Latin_1_Supplement,"Latin-1 Supplement",0x0080,0x00FF }, + { Latin_Extended_A, "Latin Extended-A",0x0100,0x017F }, + { Latin_Extended_B, "Latin Extended-B",0x0180,0x024F }, + { IPA_Extensions, "IPA Extensions",0x0250,0x02AF }, + { Spacing_Modifier_Letters, "Spacing Modifier Letters",0x02B0,0x02FF }, + { Combining_Diacritical_Marks, "Combining Diacritical Marks",0x0300,0x036F }, + { Greek, "Greek",0x0370,0x03FF }, + { Cyrillic, "Cyrillic",0x0400,0x04FF }, + { Armenian, "Armenian",0x0530,0x058F }, + { Hebrew, "Hebrew",0x0590,0x05FF }, + { Arabic, "Arabic",0x0600,0x06FF }, + { Syriac, "Syriac ",0x0700,0x074F }, + { Thaana, "Thaana",0x0780,0x07BF }, + { Devanagari, "Devanagari",0x0900,0x097F }, + { Bengali, "Bengali",0x0980,0x09FF }, + { Gurmukhi, "Gurmukhi",0x0A00,0x0A7F }, + { Gujarati, "Gujarati",0x0A80,0x0AFF }, + { Oriya, "Oriya",0x0B00,0x0B7F }, + { Tamil, "Tamil",0x0B80,0x0BFF }, + { Telugu, "Telugu",0x0C00,0x0C7F }, + { Kannada, "Kannada",0x0C80,0x0CFF }, + { Malayalam, "Malayalam",0x0D00,0x0D7F }, + { Sinhala, "Sinhala",0x0D80,0x0DFF }, + { Thai, "Thai",0x0E00,0x0E7F }, + { Lao, "Lao",0x0E80,0x0EFF }, + { Tibetan, "Tibetan",0x0F00,0x0FFF }, + { Myanmar, "Myanmar ",0x1000,0x109F }, + { Georgian, "Georgian",0x10A0,0x10FF }, + { Hangul_Jamo, "Hangul Jamo",0x1100,0x11FF }, + { Ethiopic, "Ethiopic",0x1200,0x137F }, + { Cherokee, "Cherokee",0x13A0,0x13FF }, + { Unified_Canadian_Aboriginal_Syllabics, "Unified Canadian Aboriginal Syllabics",0x1400,0x167F }, + { Ogham, "Ogham",0x1680,0x169F }, + { Runic, "Runic",0x16A0,0x16FF }, + { Khmer, "Khmer",0x1780,0x17FF }, + { Mongolian, "Mongolian",0x1800,0x18AF }, + { Latin_Extended_Additional, "Latin Extended Additional",0x1E00,0x1EFF }, + { Greek_Extended, "Greek Extended",0x1F00,0x1FFF }, + { General_Punctuation, "General Punctuation",0x2000,0x206F }, + { Superscripts_and_Subscripts, "Superscripts and Subscripts",0x2070,0x209F }, + { Currency_Symbols, "Currency Symbols",0x20A0,0x20CF }, + { Combining_Marks_for_Symbols, "Combining Marks for Symbols",0x20D0,0x20FF }, + { Letterlike_Symbols, "Letterlike Symbols",0x2100,0x214F }, + { Number_Forms, "Number Forms",0x2150,0x218F }, + { Arrows, "Arrows",0x2190,0x21FF }, + { Mathematical_Operators, "Mathematical Operators",0x2200,0x22FF }, + { Miscellaneous_Technical, "Miscellaneous Technical",0x2300,0x23FF }, + { Control_Pictures, "Control Pictures",0x2400,0x243F }, + { Optical_Character_Recognition, "Optical Character Recognition",0x2440,0x245F }, + { Enclosed_Alphanumerics, "Enclosed Alphanumerics",0x2460,0x24FF }, + { Box_Drawing, "Box Drawing",0x2500,0x257F }, + { Block_Elements, "Block Elements",0x2580,0x259F }, + { Geometric_Shapes, "Geometric Shapes",0x25A0,0x25FF }, + { Miscellaneous_Symbols, "Miscellaneous Symbols",0x2600,0x26FF }, + { Dingbats, "Dingbats",0x2700,0x27BF }, + { Braille_Patterns, "Braille Patterns",0x2800,0x28FF }, + { CJK_Radicals_Supplement, "CJK Radicals Supplement",0x2E80,0x2EFF }, + { Kangxi_Radicals, "Kangxi Radicals",0x2F00,0x2FDF }, + { Ideographic_Description_Characters, "Ideographic Description Characters",0x2FF0,0x2FFF }, + { CJK_Symbols_and_Punctuation, "CJK Symbols and Punctuation",0x3000,0x303F }, + { Hiragana, "Hiragana",0x3040,0x309F }, + { Katakana, "Katakana",0x30A0,0x30FF }, + { Bopomofo, "Bopomofo",0x3100,0x312F }, + { Hangul_Compatibility_Jamo, "Hangul Compatibility Jamo",0x3130,0x318F }, + { Kanbun, "Kanbun",0x3190,0x319F }, + { Bopomofo_Extended, "Bopomofo Extended",0x31A0,0x31BF }, + { Enclosed_CJK_Letters_and_Months, "Enclosed CJK Letters and Months",0x3200,0x32FF }, + { CJK_Compatibility, "CJK Compatibility",0x3300,0x33FF }, + { CJK_Unified_Ideographs_Extension_A, "CJK Unified Ideographs Extension A",0x3400,0x4DB5 }, + { CJK_Unified_Ideographs, "CJK Unified Ideographs",0x4E00,0x9FFF }, + { Yi_Syllables, "Yi Syllables",0xA000,0xA48F }, + { Yi_Radicals, "Yi Radicals",0xA490,0xA4CF }, + { Hangul_Syllables, "Hangul Syllables",0xAC00,0xD7A3 }, + { High_Surrogates, "High Surrogates",0xD800,0xDB7F }, + { High_Private_Use_Surrogates, "High Private Use Surrogates",0xDB80,0xDBFF }, + { Low_Surrogates, "Low Surrogates",0xDC00,0xDFFF }, + { Private_Use, "Private Use",0xE000,0xF8FF }, + { CJK_Compatibility_Ideographs, "CJK Compatibility Ideographs",0xF900,0xFAFF }, + { Alphabetic_Presentation_Forms, "Alphabetic Presentation Forms",0xFB00,0xFB4F }, + { Arabic_Presentation_Forms_A, "Arabic Presentation Forms-A",0xFB50,0xFDFF }, + { Combining_Half_Marks, "Combining Half Marks",0xFE20,0xFE2F }, + { CJK_Compatibility_Forms, "CJK Compatibility Forms",0xFE30,0xFE4F }, + { Small_Form_Variants, "Small Form Variants",0xFE50,0xFE6F }, + { Arabic_Presentation_Forms_B, "Arabic Presentation Forms-B",0xFE70,0xFEFE }, + { Specials_1, "Specials",0xFEFF,0xFEFF }, + { Halfwidth_and_Fullwidth_Forms, "Halfwidth and Fullwidth Forms",0xFF00,0xFFEF }, + { Specials_2, "Specials 2",0xFFF0,0xFFFD }, + { End_Block_Ids, "End Block Ids",0xFFFE,0xFFFF } +}; + +//----------------------------------------------------------------- + +Mapping * Mapping::ms_singleton = 0; + +//----------------------------------------------------------------- + +/** +* Initialize the singleton. This must be called before mapping is used. +*/ + +void Mapping::initSingleton () +{ + explicitDestroy (); + ms_singleton = new Mapping (ms_defaultBlockData); +} + +//----------------------------------------------------------------- + +/** +* Destroys the singleton +*/ + +void Mapping::explicitDestroy () +{ + if (ms_singleton) + delete ms_singleton; + + ms_singleton = 0; +} + +//----------------------------------------------------------------- + +/** +* Construct a Mapping from an array of RawData +*/ + +Mapping::Mapping (const RawData dataArray []) : +m_idMap (), +m_nameMap (), +m_errorData () +{ + + size_t i = 0; + for (; dataArray [i].m_id != End_Block_Ids; ++i) + { + m_idMap [dataArray[i].m_id] = Data (dataArray [i]); + m_nameMap [dataArray[i].m_name] = Data (dataArray [i]); + } + + m_errorData = Data (dataArray [i]); +} + +//---------------------------------------------------------------------- + +/** +* Construct a complete set of code points in this block. +* @param idset should enter this function empty +*/ + +const std::set & Data::generateFilteredIdSet (std::set & idset) const +{ + { + for (unicode_char_t i = m_start; i < m_end; ++i) + { + idset.insert (i); + } + } + + + for (RangeGroups_t::const_iterator iter = m_rangeGroups.begin (); iter != m_rangeGroups.end (); ++iter) + { + const RangeGroup & rg = *iter; + + if (rg.m_isInclusive) + { + for (RangeGroup::Ranges_t::const_iterator rg_iter = rg.m_ranges.begin (); rg_iter != rg.m_ranges.end (); ++rg_iter) + { + for (unicode_char_t i = (*rg_iter).m_low; i <= (*rg_iter).m_high; ++i) + { + idset.insert (i); + } + } + } + else + { + for (RangeGroup::Ranges_t::const_iterator rg_iter = rg.m_ranges.begin (); rg_iter != rg.m_ranges.end (); ++rg_iter) + { + for (unicode_char_t i = (*rg_iter).m_low; i <= (*rg_iter).m_high; ++i) + { + idset.erase (i); + } + } + } + } + + return idset; +} + +//----------------------------------------------------------------- + +/** +* Add a range group with a given string representation. Valid strings include hexadecimal numbers, dashes, and commas. +* @param inclusive indicates if this group should be additive or subtractive. It is an error to attempt to add code points outside the Block's gross range. +*/ + +bool Data::addRangeGroup (bool inclusive, const Plat_Unicode::NarrowString & str) +{ + RangeGroup rg; + rg.m_isInclusive = inclusive; + + size_t tokenStartPos = 0; + + while (tokenStartPos != NarrowString::npos) + { + size_t tokenCommaPos = str.find_first_of (',', tokenStartPos); + + size_t tokenDashPos = str.find_first_of ('-', tokenStartPos); + + Range rng; + + // this is a dashed range + if (tokenDashPos < tokenCommaPos) + { + rng.m_low = static_cast (strtoul ( str.substr (tokenStartPos, tokenDashPos - tokenStartPos).c_str (), 0, 16)); + tokenStartPos = str.find_first_not_of ('-', tokenDashPos); + + if (tokenStartPos == NarrowString::npos) + return false; + + rng.m_high = static_cast (strtoul (str.substr (tokenStartPos, tokenCommaPos - tokenStartPos).c_str (), 0, 16)); + + } + + else + { + rng.m_high = rng.m_low = static_cast (strtoul ( str.substr (tokenStartPos, tokenCommaPos - tokenStartPos).c_str (), 0, 16)); + } + + rg.m_ranges.push_back (rng); + + tokenStartPos = str.find_first_not_of (',', tokenCommaPos); + } + + m_rangeGroups.push_back (rg); + return true; + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +// ===================================================================== }, diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeBlocks.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeBlocks.h new file mode 100644 index 00000000..245e811d --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeBlocks.h @@ -0,0 +1,404 @@ +// ====================================================================== +// +// UnicodeBlocks.h +// copyright (c) 2001 Sony Online Entertainment +// +// This contains Unicode 3.0 compliant Blocks. +// +// ====================================================================== + +#ifndef INCLUDED_PlatUnicodeBlocks_H +#define INCLUDED_PlatUnicodeBlocks_H + +#if WIN32 +// stl warning func not inlined +#pragma warning (disable:4710) +#pragma warning (disable:4786) +#endif + +#include "Unicode.h" + +#include +#include +#include + +// ====================================================================== +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + + namespace Blocks + { + /** + * The enum values are precisely the beginning of the represented block range. + * These blocks are precisely the blocks defined by Unicode 3.0. + */ + enum Id + { + Basic_Latin = 0x0000, + Latin_1_Supplement = 0x0080, + Latin_Extended_A = 0x0100, + Latin_Extended_B = 0x0180, + IPA_Extensions = 0x0250, + Spacing_Modifier_Letters = 0x02B0, + Combining_Diacritical_Marks = 0x0300, + Greek = 0x0370, + Cyrillic = 0x0400, + Armenian = 0x0530, + Hebrew = 0x0590, + Arabic = 0x0600, + Syriac = 0x0700, + Thaana = 0x0780, + Devanagari = 0x0900, + Bengali = 0x0980, + Gurmukhi = 0x0A00, + Gujarati = 0x0A80, + Oriya = 0x0B00, + Tamil = 0x0B80, + Telugu = 0x0C00, + Kannada = 0x0C80, + Malayalam = 0x0D00, + Sinhala = 0x0D80, + Thai = 0x0E00, + Lao = 0x0E80, + Tibetan = 0x0F00, + Myanmar = 0x1000, + Georgian = 0x10A0, + Hangul_Jamo = 0x1100, + Ethiopic = 0x1200, + Cherokee = 0x13A0, + Unified_Canadian_Aboriginal_Syllabics = 0x1400, + Ogham = 0x1680, + Runic = 0x16A0, + Khmer = 0x1780, + Mongolian = 0x1800, + Latin_Extended_Additional = 0x1E00, + Greek_Extended = 0x1F00, + General_Punctuation = 0x2000, + Superscripts_and_Subscripts = 0x2070, + Currency_Symbols = 0x20A0, + Combining_Marks_for_Symbols = 0x20D0, + Letterlike_Symbols = 0x2100, + Number_Forms = 0x2150, + Arrows = 0x2190, + Mathematical_Operators = 0x2200, + Miscellaneous_Technical = 0x2300, + Control_Pictures = 0x2400, + Optical_Character_Recognition = 0x2440, + Enclosed_Alphanumerics = 0x2460, + Box_Drawing = 0x2500, + Block_Elements = 0x2580, + Geometric_Shapes = 0x25A0, + Miscellaneous_Symbols = 0x2600, + Dingbats = 0x2700, + Braille_Patterns = 0x2800, + CJK_Radicals_Supplement = 0x2E80, + Kangxi_Radicals = 0x2F00, + Ideographic_Description_Characters = 0x2FF0, + CJK_Symbols_and_Punctuation = 0x3000, + Hiragana = 0x3040, + Katakana = 0x30A0, + Bopomofo = 0x3100, + Hangul_Compatibility_Jamo = 0x3130, + Kanbun = 0x3190, + Bopomofo_Extended = 0x31A0, + Enclosed_CJK_Letters_and_Months = 0x3200, + CJK_Compatibility = 0x3300, + CJK_Unified_Ideographs_Extension_A = 0x3400, + CJK_Unified_Ideographs = 0x4E00, + Yi_Syllables = 0xA000, + Yi_Radicals = 0xA490, + Hangul_Syllables = 0xAC00, + High_Surrogates = 0xD800, + High_Private_Use_Surrogates = 0xDB80, + Low_Surrogates = 0xDC00, + Private_Use = 0xE000, + CJK_Compatibility_Ideographs = 0xF900, + Alphabetic_Presentation_Forms = 0xFB00, + Arabic_Presentation_Forms_A = 0xFB50, + Combining_Half_Marks = 0xFE20, + CJK_Compatibility_Forms = 0xFE30, + Small_Form_Variants = 0xFE50, + Arabic_Presentation_Forms_B = 0xFE70, + Specials_1 = 0xFEFF, + Halfwidth_and_Fullwidth_Forms = 0xFF00, + Specials_2 = 0xFFF0, + End_Block_Ids = 0xFFFE + + }; + + + //----------------------------------------------------------------- + + /** + * A simple pair representing an inclusive range of values + */ + + struct Range + { + unicode_char_t m_high; + unicode_char_t m_low; + }; + + //----------------------------------------------------------------- + + /** + * A group of ranges that can be additive or subtractive (inclusive or non) + */ + + struct RangeGroup + { + bool m_isInclusive; + typedef std::vector Ranges_t; + Ranges_t m_ranges; + }; + + //----------------------------------------------------------------- + + /** + * RawData is a simple aggregate data struct used to construct the more complex Data objects + */ + struct RawData + { + Id m_id; + const char * m_name; + unicode_char_t m_start; + unicode_char_t m_end; + }; + + /** + * Data is the representation of a single Unicode block. + * Including the Id, name, gross start-end range, and a set of RangeGroups (usually subtractive) + */ + struct Data + { + Id m_id; + NarrowString m_name; + unicode_char_t m_start; + unicode_char_t m_end; + + typedef std::vector RangeGroups_t; + RangeGroups_t m_rangeGroups; + + explicit Data (const RawData & rhs); + Data (); + + const std::set & generateFilteredIdSet (std::set & ) const; + + bool addRangeGroup (bool inclusive, const NarrowString & str); + + }; + + //----------------------------------------------------------------- + + /** + * Singleton class. + * + * Mapping creates a method of mapping block Ids _or_ names to Block Data objects. + * @todo: Data objects are duplicate for each map, need to optimize. + */ + + class Mapping + { + + public: + + explicit Mapping (const RawData dataArray[]); + static const Mapping & getDefaultMapping (); + static void explicitDestroy (); + + typedef std::map IdMap_t; + typedef std::map NameMap_t; + + const Data & findBlock (Id id) const; + Data & findBlock (Id id); + const Data & findBlock (const NarrowString &) const; + const Data & findBlock (unicode_char_t code) const; + + const IdMap_t & getIdMap () const; + + bool addBlock (const Data & data); + + static const RawData ms_defaultBlockData []; + + private: + + Mapping (); + Mapping (const Mapping & rhs); + Mapping & operator= (const Mapping & rhs); + + static void initSingleton (); + + static Mapping * ms_singleton; + + IdMap_t m_idMap; + NameMap_t m_nameMap; + + Data m_errorData; + + }; + + //----------------------------------------------------------------- + + /** + * Convert a RawData into a Data object + */ + + inline Data::Data (const RawData & rhs) : + m_id (rhs.m_id), + m_name (rhs.m_name), + m_start (rhs.m_start), + m_end (rhs.m_end), + m_rangeGroups () + { + } + + //---------------------------------------------------------------------- + + /** + * Default constructor. + */ + + inline Data::Data () : + m_id (End_Block_Ids), + m_name (), + m_start (0), + m_end (0), + m_rangeGroups () + { + } + + //----------------------------------------------------------------- + + /** + * Static singleton accessor + */ + + inline const Mapping & Mapping::getDefaultMapping () + { + if (ms_singleton) + return *ms_singleton; + + initSingleton (); + return *ms_singleton; + } + + //----------------------------------------------------------------- + + /** + * Add a block Data object to the mapping. If the block already exists + * in the mapping, the new data overwrites the old. + */ + + inline bool Mapping::addBlock (const Data & data) + { + m_idMap [data.m_id] = data; + m_nameMap [data.m_name] = data; + return true; + } + + //----------------------------------------------------------------- + + /** + * Locate the block data by Id. + * @return a Data with End_Block_Ids Id if the block was not found + */ + + inline const Data & Mapping::findBlock (Id id) const + { + + const IdMap_t::const_iterator iter = m_idMap.find (id); + if (iter != m_idMap.end ()) + return (*iter).second; + else + return m_errorData; + } + + //----------------------------------------------------------------- + + /** + * Locate the block data by Id. + * @return a Data with End_Block_Ids Id if the block was not found + */ + + inline Data & Mapping::findBlock (Id id) + { + + const IdMap_t::iterator iter = m_idMap.find (id); + if (iter != m_idMap.end ()) + return (*iter).second; + else + return m_errorData; + } + + //----------------------------------------------------------------- + + /** + * Locate the block data by Name. + * @return a Data with End_Block_Ids Id if the block was not found + */ + + inline const Data & Mapping::findBlock (const NarrowString & name) const + { + + const NameMap_t::const_iterator iter = m_nameMap.find (name); + if (iter != m_nameMap.end ()) + return (*iter).second; + else + return m_errorData; + } + + //----------------------------------------------------------------- + + /** + * Locate the block data by code point. + * @return a Data with End_Block_Ids Id if the block was not found. This only tests if the code point is in the gross range of the located block. + */ + + inline const Data & Mapping::findBlock (unicode_char_t code) const + { + + const IdMap_t::const_iterator iter = m_idMap.lower_bound (static_cast(code)); + if (iter != m_idMap.end () && code <= (*iter).second.m_end) + return (*iter).second; + else + return m_errorData; + } + + //----------------------------------------------------------------- + + /** + * Gets the Id->Data map. + */ + + inline const Mapping::IdMap_t & Mapping::getIdMap () const + { + return m_idMap; + } + + //----------------------------------------------------------------- + + /** + * Tests a character to see if belongs in an ideograph range + */ + + inline bool isIdeograph (unicode_char_t code) + { + return ((code >= static_cast(CJK_Unified_Ideographs_Extension_A) && code < static_cast(Yi_Syllables)) || + (code >= static_cast(Hangul_Syllables) && code < static_cast(CJK_Compatibility_Ideographs))); + } + + } //-- namespace Blocks + +}; // -- namespace Unicode +#ifdef EXTERNAL_DISTRO +}; +#endif + +// ====================================================================== +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharTraits.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharTraits.cpp new file mode 100644 index 00000000..64649511 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharTraits.cpp @@ -0,0 +1,72 @@ +//#if defined (linux) && ((__GNUC__ == 3) || (__GNUC__ == 2 && __GNUC_MINOR__ > 96)) +//#include +//#include "Unicode.h" +// +//#ifdef EXTERNAL_DISTRO +//using namespace NAMESPACE::Plat_Unicode; +//#else +//using namespace Plat_Unicode; +//#endif +// +//namespace std +//{ +// +//void char_traits::assign(unicode_char_t &__c1, const unicode_char_t &__c2) +//{ +// __c1 = __c2; +//} +// +//bool char_traits::eq(const unicode_char_t &__c1, const unicode_char_t &__c2) +//{ +// return __c1 == __c2; +//} +// +//bool char_traits::lt(const unicode_char_t &__c1, const unicode_char_t &__c2) +//{ +// return __c1 < __c2; +//} +// +//unicode_char_t *char_traits::copy(unicode_char_t *__s1, const unicode_char_t *__s2, size_t __n) +//{ +// return(__n == 0 ? __s1 : (unicode_char_t*)memcpy(__s1, __s2, __n * sizeof(unicode_char_t))); +//} +// +//unicode_char_t *char_traits::move(unicode_char_t *__s1, const unicode_char_t* __s2, size_t _Sz) +//{ +// return (_Sz == 0 ? __s1 : (unicode_char_t*)memmove(__s1, __s2, _Sz * sizeof(unicode_char_t))); +//} +// +//const unicode_char_t *char_traits::find(const unicode_char_t* __s, size_t __n, const unicode_char_t & __c) +//{ +// for( ; __n > 0; ++__s, --__n) +// if(eq(*__s, __c)) +// return __s; +// return 0; +//} +// +//size_t char_traits::length(const unicode_char_t *__s) +//{ +// size_t __i; +// for(__i = 0; !eq(__s[__i], 0); ++__i); +// return __i; +//} +// +//unicode_char_t *char_traits::assign(unicode_char_t *__s, size_t __n, unicode_char_t __c) +//{ +// for(size_t __i = 0; __i < __n; ++__i) +// __s[__i] = __c; +// return __s; +//} +// +//int char_traits::compare(const unicode_char_t *__s1, const unicode_char_t *__s2, size_t __n) +//{ +// for(size_t __i = 0; __i < __n; ++__i) +// if(!eq(__s1[__i], __s2[__i])) +// return __s1[__i] < __s2[__i] ? -1 : 1; +// return 0; +//} +// +//} +// +//#endif +// diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterData.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterData.cpp new file mode 100644 index 00000000..bd5b832d --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterData.cpp @@ -0,0 +1,71 @@ +// ====================================================================== +// +// Plat_UnicodeCharData.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// This contains Plat_Unicode 3.0 compliant Character data formats +// The data is loaded dynamically from the Plat_UnicodeData.txt definition file +// +// ====================================================================== + +#include "FirstUnicode.h" +#include "UnicodeCharacterData.h" + +// ====================================================================== + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + +//----------------------------------------------------------------- + +#define CAT_NAME(s) { CharData::s, #s } + +const CharData::CategoryName CharData::ms_categoryNames [] = +{ + + CAT_NAME (Lu), // Letter, Uppercase + CAT_NAME (Ll), // Letter, Lowercase + CAT_NAME (Lt), // Letter, Titlecase + CAT_NAME (Lm), // Letter, Modifier + CAT_NAME (Lo), // Letter, Other + CAT_NAME (Mn), // Mark, Non-Spacing + CAT_NAME (Mc), // Mark, Spacing Combining + CAT_NAME (Me), // Mark, Enclosing + CAT_NAME (Nd), // Number, Decimal Digit + CAT_NAME (Nl), // Number, Letter + CAT_NAME (No), // Number, Other + CAT_NAME (Pc), // Punctuation, Connector + CAT_NAME (Pd), // Punctuation, Dash + CAT_NAME (Ps), // Punctuation, Open + CAT_NAME (Pe), // Punctuation, Close + CAT_NAME (Pi), // Punctuation, Initial quote (may behave like Ps or Pe depending on usage) + CAT_NAME (Pf), // Punctuation, Final quote (may behave like Ps or Pe depending on usage) + CAT_NAME (Po), // Punctuation, Other + CAT_NAME (Sm), // Symbol, Math + CAT_NAME (Sc), // Symbol, Currency + CAT_NAME (Sk), // Symbol, Modifier + CAT_NAME (So), // Symbol, Other + CAT_NAME (Zs), // Separator, Space + CAT_NAME (Zl), // Separator, Line + CAT_NAME (Zp), // Separator, Paragraph + CAT_NAME (Cc), // Other, Control + CAT_NAME (Cf), // Other, Format + CAT_NAME (Cs), // Other, Surrogate + CAT_NAME (Co), // Other, Private Use + CAT_NAME (Cn) // Other, Not Assigned (no characters in the file have this property) +}; + +#undef CAT_NAME + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif +//----------------------------------------------------------------- + +// ====================================================================== diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterData.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterData.h new file mode 100644 index 00000000..22e76cd7 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterData.h @@ -0,0 +1,125 @@ +// ====================================================================== +// +// UnicodeCharData.h +// copyright (c) 2001 Sony Online Entertainment +// +// This contains Unicode 3.0 compliant Character data formats +// The data is loaded dynamically from the UnicodeData.txt definition file +// +// ====================================================================== + +#ifndef INCLUDED_PlatUnicodeCharData_H +#define INCLUDED_PlatUnicodeCharData_H + +#if WIN32 +// stl warning func not inlined +#pragma warning (disable:4710) +#pragma warning (disable:4786) +#endif + +// ====================================================================== + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + typedef unsigned short unicode_char_t; //lint !e761 redundant typedef + + struct CharData; + + //----------------------------------------------------------------- + + struct CharData + { + + enum Category + { + Lu, // Letter, Uppercase + Ll, // Letter, Lowercase + Lt, // Letter, Titlecase + Lm, // Letter, Modifier + Lo, // Letter, Other + Mn, // Mark, Non-Spacing + Mc, // Mark, Spacing Combining + Me, // Mark, Enclosing + Nd, // Number, Decimal Digit + Nl, // Number, Letter + No, // Number, Other + Pc, // Punctuation, Connector + Pd, // Punctuation, Dash + Ps, // Punctuation, Open + Pe, // Punctuation, Close + Pi, // Punctuation, Initial quote (may behave like Ps or Pe depending on usage) + Pf, // Punctuation, Final quote (may behave like Ps or Pe depending on usage) + Po, // Punctuation, Other + Sm, // Symbol, Math + Sc, // Symbol, Currency + Sk, // Symbol, Modifier + So, // Symbol, Other + Zs, // Separator, Space + Zl, // Separator, Line + Zp, // Separator, Paragraph + Cc, // Other, Control + Cf, // Other, Format + Cs, // Other, Surrogate + Co, // Other, Private Use + Cn // Other, Not Assigned (no characters in the file have this property) + }; + + + struct CategoryName + { + Category m_category; + const char * m_str; + }; + + static const CategoryName ms_categoryNames[]; + + unicode_char_t m_code; + Category m_category; + + /** + * Note: this Unicode system only supports upper and lower case. + * Titlecase is considered uppercase. The case of a character + * is determined by its category (Lu,Ll,or Lt) + */ + + unicode_char_t m_reverseCase; + + bool isLowerCase () const; + bool isUpperCase () const; + + unicode_char_t toUpper () const; + unicode_char_t toLower () const; + }; + + //----------------------------------------------------------------- + + /** + * Is this character lowercase. + */ + inline bool CharData::isLowerCase () const + { + return m_category == Ll; + } + + //----------------------------------------------------------------- + + /** + * Returns true for upper and title case + */ + inline bool CharData::isUpperCase () const + { + return m_category == Lu || m_category == Lt; + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +// ====================================================================== + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterDataMap.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterDataMap.cpp new file mode 100644 index 00000000..71e2c0c8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterDataMap.cpp @@ -0,0 +1,360 @@ +// ====================================================================== +// +// UnicodeCharDataMap.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// This contains Unicode 3.0 compliant Character data formats +// The data is loaded dynamically from the UnicodeData.txt definition file +// +// ====================================================================== + +#include "FirstUnicode.h" +#include "UnicodeCharacterDataMap.h" +#include "UnicodeBlocks.h" +#include "UnicodeCharacterData.h" + +#include +#include +#include + +// ====================================================================== + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + +CharDataMap * CharDataMap::ms_singleton = 0; + +//----------------------------------------------------------------- + +CharDataMap::CharDataMap () : +m_blockIds (), +m_contiguousData (0), +m_map (), +m_dataIsValid (false) +{ + +} + +//----------------------------------------------------------------- + +CharDataMap::~CharDataMap () +{ + m_map.clear (); + m_blockIds.clear (); + + if (m_contiguousData) + { + delete[] m_contiguousData; + m_contiguousData = 0; + } +} + +//----------------------------------------------------------------- + +void CharDataMap::initSingleton () +{ + explicitDestroy (); + + // TODO: default blocks? + ms_singleton = new CharDataMap (); +} + +//----------------------------------------------------------------- + +void CharDataMap::explicitDestroy () +{ + if (ms_singleton) + delete ms_singleton; + + ms_singleton = 0; +} + +//----------------------------------------------------------------- + +namespace +{ + + typedef std::map CategoryMap_t; + + //----------------------------------------------------------------- + + + /** + * Load a CharData from a string buffer representing a file. + * The bufpos is set to the beginning of a line after this method returns. + */ + + + inline bool populateDataFromBuffer (size_t desiredCode, + CharData & charData, + const std::string & buffer, + size_t & bufpos, + const CategoryMap_t & cmap) + { + + size_t endpos = 0; + + bool found = false; + + do + { + size_t tokenNum = 0; + + while ( (endpos = buffer.find ( ';', bufpos)) != std::string::npos ) //lint !e737 // loss of sign in promotion - STL bug + { + // code value + if (tokenNum == 0) + { + const size_t code = static_cast (strtoul (buffer.substr (bufpos, endpos - bufpos).c_str (), 0, 16)); + + // we passed the desired line, so it must not exist + if (code > desiredCode) + return found; + // not there yet + else if (code < desiredCode) + break; + + charData.m_code = static_cast (code); + } + + // General Category + else if (tokenNum == 2) + { + // all category codes are currently 2 characters long + if (endpos - bufpos > 2) + break; + + const CategoryMap_t::const_iterator find_iter = cmap.find (buffer.substr (bufpos, 2)); + + if (find_iter == cmap.end ()) + { + break; + } + else + charData.m_category = (*find_iter).second; + } + + // Uppercase mapping + else if (charData.isLowerCase ()) + { + if (tokenNum == 12) + { + if (endpos - bufpos > 1) + charData.m_reverseCase = static_cast (strtoul (buffer.substr (bufpos, endpos - bufpos).c_str (), 0, 16)); + + found = true; + break; + } + } + // Lowercase mapping + else if (tokenNum == 13) + { + if (endpos - bufpos > 1) + charData.m_reverseCase = static_cast (strtoul (buffer.substr (bufpos, endpos - bufpos).c_str (), 0, 16)); + + found = true; + break; + } + + bufpos = endpos + 1; + ++tokenNum; + + } + } + while ( (bufpos = buffer.find ('\n', bufpos)) != std::string::npos && //lint !e737 // loss of sign in promotion - STL bug + (bufpos = buffer.find_first_not_of ('\n', bufpos + 1)) != std::string::npos); //lint !e737 // loss of sign in promotion - STL bug + + return found; + + } +} + +//----------------------------------------------------------------- + +/** +* Create a map of CharData's from a UnicodeData.txt standard Unicode 3.0 file, which has been packed into a buffer +*/ + +CharDataMap::ErrorCode CharDataMap::generateMapFromBuffer (const Blocks::Mapping & blockMapping, const std::string & str_buf) +{ + m_dataIsValid = false; + + m_map.clear (); + + //-- create the category map for use by the inline population function + CategoryMap_t cmap; + + { + size_t i = 0; + for (; CharData::ms_categoryNames [i].m_category != CharData::Cn; ++i) + { + cmap [CharData::ms_categoryNames [i].m_str] = CharData::ms_categoryNames [i].m_category; + } + } + + typedef std::set IdSet_t; + + IdSet_t idSet; + + { + for (BlockIdSet_t::const_iterator iter = m_blockIds.begin (); iter != m_blockIds.end (); ++iter) + { + const Blocks::Data & blockData = blockMapping.findBlock (*iter); + + if (blockData.m_id != Blocks::End_Block_Ids) + { + blockData.generateFilteredIdSet (idSet); + } + } + } + + //-- read all the desired chars from file. + //-- the file must be sorted by code + + size_t bufpos = 0; + size_t validChars = 0; + + { + + for (IdSet_t::const_iterator iter = idSet.begin (); iter != idSet.end (); ++iter) + { + CharData * data = new CharData; + + assert (data); //lint !e1924 // c-style cast. MSVC bug + + data->m_reverseCase = 0; + + if (populateDataFromBuffer (*iter, *data, str_buf, bufpos, cmap) == false) + { + delete data; + continue; + } + + else + { + ++validChars; + m_map[data->m_code] = data; + } + } + } + + //-- + //-- pack all the char data into a contiguous block of memory + //-- + + if (m_contiguousData) + delete[] m_contiguousData; + + m_contiguousData = new CharData [validChars]; + + assert (m_contiguousData); //lint !e1924 // c-style cast. MSVC bug + + size_t dataIndex = 0; + + for (Map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter, ++dataIndex) + { + m_contiguousData [dataIndex] = *(*iter).second; + delete (*iter).second; + (*iter).second = &m_contiguousData [dataIndex]; + } + + m_dataIsValid = true; + + return ERR_SUCCESS; +} + +//---------------------------------------------------------------------- + +/** +* Create a map of CharData's from a UnicodeData.txt standard Unicode 3.0 file, using cstdio +*/ + +CharDataMap::ErrorCode CharDataMap::generateMap (const Blocks::Mapping & blockMapping, const char * filename) +{ + //-- load data from file as a big std::string + //-- read all the desired chars from file. + //-- the file must be sorted by code + + FILE * fl = fopen (filename, "rb"); + + if (fl == 0) + { + return ERR_NO_FILE; + } + + fseek (fl, 0, SEEK_END); + + size_t fileLen = static_cast(ftell (fl)); + + fseek (fl, 0, SEEK_SET); + + char * buffer = new char [fileLen + 1]; + buffer [fileLen] = 0; + + assert (buffer); //lint !e1924 // c-style cast. MSVC bug + + if (fread (buffer, fileLen, 1, fl) != 1) + { + delete[] buffer; + fclose (fl); + return ERR_READ_FAILED; + } + + if (fclose (fl)) + { + delete[] buffer; + return ERR_CLOSE_FAILED; + } + + std::string str_buf (buffer, fileLen); + + delete[] buffer; + + return generateMapFromBuffer (blockMapping, str_buf); +} + +//----------------------------------------------------------------- + +/** +* Add a block Id that this CharacterDataMap is concerned with. Does not change the data map. +*/ + +void CharDataMap::addBlock (Blocks::Id id) +{ + m_blockIds.insert (id); +} + +//----------------------------------------------------------------- + +/** +* Remove a block Id that this CharacterDataMap is concerned with. Does not change the data map. +*/ + +void CharDataMap::removeBlock (Blocks::Id id) +{ + m_blockIds.erase (id); +} + +//----------------------------------------------------------------- + +/* +* Add a block Id that this CharacterDataMap is concerned with. Does not change the data map. +*/ + +void CharDataMap::clearBlocks () +{ + m_blockIds.clear (); +} + +// ====================================================================== + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterDataMap.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterDataMap.h new file mode 100644 index 00000000..741a6e80 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeCharacterDataMap.h @@ -0,0 +1,156 @@ +// ====================================================================== +// +// UnicodeCharDataMap.h +// copyright (c) 2001 Sony Online Entertainment +// +// This contains Unicode 3.0 compliant Character data formats +// The data is loaded dynamically from the UnicodeData.txt definition file +// +// ====================================================================== + +#ifndef INCLUDED_PlatUnicodeCharDataMap_H +#define INCLUDED_PlatUnicodeCharDataMap_H + +#if WIN32 +// stl warning func not inlined +#pragma warning (disable:4710) +#pragma warning (disable:4786) +#endif + +#include +#include + +#include "UnicodeBlocks.h" + +// ====================================================================== + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + struct CharData; + + //----------------------------------------------------------------- + + /** + * Singleton class that allows mapping from code points to CharData objects. This will be + * used to change case of characters, character category testing, etc... + * A CharacterDataMap has a set of Unicode::Block::Id's with which it is solely concerned. + * In this way, you may instantiate many different CharDataMaps if needed. + */ + + class CharDataMap + { + public: + + enum ErrorCode + { + ERR_SUCCESS = 0, + ERR_NO_FILE, + ERR_READ_FAILED, + ERR_CLOSE_FAILED, + ERR_CHAR_NOT_FOUND, + ERR_FILE_TOO_SHORT + }; + + typedef std::map Map_t; + + static CharDataMap & getDefaultMap (); + static void explicitDestroy (); + + CharDataMap (); + ~CharDataMap (); + + void addBlock (Blocks::Id id); + void removeBlock (Blocks::Id id); + void clearBlocks (); + + ErrorCode generateMap (const Blocks::Mapping & blockMapping, const char * filename); + ErrorCode generateMapFromBuffer (const Blocks::Mapping & blockMapping, const std::string & str_buf); + + bool isValid () const; + + const CharData * findCharData (unicode_char_t code) const; + + const Map_t & getMap () const; + + private: + + static void initSingleton (); + + typedef std::set BlockIdSet_t; + + BlockIdSet_t m_blockIds; + CharData * m_contiguousData; + Map_t m_map; + bool m_dataIsValid; + + static CharDataMap * ms_singleton; + + }; + + //----------------------------------------------------------------- + + /** + * Singleton accessor. + */ + + inline CharDataMap & CharDataMap::getDefaultMap () + { + if (ms_singleton) + return *ms_singleton; + + initSingleton (); + return *ms_singleton; + } + + //----------------------------------------------------------------- + + /** + * Has the data been loaded successfully? + */ + + inline bool CharDataMap::isValid () const + { + return m_dataIsValid; + } + + //----------------------------------------------------------------- + + /** + * Find a CharData for the given code point. + * @return null if no CharData exists for this code point + */ + + inline const CharData * CharDataMap::findCharData (const unicode_char_t code) const + { + if (isValid ()) + { + const Map_t::const_iterator iter = m_map.find (code); + if (iter != m_map.end ()) + return (*iter).second; + } + + return 0; + } + + //----------------------------------------------------------------- + + /** + * Get the data mapping + */ + + inline const CharDataMap::Map_t & CharDataMap::getMap () const + { + return m_map; + } +}; +#ifdef EXTERNAL_DISTRO +}; +#endif +// ====================================================================== + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeUtils.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeUtils.cpp new file mode 100644 index 00000000..db0e8717 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeUtils.cpp @@ -0,0 +1,297 @@ +// ====================================================================== +// +// Unicode.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstUnicode.h" +#include "UnicodeUtils.h" + +#include + +#if defined (linux) +#include +#endif + +// ====================================================================== + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + + //----------------------------------------------------------------- + + /** + * Return by value a lowered version of nstr + */ + + NarrowString toLower (const NarrowString & nstr) + { + NarrowString retval (nstr.c_str()); + std::transform (retval.begin (), retval.end (), retval.begin (), trueLower); + return retval; + } + + //----------------------------------------------------------------- + + /** + * Return by value an uppered version of nstr + */ + + NarrowString toUpper (const NarrowString & nstr) + { + NarrowString retval (nstr); + std::transform (retval.begin (), retval.end (), retval.begin (), trueUpper); + return retval; + } + + //----------------------------------------------------------------- + + /** + * Return by value a lowered version of str. + * This currently only works properly with ASCII. + * @todo: implement this for all unicode blocks. + */ + + String toLower (const String & nstr) + { + String retval (nstr); + std::transform (retval.begin (), retval.end (), retval.begin (), trueLower); + return retval; + } + + //----------------------------------------------------------------- + + /** + * Return by value an uppered version of str. + * This currently only works properly with ASCII. + * @todo: implement this for all unicode blocks. + */ + + String toUpper (const String & nstr) + { + String retval (nstr); + std::transform (retval.begin (), retval.end (), retval.begin (), trueUpper); + return retval; + } + + //----------------------------------------------------------------- + + /** + * Append src to dst, padding the field as needed, and truncating the field if desired. + */ + + String & appendStringField (String & dst, const String & src, size_t width, FieldAlignment fa, unicode_char_t pad, bool truncate) + { + + if (src.length () > width && truncate) + return dst.append (src.substr (0, width)); + + if (src.length () >= width) + return dst.append (src); + + const size_t diff = width - src.length (); + + if (fa == FA_RIGHT) + dst.append (diff, pad); + else if (fa == FA_CENTER) + dst.append (diff/2, pad); + + dst.append (src); + + if (fa == FA_LEFT) + dst.append (diff, pad); + else if (fa == FA_CENTER) + dst.append (diff - diff/2, pad); + + return dst; + } + + //----------------------------------------------------------------- + + /** + * Find the first token in str, starting at pos. The value of the token is placed in the token field. endpos is updated to point past the token. + */ + + bool getFirstToken (const String & str, size_t pos, size_t & endpos, String & token, const unicode_char_t * sepChars) + { + const size_t first_nonspace = str.find_first_not_of ( sepChars, pos ); + + if (first_nonspace != std::string::npos) + { + const size_t first_space = str.find_first_of (sepChars, first_nonspace ); + + if (first_space != std::string::npos) + token = str.substr (first_nonspace, first_space - first_nonspace); + else + token = str.substr (first_nonspace); + + endpos = first_space; + return true; + } + + return false; + } + + //----------------------------------------------------------------- + + /** + * Find the first token in str, starting at pos. The value of the token is placed in the token field. endpos is updated to point past the token. + */ + + bool getFirstToken (const NarrowString & str, size_t pos, size_t & endpos, NarrowString & token, const char * sepChars) + { + const size_t first_nonspace = str.find_first_not_of ( sepChars, pos ); + + if (first_nonspace != std::string::npos) + { + const size_t first_space = str.find_first_of (sepChars, first_nonspace ); + if (first_space != std::string::npos) + token = str.substr (first_nonspace, first_space - first_nonspace); + else + token = str.substr (first_nonspace); + + endpos = first_space; + return true; + } + else + return false; + } + + //----------------------------------------------------------------- + + /** + * Find the nth token in str, starting at pos. The value of the token is placed in the token field. endpos is updated to point past the token. + * pos is updated to point to the first character of token in str. + */ + + bool getNthToken (const String & str, const size_t n, size_t & pos, size_t & endpos, String & token, const unicode_char_t * sepChars) + { + size_t desired_first_nonspace = 0; + size_t space = 0; + + //check for trivial case + if(n == 0) + desired_first_nonspace = pos; + else + { + for (size_t i = 0; i < n; ++i) + { + //find the first whitespace character + space = str.find_first_of ( sepChars, pos ); + if (space == std::string::npos) + return false; + //now find the next non-whitespace character after it + desired_first_nonspace = str.find_first_not_of( sepChars, space ); + if (desired_first_nonspace == std::string::npos) + return false; + pos = desired_first_nonspace; + } + } + //find the end of the token + const size_t first_space = str.find_first_of (sepChars, desired_first_nonspace ); + //now get that token + if (first_space != std::string::npos) + token = str.substr (desired_first_nonspace, first_space - desired_first_nonspace); + else + token = str.substr (desired_first_nonspace); + + endpos = desired_first_nonspace; + + return true; + } + + //----------------------------------------------------------------- + + /** + * Find the nth token in str, starting at pos. The value of the token is placed in the token field. endpos is updated to point past the token. + * pos is updated to point to the first character of token in str. + */ + + bool getNthToken (const NarrowString & str, const size_t n, size_t & pos, size_t & endpos, NarrowString & token, const char * sepChars) + { + size_t desired_first_nonspace = 0; + size_t space = 0; + + //check for trivial case + if(n == 0) + desired_first_nonspace = pos; + else + { + for (size_t i = 0; i < n; ++i) + { + //find the first whitespace character + space = str.find_first_of ( sepChars, pos ); + if (space == std::string::npos) + return false; + //now find the next non-whitespace character after it + desired_first_nonspace = str.find_first_not_of( sepChars, space ); + if (desired_first_nonspace == std::string::npos) + return false; + pos = desired_first_nonspace; + } + } + //find the end of the token + const size_t first_space = str.find_first_of (sepChars, desired_first_nonspace ); + //now get that token + if (first_space != std::string::npos) + token = str.substr (desired_first_nonspace, first_space - desired_first_nonspace); + else + token = str.substr (desired_first_nonspace); + + endpos = desired_first_nonspace; + + return true; + } +}; +// ====================================================================== +// Extensions to Base/Archive for String +// ====================================================================== + +namespace Base +{ +unsigned get(Base::ByteStream::ReadIterator& source, Plat_Unicode::String& target) +{ + unsigned int size = 0; + + if (source.getSize() < sizeof(size)) + { + return 0; + } + + get (source, size); + + const unsigned char * const buf = source.getBuffer(); + const Plat_Unicode::unicode_char_t * const ubuf = reinterpret_cast(buf); + unsigned int readSize = size * sizeof (Plat_Unicode::unicode_char_t); + + if (source.getSize() < readSize) + { + return 0; + } + + target.assign (ubuf, ubuf + size); + + source.advance(readSize); +// printf("%d\n", target.size()); + return (readSize + sizeof(size)); +} + +void put(Base::ByteStream& target, const Plat_Unicode::String& source) +{ + const unsigned int size = source.size (); + put (target, size); + target.put (source.data(), size * sizeof (Plat_Unicode::unicode_char_t)); +} + +}; + + +#ifdef EXTERNAL_DISTRO +}; +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeUtils.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeUtils.h new file mode 100644 index 00000000..25bd89e8 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/UnicodeUtils.h @@ -0,0 +1,385 @@ +// ====================================================================== +// +// UnicodeUtils.h +// copyright (c) 2001 Sony Online Entertainment +// +// jwatson +// +// Basic Unicode string handling/manipulating functions +// ====================================================================== + +#ifndef INCLUDED_PlatUnicodeUtils_H +#define INCLUDED_PlatUnicodeUtils_H + +#if WIN32 +// stl warning func not inlined +#pragma warning (disable:4710) +#pragma warning (disable:4786) +#endif + +#include "Unicode.h" +#include +#include + +//----------------------------------------------------------------- + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + + String narrowToWide (const NarrowString & nstr); + String & narrowToWide (const NarrowString & nstr, String & str); //lint !e1929 // function returning a reference + + NarrowString wideToNarrow (const String & nstr); + NarrowString & wideToNarrow (const String & nstr, NarrowString & str); //lint !e1929 // function returning a reference + NarrowString toLower (const NarrowString & nstr); + NarrowString toUpper (const NarrowString & nstr); + String toLower (const String & nstr); + String toUpper (const String & nstr); + + const String getTrim (const String & str, const unicode_char_t * white = whitespace); + String & trim (String & str, const unicode_char_t * white = whitespace); + + bool getFirstToken (const String & str, size_t pos, size_t & endpos, String & token, const unicode_char_t * sepChars = whitespace); + bool getNthToken (const String & str, const size_t n, size_t & pos, size_t & endpos, String & token, const unicode_char_t * sepChars = whitespace); + size_t skipWhitespace (const String & str, size_t pos, const unicode_char_t * white = whitespace); + + const NarrowString getTrim (const NarrowString & str, const char * white = ascii_whitespace); + NarrowString & trim (NarrowString & str, const char * white = ascii_whitespace); + + bool getFirstToken (const NarrowString & str, size_t pos, size_t & endpos, NarrowString & token, const char * sepChars = ascii_whitespace); + bool getNthToken (const NarrowString & str, const size_t n, size_t & pos, size_t & endpos, NarrowString & token, const char * sepChars = ascii_whitespace); + size_t skipWhitespace (const NarrowString & str, size_t pos, const char * white = ascii_whitespace); + + enum FieldAlignment + { + FA_LEFT, + FA_RIGHT, + FA_CENTER + }; + + String & appendStringField (String & dst, const String & src, size_t width, FieldAlignment fa = FA_LEFT, unicode_char_t pad = ' ', bool truncate = false); + String & appendStringField (String & dst, const NarrowString & src, size_t width, FieldAlignment fa = FA_LEFT, unicode_char_t pad = ' ', bool truncate = false); + + /** + * Compare substrings of str2 and str1, each starting with pos and containing n characters + */ + + + /** + * Compares str1 and str2, where str1 is a String and str2 is templated, + * thus could be a std::string as well. Set reverseCompare to true if you + * want to begin comparison at end of string--a useful optimization if your + * strings tend to differ at the end. + */ + template bool caseInsensitiveCompare (const String & str1, const T & str2, bool reverseCompare = false) + { + const size_t len1 = str1.size(); + const size_t len2 = str2.size(); + + if (len1 != len2) + { + return false; + } + + if (!reverseCompare) + { + for (size_t i = 0; i < len1; i++) + { + if ( trueLower(str1[i]) != trueLower(str2[i]) ) + return false; + } + } + else + { + for (size_t i = len1; i > 0; i--) + { + if ( trueLower(str1[i-1]) != trueLower(str2[i-1]) ) + return false; + } + } + + return true; + } + + /** + * Compares str1 and str2, where str1 is a String and str2 is templated, + * thus could be a std::string as well. Unlike caseInsensitiveCompare, this + * version returns an int for < or > comparisons, and comparison must start + * at the front. Note that this kind of comparison does not allow the shortcut + * of first comparing sizes--every character must be compared up to the last one. + */ + template int caseInsensitiveCompareInt (const String & str1, const T & str2) + { + const size_t len1 = str1.size(); + const size_t len2 = str2.size(); + + size_t len; + if (len1 < len2) + len = len1; + else + len = len2; + + // iterate over smallest length + for (size_t i = 0; i < len; i++) + { + if ( trueLower(str1[i]) < trueLower(str2[i]) ) + return -1; + else if ( trueLower(str1[i]) > trueLower(str2[i]) ) + return 1; + } + + // Equal so far, thus: if len1 < len2, the result is less-than, else + // if len1 = len2, the result is equal, else the result is greater-than. + + if (len1 < len2) + return -1; + else if (len1 == len2) + return 0; + else + return 1; + } + + + /** + * Optimized implementation of isWhitespace. Must be kept in line with ::whitespace array + */ + + template bool isWhitespace (T c) + { + return c == ' ' || c == '\n' || c == '\r' || c == '\t'; + } + + /* + * @todo: uncomment when caseInsensitiveCompare matures + * + template class CompareNoCasePredicate + { + public: + bool operator()( T & a, T & b ) const + { + return caseInsensitiveCompare (a, b) < 0; + }; + }; + + template class EqualsNoCasePredicate + { + public: + bool operator()( T & a, T & b ) const + { + return caseInsensitiveCompare (a, b) == 0; + }; + }; + */ + +//----------------------------------------------------------------- +//-- implementation +//----------------------------------------------------------------- + + //----------------------------------------------------------------- + /** + * Utility to convert a string and obtain the result by value + */ + + inline String narrowToWide (const NarrowString & nstr) + { +// return String (nstr.begin (), nstr.end ()); // STLPort original + String s; + unsigned index = 0; + s.resize(nstr.size()); + const NarrowString::const_iterator end = nstr.end(); + for (NarrowString::const_iterator iter = nstr.begin(); iter != end; iter++) + { + // Cast to unsigned char so that we don't pick up a negative value + // for the unsigned short + s[index++] = (unsigned char)*iter; + } + return s; + } + + //----------------------------------------------------------------- + /** + * Utility to convert a string and obtain the result by reference + */ + + inline String & narrowToWide (const NarrowString & nstr, String & str) + { +// return str.assign (nstr.begin (), nstr.end ()); // STLport original + unsigned index = 0; + str.resize(nstr.size()); + const NarrowString::const_iterator end = nstr.end(); + for (NarrowString::const_iterator iter = nstr.begin(); iter != end; iter++) + { + str[index++] = *iter; + } + return str; + } + + //----------------------------------------------------------------- + /** + + * Utility to convert a string and obtain the result by value + + * This should only be used when the Unicode string is known to contain only 8 bit assignable values + + */ + + inline NarrowString wideToNarrow (const String & str) + { +// return NarrowString (str.begin (), str.end ()); // STLPort original + NarrowString s; + unsigned index = 0; + s.resize(str.size()); + const String::const_iterator end = str.end(); + for (String::const_iterator iter = str.begin(); iter != end; iter++) + { + s[index++] = (char)*iter; + } + return s; + } + + //----------------------------------------------------------------- + /** + + * Utility to convert a string and obtain the result by reference + + * This should only be used when the Unicode string is known to contain only 8 bit assignable values + + */ + + inline NarrowString & wideToNarrow (const String & str, NarrowString & nstr) + { +// return nstr.assign (str.begin (), str.end ()); // STLPort original + unsigned index = 0; + nstr.resize(str.size()); + const String::const_iterator end = str.end(); + for (String::const_iterator iter = str.begin(); iter != end; iter++) + { + nstr[index++] = (char)*iter; + } + return nstr; + } + + /** + * Get the trimmed version of str by value. + */ + + inline const String getTrim (const String & str, const unicode_char_t * white) + { + const size_t first_nonspace = str.find_first_not_of ( white ); + const size_t last_nonspace = str.find_last_not_of ( white ); + return (first_nonspace == str.npos ? str : str.substr (first_nonspace, last_nonspace == str.npos ? last_nonspace : (last_nonspace - first_nonspace + 1))); + } + + + + //----------------------------------------------------------------- + /** + * Trim the specified string and return a reference to it. + */ + + inline String & trim (String & str, const unicode_char_t * white) + { + return (str = getTrim (str, white)); + } + + /** + * Get the trimmed version of str by value. + */ + + inline const NarrowString getTrim (const NarrowString & str, const char * white) + { + const size_t first_nonspace = str.find_first_not_of ( white ); + const size_t last_nonspace = str.find_last_not_of ( white ); + return (first_nonspace == str.npos ? str : str.substr (first_nonspace, last_nonspace == str.npos ? last_nonspace : (last_nonspace - first_nonspace + 1))); + } + + //----------------------------------------------------------------- + /** + * Trim the specified string and return a reference to it. + */ + inline NarrowString & trim (NarrowString & str, const char * white) + { + return (str = getTrim (str, white)); + } + /** + * Return the first non-white position starting with pos. returns str.npos if there is no non-white characer after pos + */ + inline size_t skipWhitespace (const String & str, size_t pos, const unicode_char_t * white) + { + return str.find_first_not_of (white, pos); + } + + //----------------------------------------------------------------- + /** + * Return the first non-white position starting with pos. returns str.npos if there is no non-white characer after pos + */ + + inline size_t skipWhitespace (const NarrowString & str, size_t pos, const char * white) + { + return str.find_first_not_of (white, pos); + } + + + + //----------------------------------------------------------------- + /** + * Append src to dst, padding the field as needed, and truncating the field if desired. + */ + + inline String & appendStringField (String & dst, const NarrowString & src, size_t width, FieldAlignment fa, unicode_char_t pad, bool truncate) + { + return appendStringField (dst, narrowToWide (src), width, fa, pad, truncate); + } +// ====================================================================== + + //----------------------------------------------------------------- + /** + * Hacky code to correctly handle Cyrillic. + */ + + inline unicode_char_t trueUpper(unicode_char_t letter) + { + if ((cyrillic_lower_first <= letter) && (letter <= cyrillic_lower_last)) { + return letter + (cyrillic_upper_first - cyrillic_lower_first); + } else { + return static_cast(toupper(letter)); + } + } + + inline unicode_char_t trueLower(unicode_char_t letter) + { + if ((cyrillic_upper_first <= letter) && (letter <= cyrillic_upper_last)) { + return letter - (cyrillic_upper_first - cyrillic_lower_first); + } else { + return static_cast(tolower(letter)); + } + } + +// ====================================================================== +}; + +// ====================================================================== +// Extensions to Base/Archive for String +// ====================================================================== +//class Base::ByteStream; +//----------------------------------------------------------------------- +namespace Base +{ +extern unsigned get(ByteStream::ReadIterator & source, Plat_Unicode::String & target); +extern void put(ByteStream & target, const Plat_Unicode::String & source); + +//--------------------------------------------------------------------- + + // namespace Base + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/data/UnicodeData.txt b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/data/UnicodeData.txt new file mode 100644 index 00000000..90f047ac --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/data/UnicodeData.txt @@ -0,0 +1,12858 @@ +0000;;Cc;0;BN;;;;;N;NULL;;;; +0001;;Cc;0;BN;;;;;N;START OF HEADING;;;; +0002;;Cc;0;BN;;;;;N;START OF TEXT;;;; +0003;;Cc;0;BN;;;;;N;END OF TEXT;;;; +0004;;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; +0005;;Cc;0;BN;;;;;N;ENQUIRY;;;; +0006;;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; +0007;;Cc;0;BN;;;;;N;BELL;;;; +0008;;Cc;0;BN;;;;;N;BACKSPACE;;;; +0009;;Cc;0;S;;;;;N;HORIZONTAL TABULATION;;;; +000A;;Cc;0;B;;;;;N;LINE FEED;;;; +000B;;Cc;0;S;;;;;N;VERTICAL TABULATION;;;; +000C;;Cc;0;WS;;;;;N;FORM FEED;;;; +000D;;Cc;0;B;;;;;N;CARRIAGE RETURN;;;; +000E;;Cc;0;BN;;;;;N;SHIFT OUT;;;; +000F;;Cc;0;BN;;;;;N;SHIFT IN;;;; +0010;;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;; +0011;;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;; +0012;;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;; +0013;;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;; +0014;;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;; +0015;;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;; +0016;;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;; +0017;;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;; +0018;;Cc;0;BN;;;;;N;CANCEL;;;; +0019;;Cc;0;BN;;;;;N;END OF MEDIUM;;;; +001A;;Cc;0;BN;;;;;N;SUBSTITUTE;;;; +001B;;Cc;0;BN;;;;;N;ESCAPE;;;; +001C;;Cc;0;B;;;;;N;FILE SEPARATOR;;;; +001D;;Cc;0;B;;;;;N;GROUP SEPARATOR;;;; +001E;;Cc;0;B;;;;;N;RECORD SEPARATOR;;;; +001F;;Cc;0;S;;;;;N;UNIT SEPARATOR;;;; +0020;SPACE;Zs;0;WS;;;;;N;;;;; +0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;; +0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;; +0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;; +0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;; +0026;AMPERSAND;Po;0;ON;;;;;N;;;;; +0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;; +0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;; +0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;; +002A;ASTERISK;Po;0;ON;;;;;N;;;;; +002B;PLUS SIGN;Sm;0;ET;;;;;N;;;;; +002C;COMMA;Po;0;CS;;;;;N;;;;; +002D;HYPHEN-MINUS;Pd;0;ET;;;;;N;;;;; +002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;; +002F;SOLIDUS;Po;0;ES;;;;;N;SLASH;;;; +0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; +0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; +0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; +0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; +0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; +0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; +0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; +0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; +0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; +0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; +003A;COLON;Po;0;CS;;;;;N;;;;; +003B;SEMICOLON;Po;0;ON;;;;;N;;;;; +003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;; +003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;; +003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;; +003F;QUESTION MARK;Po;0;ON;;;;;N;;;;; +0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;; +0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; +0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062; +0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063; +0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064; +0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065; +0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066; +0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067; +0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068; +0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069; +004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A; +004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B; +004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C; +004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D; +004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E; +004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F; +0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070; +0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071; +0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072; +0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073; +0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074; +0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075; +0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076; +0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077; +0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078; +0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079; +005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A; +005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;; +005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;; +005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;; +005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;; +005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;; +0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;; +0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041 +0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042 +0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043 +0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044 +0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045 +0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046 +0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047 +0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048 +0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049 +006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A +006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B +006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C +006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D +006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E +006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F +0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050 +0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051 +0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052 +0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053 +0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054 +0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055 +0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056 +0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057 +0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058 +0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059 +007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A +007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;; +007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;; +007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;; +007E;TILDE;Sm;0;ON;;;;;N;;;;; +007F;;Cc;0;BN;;;;;N;DELETE;;;; +0080;;Cc;0;BN;;;;;N;;;;; +0081;;Cc;0;BN;;;;;N;;;;; +0082;;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;; +0083;;Cc;0;BN;;;;;N;NO BREAK HERE;;;; +0084;;Cc;0;BN;;;;;N;;;;; +0085;;Cc;0;B;;;;;N;NEXT LINE;;;; +0086;;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;; +0087;;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;; +0088;;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;; +0089;;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;; +008A;;Cc;0;BN;;;;;N;LINE TABULATION SET;;;; +008B;;Cc;0;BN;;;;;N;PARTIAL LINE DOWN;;;; +008C;;Cc;0;BN;;;;;N;PARTIAL LINE UP;;;; +008D;;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;; +008E;;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;; +008F;;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;; +0090;;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;; +0091;;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;; +0092;;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;; +0093;;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;; +0094;;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;; +0095;;Cc;0;BN;;;;;N;MESSAGE WAITING;;;; +0096;;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;; +0097;;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;; +0098;;Cc;0;BN;;;;;N;START OF STRING;;;; +0099;;Cc;0;BN;;;;;N;;;;; +009A;;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;; +009B;;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;; +009C;;Cc;0;BN;;;;;N;STRING TERMINATOR;;;; +009D;;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;; +009E;;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;; +009F;;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;; +00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; +00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;; +00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;; +00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;; +00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; +00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;; +00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;; +00A7;SECTION SIGN;So;0;ON;;;;;N;;;;; +00A8;DIAERESIS;Sk;0;ON; 0020 0308;;;;N;SPACING DIAERESIS;;;; +00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;; +00AA;FEMININE ORDINAL INDICATOR;Ll;0;L; 0061;;;;N;;;;; +00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;; +00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;; +00AD;SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; +00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;; +00AF;MACRON;Sk;0;ON; 0020 0304;;;;N;SPACING MACRON;;;; +00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;; +00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;; +00B2;SUPERSCRIPT TWO;No;0;EN; 0032;2;2;2;N;SUPERSCRIPT DIGIT TWO;;;; +00B3;SUPERSCRIPT THREE;No;0;EN; 0033;3;3;3;N;SUPERSCRIPT DIGIT THREE;;;; +00B4;ACUTE ACCENT;Sk;0;ON; 0020 0301;;;;N;SPACING ACUTE;;;; +00B5;MICRO SIGN;Ll;0;L; 03BC;;;;N;;;039C;;039C +00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;; +00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;; +00B8;CEDILLA;Sk;0;ON; 0020 0327;;;;N;SPACING CEDILLA;;;; +00B9;SUPERSCRIPT ONE;No;0;EN; 0031;1;1;1;N;SUPERSCRIPT DIGIT ONE;;;; +00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L; 006F;;;;N;;;;; +00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;*;;; +00BC;VULGAR FRACTION ONE QUARTER;No;0;ON; 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;; +00BD;VULGAR FRACTION ONE HALF;No;0;ON; 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;; +00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON; 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;; +00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;; +00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0; +00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1; +00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2; +00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3; +00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4; +00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5; +00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;ash *;;00E6; +00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7; +00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8; +00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9; +00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA; +00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB; +00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC; +00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED; +00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE; +00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF; +00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;Icelandic;;00F0; +00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1; +00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2; +00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3; +00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4; +00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5; +00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6; +00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;; +00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8; +00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9; +00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA; +00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB; +00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC; +00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD; +00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE; +00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;; +00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0 +00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1 +00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2 +00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3 +00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4 +00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5 +00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6 +00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7 +00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8 +00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9 +00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA +00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB +00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC +00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD +00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE +00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF +00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0 +00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1 +00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2 +00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3 +00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4 +00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5 +00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6 +00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;; +00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8 +00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9 +00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA +00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB +00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC +00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD +00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;Icelandic;00DE;;00DE +00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178 +0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101; +0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100 +0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103; +0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102 +0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105; +0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104 +0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107; +0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106 +0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109; +0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108 +010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B; +010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A +010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D; +010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C +010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F; +010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E +0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111; +0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110 +0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113; +0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112 +0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115; +0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114 +0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117; +0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116 +0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119; +0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118 +011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B; +011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A +011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D; +011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C +011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F; +011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E +0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121; +0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120 +0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123; +0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122 +0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125; +0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124 +0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127; +0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126 +0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129; +0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128 +012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B; +012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A +012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D; +012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C +012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F; +012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E +0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069; +0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049 +0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L; 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133; +0133;LATIN SMALL LIGATURE IJ;Ll;0;L; 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132 +0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135; +0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134 +0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137; +0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136 +0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;Greenlandic;;; +0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A; +013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139 +013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C; +013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B +013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E; +013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D +013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L; 004C 00B7;;;;N;;;;0140; +0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L; 006C 00B7;;;;N;;;013F;;013F +0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142; +0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141 +0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144; +0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143 +0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146; +0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145 +0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148; +0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147 +0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L; 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;; +014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;Sami;;014B; +014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;Sami;014A;;014A +014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D; +014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C +014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F; +014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E +0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151; +0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150 +0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153; +0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152 +0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155; +0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154 +0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157; +0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156 +0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159; +0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158 +015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B; +015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A +015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D; +015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C +015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;*;;015F; +015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;*;015E;;015E +0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161; +0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160 +0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;*;;0163; +0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;*;0162;;0162 +0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165; +0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164 +0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167; +0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166 +0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169; +0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168 +016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B; +016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A +016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D; +016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C +016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F; +016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E +0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171; +0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170 +0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173; +0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172 +0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175; +0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174 +0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177; +0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176 +0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF; +0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A; +017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179 +017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C; +017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B +017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E; +017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D +017F;LATIN SMALL LETTER LONG S;Ll;0;L; 0073;;;;N;;;0053;;0053 +0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;; +0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253; +0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183; +0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182 +0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185; +0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184 +0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254; +0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188; +0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187 +0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;*;;0256; +018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257; +018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C; +018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B +018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;; +018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD; +018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259; +0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B; +0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192; +0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191 +0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260; +0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263; +0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;hwair;01F6;;01F6 +0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269; +0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268; +0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199; +0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198 +019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;;; +019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;; +019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F; +019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272; +019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;;; +019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;*;;0275; +01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1; +01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0 +01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;gha;;01A3; +01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;gha;01A2;;01A2 +01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5; +01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4 +01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;*;;0280; +01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8; +01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7 +01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283; +01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;; +01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;; +01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD; +01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC +01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288; +01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0; +01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF +01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A; +01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B; +01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4; +01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3 +01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6; +01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5 +01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292; +01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9; +01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8 +01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;; +01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;; +01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD; +01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC +01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;; +01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7 +01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;; +01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;; +01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;; +01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;; +01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L; 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5 +01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L; 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6; +01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L; 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5 +01C7;LATIN CAPITAL LETTER LJ;Lu;0;L; 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8 +01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L; 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9; +01C9;LATIN SMALL LETTER LJ;Ll;0;L; 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8 +01CA;LATIN CAPITAL LETTER NJ;Lu;0;L; 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB +01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L; 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC; +01CC;LATIN SMALL LETTER NJ;Ll;0;L; 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB +01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE; +01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD +01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0; +01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF +01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2; +01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1 +01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4; +01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3 +01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6; +01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5 +01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8; +01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7 +01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA; +01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9 +01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC; +01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB +01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E +01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF; +01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE +01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1; +01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0 +01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;ash *;;01E3; +01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;ash *;01E2;;01E2 +01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5; +01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4 +01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7; +01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6 +01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9; +01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8 +01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB; +01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA +01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED; +01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC +01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF; +01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE +01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;; +01F1;LATIN CAPITAL LETTER DZ;Lu;0;L; 0044 005A;;;;N;;;;01F3;01F2 +01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L; 0044 007A;;;;N;;;01F1;01F3; +01F3;LATIN SMALL LETTER DZ;Ll;0;L; 0064 007A;;;;N;;;01F1;;01F2 +01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5; +01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4 +01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195; +01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF; +01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9; +01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8 +01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB; +01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA +01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;ash *;;01FD; +01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;ash *;01FC;;01FC +01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF; +01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE +0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201; +0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200 +0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203; +0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202 +0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205; +0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204 +0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207; +0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206 +0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209; +0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208 +020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B; +020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A +020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D; +020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C +020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F; +020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E +0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211; +0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210 +0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213; +0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212 +0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215; +0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214 +0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217; +0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216 +0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;*;;0219; +0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;*;0218;;0218 +021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;*;;021B; +021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;*;021A;;021A +021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D; +021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C +021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F; +021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E +0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223; +0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222 +0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225; +0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224 +0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227; +0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226 +0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229; +0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228 +022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B; +022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A +022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D; +022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C +022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F; +022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E +0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231; +0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230 +0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233; +0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232 +0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;; +0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;; +0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;; +0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181 +0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186 +0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;; +0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189 +0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A +0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;; +0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F +025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;; +025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190 +025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;; +025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;; +025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;; +025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;; +0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193 +0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;; +0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;; +0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194 +0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;; +0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;; +0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;; +0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; +0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 +0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 +026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; +026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;; +026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;; +026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; +026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;; +026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C +0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;; +0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;; +0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D +0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;; +0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;; +0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F +0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;; +0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;; +0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;; +0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;; +027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;; +027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;; +027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;; +027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;; +027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;; +027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;; +0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6 +0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;; +0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;; +0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9 +0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;; +0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;; +0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;; +0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;; +0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE +0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;; +028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1 +028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2 +028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;; +028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;; +028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;; +028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;; +0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;; +0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;; +0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7 +0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;; +0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;;; +0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;; +0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;; +0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;; +0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;; +0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;; +029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;; +029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;; +029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;; +029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;; +029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;; +029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;; +02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;; +02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;; +02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;; +02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;; +02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;; +02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;; +02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;; +02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;; +02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;; +02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;; +02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;; +02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;; +02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; +02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;; +02B0;MODIFIER LETTER SMALL H;Lm;0;L; 0068;;;;N;;;;; +02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L; 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;; +02B2;MODIFIER LETTER SMALL J;Lm;0;L; 006A;;;;N;;;;; +02B3;MODIFIER LETTER SMALL R;Lm;0;L; 0072;;;;N;;;;; +02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L; 0279;;;;N;;;;; +02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L; 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;; +02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L; 0281;;;;N;;;;; +02B7;MODIFIER LETTER SMALL W;Lm;0;L; 0077;;;;N;;;;; +02B8;MODIFIER LETTER SMALL Y;Lm;0;L; 0079;;;;N;;;;; +02B9;MODIFIER LETTER PRIME;Sk;0;ON;;;;;N;;;;; +02BA;MODIFIER LETTER DOUBLE PRIME;Sk;0;ON;;;;;N;;;;; +02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;; +02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;; +02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;; +02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;; +02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; +02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;; +02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;; +02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;; +02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;; +02C7;CARON;Sk;0;ON;;;;;N;MODIFIER LETTER HACEK;Mandarin Chinese third tone;;; +02C8;MODIFIER LETTER VERTICAL LINE;Sk;0;ON;;;;;N;;;;; +02C9;MODIFIER LETTER MACRON;Sk;0;ON;;;;;N;;Mandarin Chinese first tone;;; +02CA;MODIFIER LETTER ACUTE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER ACUTE;Mandarin Chinese second tone;;; +02CB;MODIFIER LETTER GRAVE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER GRAVE;Mandarin Chinese fourth tone;;; +02CC;MODIFIER LETTER LOW VERTICAL LINE;Sk;0;ON;;;;;N;;;;; +02CD;MODIFIER LETTER LOW MACRON;Sk;0;ON;;;;;N;;;;; +02CE;MODIFIER LETTER LOW GRAVE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;; +02CF;MODIFIER LETTER LOW ACUTE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;; +02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; +02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;; +02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;; +02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;; +02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;; +02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;; +02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;; +02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;; +02D8;BREVE;Sk;0;ON; 0020 0306;;;;N;SPACING BREVE;;;; +02D9;DOT ABOVE;Sk;0;ON; 0020 0307;;;;N;SPACING DOT ABOVE;Mandarin Chinese light tone;;; +02DA;RING ABOVE;Sk;0;ON; 0020 030A;;;;N;SPACING RING ABOVE;;;; +02DB;OGONEK;Sk;0;ON; 0020 0328;;;;N;SPACING OGONEK;;;; +02DC;SMALL TILDE;Sk;0;ON; 0020 0303;;;;N;SPACING TILDE;;;; +02DD;DOUBLE ACUTE ACCENT;Sk;0;ON; 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;; +02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;; +02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;; +02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L; 0263;;;;N;;;;; +02E1;MODIFIER LETTER SMALL L;Lm;0;L; 006C;;;;N;;;;; +02E2;MODIFIER LETTER SMALL S;Lm;0;L; 0073;;;;N;;;;; +02E3;MODIFIER LETTER SMALL X;Lm;0;L; 0078;;;;N;;;;; +02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L; 0295;;;;N;;;;; +02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; +02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;; +02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;; +02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;; +02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;; +02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; +02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;; +02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;; +02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;; +02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;; +0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;Varia;;; +0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;Oxia;;; +0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;; +0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;; +0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;; +0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;; +0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;Vrachy;;; +0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;; +0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;Dialytika;;; +0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;; +030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;; +030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;; +030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;; +030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;Tonos;;; +030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;; +030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;; +0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;; +0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;; +0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;; +0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;Psili;;; +0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;Dasia;;; +0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;; +0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;; +0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;; +0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;; +0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;; +031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;; +031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;; +031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;; +031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;; +031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;; +031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;; +0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;; +0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;; +0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;; +0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;; +0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;; +0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;; +0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;; +0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;; +0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;; +0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;; +032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;; +032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;; +032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;; +032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;; +032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;; +032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;; +0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;; +0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;; +0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;; +0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;; +0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;; +0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;; +0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;; +0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;; +0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;; +0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;; +033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;; +033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;; +033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;; +033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;; +033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;; +033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;; +0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;Vietnamese;;; +0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;Vietnamese;;; +0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;; +0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;; +0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;; +0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399 +0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;; +0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;; +0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;; +0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;; +034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;; +034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;; +034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;; +034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;; +0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;; +0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;; +0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;; +0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;; +0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;; +037A;GREEK YPOGEGRAMMENI;Lm;0;L; 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;; +037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;; +0384;GREEK TONOS;Sk;0;ON; 0020 0301;;;;N;GREEK SPACING TONOS;;;; +0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;; +0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC; +0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;; +0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD; +0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE; +038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF; +038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC; +038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD; +038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE; +0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;; +0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1; +0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2; +0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3; +0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4; +0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5; +0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6; +0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7; +0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8; +0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9; +039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA; +039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB; +039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC; +039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD; +039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE; +039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF; +03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0; +03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1; +03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3; +03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4; +03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5; +03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6; +03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7; +03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8; +03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9; +03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA; +03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB; +03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386 +03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388 +03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389 +03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A +03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;; +03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391 +03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392 +03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393 +03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394 +03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395 +03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396 +03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397 +03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398 +03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399 +03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A +03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B +03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C +03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D +03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E +03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F +03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0 +03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1 +03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 +03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3 +03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4 +03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5 +03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6 +03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7 +03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8 +03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9 +03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA +03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB +03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C +03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E +03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F +03D0;GREEK BETA SYMBOL;Ll;0;L; 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392 +03D1;GREEK THETA SYMBOL;Ll;0;L; 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398 +03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L; 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;; +03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;; +03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;; +03D5;GREEK PHI SYMBOL;Ll;0;L; 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6 +03D6;GREEK PI SYMBOL;Ll;0;L; 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0 +03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;; +03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB; +03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA +03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD; +03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC +03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF; +03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE +03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1; +03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0 +03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3; +03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2 +03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5; +03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4 +03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7; +03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6 +03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9; +03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8 +03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB; +03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA +03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED; +03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC +03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF; +03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE +03F0;GREEK KAPPA SYMBOL;Ll;0;L; 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A +03F1;GREEK RHO SYMBOL;Ll;0;L; 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1 +03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L; 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03A3;;03A3 +03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;; +03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L; 0398;;;;N;;;;03B8; +03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L; 03B5;;;;N;;;0395;;0395 +0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450; +0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451; +0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452; +0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453; +0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454; +0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455; +0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456; +0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;Ukrainian;;0457; +0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458; +0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459; +040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A; +040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;Serbocroatian;;045B; +040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C; +040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D; +040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;Byelorussian;;045E; +040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F; +0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430; +0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431; +0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432; +0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433; +0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434; +0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435; +0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436; +0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437; +0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438; +0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439; +041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A; +041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B; +041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C; +041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D; +041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E; +041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F; +0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440; +0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441; +0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442; +0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443; +0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444; +0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445; +0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446; +0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447; +0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448; +0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449; +042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A; +042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B; +042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C; +042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D; +042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E; +042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F; +0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410 +0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411 +0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412 +0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413 +0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414 +0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415 +0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416 +0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417 +0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418 +0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419 +043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A +043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B +043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C +043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D +043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E +043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F +0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420 +0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421 +0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422 +0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423 +0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424 +0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425 +0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426 +0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427 +0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428 +0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429 +044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A +044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B +044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C +044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D +044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E +044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F +0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400 +0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401 +0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;Serbocroatian;0402;;0402 +0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403 +0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404 +0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405 +0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406 +0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;Ukrainian;0407;;0407 +0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408 +0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409 +045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A +045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;Serbocroatian;040B;;040B +045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C +045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D +045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;Byelorussian;040E;;040E +045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F +0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461; +0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460 +0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463; +0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462 +0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465; +0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464 +0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467; +0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466 +0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469; +0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468 +046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B; +046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A +046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D; +046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C +046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F; +046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E +0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471; +0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470 +0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473; +0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472 +0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475; +0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474 +0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477; +0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476 +0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479; +0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478 +047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B; +047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A +047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D; +047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C +047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F; +047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E +0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481; +0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480 +0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;; +0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;; +0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;; +0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;; +0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;; +0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;; +0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;; +048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D; +048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C +048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F; +048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E +0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491; +0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490 +0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493; +0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492 +0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495; +0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494 +0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497; +0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496 +0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499; +0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498 +049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B; +049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A +049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D; +049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C +049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F; +049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E +04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1; +04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0 +04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3; +04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2 +04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5; +04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4 +04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;Abkhasian;;04A7; +04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;Abkhasian;04A6;;04A6 +04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9; +04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8 +04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB; +04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA +04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD; +04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC +04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF; +04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE +04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1; +04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0 +04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3; +04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2 +04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;Abkhasian;;04B5; +04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;Abkhasian;04B4;;04B4 +04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7; +04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6 +04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9; +04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8 +04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB; +04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA +04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD; +04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC +04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF; +04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE +04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;; +04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2; +04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1 +04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4; +04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3 +04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8; +04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7 +04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC; +04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB +04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1; +04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0 +04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3; +04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2 +04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5; +04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4 +04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7; +04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6 +04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9; +04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8 +04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB; +04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA +04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD; +04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC +04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF; +04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE +04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1; +04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0 +04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3; +04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2 +04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5; +04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4 +04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7; +04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6 +04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9; +04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8 +04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB; +04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA +04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED; +04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC +04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF; +04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE +04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1; +04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0 +04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3; +04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2 +04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5; +04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4 +04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9; +04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8 +0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561; +0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562; +0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563; +0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564; +0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565; +0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566; +0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567; +0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568; +0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569; +053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A; +053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B; +053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C; +053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D; +053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E; +053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F; +0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570; +0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571; +0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572; +0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573; +0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574; +0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575; +0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576; +0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577; +0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578; +0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579; +054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A; +054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B; +054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C; +054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D; +054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E; +054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F; +0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580; +0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581; +0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582; +0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583; +0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584; +0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585; +0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586; +0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;; +055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;; +055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;; +055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;; +055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;; +055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;; +055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;; +0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531 +0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532 +0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533 +0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534 +0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535 +0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536 +0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537 +0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538 +0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539 +056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A +056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B +056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C +056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D +056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E +056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F +0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540 +0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541 +0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542 +0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543 +0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544 +0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545 +0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546 +0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547 +0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548 +0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549 +057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A +057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B +057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C +057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D +057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E +057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F +0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550 +0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551 +0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552 +0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553 +0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554 +0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555 +0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556 +0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L; 0565 0582;;;;N;;;;; +0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;; +058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;; +0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;; +0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;; +0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;; +0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;; +0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;; +0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;*;;; +0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;; +0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;*;;; +0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;; +059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;; +059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;; +059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;; +059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;; +059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;; +059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;; +05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;; +05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;; +05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;; +05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;; +05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;; +05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;; +05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;; +05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;*;;; +05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;; +05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;*;;; +05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;; +05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;; +05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;; +05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;; +05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;; +05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;; +05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;; +05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;; +05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;; +05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;; +05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;; +05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;; +05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;; +05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;; +05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;; +05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;; +05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;; +05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;; +05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;; +05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;; +05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;; +05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;; +05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;; +05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;; +05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;; +05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;; +05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;; +05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;; +05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;; +05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;; +05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;; +05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;; +05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;; +05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;; +05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;; +05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;; +05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;; +05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;; +05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;; +05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;; +05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;; +05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;; +05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;; +05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;; +05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;; +05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;; +05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;; +05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;; +05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;; +05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;; +05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;; +05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;; +05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;; +05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;; +05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;; +05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;; +05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;; +060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;; +061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;; +061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;; +0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;; +0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;; +0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;; +0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;; +0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;; +0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;; +0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;; +0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;; +0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;; +062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;; +062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;; +062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;; +062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;; +062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;; +062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;; +0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;; +0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;; +0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; +0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;; +0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;; +0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;; +0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;; +0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;; +0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;; +0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;; +063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;; +0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;; +0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;; +0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;; +0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;; +0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;; +0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;; +0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;; +0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;; +0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;; +0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;; +064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;; +064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;; +064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;; +064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;; +064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;; +064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;; +0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;; +0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;; +0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;; +0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;; +0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;; +0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;; +0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; +0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; +0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; +0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; +0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; +0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; +0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; +0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; +0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; +0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; +066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;; +066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;; +066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;; +066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;; +0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;; +0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;; +0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;; +0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;; +0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;; +0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL; 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;; +0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL; 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;; +0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL; 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;; +0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL; 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;; +0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;; +067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;; +067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;; +067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;; +067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;; +067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;; +067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;; +0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;; +0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;; +0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;; +0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;; +0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;; +0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;; +0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;; +0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;; +0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;; +0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;; +068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;; +068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;; +068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;; +068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;; +068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;; +0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;; +0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;; +0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;; +0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;; +0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;; +0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;; +0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;; +0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;; +0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;; +069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;; +069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;; +06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;; +06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;; +06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;; +06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;; +06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;; +06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;; +06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;; +06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;; +06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;; +06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;; +06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;; +06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;*;;; +06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;; +06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;; +06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;; +06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;; +06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;; +06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; +06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;; +06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;; +06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;; +06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;; +06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;; +06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;; +06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;; +06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;; +06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;; +06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;; +06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;; +06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;; +06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;; +06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;; +06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; +06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;; +06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;; +06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;; +06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;; +06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;; +06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;*;;; +06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;; +06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;; +06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;; +06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;; +06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;; +06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; +06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;; +06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;; +06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;; +06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;; +06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;; +06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;; +06DD;ARABIC END OF AYAH;Me;0;NSM;;;;;N;;;;; +06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;; +06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;; +06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;; +06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;; +06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;; +06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;; +06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;; +06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;; +06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;; +06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;; +06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;; +06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;; +06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;; +06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;; +06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;; +06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;; +06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; +06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; +06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; +06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; +06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; +06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; +06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; +06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; +06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; +06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; +06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;; +06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;; +0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;; +0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;; +0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;; +0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;; +0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;; +0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;; +0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; +0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; +0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;; +0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;; +070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;; +070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;; +070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;; +070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;; +070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;; +0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;; +0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;; +0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;; +0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;; +0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;; +0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;; +0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;; +0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;; +0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;; +0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;; +071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;; +071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;; +071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;; +071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;; +071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;; +071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;; +0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;; +0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;; +0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;; +0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;; +0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;; +0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;; +0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;; +0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;; +0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;; +0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;; +072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;; +072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;; +072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;; +0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;; +0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;; +0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;; +0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;; +0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;; +0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;; +0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;; +0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;; +0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;; +0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;; +073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;; +073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;; +073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;; +073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;; +073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;; +073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;; +0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;; +0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;; +0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;; +0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;; +0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;; +0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;; +0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;; +0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;; +074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;; +0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;; +0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;; +0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;; +0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;; +0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;; +0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;; +0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;; +0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;; +0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;; +0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;; +078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;; +078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;; +078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;; +078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;; +078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;; +078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;; +0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;; +0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;; +0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;; +0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;; +0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;; +0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;; +0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;; +0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;; +0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;; +0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;; +079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;; +079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;; +079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;; +079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;; +079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;; +079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;; +07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;; +07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;; +07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;; +07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;; +07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;; +07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;; +07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;; +07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;; +07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;; +07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;; +07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;; +07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;; +07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;; +07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;; +07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;; +07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;; +07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;; +0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;; +0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;; +0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;; +0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;; +0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;; +090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;; +090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;; +090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;; +090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;; +0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;; +0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;; +0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;; +0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;; +0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;; +0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;; +0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;; +0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;; +0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;; +0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;; +091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;; +091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;; +091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;; +091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;; +091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;; +091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;; +0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;; +0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;; +0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;; +0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;; +0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;; +0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;; +0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;; +0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;; +092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;; +092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;; +092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;; +092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;; +092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;; +092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;; +0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;; +0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;; +0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;; +0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;; +0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;; +0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;; +0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;; +0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;; +0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;; +0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;; +093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;; +0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;; +094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;; +0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;; +0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;; +0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;; +0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;; +0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;; +0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;; +095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;; +095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;; +095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;; +095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;; +095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;; +095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;; +0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;; +0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;; +0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;; +0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;; +0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;; +0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;; +098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;; +098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;; +0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;; +0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;; +0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;; +0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;; +0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;; +0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;; +0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;; +0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;; +099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;; +099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;; +099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;; +099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;; +099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;; +099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;; +09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;; +09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;; +09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;; +09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;; +09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;; +09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;; +09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;; +09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;; +09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;; +09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;; +09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;; +09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;; +09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;; +09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;; +09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;; +09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;; +09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;; +09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;; +09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;; +09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;; +09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;; +09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;; +09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;; +09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;; +09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;; +09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;; +09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;Assamese;;; +09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;Assamese;;; +09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;; +09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; +09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1;N;;;;; +09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;2;N;;;;; +09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3;N;;;;; +09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;4;N;;;;; +09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;;N;;;;; +09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;; +09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;; +0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; +0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;; +0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;; +0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;; +0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;; +0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;; +0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;; +0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;; +0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;; +0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;; +0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;; +0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;; +0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;; +0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;; +0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;; +0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;; +0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;; +0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;; +0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;; +0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;; +0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;; +0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;; +0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;; +0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;; +0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;; +0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;; +0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;; +0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;; +0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;; +0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;; +0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;; +0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;; +0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;; +0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;; +0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;; +0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;; +0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;; +0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;; +0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;; +0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;; +0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;; +0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;; +0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; +0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;; +0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;; +0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;; +0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;; +0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;; +0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;; +0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;; +0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;; +0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;; +0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;; +0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;; +0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;; +0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;; +0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;; +0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;; +0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;; +0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;; +0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;; +0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;; +0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;; +0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;; +0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;; +0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;; +0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;; +0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;; +0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;; +0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;; +0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;; +0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;; +0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;; +0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;; +0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;; +0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;; +0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;; +0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;; +0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;; +0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;; +0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;; +0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;; +0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;; +0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;; +0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;; +0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;; +0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;; +0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;; +0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;; +0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;; +0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;; +0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;; +0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;; +0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;; +0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;; +0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;; +0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;; +0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;; +0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;; +0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;; +0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;; +0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;; +0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;; +0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;; +0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;; +0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;; +0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;; +0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;; +0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;; +0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;; +0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;; +0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;; +0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;; +0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;; +0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;; +0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;; +0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;; +0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;; +0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;; +0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;; +0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;; +0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;; +0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;; +0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;; +0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;; +0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;; +0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;; +0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;; +0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;; +0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;; +0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;; +0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;; +0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;; +0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;; +0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;; +0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;; +0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;; +0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;; +0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;; +0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;; +0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;; +0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;; +0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;; +0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;; +0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;; +0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;; +0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;; +0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;; +0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;; +0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;; +0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;; +0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;; +0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +0B83;TAMIL SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;; +0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;; +0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;; +0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;; +0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;; +0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;; +0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;; +0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;; +0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;; +0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;; +0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;; +0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;; +0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;; +0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;; +0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;; +0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;; +0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;; +0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;; +0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;; +0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;; +0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;; +0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;; +0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;; +0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;; +0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;; +0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;; +0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;; +0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;; +0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;; +0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;; +0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;; +0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;; +0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;; +0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;; +0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;; +0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;; +0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;; +0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;; +0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;; +0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;; +0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;; +0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;; +0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;; +0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;; +0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;; +0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;; +0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;; +0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;; +0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;; +0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;; +0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;; +0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;; +0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;; +0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;; +0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;; +0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;; +0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;; +0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;; +0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;; +0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;; +0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;; +0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;; +0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;; +0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;; +0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;; +0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;; +0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;; +0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;; +0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;; +0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;; +0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;; +0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;; +0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;; +0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;; +0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;; +0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;; +0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;; +0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;; +0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;; +0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;; +0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;; +0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;; +0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;; +0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;; +0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;; +0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;; +0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;; +0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;; +0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;; +0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;; +0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;; +0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;; +0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;; +0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;; +0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;; +0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;; +0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;; +0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;; +0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;; +0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;; +0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;; +0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;; +0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;; +0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;; +0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;; +0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;; +0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;; +0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;; +0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;; +0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;; +0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;; +0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;; +0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;; +0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;; +0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;; +0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;; +0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;; +0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;; +0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;; +0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;; +0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;; +0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;; +0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;; +0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;; +0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;; +0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;; +0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;; +0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;; +0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;; +0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;; +0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;; +0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;; +0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;; +0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;; +0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;; +0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;; +0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;; +0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;; +0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;; +0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;; +0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0CBF;KANNADA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;; +0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;; +0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;; +0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +0CC6;KANNADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;; +0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;; +0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;; +0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;; +0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;; +0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;; +0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; +0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; +0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;; +0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;; +0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;; +0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;; +0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;; +0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;; +0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;; +0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;; +0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;; +0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;; +0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;; +0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;; +0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;; +0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;; +0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;; +0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;; +0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;; +0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;; +0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;; +0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;; +0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;; +0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;; +0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;; +0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;; +0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;; +0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;; +0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;; +0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;; +0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;; +0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;; +0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;; +0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;; +0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;; +0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;; +0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;; +0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;; +0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;; +0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;; +0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;; +0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;; +0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;; +0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;; +0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;; +0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;; +0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;; +0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;; +0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; +0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; +0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;; +0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;; +0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;; +0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; +0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;; +0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;; +0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;; +0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;; +0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;; +0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;; +0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;; +0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;; +0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;; +0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;; +0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;; +0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;; +0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;; +0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;; +0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;; +0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;; +0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;; +0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;; +0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;; +0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;; +0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; +0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;; +0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; +0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;; +0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; +0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;; +0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; +0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;; +0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;; +0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;; +0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;; +0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; +0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;; +0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;; +0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;; +0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; +0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;; +0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;; +0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;; +0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; +0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;; +0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; +0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;; +0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;; +0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;; +0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;; +0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;; +0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;; +0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;; +0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;; +0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;; +0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;; +0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;; +0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;; +0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;; +0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;; +0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;; +0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;; +0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;; +0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;; +0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;; +0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;; +0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;; +0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;; +0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;; +0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;; +0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;; +0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;; +0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;; +0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;; +0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;; +0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;; +0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;; +0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;; +0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;; +0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;; +0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;; +0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;; +0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;; +0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;; +0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;; +0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;; +0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;; +0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;; +0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;; +0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;; +0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;; +0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;; +0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;; +0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;; +0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;; +0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;; +0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;; +0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;; +0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;; +0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;; +0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;; +0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;; +0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;; +0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;; +0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;; +0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;; +0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;; +0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;; +0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;; +0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;; +0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;; +0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;; +0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;; +0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;; +0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;; +0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;; +0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;; +0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;; +0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;paiyan noi;;; +0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;; +0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;; +0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;; +0E33;THAI CHARACTER SARA AM;Lo;0;L; 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;; +0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;; +0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;; +0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;; +0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;sara uue;;; +0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;; +0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;; +0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;; +0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;; +0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;; +0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;; +0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;; +0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;sara ai mai muan;;; +0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;sara ai mai malai;;; +0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;lakkhang yao;;; +0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;mai yamok;;; +0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;mai taikhu;;; +0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;; +0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;; +0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;; +0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;; +0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;; +0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;nikkhahit;;; +0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;; +0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;; +0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;; +0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;; +0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;; +0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;; +0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;; +0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;; +0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;; +0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;; +0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;; +0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;; +0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;; +0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;; +0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;; +0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;; +0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;; +0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;; +0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;; +0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;; +0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;; +0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;; +0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;; +0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;; +0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;; +0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;; +0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;; +0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;; +0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;; +0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;; +0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;; +0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;; +0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;; +0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;; +0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;; +0EB3;LAO VOWEL SIGN AM;Lo;0;L; 0ECD 0EB2;;;;N;;;;; +0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; +0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; +0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;; +0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;; +0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;; +0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;; +0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;; +0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;; +0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;; +0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;; +0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;; +0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;; +0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;; +0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;; +0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;; +0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;; +0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;; +0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;; +0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;; +0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0EDC;LAO HO NO;Lo;0;L; 0EAB 0E99;;;;N;;;;; +0EDD;LAO HO MO;Lo;0;L; 0EAB 0EA1;;;;N;;;;; +0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;; +0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;ter yik go a thung;;; +0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;ter yik go wum nam chey ma;;; +0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;ter yik go wum ter tsek ma;;; +0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;yik go dun ma;;; +0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;yik go kab ma;;; +0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;yik go pur shey ma;;; +0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;yik go tsek shey ma;;; +0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;drul shey;;; +0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;kur yik go;;; +0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;ka sho yik go;;; +0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;tsek;;; +0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L; 0F0B;;;;N;;tsek tar;;; +0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;shey;;; +0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;nyi shey;;; +0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;tsek shey;;; +0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;nyi tsek shey;;; +0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;rinchen pung shey;;; +0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;gya tram shey;;; +0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;dzu ta me long chen;;; +0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;ter tsek;;; +0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;che ta;;; +0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;hlak ta;;; +0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;trachen char ta;;; +0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;kyu pa;;; +0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;dong tsu;;; +0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;deka chig;;; +0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;deka nyi;;; +0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;deka sum;;; +0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;dena chig;;; +0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;dena nyi;;; +0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;deka dena;;; +0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;; +0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;; +0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;; +0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;; +0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;; +0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;; +0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;; +0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;; +0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;; +0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;; +0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;du ta;;; +0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;nge zung nyi da;;; +0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;dzu ta shi mig chen;;; +0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;; +0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;; +0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;; +0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;; +0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;; +0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;; +0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;; +0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;; +0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;; +0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;; +0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;; +0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;; +0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;; +0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;; +0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;; +0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;; +0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;; +0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;; +0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;; +0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;; +0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;; +0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;; +0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;; +0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;; +0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;; +0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;; +0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;; +0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;; +0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;; +0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;; +0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;; +0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;; +0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;; +0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;; +0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;; +0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;; +0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;; +0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;; +0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;; +0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;; +0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;; +0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;; +0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;*;;; +0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;; +0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;; +0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;; +0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;; +0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;; +0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;; +0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;; +0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;; +0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;; +0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;; +0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;; +0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;; +0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;; +0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;; +0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM; 0FB2 0F81;;;;N;;;;; +0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;; +0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM; 0FB3 0F81;;;;N;;;;; +0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;; +0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;; +0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;; +0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;; +0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;je su nga ro;;; +0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;nam chey;;; +0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;; +0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;; +0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;nyi da na da;;; +0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;nan de;;; +0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;; +0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;; +0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;ji ta;;; +0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;yang ta;;; +0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;che tsa chen;;; +0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;chu chen;;; +0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;tru chen ging;;; +0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;tru me ging;;; +0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; +0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; +0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; +0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;; +0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; +0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; +0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; +0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; +0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; +0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;; +0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;; +0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;; +0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;; +0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;; +0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; +0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; +0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; +0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;; +0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; +0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; +0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; +0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; +0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;; +0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; +0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; +0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; +0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; +0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;; +0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;*;;; +0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; +0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; +0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;; +0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;*;;; +0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;*;;; +0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; +0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; +0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;; +0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; +0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; +0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; +0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;; +0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;*;;; +0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;*;;; +0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;*;;; +0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;kuruka;;; +0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;kuruka shi mik chen;;; +0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;; +0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;; +0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;chang tyu;;; +0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;bub chey;;; +0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;drilbu;;; +0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;dorje;;; +0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;pema den;;; +0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;dorje gya dram;;; +0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;phurba;;; +0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;norbu;;; +0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;; +0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;; +0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;; +0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;; +1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;; +1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;; +1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;; +1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;; +1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;; +1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;; +1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;; +1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;; +1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;; +1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;; +100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;; +100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;; +100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;; +100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;; +100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;; +100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;; +1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;; +1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;; +1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;; +1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;; +1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;; +1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;; +1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;; +1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;; +1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;; +1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;; +101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;; +101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;; +101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;; +101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;; +101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;; +101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;; +1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;; +1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;; +1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;; +1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;; +1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;; +1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;; +1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;; +1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;; +102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;; +102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;; +1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;; +1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;; +104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;; +104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;; +104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;; +104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;; +104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;; +1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;; +1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;; +1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;; +1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;; +1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;; +10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;; +10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;; +10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;; +10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;; +10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;; +10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;; +10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;; +10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;; +10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;; +10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;; +10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;; +10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;; +10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;; +10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;; +10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;; +10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;; +10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;; +10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;; +10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;; +10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;; +10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;; +10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;; +10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;; +10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;; +10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;; +10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;; +10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;; +10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;; +10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;; +10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;; +10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;; +10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;; +10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;; +10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;; +10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;; +10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;; +10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;; +10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;; +10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;; +10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;; +10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;; +10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;; +10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;; +10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;; +10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;; +10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;; +10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;; +10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;; +10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;; +10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;; +10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;; +10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;; +10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;; +10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;; +10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;; +10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;; +10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;; +10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;; +10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;; +10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;; +10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;; +10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;; +10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;; +10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;; +10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;; +10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;; +10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;; +10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;; +10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;; +10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;; +10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;; +10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;; +10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; +1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; +1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; +1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;; +1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;dd *;;; +1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;r *;;; +1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;m *;;; +1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;b *;;; +1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;bb *;;; +1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;s *;;; +110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;; +110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;; +110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;j *;;; +110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;jj *;;; +110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;; +110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;; +1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;; +1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;; +1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;h *;;; +1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; +1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;; +1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; +1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;; +1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; +1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; +1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; +111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;; +111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;; +111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; +111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; +111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; +111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;; +1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;; +1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;; +1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;; +1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;; +1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;; +112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;; +112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;; +112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; +1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;; +1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;; +1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;; +1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;; +1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;; +1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;; +1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;; +1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;; +113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;; +113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;; +113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;; +113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; +113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;; +113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;; +1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;; +1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; +1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;; +1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;; +1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;; +1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;; +1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; +1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; +1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;; +1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;; +114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;; +114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;; +114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; +114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;; +114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;; +114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; +1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;; +1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;; +1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;; +1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;; +1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;; +1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;; +1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; +1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; +1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;; +1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; +115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;; +1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;; +1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;; +1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;; +1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;; +1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;; +1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;; +1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;; +1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;; +1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;; +1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;; +116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;; +116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;; +116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;; +116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;; +116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;; +116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;; +1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;; +1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;; +1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;; +1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;; +1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;; +1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;; +1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;; +1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;; +1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;; +1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;; +117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;; +117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;; +117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;; +117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;; +117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;; +117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;; +1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;; +1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;; +1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;; +1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;; +1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;; +1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;; +1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;; +1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;; +1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;; +1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;; +118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;; +118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;; +118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;; +118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;; +118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;; +118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;; +1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;; +1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;; +1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;; +1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;; +1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;; +1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;; +1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;; +1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;; +1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;; +1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;; +119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;; +119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;; +119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;; +119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;; +119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;; +119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;; +11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;; +11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;; +11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;; +11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;; +11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;; +11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;gs *;;; +11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;n *;;; +11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;nj *;;; +11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;nh *;;; +11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;; +11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;l *;;; +11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;lg *;;; +11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;lm *;;; +11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;lb *;;; +11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;ls *;;; +11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;lt *;;; +11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;lp *;;; +11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;lh *;;; +11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;m *;;; +11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;b *;;; +11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;bs *;;; +11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;s *;;; +11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;; +11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;ng *;;; +11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;j *;;; +11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;; +11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;; +11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;; +11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;; +11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;h *;;; +11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;; +11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;; +11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;; +11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;; +11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;; +11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;; +11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;; +11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;; +11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;; +11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;; +11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;; +11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;; +11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;; +11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;; +11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;; +11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;; +11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;; +11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;; +11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;; +11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;; +11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;; +11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;; +11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;; +11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;; +11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;; +11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;; +11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;; +11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;; +11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;; +11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;; +11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;; +11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;; +11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;; +11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;; +11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;; +11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;; +11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;; +11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;; +11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;; +11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;; +11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;; +11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;; +11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;; +11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;; +11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;; +11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;; +11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;; +11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;; +11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;; +11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;; +1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;; +1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;; +1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;; +1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;; +1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;; +1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;; +1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;; +1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;; +1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;; +120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;; +120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;; +120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;; +120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;; +120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;; +120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;; +1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;; +1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;; +1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;; +1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;; +1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;; +1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;; +1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;; +1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;; +1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;; +1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;; +121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;; +121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;; +121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;; +121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;; +121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;; +121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;; +1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;; +1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;; +1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;; +1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;; +1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;; +1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;; +1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;; +1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;; +1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;; +1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;; +122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;; +122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;; +122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;; +122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;; +122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;; +122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;; +1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;; +1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;; +1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;; +1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;; +1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;; +1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;; +1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;; +1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;; +1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;; +123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;; +123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;; +123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;; +1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;; +1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;; +1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;; +1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;; +1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;; +1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;; +1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;; +1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;; +124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;; +124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;; +124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;; +124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;; +1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;; +1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;; +1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;; +1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;; +1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;; +1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;; +1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;; +1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;; +125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;; +125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;; +125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;; +125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;; +1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;; +1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;; +1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;; +1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;; +1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;; +1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;; +1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;; +1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;; +1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;; +1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;; +126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;; +126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;; +126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;; +126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;; +126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;; +126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;; +1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;; +1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;; +1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;; +1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;; +1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;; +1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;; +1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;; +1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;; +1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;; +1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;; +127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;; +127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;; +127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;; +127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;; +127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;; +127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;; +1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;; +1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;; +1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;; +1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;; +1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;; +1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;; +1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;; +1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;; +128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;; +128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;; +128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;; +128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;; +1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;; +1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;; +1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;; +1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;; +1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;; +1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;; +1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;; +1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;; +1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;; +1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;; +129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;; +129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;; +129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;; +12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;; +12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;; +12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;; +12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;; +12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;; +12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;; +12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;; +12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;; +12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;; +12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;; +12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;; +12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;; +12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;; +12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;; +12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;; +12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;; +12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;; +12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;; +12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;; +12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;; +12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;; +12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;; +12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;; +12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;; +12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;; +12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;; +12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;; +12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;; +12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;; +12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;; +12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;; +12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;; +12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;; +12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;; +12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;; +12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;; +12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;; +12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;; +12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;; +12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;; +12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;; +12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;; +12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;; +12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;; +12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;; +12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;; +12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;; +12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;; +12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;; +12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;; +12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;; +12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;; +12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;; +12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;; +12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;; +12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;; +12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;; +12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;; +12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;; +12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;; +12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;; +12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;; +12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;; +12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;; +12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;; +12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;; +12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;; +12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;; +12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;; +12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;; +12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;; +12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;; +12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;; +12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;; +12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;; +12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;; +1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;; +1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;; +1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;; +1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;; +1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;; +1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;; +1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;; +1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;; +1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;; +1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;; +130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;; +130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;; +130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;; +130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;; +130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;; +1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;; +1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;; +1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;; +1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;; +1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;; +1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;; +1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;; +131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;; +131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;; +131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;; +131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;; +131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;; +1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;; +1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;; +1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;; +1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;; +1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;; +1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;; +1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;; +1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;; +1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;; +132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;; +132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;; +132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;; +132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;; +132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;; +132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;; +1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;; +1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;; +1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;; +1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;; +1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;; +1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;; +1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;; +1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;; +1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;; +1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;; +133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;; +133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;; +133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;; +133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;; +133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;; +133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;; +1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;; +1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;; +1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;; +1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;; +1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;; +1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;; +1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;; +1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;; +1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;; +134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;; +134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;; +134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;; +134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;; +134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;; +134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;; +1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;; +1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;; +1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;; +1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;; +1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;; +1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;; +1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;; +1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;; +1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;; +1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;; +135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;; +1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;; +1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;; +1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;; +1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;; +1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;; +1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;; +1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;; +1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;; +1369;ETHIOPIC DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +136A;ETHIOPIC DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +136B;ETHIOPIC DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +136C;ETHIOPIC DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +136D;ETHIOPIC DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +136E;ETHIOPIC DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +136F;ETHIOPIC DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1370;ETHIOPIC DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1371;ETHIOPIC DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;; +1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;; +1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;; +1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;; +1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;; +1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;; +1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;; +137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;; +137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;; +13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;; +13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;; +13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;; +13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;; +13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;; +13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;; +13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;; +13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;; +13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;; +13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;; +13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;; +13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;; +13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;; +13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;; +13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;; +13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;; +13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;; +13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;; +13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;; +13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;; +13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;; +13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;; +13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;; +13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;; +13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;; +13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;; +13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;; +13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;; +13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;; +13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;; +13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;; +13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;; +13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;; +13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;; +13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;; +13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;; +13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;; +13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;; +13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;; +13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;; +13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;; +13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;; +13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;; +13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;; +13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;; +13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;; +13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;; +13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;; +13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;; +13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;; +13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;; +13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;; +13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;; +13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;; +13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;; +13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;; +13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;; +13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;; +13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;; +13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;; +13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;; +13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;; +13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;; +13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;; +13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;; +13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;; +13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;; +13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;; +13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;; +13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;; +13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;; +13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;; +13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;; +13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;; +13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;; +13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;; +13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;; +13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;; +13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;; +13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;; +13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;; +13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;; +13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;; +13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;; +13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;; +1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;; +1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;; +1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;; +1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;; +1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;; +1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;; +1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;; +1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;; +1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;; +140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;; +140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;; +140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;; +140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;; +140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;; +140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;; +1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;; +1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;; +1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;; +1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;; +1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;; +1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;; +1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;; +1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;; +1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;; +1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;; +141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;; +141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;; +141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;; +141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;; +141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;; +141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;; +1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;; +1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;; +1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;; +1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;; +1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;; +1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;; +1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;; +1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;; +1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;; +1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;; +142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;; +142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;; +142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;; +142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;; +142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;; +142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;; +1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;; +1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;; +1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;; +1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;; +1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;; +1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;; +1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;; +1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;; +1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;; +1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;; +143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;; +143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;; +143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;; +143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;; +143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;; +143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;; +1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;; +1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;; +1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;; +1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;; +1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;; +1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;; +1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;; +1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;; +1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;; +1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;; +144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;; +144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;; +144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;; +144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;; +144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;; +144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;; +1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;; +1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;; +1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;; +1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;; +1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;; +1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;; +1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;; +1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;; +1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;; +1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;; +145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;; +145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;; +145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;; +145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;; +145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;; +145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;; +1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;; +1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;; +1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;; +1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;; +1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;; +1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;; +1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;; +1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;; +1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;; +1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;; +146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;; +146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;; +146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;; +146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;; +146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;; +146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;; +1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;; +1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;; +1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;; +1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;; +1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;; +1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;; +1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;; +1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;; +1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;; +1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;; +147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;; +147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;; +147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;; +147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;; +147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;; +147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;; +1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;; +1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;; +1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;; +1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;; +1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;; +1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;; +1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;; +1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;; +1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;; +1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;; +148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;; +148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;; +148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;; +148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;; +148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;; +148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;; +1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;; +1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;; +1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;; +1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;; +1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;; +1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;; +1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;; +1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;; +1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;; +1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;; +149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;; +149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;; +149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;; +149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;; +149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;; +149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;; +14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;; +14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;; +14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;; +14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;; +14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;; +14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;; +14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;; +14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;; +14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;; +14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;; +14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;; +14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;; +14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;; +14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;; +14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;; +14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;; +14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;; +14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;; +14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;; +14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;; +14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;; +14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;; +14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;; +14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;; +14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;; +14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;; +14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;; +14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;; +14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;; +14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;; +14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;; +14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;; +14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;; +14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;; +14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;; +14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;; +14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;; +14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;; +14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;; +14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;; +14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;; +14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;; +14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;; +14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;; +14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;; +14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;; +14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;; +14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;; +14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;; +14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;; +14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;; +14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;; +14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;; +14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;; +14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;; +14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;; +14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;; +14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;; +14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;; +14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;; +14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;; +14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;; +14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;; +14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;; +14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;; +14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;; +14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;; +14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;; +14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;; +14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;; +14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;; +14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;; +14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;; +14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;; +14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;; +14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;; +14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;; +14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;; +14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;; +14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;; +14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;; +14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;; +14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;; +14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;; +14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;; +14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;; +14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;; +14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;; +14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;; +14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;; +14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;; +14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;; +14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;; +14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;; +14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;; +14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;; +1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;; +1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;; +1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;; +1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;; +1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;; +1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;; +1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;; +1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;; +1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;; +1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;; +150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;; +150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;; +150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;; +150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;; +150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;; +150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;; +1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;; +1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;; +1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;; +1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;; +1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;; +1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;; +1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;; +1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;; +1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;; +1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;; +151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;; +151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;; +151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;; +151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;; +151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;; +151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;; +1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;; +1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;; +1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;; +1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;; +1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;; +1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;; +1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;; +1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;; +1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;; +1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;; +152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;; +152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;; +152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;; +152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;; +152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;; +152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;; +1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;; +1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;; +1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;; +1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;; +1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;; +1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;; +1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;; +1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;; +1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;; +1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;; +153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;; +153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;; +153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;; +153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;; +153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;; +153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;; +1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;; +1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;; +1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;; +1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;; +1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;; +1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;; +1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;; +1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;; +1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;; +1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;; +154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;; +154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;; +154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;; +154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;; +154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;; +154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;; +1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;; +1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;; +1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;; +1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;; +1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;; +1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;; +1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;; +1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;; +1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;; +1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;; +155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;; +155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;; +155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;; +155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;; +155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;; +155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;; +1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;; +1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;; +1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;; +1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;; +1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;; +1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;; +1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;; +1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;; +1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;; +1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;; +156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;; +156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;; +156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;; +156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;; +156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;; +156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;; +1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;; +1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;; +1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;; +1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;; +1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;; +1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;; +1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;; +1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;; +1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;; +1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;; +157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;; +157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;; +157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;; +157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;; +157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;; +157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;; +1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;; +1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;; +1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;; +1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;; +1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;; +1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;; +1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;; +1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;; +1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;; +1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;; +158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;; +158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;; +158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;; +158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;; +158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;; +158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;; +1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;; +1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;; +1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;; +1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;; +1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;; +1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;; +1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;; +1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;; +1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;; +1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;; +159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;; +159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;; +159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;; +159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;; +159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;; +159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;; +15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;; +15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;; +15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;; +15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;; +15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;; +15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;; +15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;; +15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;; +15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;; +15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;; +15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;; +15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;; +15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;; +15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;; +15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;; +15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;; +15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;; +15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;; +15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;; +15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;; +15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;; +15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;; +15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;; +15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;; +15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;; +15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;; +15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;; +15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;; +15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;; +15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;; +15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;; +15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;; +15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;; +15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;; +15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;; +15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;; +15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;; +15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;; +15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;; +15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;; +15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;; +15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;; +15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;; +15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;; +15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;; +15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;; +15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;; +15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;; +15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;; +15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;; +15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;; +15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;; +15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;; +15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;; +15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;; +15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;; +15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;; +15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;; +15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;; +15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;; +15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;; +15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;; +15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;; +15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;; +15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;; +15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;; +15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;; +15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;; +15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;; +15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;; +15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;; +15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;; +15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;; +15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;; +15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;; +15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;; +15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;; +15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;; +15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;; +15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;; +15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;; +15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;; +15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;; +15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;; +15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;; +15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;; +15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;; +15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;; +15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;; +15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;; +15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;; +15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;; +15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;; +15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;; +15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;; +15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;; +1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;; +1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;; +1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;; +1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;; +1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;; +1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;; +1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;; +1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;; +1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;; +1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;; +160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;; +160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;; +160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;; +160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;; +160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;; +160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;; +1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;; +1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;; +1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;; +1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;; +1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;; +1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;; +1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;; +1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;; +1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;; +1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;; +161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;; +161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;; +161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;; +161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;; +161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;; +161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;; +1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;; +1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;; +1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;; +1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;; +1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;; +1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;; +1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;; +1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;; +1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;; +1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;; +162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;; +162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;; +162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;; +162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;; +162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;; +162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;; +1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;; +1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;; +1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;; +1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;; +1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;; +1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;; +1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;; +1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;; +1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;; +1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;; +163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;; +163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;; +163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;; +163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;; +163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;; +163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;; +1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;; +1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;; +1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;; +1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;; +1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;; +1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;; +1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;; +1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;; +1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;; +1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;; +164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;; +164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;; +164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;; +164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;; +164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;; +164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;; +1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;; +1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;; +1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;; +1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;; +1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;; +1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;; +1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;; +1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;; +1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;; +1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;; +165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;; +165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;; +165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;; +165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;; +165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;; +165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;; +1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;; +1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;; +1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;; +1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;; +1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;; +1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;; +1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;; +1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;; +1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;; +1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;; +166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;; +166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;; +166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;; +166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;; +166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;; +166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;; +1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;; +1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;; +1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;; +1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;; +1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;; +1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;; +1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;; +1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; +1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;; +1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;; +1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;; +1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;; +1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;; +1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;; +1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;; +1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;; +1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;; +168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;; +168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;; +168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;; +168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;; +168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;; +168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;; +1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;; +1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;; +1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;; +1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;; +1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;; +1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;; +1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;; +1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;; +1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;; +1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;; +169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;; +169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;; +169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;; +16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;; +16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;; +16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;; +16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;; +16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;; +16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;; +16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;; +16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;; +16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;; +16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;; +16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;; +16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;; +16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;; +16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;; +16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;; +16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;; +16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;; +16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;; +16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;; +16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;; +16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;; +16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;; +16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;; +16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;; +16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;; +16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;; +16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;; +16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;; +16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;; +16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;; +16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;; +16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;; +16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;; +16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;; +16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;; +16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;; +16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;; +16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;; +16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;; +16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;; +16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;; +16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;; +16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;; +16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;; +16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;; +16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;; +16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;; +16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;; +16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;; +16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;; +16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;; +16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;; +16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;; +16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;; +16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;; +16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;; +16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;; +16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;; +16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;; +16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;; +16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;; +16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;; +16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;; +16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;; +16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;; +16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;; +16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;; +16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;; +16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;; +16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;; +16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;; +16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;; +16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;; +16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;; +16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;; +16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;; +16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;; +16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;; +16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;golden number 17;;; +16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;golden number 18;;; +16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;golden number 19;;; +1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;; +1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;; +1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;; +1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;; +1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;; +1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;; +1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;; +1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;; +1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;; +1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;; +178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;; +178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;; +178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;; +178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;; +178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;; +178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;; +1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;; +1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;; +1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;; +1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;; +1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;; +1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;; +1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;; +1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;; +1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;; +1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;; +179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;; +179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;; +179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;; +179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;; +179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;; +179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;; +17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;; +17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;; +17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;; +17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;; +17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;; +17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;; +17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;; +17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;; +17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;; +17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;; +17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;; +17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;; +17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;; +17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;; +17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;; +17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;; +17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;; +17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;; +17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;; +17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;; +17B4;KHMER VOWEL INHERENT AQ;Mc;0;L;;;;;N;;;;; +17B5;KHMER VOWEL INHERENT AA;Mc;0;L;;;;;N;;;;; +17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;; +17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;; +17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;; +17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;; +17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;; +17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;; +17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;; +17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;; +17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; +17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;; +17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;; +17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;; +17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;; +17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;; +17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;; +17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;; +17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;; +17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;; +17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;; +17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;; +17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;; +17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;; +17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;; +17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;; +17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;; +17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;; +17D7;KHMER SIGN LEK TOO;Po;0;L;;;;;N;;;;; +17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;; +17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;; +17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;; +17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;; +17DC;KHMER SIGN AVAKRAHASANYA;Po;0;L;;;;;N;;;;; +17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;; +1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;; +1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;; +1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;; +1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;; +1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;; +1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;; +1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;; +1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;; +1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;; +180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;; +180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Cf;0;BN;;;;;N;;;;; +180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Cf;0;BN;;;;;N;;;;; +180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Cf;0;BN;;;;;N;;;;; +180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;; +1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;; +1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;; +1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;; +1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;; +1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;; +1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;; +1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;; +1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;; +1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;; +1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;; +182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;; +182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;; +182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;; +182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;; +182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;; +182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;; +1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;; +1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;; +1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;; +1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;; +1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;; +1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;; +1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;; +1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;; +1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;; +1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;; +183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;; +183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;; +183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;; +183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;; +183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;; +183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;; +1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;; +1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;; +1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;; +1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;; +1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;; +1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;; +1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;; +1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;; +1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;; +1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;; +184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;; +184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;; +184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;; +184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;; +184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;; +184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;; +1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;; +1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;; +1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;; +1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;; +1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;; +1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;; +1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;; +1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;; +1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;; +1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;; +185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;; +185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;; +185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;; +185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;; +185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;; +185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;; +1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;; +1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;; +1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;; +1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;; +1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;; +1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;; +1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;; +1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;; +1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;; +1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;; +186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;; +186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;; +186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;; +186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;; +186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;; +186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;; +1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;; +1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;; +1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;; +1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;; +1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;; +1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;; +1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;; +1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;; +1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;; +1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;; +1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; +1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; +1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; +1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;; +1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;; +1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; +1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; +1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; +188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;; +188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;; +188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;; +188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;; +188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;; +188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;; +1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;; +1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;; +1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;; +1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;; +1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;; +1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;; +1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;; +1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;; +1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;; +189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;; +189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;; +189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;; +189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;; +189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;; +18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;; +18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;; +18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;; +18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;; +18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;; +18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;; +18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;; +18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;; +18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;; +18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;; +1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01; +1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00 +1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03; +1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02 +1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05; +1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04 +1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07; +1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06 +1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09; +1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08 +1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B; +1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A +1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D; +1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C +1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F; +1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E +1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11; +1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10 +1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13; +1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12 +1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15; +1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14 +1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17; +1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16 +1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19; +1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18 +1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B; +1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A +1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D; +1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C +1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F; +1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E +1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21; +1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20 +1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23; +1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22 +1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25; +1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24 +1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27; +1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26 +1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29; +1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28 +1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B; +1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A +1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D; +1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C +1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F; +1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E +1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31; +1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30 +1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33; +1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32 +1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35; +1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34 +1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37; +1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36 +1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39; +1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38 +1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B; +1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A +1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D; +1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C +1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F; +1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E +1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41; +1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40 +1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43; +1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42 +1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45; +1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44 +1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47; +1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46 +1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49; +1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48 +1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B; +1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A +1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D; +1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C +1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F; +1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E +1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51; +1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50 +1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53; +1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52 +1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55; +1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54 +1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57; +1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56 +1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59; +1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58 +1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B; +1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A +1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D; +1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C +1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F; +1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E +1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61; +1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60 +1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63; +1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62 +1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65; +1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64 +1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67; +1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66 +1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69; +1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68 +1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B; +1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A +1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D; +1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C +1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F; +1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E +1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71; +1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70 +1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73; +1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72 +1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75; +1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74 +1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77; +1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76 +1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79; +1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78 +1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B; +1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A +1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D; +1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C +1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F; +1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E +1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81; +1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80 +1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83; +1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82 +1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85; +1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84 +1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87; +1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86 +1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89; +1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88 +1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B; +1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A +1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D; +1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C +1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F; +1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E +1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91; +1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90 +1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93; +1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92 +1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95; +1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94 +1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;; +1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;; +1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;; +1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;; +1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L; 0061 02BE;;;;N;;;;; +1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60 +1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1; +1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0 +1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3; +1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2 +1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5; +1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4 +1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7; +1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6 +1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9; +1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8 +1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB; +1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA +1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD; +1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC +1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF; +1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE +1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1; +1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0 +1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3; +1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2 +1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5; +1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4 +1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7; +1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6 +1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9; +1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8 +1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB; +1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA +1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD; +1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC +1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF; +1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE +1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1; +1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0 +1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3; +1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2 +1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5; +1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4 +1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7; +1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6 +1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9; +1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8 +1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB; +1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA +1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD; +1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC +1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF; +1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE +1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1; +1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0 +1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3; +1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2 +1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5; +1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4 +1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7; +1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6 +1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9; +1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8 +1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB; +1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA +1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD; +1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC +1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF; +1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE +1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1; +1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0 +1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3; +1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2 +1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5; +1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4 +1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7; +1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6 +1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9; +1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8 +1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB; +1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA +1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED; +1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC +1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF; +1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE +1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1; +1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0 +1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3; +1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2 +1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5; +1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4 +1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7; +1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6 +1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9; +1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8 +1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08 +1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09 +1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A +1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B +1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C +1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D +1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E +1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F +1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00; +1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01; +1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02; +1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03; +1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04; +1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05; +1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06; +1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07; +1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18 +1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19 +1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A +1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B +1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C +1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D +1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10; +1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11; +1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12; +1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13; +1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14; +1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15; +1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28 +1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29 +1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A +1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B +1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C +1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D +1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E +1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F +1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20; +1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21; +1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22; +1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23; +1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24; +1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25; +1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26; +1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27; +1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38 +1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39 +1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A +1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B +1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C +1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D +1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E +1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F +1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30; +1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31; +1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32; +1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33; +1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34; +1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35; +1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36; +1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37; +1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48 +1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49 +1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A +1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B +1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C +1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D +1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40; +1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41; +1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42; +1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43; +1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44; +1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45; +1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;; +1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59 +1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;; +1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B +1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;; +1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D +1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;; +1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F +1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51; +1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53; +1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55; +1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57; +1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68 +1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69 +1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A +1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B +1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C +1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D +1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E +1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F +1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60; +1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61; +1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62; +1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63; +1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64; +1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65; +1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66; +1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67; +1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA +1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB +1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8 +1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9 +1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA +1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB +1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA +1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB +1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8 +1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9 +1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA +1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB +1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA +1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB +1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88 +1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89 +1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A +1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B +1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C +1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D +1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E +1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F +1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80; +1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81; +1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82; +1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83; +1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84; +1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85; +1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86; +1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87; +1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98 +1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99 +1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A +1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B +1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C +1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D +1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E +1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F +1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90; +1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91; +1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92; +1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93; +1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94; +1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95; +1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96; +1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97; +1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8 +1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9 +1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA +1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB +1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC +1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD +1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE +1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF +1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0; +1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1; +1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2; +1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3; +1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4; +1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5; +1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6; +1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7; +1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8 +1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9 +1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;; +1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC +1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;; +1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;; +1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;; +1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0; +1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1; +1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70; +1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71; +1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3; +1FBD;GREEK KORONIS;Sk;0;ON; 0020 0313;;;;N;;;;; +1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399 +1FBF;GREEK PSILI;Sk;0;ON; 0020 0313;;;;N;;;;; +1FC0;GREEK PERISPOMENI;Sk;0;ON; 0020 0342;;;;N;;;;; +1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;; +1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;; +1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC +1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;; +1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;; +1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;; +1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72; +1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73; +1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74; +1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75; +1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3; +1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;; +1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;; +1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;; +1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8 +1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9 +1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;; +1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;; +1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;; +1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;; +1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0; +1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1; +1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76; +1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77; +1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;; +1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;; +1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;; +1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8 +1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9 +1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;; +1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;; +1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;; +1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC +1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;; +1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;; +1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0; +1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1; +1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A; +1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B; +1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5; +1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;; +1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;; +1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;; +1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;; +1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC +1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;; +1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;; +1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;; +1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78; +1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79; +1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C; +1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D; +1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3; +1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;; +1FFE;GREEK DASIA;Sk;0;ON; 0020 0314;;;;N;;;;; +2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; +2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; +2002;EN SPACE;Zs;0;WS; 0020;;;;N;;;;; +2003;EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2004;THREE-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2005;FOUR-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2006;SIX-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; +2007;FIGURE SPACE;Zs;0;WS; 0020;;;;N;;;;; +2008;PUNCTUATION SPACE;Zs;0;WS; 0020;;;;N;;;;; +2009;THIN SPACE;Zs;0;WS; 0020;;;;N;;;;; +200A;HAIR SPACE;Zs;0;WS; 0020;;;;N;;;;; +200B;ZERO WIDTH SPACE;Zs;0;BN;;;;;N;;;;; +200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;; +200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;; +200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; +200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;; +2010;HYPHEN;Pd;0;ON;;;;;N;;;;; +2011;NON-BREAKING HYPHEN;Pd;0;ON; 2010;;;;N;;;;; +2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;; +2013;EN DASH;Pd;0;ON;;;;;N;;;;; +2014;EM DASH;Pd;0;ON;;;;;N;;;;; +2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;; +2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;; +2017;DOUBLE LOW LINE;Po;0;ON; 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;; +2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;; +2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;; +201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;; +201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;; +201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;; +201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;; +201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;; +201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;; +2020;DAGGER;Po;0;ON;;;;;N;;;;; +2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;; +2022;BULLET;Po;0;ON;;;;;N;;;;; +2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;; +2024;ONE DOT LEADER;Po;0;ON; 002E;;;;N;;;;; +2025;TWO DOT LEADER;Po;0;ON; 002E 002E;;;;N;;;;; +2026;HORIZONTAL ELLIPSIS;Po;0;ON; 002E 002E 002E;;;;N;;;;; +2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;; +2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; +2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; +202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;; +202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;; +202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;; +202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;; +202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;; +202F;NARROW NO-BREAK SPACE;Zs;0;WS; 0020;;;;N;;;;; +2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;; +2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;; +2032;PRIME;Po;0;ET;;;;;N;;;;; +2033;DOUBLE PRIME;Po;0;ET; 2032 2032;;;;N;;;;; +2034;TRIPLE PRIME;Po;0;ET; 2032 2032 2032;;;;N;;;;; +2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;; +2036;REVERSED DOUBLE PRIME;Po;0;ON; 2035 2035;;;;N;;;;; +2037;REVERSED TRIPLE PRIME;Po;0;ON; 2035 2035 2035;;;;N;;;;; +2038;CARET;Po;0;ON;;;;;N;;;;; +2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;; +203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;; +203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;; +203C;DOUBLE EXCLAMATION MARK;Po;0;ON; 0021 0021;;;;N;;;;; +203D;INTERROBANG;Po;0;ON;;;;;N;;;;; +203E;OVERLINE;Po;0;ON; 0020 0305;;;;N;SPACING OVERSCORE;;;; +203F;UNDERTIE;Pc;0;ON;;;;;N;;Enotikon;;; +2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;; +2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;; +2042;ASTERISM;Po;0;ON;;;;;N;;;;; +2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;; +2044;FRACTION SLASH;Sm;0;ON;;;;;N;;;;; +2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;; +2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;; +2048;QUESTION EXCLAMATION MARK;Po;0;ON; 003F 0021;;;;N;;;;; +2049;EXCLAMATION QUESTION MARK;Po;0;ON; 0021 003F;;;;N;;;;; +204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;; +204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;; +204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;; +204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;; +206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; +206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;; +206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; +206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;; +206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; +206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;; +2070;SUPERSCRIPT ZERO;No;0;EN; 0030;0;0;0;N;SUPERSCRIPT DIGIT ZERO;;;; +2074;SUPERSCRIPT FOUR;No;0;EN; 0034;4;4;4;N;SUPERSCRIPT DIGIT FOUR;;;; +2075;SUPERSCRIPT FIVE;No;0;EN; 0035;5;5;5;N;SUPERSCRIPT DIGIT FIVE;;;; +2076;SUPERSCRIPT SIX;No;0;EN; 0036;6;6;6;N;SUPERSCRIPT DIGIT SIX;;;; +2077;SUPERSCRIPT SEVEN;No;0;EN; 0037;7;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;; +2078;SUPERSCRIPT EIGHT;No;0;EN; 0038;8;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;; +2079;SUPERSCRIPT NINE;No;0;EN; 0039;9;9;9;N;SUPERSCRIPT DIGIT NINE;;;; +207A;SUPERSCRIPT PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; +207B;SUPERSCRIPT MINUS;Sm;0;ET; 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;; +207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;; +207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;; +207F;SUPERSCRIPT LATIN SMALL LETTER N;Ll;0;L; 006E;;;;N;;;;; +2080;SUBSCRIPT ZERO;No;0;EN; 0030;0;0;0;N;SUBSCRIPT DIGIT ZERO;;;; +2081;SUBSCRIPT ONE;No;0;EN; 0031;1;1;1;N;SUBSCRIPT DIGIT ONE;;;; +2082;SUBSCRIPT TWO;No;0;EN; 0032;2;2;2;N;SUBSCRIPT DIGIT TWO;;;; +2083;SUBSCRIPT THREE;No;0;EN; 0033;3;3;3;N;SUBSCRIPT DIGIT THREE;;;; +2084;SUBSCRIPT FOUR;No;0;EN; 0034;4;4;4;N;SUBSCRIPT DIGIT FOUR;;;; +2085;SUBSCRIPT FIVE;No;0;EN; 0035;5;5;5;N;SUBSCRIPT DIGIT FIVE;;;; +2086;SUBSCRIPT SIX;No;0;EN; 0036;6;6;6;N;SUBSCRIPT DIGIT SIX;;;; +2087;SUBSCRIPT SEVEN;No;0;EN; 0037;7;7;7;N;SUBSCRIPT DIGIT SEVEN;;;; +2088;SUBSCRIPT EIGHT;No;0;EN; 0038;8;8;8;N;SUBSCRIPT DIGIT EIGHT;;;; +2089;SUBSCRIPT NINE;No;0;EN; 0039;9;9;9;N;SUBSCRIPT DIGIT NINE;;;; +208A;SUBSCRIPT PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; +208B;SUBSCRIPT MINUS;Sm;0;ET; 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;; +208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON; 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;; +208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;; +20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;; +20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;; +20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;; +20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;; +20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;; +20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;; +20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;; +20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;; +20A8;RUPEE SIGN;Sc;0;ET; 0052 0073;;;;N;;;;; +20A9;WON SIGN;Sc;0;ET;;;;;N;;;;; +20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;; +20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;; +20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;; +20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;; +20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;; +20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;; +20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; +20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; +20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; +20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;; +20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;; +20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;; +20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;; +20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;; +20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;; +20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;; +20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;; +20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;; +20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;; +20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;; +20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;; +20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;; +20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;; +20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;; +20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;; +20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;; +2100;ACCOUNT OF;So;0;ON; 0061 002F 0063;;;;N;;;;; +2101;ADDRESSED TO THE SUBJECT;So;0;ON; 0061 002F 0073;;;;N;;;;; +2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L; 0043;;;;N;DOUBLE-STRUCK C;;;; +2103;DEGREE CELSIUS;So;0;ON; 00B0 0043;;;;N;DEGREES CENTIGRADE;;;; +2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;; +2105;CARE OF;So;0;ON; 0063 002F 006F;;;;N;;;;; +2106;CADA UNA;So;0;ON; 0063 002F 0075;;;;N;;;;; +2107;EULER CONSTANT;Lu;0;L; 0190;;;;N;EULERS;;;; +2108;SCRUPLE;So;0;ON;;;;;N;;;;; +2109;DEGREE FAHRENHEIT;So;0;ON; 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;; +210A;SCRIPT SMALL G;Ll;0;L; 0067;;;;N;;;;; +210B;SCRIPT CAPITAL H;Lu;0;L; 0048;;;;N;SCRIPT H;;;; +210C;BLACK-LETTER CAPITAL H;Lu;0;L; 0048;;;;N;BLACK-LETTER H;;;; +210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L; 0048;;;;N;DOUBLE-STRUCK H;;;; +210E;PLANCK CONSTANT;Ll;0;L; 0068;;;;N;;;;; +210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L; 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;; +2110;SCRIPT CAPITAL I;Lu;0;L; 0049;;;;N;SCRIPT I;;;; +2111;BLACK-LETTER CAPITAL I;Lu;0;L; 0049;;;;N;BLACK-LETTER I;;;; +2112;SCRIPT CAPITAL L;Lu;0;L; 004C;;;;N;SCRIPT L;;;; +2113;SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; +2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;; +2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L; 004E;;;;N;DOUBLE-STRUCK N;;;; +2116;NUMERO SIGN;So;0;ON; 004E 006F;;;;N;NUMERO;;;; +2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;; +2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;; +2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L; 0050;;;;N;DOUBLE-STRUCK P;;;; +211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L; 0051;;;;N;DOUBLE-STRUCK Q;;;; +211B;SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;SCRIPT R;;;; +211C;BLACK-LETTER CAPITAL R;Lu;0;L; 0052;;;;N;BLACK-LETTER R;;;; +211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L; 0052;;;;N;DOUBLE-STRUCK R;;;; +211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;; +211F;RESPONSE;So;0;ON;;;;;N;;;;; +2120;SERVICE MARK;So;0;ON; 0053 004D;;;;N;;;;; +2121;TELEPHONE SIGN;So;0;ON; 0054 0045 004C;;;;N;T E L SYMBOL;;;; +2122;TRADE MARK SIGN;So;0;ON; 0054 004D;;;;N;TRADEMARK;;;; +2123;VERSICLE;So;0;ON;;;;;N;;;;; +2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L; 005A;;;;N;DOUBLE-STRUCK Z;;;; +2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;; +2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9; +2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;; +2128;BLACK-LETTER CAPITAL Z;Lu;0;L; 005A;;;;N;BLACK-LETTER Z;;;; +2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;; +212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B; +212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5; +212C;SCRIPT CAPITAL B;Lu;0;L; 0042;;;;N;SCRIPT B;;;; +212D;BLACK-LETTER CAPITAL C;Lu;0;L; 0043;;;;N;BLACK-LETTER C;;;; +212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;; +212F;SCRIPT SMALL E;Ll;0;L; 0065;;;;N;;;;; +2130;SCRIPT CAPITAL E;Lu;0;L; 0045;;;;N;SCRIPT E;;;; +2131;SCRIPT CAPITAL F;Lu;0;L; 0046;;;;N;SCRIPT F;;;; +2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;; +2133;SCRIPT CAPITAL M;Lu;0;L; 004D;;;;N;SCRIPT M;;;; +2134;SCRIPT SMALL O;Ll;0;L; 006F;;;;N;;;;; +2135;ALEF SYMBOL;Lo;0;L; 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;; +2136;BET SYMBOL;Lo;0;L; 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;; +2137;GIMEL SYMBOL;Lo;0;L; 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;; +2138;DALET SYMBOL;Lo;0;L; 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;; +2139;INFORMATION SOURCE;Ll;0;L; 0069;;;;N;;;;; +213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;; +2153;VULGAR FRACTION ONE THIRD;No;0;ON; 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;; +2154;VULGAR FRACTION TWO THIRDS;No;0;ON; 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;; +2155;VULGAR FRACTION ONE FIFTH;No;0;ON; 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;; +2156;VULGAR FRACTION TWO FIFTHS;No;0;ON; 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;; +2157;VULGAR FRACTION THREE FIFTHS;No;0;ON; 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;; +2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON; 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;; +2159;VULGAR FRACTION ONE SIXTH;No;0;ON; 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;; +215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON; 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;; +215B;VULGAR FRACTION ONE EIGHTH;No;0;ON; 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;; +215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON; 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;; +215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON; 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;; +215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON; 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;; +215F;FRACTION NUMERATOR ONE;No;0;ON; 0031 2044;;;1;N;;;;; +2160;ROMAN NUMERAL ONE;Nl;0;L; 0049;;;1;N;;;;2170; +2161;ROMAN NUMERAL TWO;Nl;0;L; 0049 0049;;;2;N;;;;2171; +2162;ROMAN NUMERAL THREE;Nl;0;L; 0049 0049 0049;;;3;N;;;;2172; +2163;ROMAN NUMERAL FOUR;Nl;0;L; 0049 0056;;;4;N;;;;2173; +2164;ROMAN NUMERAL FIVE;Nl;0;L; 0056;;;5;N;;;;2174; +2165;ROMAN NUMERAL SIX;Nl;0;L; 0056 0049;;;6;N;;;;2175; +2166;ROMAN NUMERAL SEVEN;Nl;0;L; 0056 0049 0049;;;7;N;;;;2176; +2167;ROMAN NUMERAL EIGHT;Nl;0;L; 0056 0049 0049 0049;;;8;N;;;;2177; +2168;ROMAN NUMERAL NINE;Nl;0;L; 0049 0058;;;9;N;;;;2178; +2169;ROMAN NUMERAL TEN;Nl;0;L; 0058;;;10;N;;;;2179; +216A;ROMAN NUMERAL ELEVEN;Nl;0;L; 0058 0049;;;11;N;;;;217A; +216B;ROMAN NUMERAL TWELVE;Nl;0;L; 0058 0049 0049;;;12;N;;;;217B; +216C;ROMAN NUMERAL FIFTY;Nl;0;L; 004C;;;50;N;;;;217C; +216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L; 0043;;;100;N;;;;217D; +216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L; 0044;;;500;N;;;;217E; +216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L; 004D;;;1000;N;;;;217F; +2170;SMALL ROMAN NUMERAL ONE;Nl;0;L; 0069;;;1;N;;;2160;;2160 +2171;SMALL ROMAN NUMERAL TWO;Nl;0;L; 0069 0069;;;2;N;;;2161;;2161 +2172;SMALL ROMAN NUMERAL THREE;Nl;0;L; 0069 0069 0069;;;3;N;;;2162;;2162 +2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L; 0069 0076;;;4;N;;;2163;;2163 +2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L; 0076;;;5;N;;;2164;;2164 +2175;SMALL ROMAN NUMERAL SIX;Nl;0;L; 0076 0069;;;6;N;;;2165;;2165 +2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L; 0076 0069 0069;;;7;N;;;2166;;2166 +2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L; 0076 0069 0069 0069;;;8;N;;;2167;;2167 +2178;SMALL ROMAN NUMERAL NINE;Nl;0;L; 0069 0078;;;9;N;;;2168;;2168 +2179;SMALL ROMAN NUMERAL TEN;Nl;0;L; 0078;;;10;N;;;2169;;2169 +217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L; 0078 0069;;;11;N;;;216A;;216A +217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L; 0078 0069 0069;;;12;N;;;216B;;216B +217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L; 006C;;;50;N;;;216C;;216C +217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L; 0063;;;100;N;;;216D;;216D +217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L; 0064;;;500;N;;;216E;;216E +217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L; 006D;;;1000;N;;;216F;;216F +2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;; +2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;; +2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;; +2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;; +2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;; +2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;; +2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;; +2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;; +2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;; +2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;; +2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;; +2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;; +2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;; +2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;; +219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;; +219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;; +219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;; +219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;; +219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;; +219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;; +21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;; +21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;; +21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;; +21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;; +21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;; +21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;; +21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;; +21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;; +21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;; +21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;; +21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;; +21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;; +21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;; +21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;; +21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;; +21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;; +21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;; +21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;; +21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;; +21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;; +21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;; +21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;; +21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; +21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;; +21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;; +21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;; +21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;; +21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;; +21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;; +21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;; +21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;; +21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;; +21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;; +21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;; +21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;; +21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;; +21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;; +21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;; +21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;; +21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;; +21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;; +21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;; +21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;; +21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;; +21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;; +21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;; +21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;; +21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;; +21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;; +21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;; +21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;; +21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;; +21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;; +21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;; +21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;; +21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;; +21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;; +21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;; +21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;; +21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;; +21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;; +21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;; +21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;; +21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;; +21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;; +21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;; +21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;; +21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;; +21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;; +21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;; +21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;; +21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;; +21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;; +21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;; +21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; +21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;; +21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;; +21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;; +21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;; +21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;; +21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;; +21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;; +21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;; +2200;FOR ALL;Sm;0;ON;;;;;N;;;;; +2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;; +2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;; +2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;; +2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;; +2205;EMPTY SET;Sm;0;ON;;;;;N;;;;; +2206;INCREMENT;Sm;0;ON;;;;;N;;;;; +2207;NABLA;Sm;0;ON;;;;;N;;;;; +2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;; +2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;; +220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;; +220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; +220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;; +220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;; +220E;END OF PROOF;Sm;0;ON;;;;;N;;;;; +220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;; +2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;; +2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;; +2212;MINUS SIGN;Sm;0;ET;;;;;N;;;;; +2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;; +2214;DOT PLUS;Sm;0;ON;;;;;N;;;;; +2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; +2216;SET MINUS;Sm;0;ON;;;;;Y;;;;; +2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; +2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;; +2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;; +221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;; +221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;; +221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;; +221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;; +221E;INFINITY;Sm;0;ON;;;;;N;;;;; +221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;; +2220;ANGLE;Sm;0;ON;;;;;Y;;;;; +2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;; +2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;; +2223;DIVIDES;Sm;0;ON;;;;;N;;;;; +2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;; +2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;; +2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;; +2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;; +2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;; +2229;INTERSECTION;Sm;0;ON;;;;;N;;;;; +222A;UNION;Sm;0;ON;;;;;N;;;;; +222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;; +222C;DOUBLE INTEGRAL;Sm;0;ON; 222B 222B;;;;Y;;;;; +222D;TRIPLE INTEGRAL;Sm;0;ON; 222B 222B 222B;;;;Y;;;;; +222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +222F;SURFACE INTEGRAL;Sm;0;ON; 222E 222E;;;;Y;;;;; +2230;VOLUME INTEGRAL;Sm;0;ON; 222E 222E 222E;;;;Y;;;;; +2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2234;THEREFORE;Sm;0;ON;;;;;N;;;;; +2235;BECAUSE;Sm;0;ON;;;;;N;;;;; +2236;RATIO;Sm;0;ON;;;;;N;;;;; +2237;PROPORTION;Sm;0;ON;;;;;N;;;;; +2238;DOT MINUS;Sm;0;ON;;;;;N;;;;; +2239;EXCESS;Sm;0;ON;;;;;Y;;;;; +223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;; +223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;; +223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;; +223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;lazy S;;; +223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;; +223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;; +2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;; +2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;; +2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;; +2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;; +2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;; +2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;; +224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;; +224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;; +224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;; +2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;; +2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;; +2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;; +2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;; +2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;; +2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;; +2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;; +2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;; +2259;ESTIMATES;Sm;0;ON;;;;;N;;;;; +225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;; +225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;; +225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;; +225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;; +225E;MEASURED BY;Sm;0;ON;;;;;N;;;;; +225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;; +2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;; +2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;; +2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;; +2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;; +2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;; +2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;; +2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;; +2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;; +2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;; +226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;; +226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;; +226C;BETWEEN;Sm;0;ON;;;;;N;;;;; +226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;; +226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;; +226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;; +2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;; +2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;; +2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;; +2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;; +2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;; +2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;; +2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;; +2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;; +2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;; +2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;; +227A;PRECEDES;Sm;0;ON;;;;;Y;;;;; +227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;; +2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;; +2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;; +2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;; +2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;; +2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;; +2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;; +2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;; +228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;; +228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;; +228C;MULTISET;Sm;0;ON;;;;;Y;;;;; +228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;; +228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;; +228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;; +2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; +2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;; +2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;; +2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;; +2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;; +2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;; +2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;; +2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;; +229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;; +229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;; +229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;; +229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;; +229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;; +22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;; +22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;; +22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;; +22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;; +22A5;UP TACK;Sm;0;ON;;;;;N;;;;; +22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;; +22A7;MODELS;Sm;0;ON;;;;;Y;;;;; +22A8;TRUE;Sm;0;ON;;;;;Y;;;;; +22A9;FORCES;Sm;0;ON;;;;;Y;;;;; +22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;; +22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;; +22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;; +22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;; +22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;; +22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;; +22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;; +22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;; +22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;; +22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;; +22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;; +22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;; +22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;; +22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;; +22BB;XOR;Sm;0;ON;;;;;N;;;;; +22BC;NAND;Sm;0;ON;;;;;N;;;;; +22BD;NOR;Sm;0;ON;;;;;N;;;;; +22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;; +22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;; +22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;; +22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;; +22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;; +22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;; +22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;; +22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;; +22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;; +22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;; +22C8;BOWTIE;Sm;0;ON;;;;;N;;;;; +22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;; +22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;; +22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;; +22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;; +22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;; +22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;; +22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;; +22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;; +22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;; +22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;; +22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;; +22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;; +22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;; +22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;; +22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;; +22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;; +22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;; +22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;; +22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;; +22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;; +22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;; +22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;; +22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;; +22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;; +22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;; +22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;; +22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;; +22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;; +22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;; +22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;; +22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;; +22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;; +22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; +22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;; +22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; +22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;; +2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;; +2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;; +2302;HOUSE;So;0;ON;;;;;N;;;;; +2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;; +2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;; +2305;PROJECTIVE;So;0;ON;;;;;N;;;;; +2306;PERSPECTIVE;So;0;ON;;;;;N;;;;; +2307;WAVY LINE;So;0;ON;;;;;N;;;;; +2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;; +2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;; +230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;; +230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;; +230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;; +230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;; +230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;; +230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;; +2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;; +2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;; +2312;ARC;So;0;ON;;;;;N;;;;; +2313;SEGMENT;So;0;ON;;;;;N;;;;; +2314;SECTOR;So;0;ON;;;;;N;;;;; +2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;; +2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;; +2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;; +2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;; +2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;; +231A;WATCH;So;0;ON;;;;;N;;;;; +231B;HOURGLASS;So;0;ON;;;;;N;;;;; +231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;; +231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;; +231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;; +231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;; +2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;; +2322;FROWN;So;0;ON;;;;;N;;;;; +2323;SMILE;So;0;ON;;;;;N;;;;; +2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;; +2325;OPTION KEY;So;0;ON;;;;;N;;;;; +2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;; +2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;; +2328;KEYBOARD;So;0;ON;;;;;N;;;;; +2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;; +232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;; +232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;; +232C;BENZENE RING;So;0;ON;;;;;N;;;;; +232D;CYLINDRICITY;So;0;ON;;;;;N;;;;; +232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;; +232F;SYMMETRY;So;0;ON;;;;;N;;;;; +2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;; +2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;; +2332;CONICAL TAPER;So;0;ON;;;;;N;;;;; +2333;SLOPE;So;0;ON;;;;;N;;;;; +2334;COUNTERBORE;So;0;ON;;;;;N;;;;; +2335;COUNTERSINK;So;0;ON;;;;;N;;;;; +2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;; +2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;; +2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;; +2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;; +233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;; +233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;; +233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;; +233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;; +233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;; +233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;; +2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;; +2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;; +2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;; +2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;; +2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;; +2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;; +2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;; +2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;; +2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;; +2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;; +234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;*;;; +234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;; +234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;; +234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;; +234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;*;;; +234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;; +2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;; +2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;*;;; +2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;; +2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;; +2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;; +2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;*;;; +2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;; +2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;; +2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;; +2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;; +235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;; +235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;; +235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;; +235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;; +235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;; +235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;; +2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;; +2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;*;;; +2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;; +2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;; +2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;; +2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;; +2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;; +2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;; +2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;; +2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;; +236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;; +236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;; +236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;; +236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;; +236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;; +236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;; +2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;; +2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;; +2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;; +2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;; +2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;; +2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;; +2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;; +2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;; +2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;; +2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;; +237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;; +237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;; +237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;; +237E;BELL SYMBOL;So;0;ON;;;;;N;;;;; +237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;; +2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;; +2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; +2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;; +2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;; +2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;; +2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;; +2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;; +2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;; +2388;HELM SYMBOL;So;0;ON;;;;;N;;;;; +2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;pause;;; +238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;break;;; +238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;escape;;; +238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;; +238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;; +238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;; +238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;; +2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;; +2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; +2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;; +2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;; +2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;; +2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;; +2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;; +2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;; +2398;NEXT PAGE;So;0;ON;;;;;N;;;;; +2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;; +239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;; +2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; +2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; +2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; +2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;; +2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;; +2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;; +2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;; +2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;; +2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;; +2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;; +240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;; +240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;; +240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;; +240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;; +240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;; +240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;; +2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;; +2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;; +2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;; +2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;; +2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;; +2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;; +2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;; +2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;; +2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;; +2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;; +241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;; +241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;; +241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;; +241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;; +241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;; +241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;; +2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;; +2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;; +2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;; +2423;OPEN BOX;So;0;ON;;;;;N;;;;; +2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;; +2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;; +2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;; +2440;OCR HOOK;So;0;ON;;;;;N;;;;; +2441;OCR CHAIR;So;0;ON;;;;;N;;;;; +2442;OCR FORK;So;0;ON;;;;;N;;;;; +2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;; +2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;; +2445;OCR BOW TIE;So;0;ON;;;;;N;;;;; +2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;; +2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;; +2448;OCR DASH;So;0;ON;;;;;N;;;;; +2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;; +244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;; +2460;CIRCLED DIGIT ONE;No;0;EN; 0031;;1;1;N;;;;; +2461;CIRCLED DIGIT TWO;No;0;EN; 0032;;2;2;N;;;;; +2462;CIRCLED DIGIT THREE;No;0;EN; 0033;;3;3;N;;;;; +2463;CIRCLED DIGIT FOUR;No;0;EN; 0034;;4;4;N;;;;; +2464;CIRCLED DIGIT FIVE;No;0;EN; 0035;;5;5;N;;;;; +2465;CIRCLED DIGIT SIX;No;0;EN; 0036;;6;6;N;;;;; +2466;CIRCLED DIGIT SEVEN;No;0;EN; 0037;;7;7;N;;;;; +2467;CIRCLED DIGIT EIGHT;No;0;EN; 0038;;8;8;N;;;;; +2468;CIRCLED DIGIT NINE;No;0;EN; 0039;;9;9;N;;;;; +2469;CIRCLED NUMBER TEN;No;0;EN; 0031 0030;;;10;N;;;;; +246A;CIRCLED NUMBER ELEVEN;No;0;EN; 0031 0031;;;11;N;;;;; +246B;CIRCLED NUMBER TWELVE;No;0;EN; 0031 0032;;;12;N;;;;; +246C;CIRCLED NUMBER THIRTEEN;No;0;EN; 0031 0033;;;13;N;;;;; +246D;CIRCLED NUMBER FOURTEEN;No;0;EN; 0031 0034;;;14;N;;;;; +246E;CIRCLED NUMBER FIFTEEN;No;0;EN; 0031 0035;;;15;N;;;;; +246F;CIRCLED NUMBER SIXTEEN;No;0;EN; 0031 0036;;;16;N;;;;; +2470;CIRCLED NUMBER SEVENTEEN;No;0;EN; 0031 0037;;;17;N;;;;; +2471;CIRCLED NUMBER EIGHTEEN;No;0;EN; 0031 0038;;;18;N;;;;; +2472;CIRCLED NUMBER NINETEEN;No;0;EN; 0031 0039;;;19;N;;;;; +2473;CIRCLED NUMBER TWENTY;No;0;EN; 0032 0030;;;20;N;;;;; +2474;PARENTHESIZED DIGIT ONE;No;0;EN; 0028 0031 0029;;1;1;N;;;;; +2475;PARENTHESIZED DIGIT TWO;No;0;EN; 0028 0032 0029;;2;2;N;;;;; +2476;PARENTHESIZED DIGIT THREE;No;0;EN; 0028 0033 0029;;3;3;N;;;;; +2477;PARENTHESIZED DIGIT FOUR;No;0;EN; 0028 0034 0029;;4;4;N;;;;; +2478;PARENTHESIZED DIGIT FIVE;No;0;EN; 0028 0035 0029;;5;5;N;;;;; +2479;PARENTHESIZED DIGIT SIX;No;0;EN; 0028 0036 0029;;6;6;N;;;;; +247A;PARENTHESIZED DIGIT SEVEN;No;0;EN; 0028 0037 0029;;7;7;N;;;;; +247B;PARENTHESIZED DIGIT EIGHT;No;0;EN; 0028 0038 0029;;8;8;N;;;;; +247C;PARENTHESIZED DIGIT NINE;No;0;EN; 0028 0039 0029;;9;9;N;;;;; +247D;PARENTHESIZED NUMBER TEN;No;0;EN; 0028 0031 0030 0029;;;10;N;;;;; +247E;PARENTHESIZED NUMBER ELEVEN;No;0;EN; 0028 0031 0031 0029;;;11;N;;;;; +247F;PARENTHESIZED NUMBER TWELVE;No;0;EN; 0028 0031 0032 0029;;;12;N;;;;; +2480;PARENTHESIZED NUMBER THIRTEEN;No;0;EN; 0028 0031 0033 0029;;;13;N;;;;; +2481;PARENTHESIZED NUMBER FOURTEEN;No;0;EN; 0028 0031 0034 0029;;;14;N;;;;; +2482;PARENTHESIZED NUMBER FIFTEEN;No;0;EN; 0028 0031 0035 0029;;;15;N;;;;; +2483;PARENTHESIZED NUMBER SIXTEEN;No;0;EN; 0028 0031 0036 0029;;;16;N;;;;; +2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;EN; 0028 0031 0037 0029;;;17;N;;;;; +2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;EN; 0028 0031 0038 0029;;;18;N;;;;; +2486;PARENTHESIZED NUMBER NINETEEN;No;0;EN; 0028 0031 0039 0029;;;19;N;;;;; +2487;PARENTHESIZED NUMBER TWENTY;No;0;EN; 0028 0032 0030 0029;;;20;N;;;;; +2488;DIGIT ONE FULL STOP;No;0;EN; 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;; +2489;DIGIT TWO FULL STOP;No;0;EN; 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;; +248A;DIGIT THREE FULL STOP;No;0;EN; 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;; +248B;DIGIT FOUR FULL STOP;No;0;EN; 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;; +248C;DIGIT FIVE FULL STOP;No;0;EN; 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;; +248D;DIGIT SIX FULL STOP;No;0;EN; 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;; +248E;DIGIT SEVEN FULL STOP;No;0;EN; 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;; +248F;DIGIT EIGHT FULL STOP;No;0;EN; 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;; +2490;DIGIT NINE FULL STOP;No;0;EN; 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;; +2491;NUMBER TEN FULL STOP;No;0;EN; 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;; +2492;NUMBER ELEVEN FULL STOP;No;0;EN; 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;; +2493;NUMBER TWELVE FULL STOP;No;0;EN; 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;; +2494;NUMBER THIRTEEN FULL STOP;No;0;EN; 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;; +2495;NUMBER FOURTEEN FULL STOP;No;0;EN; 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;; +2496;NUMBER FIFTEEN FULL STOP;No;0;EN; 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;; +2497;NUMBER SIXTEEN FULL STOP;No;0;EN; 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;; +2498;NUMBER SEVENTEEN FULL STOP;No;0;EN; 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;; +2499;NUMBER EIGHTEEN FULL STOP;No;0;EN; 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;; +249A;NUMBER NINETEEN FULL STOP;No;0;EN; 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;; +249B;NUMBER TWENTY FULL STOP;No;0;EN; 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;; +249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L; 0028 0061 0029;;;;N;;;;; +249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L; 0028 0062 0029;;;;N;;;;; +249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L; 0028 0063 0029;;;;N;;;;; +249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L; 0028 0064 0029;;;;N;;;;; +24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L; 0028 0065 0029;;;;N;;;;; +24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L; 0028 0066 0029;;;;N;;;;; +24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L; 0028 0067 0029;;;;N;;;;; +24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L; 0028 0068 0029;;;;N;;;;; +24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L; 0028 0069 0029;;;;N;;;;; +24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L; 0028 006A 0029;;;;N;;;;; +24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L; 0028 006B 0029;;;;N;;;;; +24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L; 0028 006C 0029;;;;N;;;;; +24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L; 0028 006D 0029;;;;N;;;;; +24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L; 0028 006E 0029;;;;N;;;;; +24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L; 0028 006F 0029;;;;N;;;;; +24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L; 0028 0070 0029;;;;N;;;;; +24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L; 0028 0071 0029;;;;N;;;;; +24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L; 0028 0072 0029;;;;N;;;;; +24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L; 0028 0073 0029;;;;N;;;;; +24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L; 0028 0074 0029;;;;N;;;;; +24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L; 0028 0075 0029;;;;N;;;;; +24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L; 0028 0076 0029;;;;N;;;;; +24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L; 0028 0077 0029;;;;N;;;;; +24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L; 0028 0078 0029;;;;N;;;;; +24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L; 0028 0079 0029;;;;N;;;;; +24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L; 0028 007A 0029;;;;N;;;;; +24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L; 0041;;;;N;;;;24D0; +24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L; 0042;;;;N;;;;24D1; +24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L; 0043;;;;N;;;;24D2; +24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L; 0044;;;;N;;;;24D3; +24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L; 0045;;;;N;;;;24D4; +24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L; 0046;;;;N;;;;24D5; +24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L; 0047;;;;N;;;;24D6; +24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L; 0048;;;;N;;;;24D7; +24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L; 0049;;;;N;;;;24D8; +24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L; 004A;;;;N;;;;24D9; +24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L; 004B;;;;N;;;;24DA; +24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L; 004C;;;;N;;;;24DB; +24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L; 004D;;;;N;;;;24DC; +24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L; 004E;;;;N;;;;24DD; +24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L; 004F;;;;N;;;;24DE; +24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L; 0050;;;;N;;;;24DF; +24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L; 0051;;;;N;;;;24E0; +24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L; 0052;;;;N;;;;24E1; +24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L; 0053;;;;N;;;;24E2; +24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L; 0054;;;;N;;;;24E3; +24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L; 0055;;;;N;;;;24E4; +24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L; 0056;;;;N;;;;24E5; +24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L; 0057;;;;N;;;;24E6; +24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L; 0058;;;;N;;;;24E7; +24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L; 0059;;;;N;;;;24E8; +24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L; 005A;;;;N;;;;24E9; +24D0;CIRCLED LATIN SMALL LETTER A;So;0;L; 0061;;;;N;;;24B6;;24B6 +24D1;CIRCLED LATIN SMALL LETTER B;So;0;L; 0062;;;;N;;;24B7;;24B7 +24D2;CIRCLED LATIN SMALL LETTER C;So;0;L; 0063;;;;N;;;24B8;;24B8 +24D3;CIRCLED LATIN SMALL LETTER D;So;0;L; 0064;;;;N;;;24B9;;24B9 +24D4;CIRCLED LATIN SMALL LETTER E;So;0;L; 0065;;;;N;;;24BA;;24BA +24D5;CIRCLED LATIN SMALL LETTER F;So;0;L; 0066;;;;N;;;24BB;;24BB +24D6;CIRCLED LATIN SMALL LETTER G;So;0;L; 0067;;;;N;;;24BC;;24BC +24D7;CIRCLED LATIN SMALL LETTER H;So;0;L; 0068;;;;N;;;24BD;;24BD +24D8;CIRCLED LATIN SMALL LETTER I;So;0;L; 0069;;;;N;;;24BE;;24BE +24D9;CIRCLED LATIN SMALL LETTER J;So;0;L; 006A;;;;N;;;24BF;;24BF +24DA;CIRCLED LATIN SMALL LETTER K;So;0;L; 006B;;;;N;;;24C0;;24C0 +24DB;CIRCLED LATIN SMALL LETTER L;So;0;L; 006C;;;;N;;;24C1;;24C1 +24DC;CIRCLED LATIN SMALL LETTER M;So;0;L; 006D;;;;N;;;24C2;;24C2 +24DD;CIRCLED LATIN SMALL LETTER N;So;0;L; 006E;;;;N;;;24C3;;24C3 +24DE;CIRCLED LATIN SMALL LETTER O;So;0;L; 006F;;;;N;;;24C4;;24C4 +24DF;CIRCLED LATIN SMALL LETTER P;So;0;L; 0070;;;;N;;;24C5;;24C5 +24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L; 0071;;;;N;;;24C6;;24C6 +24E1;CIRCLED LATIN SMALL LETTER R;So;0;L; 0072;;;;N;;;24C7;;24C7 +24E2;CIRCLED LATIN SMALL LETTER S;So;0;L; 0073;;;;N;;;24C8;;24C8 +24E3;CIRCLED LATIN SMALL LETTER T;So;0;L; 0074;;;;N;;;24C9;;24C9 +24E4;CIRCLED LATIN SMALL LETTER U;So;0;L; 0075;;;;N;;;24CA;;24CA +24E5;CIRCLED LATIN SMALL LETTER V;So;0;L; 0076;;;;N;;;24CB;;24CB +24E6;CIRCLED LATIN SMALL LETTER W;So;0;L; 0077;;;;N;;;24CC;;24CC +24E7;CIRCLED LATIN SMALL LETTER X;So;0;L; 0078;;;;N;;;24CD;;24CD +24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L; 0079;;;;N;;;24CE;;24CE +24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L; 007A;;;;N;;;24CF;;24CF +24EA;CIRCLED DIGIT ZERO;No;0;EN; 0030;;0;0;N;;;;; +2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;; +2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;; +2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;; +2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;; +2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;; +2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;; +2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;; +2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;; +2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;; +2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;; +250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;; +250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;; +250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;; +250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;; +250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;; +250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;; +2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;; +2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;; +2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;; +2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;; +2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;; +2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;; +2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;; +2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;; +2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;; +2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;; +251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;; +251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;; +251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;; +251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;; +251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;; +251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;; +2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;; +2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;; +2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;; +2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;; +2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;; +2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;; +2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;; +2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;; +2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;; +2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;; +252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;; +252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;; +252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;; +252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;; +252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;; +252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;; +2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;; +2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;; +2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;; +2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;; +2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;; +2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;; +2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;; +2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;; +2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;; +2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;; +253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;; +253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;; +253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;; +253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;; +253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;; +253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;; +2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;; +2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;; +2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;; +2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;; +2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;; +2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;; +2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;; +2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;; +2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;; +2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;; +254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;; +254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;; +254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;; +254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;; +254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;; +254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;; +2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;; +2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;; +2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;; +2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;; +2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;; +2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;; +2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;; +2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;; +2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;; +2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;; +255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;; +255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;; +255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;; +255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;; +255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;; +255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;; +2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;; +2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;; +2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;; +2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;; +2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;; +2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;; +2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;; +2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;; +2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;; +2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;; +256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;; +256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;; +256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;; +256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;; +256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;; +256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;; +2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;; +2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;; +2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;; +2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;; +2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;; +2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;; +2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;; +2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;; +2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;; +2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;; +257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;; +257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;; +257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;; +257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;; +257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;; +257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;; +2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;; +2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;; +2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;; +2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +2588;FULL BLOCK;So;0;ON;;;;;N;;;;; +2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;; +258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;; +258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;; +258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;; +258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;; +2591;LIGHT SHADE;So;0;ON;;;;;N;;;;; +2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;; +2593;DARK SHADE;So;0;ON;;;;;N;;;;; +2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;; +25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;; +25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;; +25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;; +25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;; +25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; +25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;; +25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;; +25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;; +25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;; +25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;; +25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;; +25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;; +25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; +25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;; +25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;; +25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;; +25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;; +25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;; +25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;; +25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;; +25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;; +25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;; +25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;; +25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;; +25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;; +25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;; +25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;; +25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;; +25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;; +25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;; +25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;; +25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;; +25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;; +25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;; +25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;; +25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;; +25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;; +25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;; +25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;; +25C9;FISHEYE;So;0;ON;;;;;N;;;;; +25CA;LOZENGE;So;0;ON;;;;;N;;;;; +25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;; +25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;; +25CE;BULLSEYE;So;0;ON;;;;;N;;;;; +25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;; +25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;; +25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;; +25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;; +25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;; +25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;; +25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;; +25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;; +25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;; +25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;; +25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; +25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;; +25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;; +25E6;WHITE BULLET;So;0;ON;;;;;N;;;;; +25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;; +25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;; +25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;; +25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;; +25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;; +25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;; +25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;; +25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;; +25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;; +25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;; +2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;; +2601;CLOUD;So;0;ON;;;;;N;;;;; +2602;UMBRELLA;So;0;ON;;;;;N;;;;; +2603;SNOWMAN;So;0;ON;;;;;N;;;;; +2604;COMET;So;0;ON;;;;;N;;;;; +2605;BLACK STAR;So;0;ON;;;;;N;;;;; +2606;WHITE STAR;So;0;ON;;;;;N;;;;; +2607;LIGHTNING;So;0;ON;;;;;N;;;;; +2608;THUNDERSTORM;So;0;ON;;;;;N;;;;; +2609;SUN;So;0;ON;;;;;N;;;;; +260A;ASCENDING NODE;So;0;ON;;;;;N;;;;; +260B;DESCENDING NODE;So;0;ON;;;;;N;;;;; +260C;CONJUNCTION;So;0;ON;;;;;N;;;;; +260D;OPPOSITION;So;0;ON;;;;;N;;;;; +260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;; +260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;; +2610;BALLOT BOX;So;0;ON;;;;;N;;;;; +2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;; +2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;; +2613;SALTIRE;So;0;ON;;;;;N;;;;; +2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; +261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;; +261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;; +261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;; +261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; +2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;; +2621;CAUTION SIGN;So;0;ON;;;;;N;;;;; +2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;; +2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;; +2624;CADUCEUS;So;0;ON;;;;;N;;;;; +2625;ANKH;So;0;ON;;;;;N;;;;; +2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;; +2627;CHI RHO;So;0;ON;;;;;N;;;;; +2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;; +2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;; +262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;; +262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;; +262C;ADI SHAKTI;So;0;ON;;;;;N;;;;; +262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;; +262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;; +262F;YIN YANG;So;0;ON;;;;;N;;;;; +2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;; +2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;; +2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;; +2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;; +2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;; +2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;; +2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;; +2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;; +2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;; +2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;; +263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;; +263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;; +263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;; +263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;; +263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;; +263F;MERCURY;So;0;ON;;;;;N;;;;; +2640;FEMALE SIGN;So;0;ON;;;;;N;;;;; +2641;EARTH;So;0;ON;;;;;N;;;;; +2642;MALE SIGN;So;0;ON;;;;;N;;;;; +2643;JUPITER;So;0;ON;;;;;N;;;;; +2644;SATURN;So;0;ON;;;;;N;;;;; +2645;URANUS;So;0;ON;;;;;N;;;;; +2646;NEPTUNE;So;0;ON;;;;;N;;;;; +2647;PLUTO;So;0;ON;;;;;N;;;;; +2648;ARIES;So;0;ON;;;;;N;;;;; +2649;TAURUS;So;0;ON;;;;;N;;;;; +264A;GEMINI;So;0;ON;;;;;N;;;;; +264B;CANCER;So;0;ON;;;;;N;;;;; +264C;LEO;So;0;ON;;;;;N;;;;; +264D;VIRGO;So;0;ON;;;;;N;;;;; +264E;LIBRA;So;0;ON;;;;;N;;;;; +264F;SCORPIUS;So;0;ON;;;;;N;;;;; +2650;SAGITTARIUS;So;0;ON;;;;;N;;;;; +2651;CAPRICORN;So;0;ON;;;;;N;;;;; +2652;AQUARIUS;So;0;ON;;;;;N;;;;; +2653;PISCES;So;0;ON;;;;;N;;;;; +2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;; +2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;; +2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;; +2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;; +2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;; +2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;; +265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;; +265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;; +265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;; +265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;; +265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;; +265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;; +2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;; +2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;; +2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;; +2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;; +2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;; +2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;; +2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;; +2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;; +2668;HOT SPRINGS;So;0;ON;;;;;N;;;;; +2669;QUARTER NOTE;So;0;ON;;;;;N;;;;; +266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;; +266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;; +266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;; +266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;; +266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;; +266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;; +2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;; +2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;; +2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;; +2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;; +2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;; +2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;; +2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;; +2707;TAPE DRIVE;So;0;ON;;;;;N;;;;; +2708;AIRPLANE;So;0;ON;;;;;N;;;;; +2709;ENVELOPE;So;0;ON;;;;;N;;;;; +270C;VICTORY HAND;So;0;ON;;;;;N;;;;; +270D;WRITING HAND;So;0;ON;;;;;N;;;;; +270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;; +270F;PENCIL;So;0;ON;;;;;N;;;;; +2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;; +2711;WHITE NIB;So;0;ON;;;;;N;;;;; +2712;BLACK NIB;So;0;ON;;;;;N;;;;; +2713;CHECK MARK;So;0;ON;;;;;N;;;;; +2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;; +2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;; +2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;; +2717;BALLOT X;So;0;ON;;;;;N;;;;; +2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;; +2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;; +271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;; +271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;; +271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;; +271D;LATIN CROSS;So;0;ON;;;;;N;;;;; +271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;; +271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;; +2720;MALTESE CROSS;So;0;ON;;;;;N;;;;; +2721;STAR OF DAVID;So;0;ON;;;;;N;;;;; +2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;; +2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;; +272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;; +272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;; +272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;; +272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; +272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;; +272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;; +2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;; +2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;; +2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;; +2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;; +2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; +2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;; +2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;; +273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;; +273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;; +273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;; +273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;; +2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;; +2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;; +2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;; +2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;; +2744;SNOWFLAKE;So;0;ON;;;;;N;;;;; +2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;; +2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;; +2747;SPARKLE;So;0;ON;;;;;N;;;;; +2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;; +2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;; +274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;; +274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;; +274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;; +2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;; +2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;; +2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;; +275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;; +275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;; +2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;; +2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;; +2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;; +2766;FLORAL HEART;So;0;ON;;;;;N;;;;; +2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;; +2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;; +2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;; +2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;; +2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;; +277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;; +277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;; +277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;; +277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;; +277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;; +277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;; +2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;; +2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;; +2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;; +2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;; +2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;; +2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;; +2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;; +2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;; +2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;; +2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;; +278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;; +278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;; +278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;; +278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;; +278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;; +278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;; +2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;; +2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;; +2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;; +2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;; +2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;; +2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;; +2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;; +279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;; +279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;; +279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;; +279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;; +279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;; +279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;; +27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;; +27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;; +27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;; +27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;; +27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;; +27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;; +27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;; +27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;; +27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;; +27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;; +27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;; +27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;; +27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;; +27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;; +27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;; +27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;; +27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;; +27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;; +27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;; +27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;; +27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;; +27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;; +27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;; +27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;; +27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;; +27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;; +27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;; +2800;BRAILLE PATTERN BLANK;So;0;ON;;;;;N;;;;; +2801;BRAILLE PATTERN DOTS-1;So;0;ON;;;;;N;;;;; +2802;BRAILLE PATTERN DOTS-2;So;0;ON;;;;;N;;;;; +2803;BRAILLE PATTERN DOTS-12;So;0;ON;;;;;N;;;;; +2804;BRAILLE PATTERN DOTS-3;So;0;ON;;;;;N;;;;; +2805;BRAILLE PATTERN DOTS-13;So;0;ON;;;;;N;;;;; +2806;BRAILLE PATTERN DOTS-23;So;0;ON;;;;;N;;;;; +2807;BRAILLE PATTERN DOTS-123;So;0;ON;;;;;N;;;;; +2808;BRAILLE PATTERN DOTS-4;So;0;ON;;;;;N;;;;; +2809;BRAILLE PATTERN DOTS-14;So;0;ON;;;;;N;;;;; +280A;BRAILLE PATTERN DOTS-24;So;0;ON;;;;;N;;;;; +280B;BRAILLE PATTERN DOTS-124;So;0;ON;;;;;N;;;;; +280C;BRAILLE PATTERN DOTS-34;So;0;ON;;;;;N;;;;; +280D;BRAILLE PATTERN DOTS-134;So;0;ON;;;;;N;;;;; +280E;BRAILLE PATTERN DOTS-234;So;0;ON;;;;;N;;;;; +280F;BRAILLE PATTERN DOTS-1234;So;0;ON;;;;;N;;;;; +2810;BRAILLE PATTERN DOTS-5;So;0;ON;;;;;N;;;;; +2811;BRAILLE PATTERN DOTS-15;So;0;ON;;;;;N;;;;; +2812;BRAILLE PATTERN DOTS-25;So;0;ON;;;;;N;;;;; +2813;BRAILLE PATTERN DOTS-125;So;0;ON;;;;;N;;;;; +2814;BRAILLE PATTERN DOTS-35;So;0;ON;;;;;N;;;;; +2815;BRAILLE PATTERN DOTS-135;So;0;ON;;;;;N;;;;; +2816;BRAILLE PATTERN DOTS-235;So;0;ON;;;;;N;;;;; +2817;BRAILLE PATTERN DOTS-1235;So;0;ON;;;;;N;;;;; +2818;BRAILLE PATTERN DOTS-45;So;0;ON;;;;;N;;;;; +2819;BRAILLE PATTERN DOTS-145;So;0;ON;;;;;N;;;;; +281A;BRAILLE PATTERN DOTS-245;So;0;ON;;;;;N;;;;; +281B;BRAILLE PATTERN DOTS-1245;So;0;ON;;;;;N;;;;; +281C;BRAILLE PATTERN DOTS-345;So;0;ON;;;;;N;;;;; +281D;BRAILLE PATTERN DOTS-1345;So;0;ON;;;;;N;;;;; +281E;BRAILLE PATTERN DOTS-2345;So;0;ON;;;;;N;;;;; +281F;BRAILLE PATTERN DOTS-12345;So;0;ON;;;;;N;;;;; +2820;BRAILLE PATTERN DOTS-6;So;0;ON;;;;;N;;;;; +2821;BRAILLE PATTERN DOTS-16;So;0;ON;;;;;N;;;;; +2822;BRAILLE PATTERN DOTS-26;So;0;ON;;;;;N;;;;; +2823;BRAILLE PATTERN DOTS-126;So;0;ON;;;;;N;;;;; +2824;BRAILLE PATTERN DOTS-36;So;0;ON;;;;;N;;;;; +2825;BRAILLE PATTERN DOTS-136;So;0;ON;;;;;N;;;;; +2826;BRAILLE PATTERN DOTS-236;So;0;ON;;;;;N;;;;; +2827;BRAILLE PATTERN DOTS-1236;So;0;ON;;;;;N;;;;; +2828;BRAILLE PATTERN DOTS-46;So;0;ON;;;;;N;;;;; +2829;BRAILLE PATTERN DOTS-146;So;0;ON;;;;;N;;;;; +282A;BRAILLE PATTERN DOTS-246;So;0;ON;;;;;N;;;;; +282B;BRAILLE PATTERN DOTS-1246;So;0;ON;;;;;N;;;;; +282C;BRAILLE PATTERN DOTS-346;So;0;ON;;;;;N;;;;; +282D;BRAILLE PATTERN DOTS-1346;So;0;ON;;;;;N;;;;; +282E;BRAILLE PATTERN DOTS-2346;So;0;ON;;;;;N;;;;; +282F;BRAILLE PATTERN DOTS-12346;So;0;ON;;;;;N;;;;; +2830;BRAILLE PATTERN DOTS-56;So;0;ON;;;;;N;;;;; +2831;BRAILLE PATTERN DOTS-156;So;0;ON;;;;;N;;;;; +2832;BRAILLE PATTERN DOTS-256;So;0;ON;;;;;N;;;;; +2833;BRAILLE PATTERN DOTS-1256;So;0;ON;;;;;N;;;;; +2834;BRAILLE PATTERN DOTS-356;So;0;ON;;;;;N;;;;; +2835;BRAILLE PATTERN DOTS-1356;So;0;ON;;;;;N;;;;; +2836;BRAILLE PATTERN DOTS-2356;So;0;ON;;;;;N;;;;; +2837;BRAILLE PATTERN DOTS-12356;So;0;ON;;;;;N;;;;; +2838;BRAILLE PATTERN DOTS-456;So;0;ON;;;;;N;;;;; +2839;BRAILLE PATTERN DOTS-1456;So;0;ON;;;;;N;;;;; +283A;BRAILLE PATTERN DOTS-2456;So;0;ON;;;;;N;;;;; +283B;BRAILLE PATTERN DOTS-12456;So;0;ON;;;;;N;;;;; +283C;BRAILLE PATTERN DOTS-3456;So;0;ON;;;;;N;;;;; +283D;BRAILLE PATTERN DOTS-13456;So;0;ON;;;;;N;;;;; +283E;BRAILLE PATTERN DOTS-23456;So;0;ON;;;;;N;;;;; +283F;BRAILLE PATTERN DOTS-123456;So;0;ON;;;;;N;;;;; +2840;BRAILLE PATTERN DOTS-7;So;0;ON;;;;;N;;;;; +2841;BRAILLE PATTERN DOTS-17;So;0;ON;;;;;N;;;;; +2842;BRAILLE PATTERN DOTS-27;So;0;ON;;;;;N;;;;; +2843;BRAILLE PATTERN DOTS-127;So;0;ON;;;;;N;;;;; +2844;BRAILLE PATTERN DOTS-37;So;0;ON;;;;;N;;;;; +2845;BRAILLE PATTERN DOTS-137;So;0;ON;;;;;N;;;;; +2846;BRAILLE PATTERN DOTS-237;So;0;ON;;;;;N;;;;; +2847;BRAILLE PATTERN DOTS-1237;So;0;ON;;;;;N;;;;; +2848;BRAILLE PATTERN DOTS-47;So;0;ON;;;;;N;;;;; +2849;BRAILLE PATTERN DOTS-147;So;0;ON;;;;;N;;;;; +284A;BRAILLE PATTERN DOTS-247;So;0;ON;;;;;N;;;;; +284B;BRAILLE PATTERN DOTS-1247;So;0;ON;;;;;N;;;;; +284C;BRAILLE PATTERN DOTS-347;So;0;ON;;;;;N;;;;; +284D;BRAILLE PATTERN DOTS-1347;So;0;ON;;;;;N;;;;; +284E;BRAILLE PATTERN DOTS-2347;So;0;ON;;;;;N;;;;; +284F;BRAILLE PATTERN DOTS-12347;So;0;ON;;;;;N;;;;; +2850;BRAILLE PATTERN DOTS-57;So;0;ON;;;;;N;;;;; +2851;BRAILLE PATTERN DOTS-157;So;0;ON;;;;;N;;;;; +2852;BRAILLE PATTERN DOTS-257;So;0;ON;;;;;N;;;;; +2853;BRAILLE PATTERN DOTS-1257;So;0;ON;;;;;N;;;;; +2854;BRAILLE PATTERN DOTS-357;So;0;ON;;;;;N;;;;; +2855;BRAILLE PATTERN DOTS-1357;So;0;ON;;;;;N;;;;; +2856;BRAILLE PATTERN DOTS-2357;So;0;ON;;;;;N;;;;; +2857;BRAILLE PATTERN DOTS-12357;So;0;ON;;;;;N;;;;; +2858;BRAILLE PATTERN DOTS-457;So;0;ON;;;;;N;;;;; +2859;BRAILLE PATTERN DOTS-1457;So;0;ON;;;;;N;;;;; +285A;BRAILLE PATTERN DOTS-2457;So;0;ON;;;;;N;;;;; +285B;BRAILLE PATTERN DOTS-12457;So;0;ON;;;;;N;;;;; +285C;BRAILLE PATTERN DOTS-3457;So;0;ON;;;;;N;;;;; +285D;BRAILLE PATTERN DOTS-13457;So;0;ON;;;;;N;;;;; +285E;BRAILLE PATTERN DOTS-23457;So;0;ON;;;;;N;;;;; +285F;BRAILLE PATTERN DOTS-123457;So;0;ON;;;;;N;;;;; +2860;BRAILLE PATTERN DOTS-67;So;0;ON;;;;;N;;;;; +2861;BRAILLE PATTERN DOTS-167;So;0;ON;;;;;N;;;;; +2862;BRAILLE PATTERN DOTS-267;So;0;ON;;;;;N;;;;; +2863;BRAILLE PATTERN DOTS-1267;So;0;ON;;;;;N;;;;; +2864;BRAILLE PATTERN DOTS-367;So;0;ON;;;;;N;;;;; +2865;BRAILLE PATTERN DOTS-1367;So;0;ON;;;;;N;;;;; +2866;BRAILLE PATTERN DOTS-2367;So;0;ON;;;;;N;;;;; +2867;BRAILLE PATTERN DOTS-12367;So;0;ON;;;;;N;;;;; +2868;BRAILLE PATTERN DOTS-467;So;0;ON;;;;;N;;;;; +2869;BRAILLE PATTERN DOTS-1467;So;0;ON;;;;;N;;;;; +286A;BRAILLE PATTERN DOTS-2467;So;0;ON;;;;;N;;;;; +286B;BRAILLE PATTERN DOTS-12467;So;0;ON;;;;;N;;;;; +286C;BRAILLE PATTERN DOTS-3467;So;0;ON;;;;;N;;;;; +286D;BRAILLE PATTERN DOTS-13467;So;0;ON;;;;;N;;;;; +286E;BRAILLE PATTERN DOTS-23467;So;0;ON;;;;;N;;;;; +286F;BRAILLE PATTERN DOTS-123467;So;0;ON;;;;;N;;;;; +2870;BRAILLE PATTERN DOTS-567;So;0;ON;;;;;N;;;;; +2871;BRAILLE PATTERN DOTS-1567;So;0;ON;;;;;N;;;;; +2872;BRAILLE PATTERN DOTS-2567;So;0;ON;;;;;N;;;;; +2873;BRAILLE PATTERN DOTS-12567;So;0;ON;;;;;N;;;;; +2874;BRAILLE PATTERN DOTS-3567;So;0;ON;;;;;N;;;;; +2875;BRAILLE PATTERN DOTS-13567;So;0;ON;;;;;N;;;;; +2876;BRAILLE PATTERN DOTS-23567;So;0;ON;;;;;N;;;;; +2877;BRAILLE PATTERN DOTS-123567;So;0;ON;;;;;N;;;;; +2878;BRAILLE PATTERN DOTS-4567;So;0;ON;;;;;N;;;;; +2879;BRAILLE PATTERN DOTS-14567;So;0;ON;;;;;N;;;;; +287A;BRAILLE PATTERN DOTS-24567;So;0;ON;;;;;N;;;;; +287B;BRAILLE PATTERN DOTS-124567;So;0;ON;;;;;N;;;;; +287C;BRAILLE PATTERN DOTS-34567;So;0;ON;;;;;N;;;;; +287D;BRAILLE PATTERN DOTS-134567;So;0;ON;;;;;N;;;;; +287E;BRAILLE PATTERN DOTS-234567;So;0;ON;;;;;N;;;;; +287F;BRAILLE PATTERN DOTS-1234567;So;0;ON;;;;;N;;;;; +2880;BRAILLE PATTERN DOTS-8;So;0;ON;;;;;N;;;;; +2881;BRAILLE PATTERN DOTS-18;So;0;ON;;;;;N;;;;; +2882;BRAILLE PATTERN DOTS-28;So;0;ON;;;;;N;;;;; +2883;BRAILLE PATTERN DOTS-128;So;0;ON;;;;;N;;;;; +2884;BRAILLE PATTERN DOTS-38;So;0;ON;;;;;N;;;;; +2885;BRAILLE PATTERN DOTS-138;So;0;ON;;;;;N;;;;; +2886;BRAILLE PATTERN DOTS-238;So;0;ON;;;;;N;;;;; +2887;BRAILLE PATTERN DOTS-1238;So;0;ON;;;;;N;;;;; +2888;BRAILLE PATTERN DOTS-48;So;0;ON;;;;;N;;;;; +2889;BRAILLE PATTERN DOTS-148;So;0;ON;;;;;N;;;;; +288A;BRAILLE PATTERN DOTS-248;So;0;ON;;;;;N;;;;; +288B;BRAILLE PATTERN DOTS-1248;So;0;ON;;;;;N;;;;; +288C;BRAILLE PATTERN DOTS-348;So;0;ON;;;;;N;;;;; +288D;BRAILLE PATTERN DOTS-1348;So;0;ON;;;;;N;;;;; +288E;BRAILLE PATTERN DOTS-2348;So;0;ON;;;;;N;;;;; +288F;BRAILLE PATTERN DOTS-12348;So;0;ON;;;;;N;;;;; +2890;BRAILLE PATTERN DOTS-58;So;0;ON;;;;;N;;;;; +2891;BRAILLE PATTERN DOTS-158;So;0;ON;;;;;N;;;;; +2892;BRAILLE PATTERN DOTS-258;So;0;ON;;;;;N;;;;; +2893;BRAILLE PATTERN DOTS-1258;So;0;ON;;;;;N;;;;; +2894;BRAILLE PATTERN DOTS-358;So;0;ON;;;;;N;;;;; +2895;BRAILLE PATTERN DOTS-1358;So;0;ON;;;;;N;;;;; +2896;BRAILLE PATTERN DOTS-2358;So;0;ON;;;;;N;;;;; +2897;BRAILLE PATTERN DOTS-12358;So;0;ON;;;;;N;;;;; +2898;BRAILLE PATTERN DOTS-458;So;0;ON;;;;;N;;;;; +2899;BRAILLE PATTERN DOTS-1458;So;0;ON;;;;;N;;;;; +289A;BRAILLE PATTERN DOTS-2458;So;0;ON;;;;;N;;;;; +289B;BRAILLE PATTERN DOTS-12458;So;0;ON;;;;;N;;;;; +289C;BRAILLE PATTERN DOTS-3458;So;0;ON;;;;;N;;;;; +289D;BRAILLE PATTERN DOTS-13458;So;0;ON;;;;;N;;;;; +289E;BRAILLE PATTERN DOTS-23458;So;0;ON;;;;;N;;;;; +289F;BRAILLE PATTERN DOTS-123458;So;0;ON;;;;;N;;;;; +28A0;BRAILLE PATTERN DOTS-68;So;0;ON;;;;;N;;;;; +28A1;BRAILLE PATTERN DOTS-168;So;0;ON;;;;;N;;;;; +28A2;BRAILLE PATTERN DOTS-268;So;0;ON;;;;;N;;;;; +28A3;BRAILLE PATTERN DOTS-1268;So;0;ON;;;;;N;;;;; +28A4;BRAILLE PATTERN DOTS-368;So;0;ON;;;;;N;;;;; +28A5;BRAILLE PATTERN DOTS-1368;So;0;ON;;;;;N;;;;; +28A6;BRAILLE PATTERN DOTS-2368;So;0;ON;;;;;N;;;;; +28A7;BRAILLE PATTERN DOTS-12368;So;0;ON;;;;;N;;;;; +28A8;BRAILLE PATTERN DOTS-468;So;0;ON;;;;;N;;;;; +28A9;BRAILLE PATTERN DOTS-1468;So;0;ON;;;;;N;;;;; +28AA;BRAILLE PATTERN DOTS-2468;So;0;ON;;;;;N;;;;; +28AB;BRAILLE PATTERN DOTS-12468;So;0;ON;;;;;N;;;;; +28AC;BRAILLE PATTERN DOTS-3468;So;0;ON;;;;;N;;;;; +28AD;BRAILLE PATTERN DOTS-13468;So;0;ON;;;;;N;;;;; +28AE;BRAILLE PATTERN DOTS-23468;So;0;ON;;;;;N;;;;; +28AF;BRAILLE PATTERN DOTS-123468;So;0;ON;;;;;N;;;;; +28B0;BRAILLE PATTERN DOTS-568;So;0;ON;;;;;N;;;;; +28B1;BRAILLE PATTERN DOTS-1568;So;0;ON;;;;;N;;;;; +28B2;BRAILLE PATTERN DOTS-2568;So;0;ON;;;;;N;;;;; +28B3;BRAILLE PATTERN DOTS-12568;So;0;ON;;;;;N;;;;; +28B4;BRAILLE PATTERN DOTS-3568;So;0;ON;;;;;N;;;;; +28B5;BRAILLE PATTERN DOTS-13568;So;0;ON;;;;;N;;;;; +28B6;BRAILLE PATTERN DOTS-23568;So;0;ON;;;;;N;;;;; +28B7;BRAILLE PATTERN DOTS-123568;So;0;ON;;;;;N;;;;; +28B8;BRAILLE PATTERN DOTS-4568;So;0;ON;;;;;N;;;;; +28B9;BRAILLE PATTERN DOTS-14568;So;0;ON;;;;;N;;;;; +28BA;BRAILLE PATTERN DOTS-24568;So;0;ON;;;;;N;;;;; +28BB;BRAILLE PATTERN DOTS-124568;So;0;ON;;;;;N;;;;; +28BC;BRAILLE PATTERN DOTS-34568;So;0;ON;;;;;N;;;;; +28BD;BRAILLE PATTERN DOTS-134568;So;0;ON;;;;;N;;;;; +28BE;BRAILLE PATTERN DOTS-234568;So;0;ON;;;;;N;;;;; +28BF;BRAILLE PATTERN DOTS-1234568;So;0;ON;;;;;N;;;;; +28C0;BRAILLE PATTERN DOTS-78;So;0;ON;;;;;N;;;;; +28C1;BRAILLE PATTERN DOTS-178;So;0;ON;;;;;N;;;;; +28C2;BRAILLE PATTERN DOTS-278;So;0;ON;;;;;N;;;;; +28C3;BRAILLE PATTERN DOTS-1278;So;0;ON;;;;;N;;;;; +28C4;BRAILLE PATTERN DOTS-378;So;0;ON;;;;;N;;;;; +28C5;BRAILLE PATTERN DOTS-1378;So;0;ON;;;;;N;;;;; +28C6;BRAILLE PATTERN DOTS-2378;So;0;ON;;;;;N;;;;; +28C7;BRAILLE PATTERN DOTS-12378;So;0;ON;;;;;N;;;;; +28C8;BRAILLE PATTERN DOTS-478;So;0;ON;;;;;N;;;;; +28C9;BRAILLE PATTERN DOTS-1478;So;0;ON;;;;;N;;;;; +28CA;BRAILLE PATTERN DOTS-2478;So;0;ON;;;;;N;;;;; +28CB;BRAILLE PATTERN DOTS-12478;So;0;ON;;;;;N;;;;; +28CC;BRAILLE PATTERN DOTS-3478;So;0;ON;;;;;N;;;;; +28CD;BRAILLE PATTERN DOTS-13478;So;0;ON;;;;;N;;;;; +28CE;BRAILLE PATTERN DOTS-23478;So;0;ON;;;;;N;;;;; +28CF;BRAILLE PATTERN DOTS-123478;So;0;ON;;;;;N;;;;; +28D0;BRAILLE PATTERN DOTS-578;So;0;ON;;;;;N;;;;; +28D1;BRAILLE PATTERN DOTS-1578;So;0;ON;;;;;N;;;;; +28D2;BRAILLE PATTERN DOTS-2578;So;0;ON;;;;;N;;;;; +28D3;BRAILLE PATTERN DOTS-12578;So;0;ON;;;;;N;;;;; +28D4;BRAILLE PATTERN DOTS-3578;So;0;ON;;;;;N;;;;; +28D5;BRAILLE PATTERN DOTS-13578;So;0;ON;;;;;N;;;;; +28D6;BRAILLE PATTERN DOTS-23578;So;0;ON;;;;;N;;;;; +28D7;BRAILLE PATTERN DOTS-123578;So;0;ON;;;;;N;;;;; +28D8;BRAILLE PATTERN DOTS-4578;So;0;ON;;;;;N;;;;; +28D9;BRAILLE PATTERN DOTS-14578;So;0;ON;;;;;N;;;;; +28DA;BRAILLE PATTERN DOTS-24578;So;0;ON;;;;;N;;;;; +28DB;BRAILLE PATTERN DOTS-124578;So;0;ON;;;;;N;;;;; +28DC;BRAILLE PATTERN DOTS-34578;So;0;ON;;;;;N;;;;; +28DD;BRAILLE PATTERN DOTS-134578;So;0;ON;;;;;N;;;;; +28DE;BRAILLE PATTERN DOTS-234578;So;0;ON;;;;;N;;;;; +28DF;BRAILLE PATTERN DOTS-1234578;So;0;ON;;;;;N;;;;; +28E0;BRAILLE PATTERN DOTS-678;So;0;ON;;;;;N;;;;; +28E1;BRAILLE PATTERN DOTS-1678;So;0;ON;;;;;N;;;;; +28E2;BRAILLE PATTERN DOTS-2678;So;0;ON;;;;;N;;;;; +28E3;BRAILLE PATTERN DOTS-12678;So;0;ON;;;;;N;;;;; +28E4;BRAILLE PATTERN DOTS-3678;So;0;ON;;;;;N;;;;; +28E5;BRAILLE PATTERN DOTS-13678;So;0;ON;;;;;N;;;;; +28E6;BRAILLE PATTERN DOTS-23678;So;0;ON;;;;;N;;;;; +28E7;BRAILLE PATTERN DOTS-123678;So;0;ON;;;;;N;;;;; +28E8;BRAILLE PATTERN DOTS-4678;So;0;ON;;;;;N;;;;; +28E9;BRAILLE PATTERN DOTS-14678;So;0;ON;;;;;N;;;;; +28EA;BRAILLE PATTERN DOTS-24678;So;0;ON;;;;;N;;;;; +28EB;BRAILLE PATTERN DOTS-124678;So;0;ON;;;;;N;;;;; +28EC;BRAILLE PATTERN DOTS-34678;So;0;ON;;;;;N;;;;; +28ED;BRAILLE PATTERN DOTS-134678;So;0;ON;;;;;N;;;;; +28EE;BRAILLE PATTERN DOTS-234678;So;0;ON;;;;;N;;;;; +28EF;BRAILLE PATTERN DOTS-1234678;So;0;ON;;;;;N;;;;; +28F0;BRAILLE PATTERN DOTS-5678;So;0;ON;;;;;N;;;;; +28F1;BRAILLE PATTERN DOTS-15678;So;0;ON;;;;;N;;;;; +28F2;BRAILLE PATTERN DOTS-25678;So;0;ON;;;;;N;;;;; +28F3;BRAILLE PATTERN DOTS-125678;So;0;ON;;;;;N;;;;; +28F4;BRAILLE PATTERN DOTS-35678;So;0;ON;;;;;N;;;;; +28F5;BRAILLE PATTERN DOTS-135678;So;0;ON;;;;;N;;;;; +28F6;BRAILLE PATTERN DOTS-235678;So;0;ON;;;;;N;;;;; +28F7;BRAILLE PATTERN DOTS-1235678;So;0;ON;;;;;N;;;;; +28F8;BRAILLE PATTERN DOTS-45678;So;0;ON;;;;;N;;;;; +28F9;BRAILLE PATTERN DOTS-145678;So;0;ON;;;;;N;;;;; +28FA;BRAILLE PATTERN DOTS-245678;So;0;ON;;;;;N;;;;; +28FB;BRAILLE PATTERN DOTS-1245678;So;0;ON;;;;;N;;;;; +28FC;BRAILLE PATTERN DOTS-345678;So;0;ON;;;;;N;;;;; +28FD;BRAILLE PATTERN DOTS-1345678;So;0;ON;;;;;N;;;;; +28FE;BRAILLE PATTERN DOTS-2345678;So;0;ON;;;;;N;;;;; +28FF;BRAILLE PATTERN DOTS-12345678;So;0;ON;;;;;N;;;;; +2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; +2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; +2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; +2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;; +2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;; +2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;; +2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;; +2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;; +2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;; +2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;; +2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;; +2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;; +2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;; +2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;; +2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;; +2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;; +2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;; +2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;; +2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;; +2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;; +2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;; +2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;; +2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;; +2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;; +2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;; +2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;; +2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;; +2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;; +2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;; +2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;; +2E9F;CJK RADICAL MOTHER;So;0;ON; 6BCD;;;;N;;;;; +2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;; +2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;; +2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;; +2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;; +2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;; +2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;; +2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;; +2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;; +2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;; +2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;; +2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;; +2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;; +2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;; +2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;; +2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;; +2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;; +2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;; +2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;; +2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;; +2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;; +2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;; +2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;; +2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;; +2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;; +2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;; +2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;; +2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;; +2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;; +2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;; +2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;; +2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;; +2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;; +2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;; +2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;; +2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;; +2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;; +2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;; +2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;; +2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;; +2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;; +2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;; +2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;; +2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;; +2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;; +2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;; +2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;; +2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;; +2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;; +2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;; +2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;; +2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;; +2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;; +2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;; +2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;; +2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;; +2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;; +2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;; +2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;; +2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;; +2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;; +2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;; +2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;; +2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;; +2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;; +2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;; +2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;; +2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;; +2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;; +2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;; +2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;; +2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;; +2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;; +2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;; +2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;; +2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;; +2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; +2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;; +2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; +2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;; +2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; +2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;; +2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;; +2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;; +2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON; 9F9F;;;;N;;;;; +2F00;KANGXI RADICAL ONE;So;0;ON; 4E00;;;;N;;;;; +2F01;KANGXI RADICAL LINE;So;0;ON; 4E28;;;;N;;;;; +2F02;KANGXI RADICAL DOT;So;0;ON; 4E36;;;;N;;;;; +2F03;KANGXI RADICAL SLASH;So;0;ON; 4E3F;;;;N;;;;; +2F04;KANGXI RADICAL SECOND;So;0;ON; 4E59;;;;N;;;;; +2F05;KANGXI RADICAL HOOK;So;0;ON; 4E85;;;;N;;;;; +2F06;KANGXI RADICAL TWO;So;0;ON; 4E8C;;;;N;;;;; +2F07;KANGXI RADICAL LID;So;0;ON; 4EA0;;;;N;;;;; +2F08;KANGXI RADICAL MAN;So;0;ON; 4EBA;;;;N;;;;; +2F09;KANGXI RADICAL LEGS;So;0;ON; 513F;;;;N;;;;; +2F0A;KANGXI RADICAL ENTER;So;0;ON; 5165;;;;N;;;;; +2F0B;KANGXI RADICAL EIGHT;So;0;ON; 516B;;;;N;;;;; +2F0C;KANGXI RADICAL DOWN BOX;So;0;ON; 5182;;;;N;;;;; +2F0D;KANGXI RADICAL COVER;So;0;ON; 5196;;;;N;;;;; +2F0E;KANGXI RADICAL ICE;So;0;ON; 51AB;;;;N;;;;; +2F0F;KANGXI RADICAL TABLE;So;0;ON; 51E0;;;;N;;;;; +2F10;KANGXI RADICAL OPEN BOX;So;0;ON; 51F5;;;;N;;;;; +2F11;KANGXI RADICAL KNIFE;So;0;ON; 5200;;;;N;;;;; +2F12;KANGXI RADICAL POWER;So;0;ON; 529B;;;;N;;;;; +2F13;KANGXI RADICAL WRAP;So;0;ON; 52F9;;;;N;;;;; +2F14;KANGXI RADICAL SPOON;So;0;ON; 5315;;;;N;;;;; +2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON; 531A;;;;N;;;;; +2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON; 5338;;;;N;;;;; +2F17;KANGXI RADICAL TEN;So;0;ON; 5341;;;;N;;;;; +2F18;KANGXI RADICAL DIVINATION;So;0;ON; 535C;;;;N;;;;; +2F19;KANGXI RADICAL SEAL;So;0;ON; 5369;;;;N;;;;; +2F1A;KANGXI RADICAL CLIFF;So;0;ON; 5382;;;;N;;;;; +2F1B;KANGXI RADICAL PRIVATE;So;0;ON; 53B6;;;;N;;;;; +2F1C;KANGXI RADICAL AGAIN;So;0;ON; 53C8;;;;N;;;;; +2F1D;KANGXI RADICAL MOUTH;So;0;ON; 53E3;;;;N;;;;; +2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON; 56D7;;;;N;;;;; +2F1F;KANGXI RADICAL EARTH;So;0;ON; 571F;;;;N;;;;; +2F20;KANGXI RADICAL SCHOLAR;So;0;ON; 58EB;;;;N;;;;; +2F21;KANGXI RADICAL GO;So;0;ON; 5902;;;;N;;;;; +2F22;KANGXI RADICAL GO SLOWLY;So;0;ON; 590A;;;;N;;;;; +2F23;KANGXI RADICAL EVENING;So;0;ON; 5915;;;;N;;;;; +2F24;KANGXI RADICAL BIG;So;0;ON; 5927;;;;N;;;;; +2F25;KANGXI RADICAL WOMAN;So;0;ON; 5973;;;;N;;;;; +2F26;KANGXI RADICAL CHILD;So;0;ON; 5B50;;;;N;;;;; +2F27;KANGXI RADICAL ROOF;So;0;ON; 5B80;;;;N;;;;; +2F28;KANGXI RADICAL INCH;So;0;ON; 5BF8;;;;N;;;;; +2F29;KANGXI RADICAL SMALL;So;0;ON; 5C0F;;;;N;;;;; +2F2A;KANGXI RADICAL LAME;So;0;ON; 5C22;;;;N;;;;; +2F2B;KANGXI RADICAL CORPSE;So;0;ON; 5C38;;;;N;;;;; +2F2C;KANGXI RADICAL SPROUT;So;0;ON; 5C6E;;;;N;;;;; +2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON; 5C71;;;;N;;;;; +2F2E;KANGXI RADICAL RIVER;So;0;ON; 5DDB;;;;N;;;;; +2F2F;KANGXI RADICAL WORK;So;0;ON; 5DE5;;;;N;;;;; +2F30;KANGXI RADICAL ONESELF;So;0;ON; 5DF1;;;;N;;;;; +2F31;KANGXI RADICAL TURBAN;So;0;ON; 5DFE;;;;N;;;;; +2F32;KANGXI RADICAL DRY;So;0;ON; 5E72;;;;N;;;;; +2F33;KANGXI RADICAL SHORT THREAD;So;0;ON; 5E7A;;;;N;;;;; +2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON; 5E7F;;;;N;;;;; +2F35;KANGXI RADICAL LONG STRIDE;So;0;ON; 5EF4;;;;N;;;;; +2F36;KANGXI RADICAL TWO HANDS;So;0;ON; 5EFE;;;;N;;;;; +2F37;KANGXI RADICAL SHOOT;So;0;ON; 5F0B;;;;N;;;;; +2F38;KANGXI RADICAL BOW;So;0;ON; 5F13;;;;N;;;;; +2F39;KANGXI RADICAL SNOUT;So;0;ON; 5F50;;;;N;;;;; +2F3A;KANGXI RADICAL BRISTLE;So;0;ON; 5F61;;;;N;;;;; +2F3B;KANGXI RADICAL STEP;So;0;ON; 5F73;;;;N;;;;; +2F3C;KANGXI RADICAL HEART;So;0;ON; 5FC3;;;;N;;;;; +2F3D;KANGXI RADICAL HALBERD;So;0;ON; 6208;;;;N;;;;; +2F3E;KANGXI RADICAL DOOR;So;0;ON; 6236;;;;N;;;;; +2F3F;KANGXI RADICAL HAND;So;0;ON; 624B;;;;N;;;;; +2F40;KANGXI RADICAL BRANCH;So;0;ON; 652F;;;;N;;;;; +2F41;KANGXI RADICAL RAP;So;0;ON; 6534;;;;N;;;;; +2F42;KANGXI RADICAL SCRIPT;So;0;ON; 6587;;;;N;;;;; +2F43;KANGXI RADICAL DIPPER;So;0;ON; 6597;;;;N;;;;; +2F44;KANGXI RADICAL AXE;So;0;ON; 65A4;;;;N;;;;; +2F45;KANGXI RADICAL SQUARE;So;0;ON; 65B9;;;;N;;;;; +2F46;KANGXI RADICAL NOT;So;0;ON; 65E0;;;;N;;;;; +2F47;KANGXI RADICAL SUN;So;0;ON; 65E5;;;;N;;;;; +2F48;KANGXI RADICAL SAY;So;0;ON; 66F0;;;;N;;;;; +2F49;KANGXI RADICAL MOON;So;0;ON; 6708;;;;N;;;;; +2F4A;KANGXI RADICAL TREE;So;0;ON; 6728;;;;N;;;;; +2F4B;KANGXI RADICAL LACK;So;0;ON; 6B20;;;;N;;;;; +2F4C;KANGXI RADICAL STOP;So;0;ON; 6B62;;;;N;;;;; +2F4D;KANGXI RADICAL DEATH;So;0;ON; 6B79;;;;N;;;;; +2F4E;KANGXI RADICAL WEAPON;So;0;ON; 6BB3;;;;N;;;;; +2F4F;KANGXI RADICAL DO NOT;So;0;ON; 6BCB;;;;N;;;;; +2F50;KANGXI RADICAL COMPARE;So;0;ON; 6BD4;;;;N;;;;; +2F51;KANGXI RADICAL FUR;So;0;ON; 6BDB;;;;N;;;;; +2F52;KANGXI RADICAL CLAN;So;0;ON; 6C0F;;;;N;;;;; +2F53;KANGXI RADICAL STEAM;So;0;ON; 6C14;;;;N;;;;; +2F54;KANGXI RADICAL WATER;So;0;ON; 6C34;;;;N;;;;; +2F55;KANGXI RADICAL FIRE;So;0;ON; 706B;;;;N;;;;; +2F56;KANGXI RADICAL CLAW;So;0;ON; 722A;;;;N;;;;; +2F57;KANGXI RADICAL FATHER;So;0;ON; 7236;;;;N;;;;; +2F58;KANGXI RADICAL DOUBLE X;So;0;ON; 723B;;;;N;;;;; +2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON; 723F;;;;N;;;;; +2F5A;KANGXI RADICAL SLICE;So;0;ON; 7247;;;;N;;;;; +2F5B;KANGXI RADICAL FANG;So;0;ON; 7259;;;;N;;;;; +2F5C;KANGXI RADICAL COW;So;0;ON; 725B;;;;N;;;;; +2F5D;KANGXI RADICAL DOG;So;0;ON; 72AC;;;;N;;;;; +2F5E;KANGXI RADICAL PROFOUND;So;0;ON; 7384;;;;N;;;;; +2F5F;KANGXI RADICAL JADE;So;0;ON; 7389;;;;N;;;;; +2F60;KANGXI RADICAL MELON;So;0;ON; 74DC;;;;N;;;;; +2F61;KANGXI RADICAL TILE;So;0;ON; 74E6;;;;N;;;;; +2F62;KANGXI RADICAL SWEET;So;0;ON; 7518;;;;N;;;;; +2F63;KANGXI RADICAL LIFE;So;0;ON; 751F;;;;N;;;;; +2F64;KANGXI RADICAL USE;So;0;ON; 7528;;;;N;;;;; +2F65;KANGXI RADICAL FIELD;So;0;ON; 7530;;;;N;;;;; +2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON; 758B;;;;N;;;;; +2F67;KANGXI RADICAL SICKNESS;So;0;ON; 7592;;;;N;;;;; +2F68;KANGXI RADICAL DOTTED TENT;So;0;ON; 7676;;;;N;;;;; +2F69;KANGXI RADICAL WHITE;So;0;ON; 767D;;;;N;;;;; +2F6A;KANGXI RADICAL SKIN;So;0;ON; 76AE;;;;N;;;;; +2F6B;KANGXI RADICAL DISH;So;0;ON; 76BF;;;;N;;;;; +2F6C;KANGXI RADICAL EYE;So;0;ON; 76EE;;;;N;;;;; +2F6D;KANGXI RADICAL SPEAR;So;0;ON; 77DB;;;;N;;;;; +2F6E;KANGXI RADICAL ARROW;So;0;ON; 77E2;;;;N;;;;; +2F6F;KANGXI RADICAL STONE;So;0;ON; 77F3;;;;N;;;;; +2F70;KANGXI RADICAL SPIRIT;So;0;ON; 793A;;;;N;;;;; +2F71;KANGXI RADICAL TRACK;So;0;ON; 79B8;;;;N;;;;; +2F72;KANGXI RADICAL GRAIN;So;0;ON; 79BE;;;;N;;;;; +2F73;KANGXI RADICAL CAVE;So;0;ON; 7A74;;;;N;;;;; +2F74;KANGXI RADICAL STAND;So;0;ON; 7ACB;;;;N;;;;; +2F75;KANGXI RADICAL BAMBOO;So;0;ON; 7AF9;;;;N;;;;; +2F76;KANGXI RADICAL RICE;So;0;ON; 7C73;;;;N;;;;; +2F77;KANGXI RADICAL SILK;So;0;ON; 7CF8;;;;N;;;;; +2F78;KANGXI RADICAL JAR;So;0;ON; 7F36;;;;N;;;;; +2F79;KANGXI RADICAL NET;So;0;ON; 7F51;;;;N;;;;; +2F7A;KANGXI RADICAL SHEEP;So;0;ON; 7F8A;;;;N;;;;; +2F7B;KANGXI RADICAL FEATHER;So;0;ON; 7FBD;;;;N;;;;; +2F7C;KANGXI RADICAL OLD;So;0;ON; 8001;;;;N;;;;; +2F7D;KANGXI RADICAL AND;So;0;ON; 800C;;;;N;;;;; +2F7E;KANGXI RADICAL PLOW;So;0;ON; 8012;;;;N;;;;; +2F7F;KANGXI RADICAL EAR;So;0;ON; 8033;;;;N;;;;; +2F80;KANGXI RADICAL BRUSH;So;0;ON; 807F;;;;N;;;;; +2F81;KANGXI RADICAL MEAT;So;0;ON; 8089;;;;N;;;;; +2F82;KANGXI RADICAL MINISTER;So;0;ON; 81E3;;;;N;;;;; +2F83;KANGXI RADICAL SELF;So;0;ON; 81EA;;;;N;;;;; +2F84;KANGXI RADICAL ARRIVE;So;0;ON; 81F3;;;;N;;;;; +2F85;KANGXI RADICAL MORTAR;So;0;ON; 81FC;;;;N;;;;; +2F86;KANGXI RADICAL TONGUE;So;0;ON; 820C;;;;N;;;;; +2F87;KANGXI RADICAL OPPOSE;So;0;ON; 821B;;;;N;;;;; +2F88;KANGXI RADICAL BOAT;So;0;ON; 821F;;;;N;;;;; +2F89;KANGXI RADICAL STOPPING;So;0;ON; 826E;;;;N;;;;; +2F8A;KANGXI RADICAL COLOR;So;0;ON; 8272;;;;N;;;;; +2F8B;KANGXI RADICAL GRASS;So;0;ON; 8278;;;;N;;;;; +2F8C;KANGXI RADICAL TIGER;So;0;ON; 864D;;;;N;;;;; +2F8D;KANGXI RADICAL INSECT;So;0;ON; 866B;;;;N;;;;; +2F8E;KANGXI RADICAL BLOOD;So;0;ON; 8840;;;;N;;;;; +2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON; 884C;;;;N;;;;; +2F90;KANGXI RADICAL CLOTHES;So;0;ON; 8863;;;;N;;;;; +2F91;KANGXI RADICAL WEST;So;0;ON; 897E;;;;N;;;;; +2F92;KANGXI RADICAL SEE;So;0;ON; 898B;;;;N;;;;; +2F93;KANGXI RADICAL HORN;So;0;ON; 89D2;;;;N;;;;; +2F94;KANGXI RADICAL SPEECH;So;0;ON; 8A00;;;;N;;;;; +2F95;KANGXI RADICAL VALLEY;So;0;ON; 8C37;;;;N;;;;; +2F96;KANGXI RADICAL BEAN;So;0;ON; 8C46;;;;N;;;;; +2F97;KANGXI RADICAL PIG;So;0;ON; 8C55;;;;N;;;;; +2F98;KANGXI RADICAL BADGER;So;0;ON; 8C78;;;;N;;;;; +2F99;KANGXI RADICAL SHELL;So;0;ON; 8C9D;;;;N;;;;; +2F9A;KANGXI RADICAL RED;So;0;ON; 8D64;;;;N;;;;; +2F9B;KANGXI RADICAL RUN;So;0;ON; 8D70;;;;N;;;;; +2F9C;KANGXI RADICAL FOOT;So;0;ON; 8DB3;;;;N;;;;; +2F9D;KANGXI RADICAL BODY;So;0;ON; 8EAB;;;;N;;;;; +2F9E;KANGXI RADICAL CART;So;0;ON; 8ECA;;;;N;;;;; +2F9F;KANGXI RADICAL BITTER;So;0;ON; 8F9B;;;;N;;;;; +2FA0;KANGXI RADICAL MORNING;So;0;ON; 8FB0;;;;N;;;;; +2FA1;KANGXI RADICAL WALK;So;0;ON; 8FB5;;;;N;;;;; +2FA2;KANGXI RADICAL CITY;So;0;ON; 9091;;;;N;;;;; +2FA3;KANGXI RADICAL WINE;So;0;ON; 9149;;;;N;;;;; +2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON; 91C6;;;;N;;;;; +2FA5;KANGXI RADICAL VILLAGE;So;0;ON; 91CC;;;;N;;;;; +2FA6;KANGXI RADICAL GOLD;So;0;ON; 91D1;;;;N;;;;; +2FA7;KANGXI RADICAL LONG;So;0;ON; 9577;;;;N;;;;; +2FA8;KANGXI RADICAL GATE;So;0;ON; 9580;;;;N;;;;; +2FA9;KANGXI RADICAL MOUND;So;0;ON; 961C;;;;N;;;;; +2FAA;KANGXI RADICAL SLAVE;So;0;ON; 96B6;;;;N;;;;; +2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON; 96B9;;;;N;;;;; +2FAC;KANGXI RADICAL RAIN;So;0;ON; 96E8;;;;N;;;;; +2FAD;KANGXI RADICAL BLUE;So;0;ON; 9751;;;;N;;;;; +2FAE;KANGXI RADICAL WRONG;So;0;ON; 975E;;;;N;;;;; +2FAF;KANGXI RADICAL FACE;So;0;ON; 9762;;;;N;;;;; +2FB0;KANGXI RADICAL LEATHER;So;0;ON; 9769;;;;N;;;;; +2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON; 97CB;;;;N;;;;; +2FB2;KANGXI RADICAL LEEK;So;0;ON; 97ED;;;;N;;;;; +2FB3;KANGXI RADICAL SOUND;So;0;ON; 97F3;;;;N;;;;; +2FB4;KANGXI RADICAL LEAF;So;0;ON; 9801;;;;N;;;;; +2FB5;KANGXI RADICAL WIND;So;0;ON; 98A8;;;;N;;;;; +2FB6;KANGXI RADICAL FLY;So;0;ON; 98DB;;;;N;;;;; +2FB7;KANGXI RADICAL EAT;So;0;ON; 98DF;;;;N;;;;; +2FB8;KANGXI RADICAL HEAD;So;0;ON; 9996;;;;N;;;;; +2FB9;KANGXI RADICAL FRAGRANT;So;0;ON; 9999;;;;N;;;;; +2FBA;KANGXI RADICAL HORSE;So;0;ON; 99AC;;;;N;;;;; +2FBB;KANGXI RADICAL BONE;So;0;ON; 9AA8;;;;N;;;;; +2FBC;KANGXI RADICAL TALL;So;0;ON; 9AD8;;;;N;;;;; +2FBD;KANGXI RADICAL HAIR;So;0;ON; 9ADF;;;;N;;;;; +2FBE;KANGXI RADICAL FIGHT;So;0;ON; 9B25;;;;N;;;;; +2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON; 9B2F;;;;N;;;;; +2FC0;KANGXI RADICAL CAULDRON;So;0;ON; 9B32;;;;N;;;;; +2FC1;KANGXI RADICAL GHOST;So;0;ON; 9B3C;;;;N;;;;; +2FC2;KANGXI RADICAL FISH;So;0;ON; 9B5A;;;;N;;;;; +2FC3;KANGXI RADICAL BIRD;So;0;ON; 9CE5;;;;N;;;;; +2FC4;KANGXI RADICAL SALT;So;0;ON; 9E75;;;;N;;;;; +2FC5;KANGXI RADICAL DEER;So;0;ON; 9E7F;;;;N;;;;; +2FC6;KANGXI RADICAL WHEAT;So;0;ON; 9EA5;;;;N;;;;; +2FC7;KANGXI RADICAL HEMP;So;0;ON; 9EBB;;;;N;;;;; +2FC8;KANGXI RADICAL YELLOW;So;0;ON; 9EC3;;;;N;;;;; +2FC9;KANGXI RADICAL MILLET;So;0;ON; 9ECD;;;;N;;;;; +2FCA;KANGXI RADICAL BLACK;So;0;ON; 9ED1;;;;N;;;;; +2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON; 9EF9;;;;N;;;;; +2FCC;KANGXI RADICAL FROG;So;0;ON; 9EFD;;;;N;;;;; +2FCD;KANGXI RADICAL TRIPOD;So;0;ON; 9F0E;;;;N;;;;; +2FCE;KANGXI RADICAL DRUM;So;0;ON; 9F13;;;;N;;;;; +2FCF;KANGXI RADICAL RAT;So;0;ON; 9F20;;;;N;;;;; +2FD0;KANGXI RADICAL NOSE;So;0;ON; 9F3B;;;;N;;;;; +2FD1;KANGXI RADICAL EVEN;So;0;ON; 9F4A;;;;N;;;;; +2FD2;KANGXI RADICAL TOOTH;So;0;ON; 9F52;;;;N;;;;; +2FD3;KANGXI RADICAL DRAGON;So;0;ON; 9F8D;;;;N;;;;; +2FD4;KANGXI RADICAL TURTLE;So;0;ON; 9F9C;;;;N;;;;; +2FD5;KANGXI RADICAL FLUTE;So;0;ON; 9FA0;;;;N;;;;; +2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;; +2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;; +2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;; +2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;; +2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;; +2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;; +2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;; +2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;; +2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;; +2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;; +2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;; +2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;; +3000;IDEOGRAPHIC SPACE;Zs;0;WS; 0020;;;;N;;;;; +3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;; +3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;; +3003;DITTO MARK;Po;0;ON;;;;;N;;;;; +3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;; +3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;; +3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;; +3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;; +3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;; +3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;; +300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;; +300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;; +300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;; +300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;; +300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;; +300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;; +3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;; +3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;; +3012;POSTAL MARK;So;0;ON;;;;;N;;;;; +3013;GETA MARK;So;0;ON;;;;;N;;;;; +3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;; +3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;; +3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;; +3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;; +3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;; +3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;; +301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;; +301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;; +301C;WAVE DASH;Pd;0;ON;;;;;N;;;;; +301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;; +301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; +301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;; +3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;; +3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;; +3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;; +3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;; +3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;; +3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;; +3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;; +3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;; +3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;; +3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;; +302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;; +302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;; +302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;; +302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;; +302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; +302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;; +3030;WAVY DASH;Pd;0;ON;;;;;N;;;;; +3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;; +3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;; +3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;; +3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;; +3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;; +3036;CIRCLED POSTAL MARK;So;0;ON; 3012;;;;N;;;;; +3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;; +3038;HANGZHOU NUMERAL TEN;Nl;0;L; 5341;;;10;N;;;;; +3039;HANGZHOU NUMERAL TWENTY;Nl;0;L; 5344;;;20;N;;;;; +303A;HANGZHOU NUMERAL THIRTY;Nl;0;L; 5345;;;30;N;;;;; +303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;; +303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;; +3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;; +3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; +3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;; +3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; +3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;; +3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; +3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;; +3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; +304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;; +304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;; +304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;; +304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;; +304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;; +304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;; +3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;; +3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;; +3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;; +3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;; +3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;; +3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;; +3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;; +3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;; +3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;; +3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;; +305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;; +305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;; +305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;; +305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;; +305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;; +305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;; +3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;; +3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;; +3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;; +3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; +3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;; +3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;; +3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;; +3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;; +3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;; +3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;; +306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;; +306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;; +306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;; +306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;; +306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;; +306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;; +3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;; +3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;; +3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;; +3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;; +3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;; +3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;; +3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;; +3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;; +3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;; +3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;; +307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;; +307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;; +307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;; +307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;; +307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;; +307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;; +3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;; +3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;; +3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;; +3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; +3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;; +3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; +3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;; +3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; +3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;; +3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;; +308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;; +308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;; +308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;; +308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;; +308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; +308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;; +3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;; +3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;; +3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;; +3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;; +3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;; +3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;; +309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;; +309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON; 0020 3099;;;;N;;;;; +309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON; 0020 309A;;;;N;;;;; +309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;; +309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;; +30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;; +30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;; +30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;; +30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;; +30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;; +30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;; +30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;; +30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;; +30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;; +30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;; +30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;; +30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;; +30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;; +30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;; +30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;; +30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;; +30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;; +30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;; +30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;; +30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;; +30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;; +30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;; +30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;; +30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;; +30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;; +30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;; +30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;; +30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;; +30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;; +30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;; +30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;; +30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;; +30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;; +30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;; +30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;; +30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;; +30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;; +30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;; +30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;; +30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;; +30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;; +30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;; +30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;; +30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;; +30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;; +30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;; +30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;; +30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;; +30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;; +30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;; +30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;; +30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;; +30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;; +30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;; +30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;; +30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;; +30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;; +30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;; +30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;; +30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;; +30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;; +30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;; +30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;; +30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;; +30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;; +30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;; +30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;; +30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;; +30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;; +30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;; +30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;; +30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;; +30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;; +30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;; +30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;; +30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;; +30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;; +30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;; +30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;; +30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;; +30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;; +30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;; +30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;; +30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;; +30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;; +30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;; +30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;; +30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;; +30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;; +30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;; +30FB;KATAKANA MIDDLE DOT;Pc;0;ON;;;;;N;;;;; +30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;; +30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;; +30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;; +3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;; +3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;; +3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;; +3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;; +3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;; +310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;; +310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;; +310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;; +310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;; +310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;; +310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;; +3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;; +3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;; +3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;; +3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;; +3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;; +3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;; +3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;; +3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;; +3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;; +3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;; +311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;; +311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;; +311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;; +311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;; +311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;; +311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;; +3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;; +3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;; +3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;; +3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;; +3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;; +3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;; +3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;; +3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;; +3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;; +3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;; +312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;; +312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; +312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; +3131;HANGUL LETTER KIYEOK;Lo;0;L; 1100;;;;N;HANGUL LETTER GIYEOG;;;; +3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L; 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; +3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; +3134;HANGUL LETTER NIEUN;Lo;0;L; 1102;;;;N;;;;; +3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L; 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;; +3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L; 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;; +3137;HANGUL LETTER TIKEUT;Lo;0;L; 1103;;;;N;HANGUL LETTER DIGEUD;;;; +3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L; 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;; +3139;HANGUL LETTER RIEUL;Lo;0;L; 1105;;;;N;HANGUL LETTER LIEUL;;;; +313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L; 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;; +313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L; 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;; +313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L; 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;; +313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L; 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;; +313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L; 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;; +313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L; 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;; +3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L; 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;; +3141;HANGUL LETTER MIEUM;Lo;0;L; 1106;;;;N;;;;; +3142;HANGUL LETTER PIEUP;Lo;0;L; 1107;;;;N;HANGUL LETTER BIEUB;;;; +3143;HANGUL LETTER SSANGPIEUP;Lo;0;L; 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;; +3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L; 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;; +3145;HANGUL LETTER SIOS;Lo;0;L; 1109;;;;N;;;;; +3146;HANGUL LETTER SSANGSIOS;Lo;0;L; 110A;;;;N;HANGUL LETTER SSANG SIOS;;;; +3147;HANGUL LETTER IEUNG;Lo;0;L; 110B;;;;N;;;;; +3148;HANGUL LETTER CIEUC;Lo;0;L; 110C;;;;N;HANGUL LETTER JIEUJ;;;; +3149;HANGUL LETTER SSANGCIEUC;Lo;0;L; 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;; +314A;HANGUL LETTER CHIEUCH;Lo;0;L; 110E;;;;N;HANGUL LETTER CIEUC;;;; +314B;HANGUL LETTER KHIEUKH;Lo;0;L; 110F;;;;N;HANGUL LETTER KIYEOK;;;; +314C;HANGUL LETTER THIEUTH;Lo;0;L; 1110;;;;N;HANGUL LETTER TIEUT;;;; +314D;HANGUL LETTER PHIEUPH;Lo;0;L; 1111;;;;N;HANGUL LETTER PIEUP;;;; +314E;HANGUL LETTER HIEUH;Lo;0;L; 1112;;;;N;;;;; +314F;HANGUL LETTER A;Lo;0;L; 1161;;;;N;;;;; +3150;HANGUL LETTER AE;Lo;0;L; 1162;;;;N;;;;; +3151;HANGUL LETTER YA;Lo;0;L; 1163;;;;N;;;;; +3152;HANGUL LETTER YAE;Lo;0;L; 1164;;;;N;;;;; +3153;HANGUL LETTER EO;Lo;0;L; 1165;;;;N;;;;; +3154;HANGUL LETTER E;Lo;0;L; 1166;;;;N;;;;; +3155;HANGUL LETTER YEO;Lo;0;L; 1167;;;;N;;;;; +3156;HANGUL LETTER YE;Lo;0;L; 1168;;;;N;;;;; +3157;HANGUL LETTER O;Lo;0;L; 1169;;;;N;;;;; +3158;HANGUL LETTER WA;Lo;0;L; 116A;;;;N;;;;; +3159;HANGUL LETTER WAE;Lo;0;L; 116B;;;;N;;;;; +315A;HANGUL LETTER OE;Lo;0;L; 116C;;;;N;;;;; +315B;HANGUL LETTER YO;Lo;0;L; 116D;;;;N;;;;; +315C;HANGUL LETTER U;Lo;0;L; 116E;;;;N;;;;; +315D;HANGUL LETTER WEO;Lo;0;L; 116F;;;;N;;;;; +315E;HANGUL LETTER WE;Lo;0;L; 1170;;;;N;;;;; +315F;HANGUL LETTER WI;Lo;0;L; 1171;;;;N;;;;; +3160;HANGUL LETTER YU;Lo;0;L; 1172;;;;N;;;;; +3161;HANGUL LETTER EU;Lo;0;L; 1173;;;;N;;;;; +3162;HANGUL LETTER YI;Lo;0;L; 1174;;;;N;;;;; +3163;HANGUL LETTER I;Lo;0;L; 1175;;;;N;;;;; +3164;HANGUL FILLER;Lo;0;L; 1160;;;;N;HANGUL CAE OM;;;; +3165;HANGUL LETTER SSANGNIEUN;Lo;0;L; 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;; +3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L; 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;; +3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L; 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;; +3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L; 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;; +3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L; 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;; +316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L; 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;; +316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L; 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;; +316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L; 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;; +316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L; 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;; +316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L; 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;; +316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L; 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;; +3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L; 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;; +3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L; 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;; +3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L; 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;; +3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L; 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;; +3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L; 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;; +3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L; 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;; +3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L; 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;; +3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L; 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;; +3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L; 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;; +3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L; 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;; +317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L; 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;; +317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L; 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;; +317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L; 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;; +317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L; 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;; +317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L; 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;; +317F;HANGUL LETTER PANSIOS;Lo;0;L; 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;; +3180;HANGUL LETTER SSANGIEUNG;Lo;0;L; 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;; +3181;HANGUL LETTER YESIEUNG;Lo;0;L; 114C;;;;N;HANGUL LETTER NGIEUNG;;;; +3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L; 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;; +3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L; 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;; +3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L; 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;; +3185;HANGUL LETTER SSANGHIEUH;Lo;0;L; 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;; +3186;HANGUL LETTER YEORINHIEUH;Lo;0;L; 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;; +3187;HANGUL LETTER YO-YA;Lo;0;L; 1184;;;;N;HANGUL LETTER YOYA;;;; +3188;HANGUL LETTER YO-YAE;Lo;0;L; 1185;;;;N;HANGUL LETTER YOYAE;;;; +3189;HANGUL LETTER YO-I;Lo;0;L; 1188;;;;N;HANGUL LETTER YOI;;;; +318A;HANGUL LETTER YU-YEO;Lo;0;L; 1191;;;;N;HANGUL LETTER YUYEO;;;; +318B;HANGUL LETTER YU-YE;Lo;0;L; 1192;;;;N;HANGUL LETTER YUYE;;;; +318C;HANGUL LETTER YU-I;Lo;0;L; 1194;;;;N;HANGUL LETTER YUI;;;; +318D;HANGUL LETTER ARAEA;Lo;0;L; 119E;;;;N;HANGUL LETTER ALAE A;;;; +318E;HANGUL LETTER ARAEAE;Lo;0;L; 11A1;;;;N;HANGUL LETTER ALAE AE;;;; +3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;Kanbun Tateten;;; +3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;Kaeriten;;; +3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L; 4E00;;;1;N;KAERITEN ITI;Kaeriten;;; +3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L; 4E8C;;;2;N;KAERITEN NI;Kaeriten;;; +3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L; 4E09;;;3;N;KAERITEN SAN;Kaeriten;;; +3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L; 56DB;;;4;N;KAERITEN SI;Kaeriten;;; +3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L; 4E0A;;;;N;KAERITEN ZYOU;Kaeriten;;; +3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L; 4E2D;;;;N;KAERITEN TYUU;Kaeriten;;; +3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L; 4E0B;;;;N;KAERITEN GE;Kaeriten;;; +3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L; 7532;;;;N;KAERITEN KOU;Kaeriten;;; +319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L; 4E59;;;;N;KAERITEN OTU;Kaeriten;;; +319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L; 4E19;;;;N;KAERITEN HEI;Kaeriten;;; +319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L; 4E01;;;;N;KAERITEN TEI;Kaeriten;;; +319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L; 5929;;;;N;KAERITEN TEN;Kaeriten;;; +319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L; 5730;;;;N;KAERITEN TI;Kaeriten;;; +319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L; 4EBA;;;;N;KAERITEN ZIN;Kaeriten;;; +31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;; +31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;; +31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;; +31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;; +31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;; +31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;; +31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;; +31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;; +31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;; +31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;; +31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;; +31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;; +31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;; +31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;; +31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;; +31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;; +31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;; +31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;; +31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;; +31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;; +31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;; +31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;; +31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;; +31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;; +3200;PARENTHESIZED HANGUL KIYEOK;So;0;L; 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;; +3201;PARENTHESIZED HANGUL NIEUN;So;0;L; 0028 1102 0029;;;;N;;;;; +3202;PARENTHESIZED HANGUL TIKEUT;So;0;L; 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;; +3203;PARENTHESIZED HANGUL RIEUL;So;0;L; 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;; +3204;PARENTHESIZED HANGUL MIEUM;So;0;L; 0028 1106 0029;;;;N;;;;; +3205;PARENTHESIZED HANGUL PIEUP;So;0;L; 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;; +3206;PARENTHESIZED HANGUL SIOS;So;0;L; 0028 1109 0029;;;;N;;;;; +3207;PARENTHESIZED HANGUL IEUNG;So;0;L; 0028 110B 0029;;;;N;;;;; +3208;PARENTHESIZED HANGUL CIEUC;So;0;L; 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;; +3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L; 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;; +320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L; 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;; +320B;PARENTHESIZED HANGUL THIEUTH;So;0;L; 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;; +320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L; 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;; +320D;PARENTHESIZED HANGUL HIEUH;So;0;L; 0028 1112 0029;;;;N;;;;; +320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L; 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;; +320F;PARENTHESIZED HANGUL NIEUN A;So;0;L; 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;; +3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L; 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;; +3211;PARENTHESIZED HANGUL RIEUL A;So;0;L; 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;; +3212;PARENTHESIZED HANGUL MIEUM A;So;0;L; 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;; +3213;PARENTHESIZED HANGUL PIEUP A;So;0;L; 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;; +3214;PARENTHESIZED HANGUL SIOS A;So;0;L; 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;; +3215;PARENTHESIZED HANGUL IEUNG A;So;0;L; 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;; +3216;PARENTHESIZED HANGUL CIEUC A;So;0;L; 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;; +3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L; 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;; +3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L; 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;; +3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L; 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;; +321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L; 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;; +321B;PARENTHESIZED HANGUL HIEUH A;So;0;L; 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;; +321C;PARENTHESIZED HANGUL CIEUC U;So;0;L; 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;; +3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L; 0028 4E00 0029;;;1;N;;;;; +3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L; 0028 4E8C 0029;;;2;N;;;;; +3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L; 0028 4E09 0029;;;3;N;;;;; +3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L; 0028 56DB 0029;;;4;N;;;;; +3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L; 0028 4E94 0029;;;5;N;;;;; +3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L; 0028 516D 0029;;;6;N;;;;; +3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L; 0028 4E03 0029;;;7;N;;;;; +3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L; 0028 516B 0029;;;8;N;;;;; +3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L; 0028 4E5D 0029;;;9;N;;;;; +3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L; 0028 5341 0029;;;10;N;;;;; +322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L; 0028 6708 0029;;;;N;;;;; +322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L; 0028 706B 0029;;;;N;;;;; +322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L; 0028 6C34 0029;;;;N;;;;; +322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L; 0028 6728 0029;;;;N;;;;; +322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L; 0028 91D1 0029;;;;N;;;;; +322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L; 0028 571F 0029;;;;N;;;;; +3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L; 0028 65E5 0029;;;;N;;;;; +3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L; 0028 682A 0029;;;;N;;;;; +3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L; 0028 6709 0029;;;;N;;;;; +3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L; 0028 793E 0029;;;;N;;;;; +3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L; 0028 540D 0029;;;;N;;;;; +3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L; 0028 7279 0029;;;;N;;;;; +3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L; 0028 8CA1 0029;;;;N;;;;; +3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L; 0028 795D 0029;;;;N;;;;; +3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L; 0028 52B4 0029;;;;N;;;;; +3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L; 0028 4EE3 0029;;;;N;;;;; +323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L; 0028 547C 0029;;;;N;;;;; +323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L; 0028 5B66 0029;;;;N;;;;; +323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L; 0028 76E3 0029;;;;N;;;;; +323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L; 0028 4F01 0029;;;;N;;;;; +323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L; 0028 8CC7 0029;;;;N;;;;; +323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L; 0028 5354 0029;;;;N;;;;; +3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L; 0028 796D 0029;;;;N;;;;; +3241;PARENTHESIZED IDEOGRAPH REST;So;0;L; 0028 4F11 0029;;;;N;;;;; +3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L; 0028 81EA 0029;;;;N;;;;; +3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L; 0028 81F3 0029;;;;N;;;;; +3260;CIRCLED HANGUL KIYEOK;So;0;L; 1100;;;;N;CIRCLED HANGUL GIYEOG;;;; +3261;CIRCLED HANGUL NIEUN;So;0;L; 1102;;;;N;;;;; +3262;CIRCLED HANGUL TIKEUT;So;0;L; 1103;;;;N;CIRCLED HANGUL DIGEUD;;;; +3263;CIRCLED HANGUL RIEUL;So;0;L; 1105;;;;N;CIRCLED HANGUL LIEUL;;;; +3264;CIRCLED HANGUL MIEUM;So;0;L; 1106;;;;N;;;;; +3265;CIRCLED HANGUL PIEUP;So;0;L; 1107;;;;N;CIRCLED HANGUL BIEUB;;;; +3266;CIRCLED HANGUL SIOS;So;0;L; 1109;;;;N;;;;; +3267;CIRCLED HANGUL IEUNG;So;0;L; 110B;;;;N;;;;; +3268;CIRCLED HANGUL CIEUC;So;0;L; 110C;;;;N;CIRCLED HANGUL JIEUJ;;;; +3269;CIRCLED HANGUL CHIEUCH;So;0;L; 110E;;;;N;CIRCLED HANGUL CIEUC;;;; +326A;CIRCLED HANGUL KHIEUKH;So;0;L; 110F;;;;N;CIRCLED HANGUL KIYEOK;;;; +326B;CIRCLED HANGUL THIEUTH;So;0;L; 1110;;;;N;CIRCLED HANGUL TIEUT;;;; +326C;CIRCLED HANGUL PHIEUPH;So;0;L; 1111;;;;N;CIRCLED HANGUL PIEUP;;;; +326D;CIRCLED HANGUL HIEUH;So;0;L; 1112;;;;N;;;;; +326E;CIRCLED HANGUL KIYEOK A;So;0;L; 1100 1161;;;;N;CIRCLED HANGUL GA;;;; +326F;CIRCLED HANGUL NIEUN A;So;0;L; 1102 1161;;;;N;CIRCLED HANGUL NA;;;; +3270;CIRCLED HANGUL TIKEUT A;So;0;L; 1103 1161;;;;N;CIRCLED HANGUL DA;;;; +3271;CIRCLED HANGUL RIEUL A;So;0;L; 1105 1161;;;;N;CIRCLED HANGUL LA;;;; +3272;CIRCLED HANGUL MIEUM A;So;0;L; 1106 1161;;;;N;CIRCLED HANGUL MA;;;; +3273;CIRCLED HANGUL PIEUP A;So;0;L; 1107 1161;;;;N;CIRCLED HANGUL BA;;;; +3274;CIRCLED HANGUL SIOS A;So;0;L; 1109 1161;;;;N;CIRCLED HANGUL SA;;;; +3275;CIRCLED HANGUL IEUNG A;So;0;L; 110B 1161;;;;N;CIRCLED HANGUL A;;;; +3276;CIRCLED HANGUL CIEUC A;So;0;L; 110C 1161;;;;N;CIRCLED HANGUL JA;;;; +3277;CIRCLED HANGUL CHIEUCH A;So;0;L; 110E 1161;;;;N;CIRCLED HANGUL CA;;;; +3278;CIRCLED HANGUL KHIEUKH A;So;0;L; 110F 1161;;;;N;CIRCLED HANGUL KA;;;; +3279;CIRCLED HANGUL THIEUTH A;So;0;L; 1110 1161;;;;N;CIRCLED HANGUL TA;;;; +327A;CIRCLED HANGUL PHIEUPH A;So;0;L; 1111 1161;;;;N;CIRCLED HANGUL PA;;;; +327B;CIRCLED HANGUL HIEUH A;So;0;L; 1112 1161;;;;N;CIRCLED HANGUL HA;;;; +327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;; +3280;CIRCLED IDEOGRAPH ONE;No;0;L; 4E00;;;1;N;;;;; +3281;CIRCLED IDEOGRAPH TWO;No;0;L; 4E8C;;;2;N;;;;; +3282;CIRCLED IDEOGRAPH THREE;No;0;L; 4E09;;;3;N;;;;; +3283;CIRCLED IDEOGRAPH FOUR;No;0;L; 56DB;;;4;N;;;;; +3284;CIRCLED IDEOGRAPH FIVE;No;0;L; 4E94;;;5;N;;;;; +3285;CIRCLED IDEOGRAPH SIX;No;0;L; 516D;;;6;N;;;;; +3286;CIRCLED IDEOGRAPH SEVEN;No;0;L; 4E03;;;7;N;;;;; +3287;CIRCLED IDEOGRAPH EIGHT;No;0;L; 516B;;;8;N;;;;; +3288;CIRCLED IDEOGRAPH NINE;No;0;L; 4E5D;;;9;N;;;;; +3289;CIRCLED IDEOGRAPH TEN;No;0;L; 5341;;;10;N;;;;; +328A;CIRCLED IDEOGRAPH MOON;So;0;L; 6708;;;;N;;;;; +328B;CIRCLED IDEOGRAPH FIRE;So;0;L; 706B;;;;N;;;;; +328C;CIRCLED IDEOGRAPH WATER;So;0;L; 6C34;;;;N;;;;; +328D;CIRCLED IDEOGRAPH WOOD;So;0;L; 6728;;;;N;;;;; +328E;CIRCLED IDEOGRAPH METAL;So;0;L; 91D1;;;;N;;;;; +328F;CIRCLED IDEOGRAPH EARTH;So;0;L; 571F;;;;N;;;;; +3290;CIRCLED IDEOGRAPH SUN;So;0;L; 65E5;;;;N;;;;; +3291;CIRCLED IDEOGRAPH STOCK;So;0;L; 682A;;;;N;;;;; +3292;CIRCLED IDEOGRAPH HAVE;So;0;L; 6709;;;;N;;;;; +3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L; 793E;;;;N;;;;; +3294;CIRCLED IDEOGRAPH NAME;So;0;L; 540D;;;;N;;;;; +3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L; 7279;;;;N;;;;; +3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L; 8CA1;;;;N;;;;; +3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L; 795D;;;;N;;;;; +3298;CIRCLED IDEOGRAPH LABOR;So;0;L; 52B4;;;;N;;;;; +3299;CIRCLED IDEOGRAPH SECRET;So;0;L; 79D8;;;;N;;;;; +329A;CIRCLED IDEOGRAPH MALE;So;0;L; 7537;;;;N;;;;; +329B;CIRCLED IDEOGRAPH FEMALE;So;0;L; 5973;;;;N;;;;; +329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L; 9069;;;;N;;;;; +329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L; 512A;;;;N;;;;; +329E;CIRCLED IDEOGRAPH PRINT;So;0;L; 5370;;;;N;;;;; +329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L; 6CE8;;;;N;;;;; +32A0;CIRCLED IDEOGRAPH ITEM;So;0;L; 9805;;;;N;;;;; +32A1;CIRCLED IDEOGRAPH REST;So;0;L; 4F11;;;;N;;;;; +32A2;CIRCLED IDEOGRAPH COPY;So;0;L; 5199;;;;N;;;;; +32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L; 6B63;;;;N;;;;; +32A4;CIRCLED IDEOGRAPH HIGH;So;0;L; 4E0A;;;;N;;;;; +32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L; 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;; +32A6;CIRCLED IDEOGRAPH LOW;So;0;L; 4E0B;;;;N;;;;; +32A7;CIRCLED IDEOGRAPH LEFT;So;0;L; 5DE6;;;;N;;;;; +32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L; 53F3;;;;N;;;;; +32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L; 533B;;;;N;;;;; +32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L; 5B97;;;;N;;;;; +32AB;CIRCLED IDEOGRAPH STUDY;So;0;L; 5B66;;;;N;;;;; +32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L; 76E3;;;;N;;;;; +32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L; 4F01;;;;N;;;;; +32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L; 8CC7;;;;N;;;;; +32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L; 5354;;;;N;;;;; +32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L; 591C;;;;N;;;;; +32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L; 0031 6708;;;;N;;;;; +32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L; 0032 6708;;;;N;;;;; +32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L; 0033 6708;;;;N;;;;; +32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L; 0034 6708;;;;N;;;;; +32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L; 0035 6708;;;;N;;;;; +32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L; 0036 6708;;;;N;;;;; +32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L; 0037 6708;;;;N;;;;; +32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L; 0038 6708;;;;N;;;;; +32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L; 0039 6708;;;;N;;;;; +32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L; 0031 0030 6708;;;;N;;;;; +32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L; 0031 0031 6708;;;;N;;;;; +32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L; 0031 0032 6708;;;;N;;;;; +32D0;CIRCLED KATAKANA A;So;0;L; 30A2;;;;N;;;;; +32D1;CIRCLED KATAKANA I;So;0;L; 30A4;;;;N;;;;; +32D2;CIRCLED KATAKANA U;So;0;L; 30A6;;;;N;;;;; +32D3;CIRCLED KATAKANA E;So;0;L; 30A8;;;;N;;;;; +32D4;CIRCLED KATAKANA O;So;0;L; 30AA;;;;N;;;;; +32D5;CIRCLED KATAKANA KA;So;0;L; 30AB;;;;N;;;;; +32D6;CIRCLED KATAKANA KI;So;0;L; 30AD;;;;N;;;;; +32D7;CIRCLED KATAKANA KU;So;0;L; 30AF;;;;N;;;;; +32D8;CIRCLED KATAKANA KE;So;0;L; 30B1;;;;N;;;;; +32D9;CIRCLED KATAKANA KO;So;0;L; 30B3;;;;N;;;;; +32DA;CIRCLED KATAKANA SA;So;0;L; 30B5;;;;N;;;;; +32DB;CIRCLED KATAKANA SI;So;0;L; 30B7;;;;N;;;;; +32DC;CIRCLED KATAKANA SU;So;0;L; 30B9;;;;N;;;;; +32DD;CIRCLED KATAKANA SE;So;0;L; 30BB;;;;N;;;;; +32DE;CIRCLED KATAKANA SO;So;0;L; 30BD;;;;N;;;;; +32DF;CIRCLED KATAKANA TA;So;0;L; 30BF;;;;N;;;;; +32E0;CIRCLED KATAKANA TI;So;0;L; 30C1;;;;N;;;;; +32E1;CIRCLED KATAKANA TU;So;0;L; 30C4;;;;N;;;;; +32E2;CIRCLED KATAKANA TE;So;0;L; 30C6;;;;N;;;;; +32E3;CIRCLED KATAKANA TO;So;0;L; 30C8;;;;N;;;;; +32E4;CIRCLED KATAKANA NA;So;0;L; 30CA;;;;N;;;;; +32E5;CIRCLED KATAKANA NI;So;0;L; 30CB;;;;N;;;;; +32E6;CIRCLED KATAKANA NU;So;0;L; 30CC;;;;N;;;;; +32E7;CIRCLED KATAKANA NE;So;0;L; 30CD;;;;N;;;;; +32E8;CIRCLED KATAKANA NO;So;0;L; 30CE;;;;N;;;;; +32E9;CIRCLED KATAKANA HA;So;0;L; 30CF;;;;N;;;;; +32EA;CIRCLED KATAKANA HI;So;0;L; 30D2;;;;N;;;;; +32EB;CIRCLED KATAKANA HU;So;0;L; 30D5;;;;N;;;;; +32EC;CIRCLED KATAKANA HE;So;0;L; 30D8;;;;N;;;;; +32ED;CIRCLED KATAKANA HO;So;0;L; 30DB;;;;N;;;;; +32EE;CIRCLED KATAKANA MA;So;0;L; 30DE;;;;N;;;;; +32EF;CIRCLED KATAKANA MI;So;0;L; 30DF;;;;N;;;;; +32F0;CIRCLED KATAKANA MU;So;0;L; 30E0;;;;N;;;;; +32F1;CIRCLED KATAKANA ME;So;0;L; 30E1;;;;N;;;;; +32F2;CIRCLED KATAKANA MO;So;0;L; 30E2;;;;N;;;;; +32F3;CIRCLED KATAKANA YA;So;0;L; 30E4;;;;N;;;;; +32F4;CIRCLED KATAKANA YU;So;0;L; 30E6;;;;N;;;;; +32F5;CIRCLED KATAKANA YO;So;0;L; 30E8;;;;N;;;;; +32F6;CIRCLED KATAKANA RA;So;0;L; 30E9;;;;N;;;;; +32F7;CIRCLED KATAKANA RI;So;0;L; 30EA;;;;N;;;;; +32F8;CIRCLED KATAKANA RU;So;0;L; 30EB;;;;N;;;;; +32F9;CIRCLED KATAKANA RE;So;0;L; 30EC;;;;N;;;;; +32FA;CIRCLED KATAKANA RO;So;0;L; 30ED;;;;N;;;;; +32FB;CIRCLED KATAKANA WA;So;0;L; 30EF;;;;N;;;;; +32FC;CIRCLED KATAKANA WI;So;0;L; 30F0;;;;N;;;;; +32FD;CIRCLED KATAKANA WE;So;0;L; 30F1;;;;N;;;;; +32FE;CIRCLED KATAKANA WO;So;0;L; 30F2;;;;N;;;;; +3300;SQUARE APAATO;So;0;L; 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;; +3301;SQUARE ARUHUA;So;0;L; 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;; +3302;SQUARE ANPEA;So;0;L; 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;; +3303;SQUARE AARU;So;0;L; 30A2 30FC 30EB;;;;N;SQUARED AARU;;;; +3304;SQUARE ININGU;So;0;L; 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;; +3305;SQUARE INTI;So;0;L; 30A4 30F3 30C1;;;;N;SQUARED INTI;;;; +3306;SQUARE UON;So;0;L; 30A6 30A9 30F3;;;;N;SQUARED UON;;;; +3307;SQUARE ESUKUUDO;So;0;L; 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;; +3308;SQUARE EEKAA;So;0;L; 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;; +3309;SQUARE ONSU;So;0;L; 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;; +330A;SQUARE OOMU;So;0;L; 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;; +330B;SQUARE KAIRI;So;0;L; 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;; +330C;SQUARE KARATTO;So;0;L; 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;; +330D;SQUARE KARORII;So;0;L; 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;; +330E;SQUARE GARON;So;0;L; 30AC 30ED 30F3;;;;N;SQUARED GARON;;;; +330F;SQUARE GANMA;So;0;L; 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;; +3310;SQUARE GIGA;So;0;L; 30AE 30AC;;;;N;SQUARED GIGA;;;; +3311;SQUARE GINII;So;0;L; 30AE 30CB 30FC;;;;N;SQUARED GINII;;;; +3312;SQUARE KYURII;So;0;L; 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;; +3313;SQUARE GIRUDAA;So;0;L; 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;; +3314;SQUARE KIRO;So;0;L; 30AD 30ED;;;;N;SQUARED KIRO;;;; +3315;SQUARE KIROGURAMU;So;0;L; 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;; +3316;SQUARE KIROMEETORU;So;0;L; 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;; +3317;SQUARE KIROWATTO;So;0;L; 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;; +3318;SQUARE GURAMU;So;0;L; 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;; +3319;SQUARE GURAMUTON;So;0;L; 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;; +331A;SQUARE KURUZEIRO;So;0;L; 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;; +331B;SQUARE KUROONE;So;0;L; 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;; +331C;SQUARE KEESU;So;0;L; 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;; +331D;SQUARE KORUNA;So;0;L; 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;; +331E;SQUARE KOOPO;So;0;L; 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;; +331F;SQUARE SAIKURU;So;0;L; 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;; +3320;SQUARE SANTIIMU;So;0;L; 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;; +3321;SQUARE SIRINGU;So;0;L; 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;; +3322;SQUARE SENTI;So;0;L; 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;; +3323;SQUARE SENTO;So;0;L; 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;; +3324;SQUARE DAASU;So;0;L; 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;; +3325;SQUARE DESI;So;0;L; 30C7 30B7;;;;N;SQUARED DESI;;;; +3326;SQUARE DORU;So;0;L; 30C9 30EB;;;;N;SQUARED DORU;;;; +3327;SQUARE TON;So;0;L; 30C8 30F3;;;;N;SQUARED TON;;;; +3328;SQUARE NANO;So;0;L; 30CA 30CE;;;;N;SQUARED NANO;;;; +3329;SQUARE NOTTO;So;0;L; 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;; +332A;SQUARE HAITU;So;0;L; 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;; +332B;SQUARE PAASENTO;So;0;L; 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;; +332C;SQUARE PAATU;So;0;L; 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;; +332D;SQUARE BAARERU;So;0;L; 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;; +332E;SQUARE PIASUTORU;So;0;L; 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;; +332F;SQUARE PIKURU;So;0;L; 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;; +3330;SQUARE PIKO;So;0;L; 30D4 30B3;;;;N;SQUARED PIKO;;;; +3331;SQUARE BIRU;So;0;L; 30D3 30EB;;;;N;SQUARED BIRU;;;; +3332;SQUARE HUARADDO;So;0;L; 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;; +3333;SQUARE HUIITO;So;0;L; 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;; +3334;SQUARE BUSSYERU;So;0;L; 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;; +3335;SQUARE HURAN;So;0;L; 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;; +3336;SQUARE HEKUTAARU;So;0;L; 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;; +3337;SQUARE PESO;So;0;L; 30DA 30BD;;;;N;SQUARED PESO;;;; +3338;SQUARE PENIHI;So;0;L; 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;; +3339;SQUARE HERUTU;So;0;L; 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;; +333A;SQUARE PENSU;So;0;L; 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;; +333B;SQUARE PEEZI;So;0;L; 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;; +333C;SQUARE BEETA;So;0;L; 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;; +333D;SQUARE POINTO;So;0;L; 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;; +333E;SQUARE BORUTO;So;0;L; 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;; +333F;SQUARE HON;So;0;L; 30DB 30F3;;;;N;SQUARED HON;;;; +3340;SQUARE PONDO;So;0;L; 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;; +3341;SQUARE HOORU;So;0;L; 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;; +3342;SQUARE HOON;So;0;L; 30DB 30FC 30F3;;;;N;SQUARED HOON;;;; +3343;SQUARE MAIKURO;So;0;L; 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;; +3344;SQUARE MAIRU;So;0;L; 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;; +3345;SQUARE MAHHA;So;0;L; 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;; +3346;SQUARE MARUKU;So;0;L; 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;; +3347;SQUARE MANSYON;So;0;L; 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;; +3348;SQUARE MIKURON;So;0;L; 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;; +3349;SQUARE MIRI;So;0;L; 30DF 30EA;;;;N;SQUARED MIRI;;;; +334A;SQUARE MIRIBAARU;So;0;L; 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;; +334B;SQUARE MEGA;So;0;L; 30E1 30AC;;;;N;SQUARED MEGA;;;; +334C;SQUARE MEGATON;So;0;L; 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;; +334D;SQUARE MEETORU;So;0;L; 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;; +334E;SQUARE YAADO;So;0;L; 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;; +334F;SQUARE YAARU;So;0;L; 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;; +3350;SQUARE YUAN;So;0;L; 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;; +3351;SQUARE RITTORU;So;0;L; 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;; +3352;SQUARE RIRA;So;0;L; 30EA 30E9;;;;N;SQUARED RIRA;;;; +3353;SQUARE RUPII;So;0;L; 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;; +3354;SQUARE RUUBURU;So;0;L; 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;; +3355;SQUARE REMU;So;0;L; 30EC 30E0;;;;N;SQUARED REMU;;;; +3356;SQUARE RENTOGEN;So;0;L; 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;; +3357;SQUARE WATTO;So;0;L; 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;; +3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L; 0030 70B9;;;;N;;;;; +3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L; 0031 70B9;;;;N;;;;; +335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L; 0032 70B9;;;;N;;;;; +335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L; 0033 70B9;;;;N;;;;; +335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L; 0034 70B9;;;;N;;;;; +335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L; 0035 70B9;;;;N;;;;; +335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L; 0036 70B9;;;;N;;;;; +335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L; 0037 70B9;;;;N;;;;; +3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L; 0038 70B9;;;;N;;;;; +3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L; 0039 70B9;;;;N;;;;; +3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L; 0031 0030 70B9;;;;N;;;;; +3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L; 0031 0031 70B9;;;;N;;;;; +3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L; 0031 0032 70B9;;;;N;;;;; +3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L; 0031 0033 70B9;;;;N;;;;; +3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L; 0031 0034 70B9;;;;N;;;;; +3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L; 0031 0035 70B9;;;;N;;;;; +3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L; 0031 0036 70B9;;;;N;;;;; +3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L; 0031 0037 70B9;;;;N;;;;; +336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L; 0031 0038 70B9;;;;N;;;;; +336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L; 0031 0039 70B9;;;;N;;;;; +336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L; 0032 0030 70B9;;;;N;;;;; +336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L; 0032 0031 70B9;;;;N;;;;; +336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L; 0032 0032 70B9;;;;N;;;;; +336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L; 0032 0033 70B9;;;;N;;;;; +3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L; 0032 0034 70B9;;;;N;;;;; +3371;SQUARE HPA;So;0;L; 0068 0050 0061;;;;N;;;;; +3372;SQUARE DA;So;0;L; 0064 0061;;;;N;;;;; +3373;SQUARE AU;So;0;L; 0041 0055;;;;N;;;;; +3374;SQUARE BAR;So;0;L; 0062 0061 0072;;;;N;;;;; +3375;SQUARE OV;So;0;L; 006F 0056;;;;N;;;;; +3376;SQUARE PC;So;0;L; 0070 0063;;;;N;;;;; +337B;SQUARE ERA NAME HEISEI;So;0;L; 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;; +337C;SQUARE ERA NAME SYOUWA;So;0;L; 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;; +337D;SQUARE ERA NAME TAISYOU;So;0;L; 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;; +337E;SQUARE ERA NAME MEIZI;So;0;L; 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;; +337F;SQUARE CORPORATION;So;0;L; 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;; +3380;SQUARE PA AMPS;So;0;L; 0070 0041;;;;N;SQUARED PA AMPS;;;; +3381;SQUARE NA;So;0;L; 006E 0041;;;;N;SQUARED NA;;;; +3382;SQUARE MU A;So;0;L; 03BC 0041;;;;N;SQUARED MU A;;;; +3383;SQUARE MA;So;0;L; 006D 0041;;;;N;SQUARED MA;;;; +3384;SQUARE KA;So;0;L; 006B 0041;;;;N;SQUARED KA;;;; +3385;SQUARE KB;So;0;L; 004B 0042;;;;N;SQUARED KB;;;; +3386;SQUARE MB;So;0;L; 004D 0042;;;;N;SQUARED MB;;;; +3387;SQUARE GB;So;0;L; 0047 0042;;;;N;SQUARED GB;;;; +3388;SQUARE CAL;So;0;L; 0063 0061 006C;;;;N;SQUARED CAL;;;; +3389;SQUARE KCAL;So;0;L; 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;; +338A;SQUARE PF;So;0;L; 0070 0046;;;;N;SQUARED PF;;;; +338B;SQUARE NF;So;0;L; 006E 0046;;;;N;SQUARED NF;;;; +338C;SQUARE MU F;So;0;L; 03BC 0046;;;;N;SQUARED MU F;;;; +338D;SQUARE MU G;So;0;L; 03BC 0067;;;;N;SQUARED MU G;;;; +338E;SQUARE MG;So;0;L; 006D 0067;;;;N;SQUARED MG;;;; +338F;SQUARE KG;So;0;L; 006B 0067;;;;N;SQUARED KG;;;; +3390;SQUARE HZ;So;0;L; 0048 007A;;;;N;SQUARED HZ;;;; +3391;SQUARE KHZ;So;0;L; 006B 0048 007A;;;;N;SQUARED KHZ;;;; +3392;SQUARE MHZ;So;0;L; 004D 0048 007A;;;;N;SQUARED MHZ;;;; +3393;SQUARE GHZ;So;0;L; 0047 0048 007A;;;;N;SQUARED GHZ;;;; +3394;SQUARE THZ;So;0;L; 0054 0048 007A;;;;N;SQUARED THZ;;;; +3395;SQUARE MU L;So;0;L; 03BC 2113;;;;N;SQUARED MU L;;;; +3396;SQUARE ML;So;0;L; 006D 2113;;;;N;SQUARED ML;;;; +3397;SQUARE DL;So;0;L; 0064 2113;;;;N;SQUARED DL;;;; +3398;SQUARE KL;So;0;L; 006B 2113;;;;N;SQUARED KL;;;; +3399;SQUARE FM;So;0;L; 0066 006D;;;;N;SQUARED FM;;;; +339A;SQUARE NM;So;0;L; 006E 006D;;;;N;SQUARED NM;;;; +339B;SQUARE MU M;So;0;L; 03BC 006D;;;;N;SQUARED MU M;;;; +339C;SQUARE MM;So;0;L; 006D 006D;;;;N;SQUARED MM;;;; +339D;SQUARE CM;So;0;L; 0063 006D;;;;N;SQUARED CM;;;; +339E;SQUARE KM;So;0;L; 006B 006D;;;;N;SQUARED KM;;;; +339F;SQUARE MM SQUARED;So;0;L; 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;; +33A0;SQUARE CM SQUARED;So;0;L; 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;; +33A1;SQUARE M SQUARED;So;0;L; 006D 00B2;;;;N;SQUARED M SQUARED;;;; +33A2;SQUARE KM SQUARED;So;0;L; 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;; +33A3;SQUARE MM CUBED;So;0;L; 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;; +33A4;SQUARE CM CUBED;So;0;L; 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;; +33A5;SQUARE M CUBED;So;0;L; 006D 00B3;;;;N;SQUARED M CUBED;;;; +33A6;SQUARE KM CUBED;So;0;L; 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;; +33A7;SQUARE M OVER S;So;0;L; 006D 2215 0073;;;;N;SQUARED M OVER S;;;; +33A8;SQUARE M OVER S SQUARED;So;0;L; 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;; +33A9;SQUARE PA;So;0;L; 0050 0061;;;;N;SQUARED PA;;;; +33AA;SQUARE KPA;So;0;L; 006B 0050 0061;;;;N;SQUARED KPA;;;; +33AB;SQUARE MPA;So;0;L; 004D 0050 0061;;;;N;SQUARED MPA;;;; +33AC;SQUARE GPA;So;0;L; 0047 0050 0061;;;;N;SQUARED GPA;;;; +33AD;SQUARE RAD;So;0;L; 0072 0061 0064;;;;N;SQUARED RAD;;;; +33AE;SQUARE RAD OVER S;So;0;L; 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;; +33AF;SQUARE RAD OVER S SQUARED;So;0;L; 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;; +33B0;SQUARE PS;So;0;L; 0070 0073;;;;N;SQUARED PS;;;; +33B1;SQUARE NS;So;0;L; 006E 0073;;;;N;SQUARED NS;;;; +33B2;SQUARE MU S;So;0;L; 03BC 0073;;;;N;SQUARED MU S;;;; +33B3;SQUARE MS;So;0;L; 006D 0073;;;;N;SQUARED MS;;;; +33B4;SQUARE PV;So;0;L; 0070 0056;;;;N;SQUARED PV;;;; +33B5;SQUARE NV;So;0;L; 006E 0056;;;;N;SQUARED NV;;;; +33B6;SQUARE MU V;So;0;L; 03BC 0056;;;;N;SQUARED MU V;;;; +33B7;SQUARE MV;So;0;L; 006D 0056;;;;N;SQUARED MV;;;; +33B8;SQUARE KV;So;0;L; 006B 0056;;;;N;SQUARED KV;;;; +33B9;SQUARE MV MEGA;So;0;L; 004D 0056;;;;N;SQUARED MV MEGA;;;; +33BA;SQUARE PW;So;0;L; 0070 0057;;;;N;SQUARED PW;;;; +33BB;SQUARE NW;So;0;L; 006E 0057;;;;N;SQUARED NW;;;; +33BC;SQUARE MU W;So;0;L; 03BC 0057;;;;N;SQUARED MU W;;;; +33BD;SQUARE MW;So;0;L; 006D 0057;;;;N;SQUARED MW;;;; +33BE;SQUARE KW;So;0;L; 006B 0057;;;;N;SQUARED KW;;;; +33BF;SQUARE MW MEGA;So;0;L; 004D 0057;;;;N;SQUARED MW MEGA;;;; +33C0;SQUARE K OHM;So;0;L; 006B 03A9;;;;N;SQUARED K OHM;;;; +33C1;SQUARE M OHM;So;0;L; 004D 03A9;;;;N;SQUARED M OHM;;;; +33C2;SQUARE AM;So;0;L; 0061 002E 006D 002E;;;;N;SQUARED AM;;;; +33C3;SQUARE BQ;So;0;L; 0042 0071;;;;N;SQUARED BQ;;;; +33C4;SQUARE CC;So;0;L; 0063 0063;;;;N;SQUARED CC;;;; +33C5;SQUARE CD;So;0;L; 0063 0064;;;;N;SQUARED CD;;;; +33C6;SQUARE C OVER KG;So;0;L; 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;; +33C7;SQUARE CO;So;0;L; 0043 006F 002E;;;;N;SQUARED CO;;;; +33C8;SQUARE DB;So;0;L; 0064 0042;;;;N;SQUARED DB;;;; +33C9;SQUARE GY;So;0;L; 0047 0079;;;;N;SQUARED GY;;;; +33CA;SQUARE HA;So;0;L; 0068 0061;;;;N;SQUARED HA;;;; +33CB;SQUARE HP;So;0;L; 0048 0050;;;;N;SQUARED HP;;;; +33CC;SQUARE IN;So;0;L; 0069 006E;;;;N;SQUARED IN;;;; +33CD;SQUARE KK;So;0;L; 004B 004B;;;;N;SQUARED KK;;;; +33CE;SQUARE KM CAPITAL;So;0;L; 004B 004D;;;;N;SQUARED KM CAPITAL;;;; +33CF;SQUARE KT;So;0;L; 006B 0074;;;;N;SQUARED KT;;;; +33D0;SQUARE LM;So;0;L; 006C 006D;;;;N;SQUARED LM;;;; +33D1;SQUARE LN;So;0;L; 006C 006E;;;;N;SQUARED LN;;;; +33D2;SQUARE LOG;So;0;L; 006C 006F 0067;;;;N;SQUARED LOG;;;; +33D3;SQUARE LX;So;0;L; 006C 0078;;;;N;SQUARED LX;;;; +33D4;SQUARE MB SMALL;So;0;L; 006D 0062;;;;N;SQUARED MB SMALL;;;; +33D5;SQUARE MIL;So;0;L; 006D 0069 006C;;;;N;SQUARED MIL;;;; +33D6;SQUARE MOL;So;0;L; 006D 006F 006C;;;;N;SQUARED MOL;;;; +33D7;SQUARE PH;So;0;L; 0050 0048;;;;N;SQUARED PH;;;; +33D8;SQUARE PM;So;0;L; 0070 002E 006D 002E;;;;N;SQUARED PM;;;; +33D9;SQUARE PPM;So;0;L; 0050 0050 004D;;;;N;SQUARED PPM;;;; +33DA;SQUARE PR;So;0;L; 0050 0052;;;;N;SQUARED PR;;;; +33DB;SQUARE SR;So;0;L; 0073 0072;;;;N;SQUARED SR;;;; +33DC;SQUARE SV;So;0;L; 0053 0076;;;;N;SQUARED SV;;;; +33DD;SQUARE WB;So;0;L; 0057 0062;;;;N;SQUARED WB;;;; +33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L; 0031 65E5;;;;N;;;;; +33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L; 0032 65E5;;;;N;;;;; +33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L; 0033 65E5;;;;N;;;;; +33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L; 0034 65E5;;;;N;;;;; +33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L; 0035 65E5;;;;N;;;;; +33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L; 0036 65E5;;;;N;;;;; +33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L; 0037 65E5;;;;N;;;;; +33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L; 0038 65E5;;;;N;;;;; +33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L; 0039 65E5;;;;N;;;;; +33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L; 0031 0030 65E5;;;;N;;;;; +33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L; 0031 0031 65E5;;;;N;;;;; +33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L; 0031 0032 65E5;;;;N;;;;; +33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L; 0031 0033 65E5;;;;N;;;;; +33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L; 0031 0034 65E5;;;;N;;;;; +33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L; 0031 0035 65E5;;;;N;;;;; +33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L; 0031 0036 65E5;;;;N;;;;; +33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L; 0031 0037 65E5;;;;N;;;;; +33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L; 0031 0038 65E5;;;;N;;;;; +33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L; 0031 0039 65E5;;;;N;;;;; +33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L; 0032 0030 65E5;;;;N;;;;; +33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L; 0032 0031 65E5;;;;N;;;;; +33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L; 0032 0032 65E5;;;;N;;;;; +33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L; 0032 0033 65E5;;;;N;;;;; +33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L; 0032 0034 65E5;;;;N;;;;; +33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L; 0032 0035 65E5;;;;N;;;;; +33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L; 0032 0036 65E5;;;;N;;;;; +33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L; 0032 0037 65E5;;;;N;;;;; +33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L; 0032 0038 65E5;;;;N;;;;; +33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L; 0032 0039 65E5;;;;N;;;;; +33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L; 0033 0030 65E5;;;;N;;;;; +33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L; 0033 0031 65E5;;;;N;;;;; +3400;;Lo;0;L;;;;;N;;;;; +4DB5;;Lo;0;L;;;;;N;;;;; +4E00;;Lo;0;L;;;;;N;;;;; +9FA5;;Lo;0;L;;;;;N;;;;; +A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; +A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; +A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; +A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;; +A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;; +A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;; +A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;; +A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;; +A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;; +A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;; +A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;; +A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;; +A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;; +A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;; +A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;; +A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;; +A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;; +A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;; +A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;; +A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;; +A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;; +A015;YI SYLLABLE WU;Lo;0;L;;;;;N;;;;; +A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;; +A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;; +A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;; +A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;; +A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;; +A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;; +A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;; +A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;; +A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;; +A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;; +A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;; +A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;; +A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;; +A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;; +A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;; +A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;; +A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;; +A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;; +A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;; +A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;; +A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;; +A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;; +A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;; +A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;; +A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;; +A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;; +A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;; +A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;; +A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;; +A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;; +A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;; +A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;; +A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;; +A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;; +A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;; +A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;; +A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;; +A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;; +A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;; +A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;; +A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;; +A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;; +A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;; +A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;; +A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;; +A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;; +A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;; +A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;; +A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;; +A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;; +A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;; +A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;; +A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;; +A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;; +A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;; +A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;; +A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;; +A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;; +A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;; +A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;; +A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;; +A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;; +A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;; +A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;; +A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;; +A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;; +A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;; +A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;; +A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;; +A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;; +A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;; +A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;; +A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;; +A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;; +A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;; +A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;; +A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;; +A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;; +A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;; +A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;; +A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;; +A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;; +A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;; +A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;; +A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;; +A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;; +A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;; +A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;; +A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;; +A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;; +A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;; +A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;; +A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;; +A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;; +A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;; +A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;; +A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;; +A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;; +A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;; +A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;; +A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;; +A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;; +A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;; +A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;; +A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;; +A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;; +A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;; +A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;; +A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;; +A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;; +A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;; +A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;; +A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;; +A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;; +A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;; +A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;; +A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;; +A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;; +A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;; +A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;; +A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;; +A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;; +A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;; +A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;; +A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;; +A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;; +A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;; +A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;; +A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;; +A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;; +A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;; +A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;; +A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;; +A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;; +A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;; +A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;; +A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;; +A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;; +A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;; +A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;; +A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;; +A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;; +A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;; +A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;; +A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;; +A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;; +A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;; +A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;; +A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;; +A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;; +A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;; +A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;; +A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;; +A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;; +A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;; +A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;; +A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;; +A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;; +A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;; +A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;; +A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;; +A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;; +A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;; +A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;; +A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;; +A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;; +A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;; +A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;; +A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;; +A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;; +A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;; +A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;; +A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;; +A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;; +A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;; +A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;; +A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;; +A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;; +A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;; +A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;; +A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;; +A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;; +A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;; +A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;; +A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;; +A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;; +A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;; +A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;; +A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;; +A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;; +A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;; +A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;; +A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;; +A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;; +A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;; +A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;; +A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;; +A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;; +A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;; +A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;; +A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;; +A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;; +A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;; +A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;; +A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;; +A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;; +A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;; +A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;; +A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;; +A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;; +A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;; +A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;; +A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;; +A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;; +A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;; +A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;; +A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;; +A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;; +A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;; +A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;; +A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;; +A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;; +A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;; +A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;; +A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;; +A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;; +A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;; +A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;; +A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;; +A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;; +A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;; +A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;; +A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;; +A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;; +A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;; +A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;; +A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;; +A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;; +A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;; +A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;; +A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;; +A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;; +A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;; +A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;; +A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;; +A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;; +A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;; +A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;; +A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;; +A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;; +A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;; +A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;; +A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;; +A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;; +A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;; +A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;; +A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;; +A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;; +A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;; +A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;; +A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;; +A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;; +A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;; +A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;; +A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;; +A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;; +A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;; +A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;; +A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;; +A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;; +A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;; +A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;; +A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;; +A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;; +A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;; +A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;; +A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;; +A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;; +A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;; +A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;; +A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;; +A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;; +A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;; +A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;; +A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;; +A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;; +A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;; +A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;; +A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;; +A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;; +A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;; +A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;; +A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;; +A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;; +A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;; +A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;; +A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;; +A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;; +A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;; +A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;; +A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;; +A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;; +A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;; +A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;; +A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;; +A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;; +A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;; +A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;; +A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;; +A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;; +A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;; +A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;; +A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;; +A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;; +A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;; +A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;; +A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;; +A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;; +A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;; +A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;; +A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;; +A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;; +A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;; +A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;; +A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;; +A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;; +A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;; +A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;; +A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;; +A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;; +A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;; +A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;; +A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;; +A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;; +A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;; +A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;; +A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;; +A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;; +A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;; +A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;; +A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;; +A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;; +A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;; +A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;; +A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;; +A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;; +A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;; +A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;; +A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;; +A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;; +A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;; +A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;; +A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;; +A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;; +A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;; +A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;; +A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;; +A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;; +A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;; +A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;; +A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;; +A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;; +A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;; +A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;; +A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;; +A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;; +A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;; +A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;; +A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;; +A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;; +A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;; +A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;; +A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;; +A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;; +A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;; +A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;; +A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;; +A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;; +A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;; +A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;; +A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;; +A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;; +A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;; +A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;; +A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;; +A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;; +A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;; +A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;; +A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;; +A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;; +A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;; +A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;; +A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;; +A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;; +A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;; +A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;; +A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;; +A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;; +A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;; +A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;; +A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;; +A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;; +A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;; +A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;; +A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;; +A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;; +A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;; +A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;; +A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;; +A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;; +A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;; +A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;; +A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;; +A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;; +A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;; +A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;; +A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;; +A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;; +A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;; +A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;; +A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;; +A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;; +A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;; +A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;; +A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;; +A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;; +A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;; +A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;; +A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;; +A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;; +A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;; +A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;; +A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;; +A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;; +A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;; +A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;; +A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;; +A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;; +A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;; +A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;; +A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;; +A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;; +A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;; +A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;; +A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;; +A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;; +A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;; +A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;; +A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;; +A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;; +A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;; +A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;; +A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;; +A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;; +A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;; +A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;; +A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;; +A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;; +A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;; +A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;; +A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;; +A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;; +A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;; +A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;; +A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;; +A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;; +A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;; +A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;; +A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;; +A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;; +A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;; +A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;; +A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;; +A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;; +A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;; +A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;; +A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;; +A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;; +A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;; +A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;; +A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;; +A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;; +A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;; +A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;; +A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;; +A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;; +A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;; +A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;; +A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;; +A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;; +A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;; +A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;; +A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;; +A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;; +A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;; +A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;; +A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;; +A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;; +A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;; +A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;; +A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;; +A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;; +A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;; +A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;; +A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;; +A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;; +A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;; +A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;; +A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;; +A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;; +A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;; +A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;; +A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;; +A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;; +A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;; +A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;; +A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;; +A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;; +A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;; +A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;; +A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;; +A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;; +A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;; +A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;; +A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;; +A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;; +A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;; +A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;; +A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;; +A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;; +A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;; +A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;; +A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;; +A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;; +A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;; +A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;; +A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;; +A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;; +A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;; +A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;; +A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;; +A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;; +A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;; +A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;; +A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;; +A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;; +A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;; +A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;; +A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;; +A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;; +A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;; +A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;; +A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;; +A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;; +A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;; +A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;; +A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;; +A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;; +A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;; +A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;; +A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;; +A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;; +A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;; +A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;; +A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;; +A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;; +A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;; +A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;; +A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;; +A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;; +A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;; +A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;; +A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;; +A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;; +A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;; +A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;; +A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;; +A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;; +A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;; +A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;; +A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;; +A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;; +A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;; +A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;; +A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;; +A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;; +A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;; +A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;; +A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;; +A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;; +A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;; +A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;; +A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;; +A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;; +A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;; +A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;; +A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;; +A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;; +A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;; +A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;; +A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;; +A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;; +A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;; +A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;; +A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;; +A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;; +A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;; +A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;; +A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;; +A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;; +A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;; +A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;; +A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;; +A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;; +A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;; +A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;; +A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;; +A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;; +A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;; +A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;; +A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;; +A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;; +A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;; +A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;; +A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;; +A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;; +A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;; +A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;; +A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;; +A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;; +A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;; +A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;; +A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;; +A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;; +A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;; +A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;; +A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;; +A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;; +A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;; +A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;; +A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;; +A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;; +A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;; +A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;; +A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;; +A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;; +A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;; +A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;; +A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;; +A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;; +A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;; +A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;; +A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;; +A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;; +A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;; +A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;; +A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;; +A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;; +A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;; +A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;; +A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;; +A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;; +A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;; +A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;; +A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;; +A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;; +A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;; +A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;; +A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;; +A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;; +A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;; +A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;; +A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;; +A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;; +A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;; +A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;; +A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;; +A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;; +A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;; +A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;; +A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;; +A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;; +A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;; +A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;; +A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;; +A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;; +A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;; +A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;; +A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;; +A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;; +A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;; +A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;; +A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;; +A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;; +A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;; +A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;; +A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;; +A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;; +A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;; +A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;; +A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;; +A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;; +A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;; +A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;; +A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;; +A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;; +A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;; +A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;; +A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;; +A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;; +A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;; +A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;; +A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;; +A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;; +A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;; +A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;; +A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;; +A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;; +A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;; +A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;; +A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;; +A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;; +A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;; +A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;; +A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;; +A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;; +A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;; +A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;; +A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;; +A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;; +A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;; +A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;; +A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;; +A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;; +A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;; +A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;; +A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;; +A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;; +A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;; +A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;; +A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;; +A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;; +A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;; +A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;; +A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;; +A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;; +A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;; +A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;; +A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;; +A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;; +A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;; +A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;; +A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;; +A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;; +A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;; +A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;; +A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;; +A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;; +A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;; +A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;; +A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;; +A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;; +A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;; +A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;; +A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;; +A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;; +A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;; +A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;; +A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;; +A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;; +A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;; +A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;; +A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;; +A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;; +A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;; +A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;; +A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;; +A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;; +A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;; +A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;; +A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;; +A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;; +A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;; +A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;; +A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;; +A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;; +A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;; +A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;; +A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;; +A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;; +A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;; +A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;; +A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;; +A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;; +A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;; +A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;; +A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;; +A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;; +A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;; +A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;; +A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;; +A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;; +A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;; +A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;; +A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;; +A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;; +A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;; +A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;; +A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;; +A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;; +A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;; +A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;; +A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;; +A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;; +A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;; +A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;; +A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;; +A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;; +A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;; +A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;; +A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;; +A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;; +A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;; +A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;; +A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;; +A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;; +A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;; +A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;; +A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;; +A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;; +A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;; +A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;; +A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;; +A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;; +A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;; +A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;; +A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;; +A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;; +A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;; +A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;; +A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;; +A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;; +A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;; +A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;; +A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;; +A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;; +A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;; +A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;; +A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;; +A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;; +A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;; +A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;; +A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;; +A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;; +A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;; +A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;; +A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;; +A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;; +A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;; +A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;; +A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;; +A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;; +A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;; +A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;; +A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;; +A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;; +A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;; +A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;; +A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;; +A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;; +A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;; +A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;; +A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;; +A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;; +A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;; +A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;; +A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;; +A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;; +A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;; +A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;; +A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;; +A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;; +A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;; +A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;; +A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;; +A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;; +A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;; +A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;; +A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;; +A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;; +A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;; +A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;; +A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;; +A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;; +A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;; +A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;; +A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;; +A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;; +A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;; +A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;; +A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;; +A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;; +A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;; +A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;; +A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;; +A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;; +A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;; +A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;; +A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;; +A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;; +A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;; +A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;; +A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;; +A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;; +A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;; +A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;; +A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;; +A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;; +A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;; +A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;; +A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;; +A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;; +A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;; +A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;; +A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;; +A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;; +A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;; +A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;; +A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;; +A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;; +A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;; +A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;; +A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;; +A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;; +A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;; +A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;; +A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;; +A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;; +A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;; +A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;; +A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;; +A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;; +A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;; +A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;; +A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;; +A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;; +A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;; +A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;; +A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;; +A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;; +A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;; +A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;; +A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;; +A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;; +A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;; +A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;; +A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;; +A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;; +A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;; +A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;; +A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;; +A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;; +A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;; +A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;; +A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;; +A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;; +A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;; +A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;; +A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;; +A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;; +A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;; +A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;; +A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;; +A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;; +A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;; +A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;; +A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;; +A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;; +A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;; +A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;; +A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;; +A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;; +A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;; +A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;; +A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;; +A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;; +A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;; +A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;; +A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;; +A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;; +A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;; +A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;; +A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;; +A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;; +A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;; +A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;; +A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;; +A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;; +A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;; +A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;; +A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;; +A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;; +A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;; +A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;; +A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;; +A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;; +A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;; +A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;; +A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;; +A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;; +A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;; +A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;; +A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;; +A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;; +A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;; +A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;; +A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;; +A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;; +A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;; +A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;; +A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;; +A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;; +A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;; +A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;; +A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;; +A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;; +A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;; +A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;; +A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;; +A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;; +A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;; +A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;; +A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;; +A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;; +A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;; +A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;; +A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;; +A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;; +A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;; +A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;; +A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;; +A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;; +A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;; +A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;; +A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;; +A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;; +A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;; +A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;; +A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;; +A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;; +A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;; +A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;; +A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;; +A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;; +A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;; +A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;; +A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;; +A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;; +A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;; +A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;; +A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;; +A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;; +A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;; +A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;; +A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;; +A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;; +A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;; +A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;; +A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;; +A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;; +A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;; +A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;; +A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;; +A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;; +A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;; +A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;; +A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;; +A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;; +A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;; +A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;; +A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;; +A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;; +A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;; +A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;; +A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;; +A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;; +A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;; +A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;; +A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;; +A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;; +A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;; +A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;; +A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;; +A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;; +A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;; +A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;; +A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;; +A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;; +A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;; +A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;; +A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;; +A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;; +A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;; +A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;; +A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;; +A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;; +A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;; +A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;; +A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;; +A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;; +A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;; +A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;; +A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;; +A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;; +A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;; +A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;; +A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;; +A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;; +A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;; +A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;; +A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;; +A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;; +A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;; +A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;; +A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;; +A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;; +A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;; +A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;; +A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;; +A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;; +A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;; +A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;; +A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;; +A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;; +A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;; +A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;; +A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;; +A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;; +A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;; +A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;; +A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;; +A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;; +A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;; +A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;; +A491;YI RADICAL LI;So;0;ON;;;;;N;;;;; +A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;; +A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;; +A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;; +A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;; +A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;; +A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;; +A498;YI RADICAL MI;So;0;ON;;;;;N;;;;; +A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;; +A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;; +A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;; +A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;; +A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;; +A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;; +A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;; +A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;; +A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;; +A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;; +A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;; +A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;; +A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;; +A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;; +A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;; +A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;; +A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;; +A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;; +A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;; +A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;; +A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;; +A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;; +A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;; +A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;; +A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;; +A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;; +A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;; +A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;; +A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;; +A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;; +A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;; +A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;; +A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;; +A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;; +A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;; +A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;; +A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;; +A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;; +A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;; +A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;; +A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;; +AC00;;Lo;0;L;;;;;N;;;;; +D7A3;;Lo;0;L;;;;;N;;;;; +D800;;Cs;0;L;;;;;N;;;;; +DB7F;;Cs;0;L;;;;;N;;;;; +DB80;;Cs;0;L;;;;;N;;;;; +DBFF;;Cs;0;L;;;;;N;;;;; +DC00;;Cs;0;L;;;;;N;;;;; +DFFF;;Cs;0;L;;;;;N;;;;; +E000;;Co;0;L;;;;;N;;;;; +F8FF;;Co;0;L;;;;;N;;;;; +F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;; +F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;; +F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;; +F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;; +F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;; +F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;; +F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;; +F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;; +F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;; +F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;; +F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;; +F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;; +F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;; +F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;; +F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;; +F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;; +F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;; +F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;; +F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;; +F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;; +F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;; +F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;; +F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;; +F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;; +F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;; +F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;; +F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;; +F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;; +F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;; +F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;; +F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;; +F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;; +F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;; +F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;; +F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;; +F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;; +F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;; +F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;; +F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;; +F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;; +F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;; +F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;; +F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;; +F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;; +F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;; +F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;; +F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;; +F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;; +F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;; +F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;; +F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;; +F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;; +F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;; +F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;; +F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;; +F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;; +F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;; +F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;; +F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;; +F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;; +F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;; +F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;; +F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;; +F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;; +F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;; +F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;; +F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;; +F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;; +F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;; +F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;; +F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;; +F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;; +F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;; +F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;; +F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;; +F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;; +F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;; +F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;; +F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;; +F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;; +F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;; +F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;96FB;;;;N;;;;; +F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;; +F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;; +F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;; +F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;; +F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;; +F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;; +F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;; +F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;; +F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;; +F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;; +F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;; +F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;; +F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;; +F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;; +F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;; +F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;; +F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;; +F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;; +F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;; +F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;; +F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;; +F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;; +F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;; +F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;; +F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;; +F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;; +F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;; +F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;; +F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;; +F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;; +F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;; +F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;; +F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;; +F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;; +F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;; +F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;; +F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;; +F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;; +F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;; +F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;; +F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;; +F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;; +F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;; +F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;; +F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;; +F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;; +F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;; +F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;; +F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;; +F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;; +F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;; +F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;; +F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;; +F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;; +F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;; +F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;; +F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;; +F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;; +F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;; +F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;; +F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;; +F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;; +F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;; +F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;; +F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;; +F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;; +F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;; +F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;; +F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;; +F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;; +F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;; +F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;; +F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;; +F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;; +F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;; +F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;; +F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;; +F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;; +F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;; +F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;; +F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;; +F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;; +F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;; +F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;; +F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;; +F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;; +F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;; +F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;; +F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;; +F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;; +F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;; +F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;; +F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;; +F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;; +F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;; +F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;; +F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;; +F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;; +F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;; +F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;; +F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;; +F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;; +F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;; +F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;; +F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;; +F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;; +F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;; +F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;; +F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;; +F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;; +F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;; +F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;; +F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;; +F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;; +F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;; +F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;; +F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;; +F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;; +F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;; +F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;; +F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;; +F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;; +F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;; +F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;; +F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;; +F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;; +F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;; +F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;; +F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;; +F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;; +F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;; +F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;; +F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;; +F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;; +F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;; +F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;; +F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;; +F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;; +F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;; +F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;; +F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;; +F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;; +F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;; +F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;; +F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;; +F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;; +F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;; +F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;; +F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;; +F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;; +F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;; +F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;; +F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;; +F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;; +F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;; +F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;; +F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;; +F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;; +F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;; +F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;; +F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;; +F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;; +F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;; +F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;; +F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;; +F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;; +F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;; +F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;; +F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;; +F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;; +F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;; +F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;; +F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;; +F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;; +FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;; +FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;; +FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;; +FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;; +FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;; +FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;; +FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;; +FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;; +FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;; +FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;; +FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;; +FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;; +FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;; +FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;; +FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;; +FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;; +FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;; +FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;; +FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;; +FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;; +FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;; +FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;; +FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;; +FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;; +FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;; +FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;; +FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;; +FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;; +FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;; +FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;; +FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;; +FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;*;;; +FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;; +FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;; +FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;; +FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;*;;; +FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;; +FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;; +FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;; +FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;; +FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;; +FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;; +FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;; +FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;; +FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;; +FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;; +FB00;LATIN SMALL LIGATURE FF;Ll;0;L; 0066 0066;;;;N;;;;; +FB01;LATIN SMALL LIGATURE FI;Ll;0;L; 0066 0069;;;;N;;;;; +FB02;LATIN SMALL LIGATURE FL;Ll;0;L; 0066 006C;;;;N;;;;; +FB03;LATIN SMALL LIGATURE FFI;Ll;0;L; 0066 0066 0069;;;;N;;;;; +FB04;LATIN SMALL LIGATURE FFL;Ll;0;L; 0066 0066 006C;;;;N;;;;; +FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L; 017F 0074;;;;N;;;;; +FB06;LATIN SMALL LIGATURE ST;Ll;0;L; 0073 0074;;;;N;;;;; +FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L; 0574 0576;;;;N;;;;; +FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L; 0574 0565;;;;N;;;;; +FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L; 0574 056B;;;;N;;;;; +FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L; 057E 0576;;;;N;;;;; +FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L; 0574 056D;;;;N;;;;; +FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;; +FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;; +FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;; +FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R; 05E2;;;;N;;;;; +FB21;HEBREW LETTER WIDE ALEF;Lo;0;R; 05D0;;;;N;;;;; +FB22;HEBREW LETTER WIDE DALET;Lo;0;R; 05D3;;;;N;;;;; +FB23;HEBREW LETTER WIDE HE;Lo;0;R; 05D4;;;;N;;;;; +FB24;HEBREW LETTER WIDE KAF;Lo;0;R; 05DB;;;;N;;;;; +FB25;HEBREW LETTER WIDE LAMED;Lo;0;R; 05DC;;;;N;;;;; +FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R; 05DD;;;;N;;;;; +FB27;HEBREW LETTER WIDE RESH;Lo;0;R; 05E8;;;;N;;;;; +FB28;HEBREW LETTER WIDE TAV;Lo;0;R; 05EA;;;;N;;;;; +FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; +FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;; +FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;; +FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;; +FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;; +FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;; +FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;; +FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;; +FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;; +FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;; +FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;; +FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;; +FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;; +FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;; +FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;; +FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;; +FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;; +FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;; +FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;; +FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;; +FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;; +FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;; +FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;; +FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;; +FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;; +FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;; +FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;; +FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;; +FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;; +FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;; +FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;; +FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;; +FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;; +FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R; 05D0 05DC;;;;N;;;;; +FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL; 0671;;;;N;;;;; +FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL; 0671;;;;N;;;;; +FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL; 067B;;;;N;;;;; +FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL; 067B;;;;N;;;;; +FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL; 067B;;;;N;;;;; +FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL; 067B;;;;N;;;;; +FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL; 067E;;;;N;;;;; +FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL; 067E;;;;N;;;;; +FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL; 067E;;;;N;;;;; +FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL; 067E;;;;N;;;;; +FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL; 0680;;;;N;;;;; +FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL; 067A;;;;N;;;;; +FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL; 067A;;;;N;;;;; +FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL; 067A;;;;N;;;;; +FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL; 067A;;;;N;;;;; +FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL; 067F;;;;N;;;;; +FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL; 067F;;;;N;;;;; +FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL; 067F;;;;N;;;;; +FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL; 067F;;;;N;;;;; +FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL; 0679;;;;N;;;;; +FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL; 0679;;;;N;;;;; +FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL; 0679;;;;N;;;;; +FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL; 0679;;;;N;;;;; +FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL; 06A4;;;;N;;;;; +FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL; 06A6;;;;N;;;;; +FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL; 0684;;;;N;;;;; +FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL; 0684;;;;N;;;;; +FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL; 0684;;;;N;;;;; +FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL; 0684;;;;N;;;;; +FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL; 0683;;;;N;;;;; +FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL; 0683;;;;N;;;;; +FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL; 0683;;;;N;;;;; +FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL; 0683;;;;N;;;;; +FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL; 0686;;;;N;;;;; +FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL; 0687;;;;N;;;;; +FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL; 0687;;;;N;;;;; +FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL; 0687;;;;N;;;;; +FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL; 0687;;;;N;;;;; +FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL; 068D;;;;N;;;;; +FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL; 068D;;;;N;;;;; +FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL; 068C;;;;N;;;;; +FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL; 068C;;;;N;;;;; +FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL; 068E;;;;N;;;;; +FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL; 068E;;;;N;;;;; +FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL; 0688;;;;N;;;;; +FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL; 0688;;;;N;;;;; +FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL; 0698;;;;N;;;;; +FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL; 0698;;;;N;;;;; +FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL; 0691;;;;N;;;;; +FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL; 0691;;;;N;;;;; +FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL; 06A9;;;;N;;;;; +FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL; 06AF;;;;N;;;;; +FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL; 06B3;;;;N;;;;; +FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL; 06B1;;;;N;;;;; +FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL; 06BA;;;;N;;;;; +FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL; 06BA;;;;N;;;;; +FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL; 06BB;;;;N;;;;; +FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL; 06C0;;;;N;;;;; +FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL; 06C0;;;;N;;;;; +FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL; 06C1;;;;N;;;;; +FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL; 06BE;;;;N;;;;; +FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL; 06D2;;;;N;;;;; +FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL; 06D2;;;;N;;;;; +FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 06D3;;;;N;;;;; +FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 06D3;;;;N;;;;; +FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL; 06AD;;;;N;;;;; +FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL; 06C7;;;;N;;;;; +FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL; 06C7;;;;N;;;;; +FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL; 06C6;;;;N;;;;; +FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL; 06C6;;;;N;;;;; +FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL; 06C8;;;;N;;;;; +FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL; 06C8;;;;N;;;;; +FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0677;;;;N;;;;; +FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL; 06CB;;;;N;;;;; +FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL; 06CB;;;;N;;;;; +FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL; 06C5;;;;N;;;;; +FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL; 06C5;;;;N;;;;; +FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL; 06C9;;;;N;;;;; +FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL; 06C9;;;;N;;;;; +FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL; 06D0;;;;N;;;;; +FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL; 0649;;;;N;;;;; +FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL; 0649;;;;N;;;;; +FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL; 0626 0627;;;;N;;;;; +FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL; 0626 0627;;;;N;;;;; +FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL; 0626 06D5;;;;N;;;;; +FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL; 0626 06D5;;;;N;;;;; +FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL; 0626 0648;;;;N;;;;; +FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL; 0626 0648;;;;N;;;;; +FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL; 0626 06C7;;;;N;;;;; +FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL; 0626 06C7;;;;N;;;;; +FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL; 0626 06C6;;;;N;;;;; +FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL; 0626 06C6;;;;N;;;;; +FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL; 0626 06C8;;;;N;;;;; +FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL; 0626 06C8;;;;N;;;;; +FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; +FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; +FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL; 0626 06D0;;;;N;;;;; +FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL; 06CC;;;;N;;;;; +FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL; 06CC;;;;N;;;;; +FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL; 06CC;;;;N;;;;; +FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL; 06CC;;;;N;;;;; +FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL; 0626 062C;;;;N;;;;; +FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL; 0626 062D;;;;N;;;;; +FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL; 0626 064A;;;;N;;;;; +FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0628 062C;;;;N;;;;; +FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL; 0628 062D;;;;N;;;;; +FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL; 0628 062E;;;;N;;;;; +FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0628 0649;;;;N;;;;; +FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL; 0628 064A;;;;N;;;;; +FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL; 062A 062C;;;;N;;;;; +FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL; 062A 062D;;;;N;;;;; +FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL; 062A 062E;;;;N;;;;; +FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062A 0649;;;;N;;;;; +FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL; 062A 064A;;;;N;;;;; +FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL; 062B 062C;;;;N;;;;; +FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062B 0649;;;;N;;;;; +FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL; 062B 064A;;;;N;;;;; +FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL; 062C 062D;;;;N;;;;; +FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL; 062C 0645;;;;N;;;;; +FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL; 062D 062C;;;;N;;;;; +FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL; 062D 0645;;;;N;;;;; +FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL; 062E 062C;;;;N;;;;; +FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL; 062E 062D;;;;N;;;;; +FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL; 062E 0645;;;;N;;;;; +FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL; 0633 062C;;;;N;;;;; +FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL; 0633 062D;;;;N;;;;; +FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL; 0633 062E;;;;N;;;;; +FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL; 0633 0645;;;;N;;;;; +FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL; 0635 062D;;;;N;;;;; +FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL; 0635 0645;;;;N;;;;; +FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL; 0636 062C;;;;N;;;;; +FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL; 0636 062D;;;;N;;;;; +FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL; 0636 062E;;;;N;;;;; +FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL; 0636 0645;;;;N;;;;; +FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL; 0637 062D;;;;N;;;;; +FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL; 0637 0645;;;;N;;;;; +FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL; 0638 0645;;;;N;;;;; +FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL; 0639 062C;;;;N;;;;; +FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL; 0639 0645;;;;N;;;;; +FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL; 063A 062C;;;;N;;;;; +FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL; 063A 0645;;;;N;;;;; +FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0641 062C;;;;N;;;;; +FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL; 0641 062D;;;;N;;;;; +FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL; 0641 062E;;;;N;;;;; +FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0641 0645;;;;N;;;;; +FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0641 0649;;;;N;;;;; +FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL; 0641 064A;;;;N;;;;; +FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL; 0642 062D;;;;N;;;;; +FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL; 0642 0645;;;;N;;;;; +FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0642 0649;;;;N;;;;; +FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL; 0642 064A;;;;N;;;;; +FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL; 0643 0627;;;;N;;;;; +FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL; 0643 062C;;;;N;;;;; +FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL; 0643 062D;;;;N;;;;; +FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL; 0643 062E;;;;N;;;;; +FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0643 0649;;;;N;;;;; +FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL; 0643 064A;;;;N;;;;; +FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL; 0644 062C;;;;N;;;;; +FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL; 0644 062D;;;;N;;;;; +FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL; 0644 062E;;;;N;;;;; +FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0644 0649;;;;N;;;;; +FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL; 0644 064A;;;;N;;;;; +FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL; 0645 062C;;;;N;;;;; +FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL; 0645 062D;;;;N;;;;; +FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL; 0645 062E;;;;N;;;;; +FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL; 0645 0645;;;;N;;;;; +FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0645 0649;;;;N;;;;; +FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL; 0645 064A;;;;N;;;;; +FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL; 0646 062C;;;;N;;;;; +FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL; 0646 062D;;;;N;;;;; +FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL; 0646 062E;;;;N;;;;; +FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0646 0649;;;;N;;;;; +FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL; 0646 064A;;;;N;;;;; +FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL; 0647 062C;;;;N;;;;; +FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL; 0647 0645;;;;N;;;;; +FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0647 0649;;;;N;;;;; +FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL; 0647 064A;;;;N;;;;; +FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL; 064A 062C;;;;N;;;;; +FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL; 064A 062D;;;;N;;;;; +FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL; 064A 062E;;;;N;;;;; +FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 064A 0649;;;;N;;;;; +FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL; 064A 064A;;;;N;;;;; +FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0630 0670;;;;N;;;;; +FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0631 0670;;;;N;;;;; +FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0649 0670;;;;N;;;;; +FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL; 0020 064C 0651;;;;N;;;;; +FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL; 0020 064D 0651;;;;N;;;;; +FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL; 0020 064E 0651;;;;N;;;;; +FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL; 0020 064F 0651;;;;N;;;;; +FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL; 0020 0650 0651;;;;N;;;;; +FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL; 0020 0651 0670;;;;N;;;;; +FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL; 0626 0631;;;;N;;;;; +FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL; 0626 0632;;;;N;;;;; +FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL; 0626 0646;;;;N;;;;; +FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0626 0649;;;;N;;;;; +FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL; 0626 064A;;;;N;;;;; +FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL; 0628 0631;;;;N;;;;; +FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL; 0628 0632;;;;N;;;;; +FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL; 0628 0646;;;;N;;;;; +FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0628 0649;;;;N;;;;; +FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL; 0628 064A;;;;N;;;;; +FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL; 062A 0631;;;;N;;;;; +FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL; 062A 0632;;;;N;;;;; +FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL; 062A 0646;;;;N;;;;; +FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 0649;;;;N;;;;; +FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL; 062A 064A;;;;N;;;;; +FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL; 062B 0631;;;;N;;;;; +FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL; 062B 0632;;;;N;;;;; +FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL; 062B 0646;;;;N;;;;; +FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062B 0649;;;;N;;;;; +FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL; 062B 064A;;;;N;;;;; +FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0641 0649;;;;N;;;;; +FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL; 0641 064A;;;;N;;;;; +FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0642 0649;;;;N;;;;; +FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL; 0642 064A;;;;N;;;;; +FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL; 0643 0627;;;;N;;;;; +FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0643 0649;;;;N;;;;; +FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL; 0643 064A;;;;N;;;;; +FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0644 0649;;;;N;;;;; +FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL; 0644 064A;;;;N;;;;; +FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL; 0645 0627;;;;N;;;;; +FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0645 0645;;;;N;;;;; +FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL; 0646 0631;;;;N;;;;; +FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL; 0646 0632;;;;N;;;;; +FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL; 0646 0646;;;;N;;;;; +FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 0649;;;;N;;;;; +FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL; 0646 064A;;;;N;;;;; +FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL; 0649 0670;;;;N;;;;; +FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL; 064A 0631;;;;N;;;;; +FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL; 064A 0632;;;;N;;;;; +FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL; 064A 0646;;;;N;;;;; +FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 064A 0649;;;;N;;;;; +FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL; 064A 064A;;;;N;;;;; +FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL; 0626 062C;;;;N;;;;; +FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL; 0626 062D;;;;N;;;;; +FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL; 0626 062E;;;;N;;;;; +FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL; 0626 0647;;;;N;;;;; +FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL; 0628 062C;;;;N;;;;; +FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL; 0628 062D;;;;N;;;;; +FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL; 0628 062E;;;;N;;;;; +FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL; 0628 0647;;;;N;;;;; +FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062C;;;;N;;;;; +FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL; 062A 062D;;;;N;;;;; +FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL; 062A 062E;;;;N;;;;; +FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL; 062A 0647;;;;N;;;;; +FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL; 062C 062D;;;;N;;;;; +FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062C 0645;;;;N;;;;; +FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062D 062C;;;;N;;;;; +FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL; 062D 0645;;;;N;;;;; +FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 062E 062C;;;;N;;;;; +FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 062E 0645;;;;N;;;;; +FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL; 0633 062C;;;;N;;;;; +FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL; 0633 062D;;;;N;;;;; +FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL; 0633 062E;;;;N;;;;; +FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL; 0633 0645;;;;N;;;;; +FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL; 0635 062D;;;;N;;;;; +FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL; 0635 062E;;;;N;;;;; +FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645;;;;N;;;;; +FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL; 0636 062C;;;;N;;;;; +FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL; 0636 062D;;;;N;;;;; +FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL; 0636 062E;;;;N;;;;; +FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL; 0636 0645;;;;N;;;;; +FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL; 0637 062D;;;;N;;;;; +FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL; 0638 0645;;;;N;;;;; +FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL; 0639 062C;;;;N;;;;; +FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL; 0639 0645;;;;N;;;;; +FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL; 063A 062C;;;;N;;;;; +FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL; 063A 0645;;;;N;;;;; +FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL; 0641 062C;;;;N;;;;; +FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL; 0641 062D;;;;N;;;;; +FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL; 0641 062E;;;;N;;;;; +FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL; 0641 0645;;;;N;;;;; +FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL; 0642 062D;;;;N;;;;; +FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL; 0642 0645;;;;N;;;;; +FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL; 0643 062C;;;;N;;;;; +FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL; 0643 062D;;;;N;;;;; +FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL; 0643 062E;;;;N;;;;; +FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL; 0644 062C;;;;N;;;;; +FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL; 0644 062D;;;;N;;;;; +FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL; 0644 062E;;;;N;;;;; +FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL; 0644 0647;;;;N;;;;; +FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062C;;;;N;;;;; +FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 062D;;;;N;;;;; +FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062E;;;;N;;;;; +FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 0645;;;;N;;;;; +FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL; 0646 062C;;;;N;;;;; +FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL; 0646 062D;;;;N;;;;; +FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL; 0646 062E;;;;N;;;;; +FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL; 0646 0647;;;;N;;;;; +FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL; 0647 062C;;;;N;;;;; +FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645;;;;N;;;;; +FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL; 0647 0670;;;;N;;;;; +FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL; 064A 062C;;;;N;;;;; +FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL; 064A 062D;;;;N;;;;; +FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL; 064A 062E;;;;N;;;;; +FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL; 064A 0647;;;;N;;;;; +FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL; 0626 0645;;;;N;;;;; +FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL; 0626 0647;;;;N;;;;; +FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL; 0628 0645;;;;N;;;;; +FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL; 0628 0647;;;;N;;;;; +FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL; 062A 0645;;;;N;;;;; +FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL; 062A 0647;;;;N;;;;; +FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL; 062B 0645;;;;N;;;;; +FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL; 062B 0647;;;;N;;;;; +FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL; 0633 0645;;;;N;;;;; +FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL; 0633 0647;;;;N;;;;; +FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL; 0634 0647;;;;N;;;;; +FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL; 0643 0644;;;;N;;;;; +FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL; 0643 0645;;;;N;;;;; +FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL; 0644 0645;;;;N;;;;; +FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL; 0646 0645;;;;N;;;;; +FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL; 0646 0647;;;;N;;;;; +FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL; 064A 0645;;;;N;;;;; +FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL; 064A 0647;;;;N;;;;; +FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL; 0640 064E 0651;;;;N;;;;; +FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL; 0640 064F 0651;;;;N;;;;; +FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL; 0640 0650 0651;;;;N;;;;; +FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0637 0649;;;;N;;;;; +FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL; 0637 064A;;;;N;;;;; +FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0639 0649;;;;N;;;;; +FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL; 0639 064A;;;;N;;;;; +FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 063A 0649;;;;N;;;;; +FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL; 063A 064A;;;;N;;;;; +FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0633 0649;;;;N;;;;; +FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL; 0633 064A;;;;N;;;;; +FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0634 0649;;;;N;;;;; +FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL; 0634 064A;;;;N;;;;; +FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062D 0649;;;;N;;;;; +FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL; 062D 064A;;;;N;;;;; +FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062C 0649;;;;N;;;;; +FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL; 062C 064A;;;;N;;;;; +FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 062E 0649;;;;N;;;;; +FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL; 062E 064A;;;;N;;;;; +FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0635 0649;;;;N;;;;; +FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL; 0635 064A;;;;N;;;;; +FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0636 0649;;;;N;;;;; +FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL; 0636 064A;;;;N;;;;; +FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL; 0634 0631;;;;N;;;;; +FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL; 0633 0631;;;;N;;;;; +FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL; 0635 0631;;;;N;;;;; +FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL; 0636 0631;;;;N;;;;; +FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0637 0649;;;;N;;;;; +FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL; 0637 064A;;;;N;;;;; +FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0639 0649;;;;N;;;;; +FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL; 0639 064A;;;;N;;;;; +FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 063A 0649;;;;N;;;;; +FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL; 063A 064A;;;;N;;;;; +FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 0649;;;;N;;;;; +FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL; 0633 064A;;;;N;;;;; +FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0634 0649;;;;N;;;;; +FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL; 0634 064A;;;;N;;;;; +FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062D 0649;;;;N;;;;; +FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL; 062D 064A;;;;N;;;;; +FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 0649;;;;N;;;;; +FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL; 062C 064A;;;;N;;;;; +FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062E 0649;;;;N;;;;; +FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL; 062E 064A;;;;N;;;;; +FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0635 0649;;;;N;;;;; +FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL; 0635 064A;;;;N;;;;; +FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0636 0649;;;;N;;;;; +FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL; 0636 064A;;;;N;;;;; +FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL; 0634 0631;;;;N;;;;; +FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL; 0633 0631;;;;N;;;;; +FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL; 0635 0631;;;;N;;;;; +FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL; 0636 0631;;;;N;;;;; +FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL; 0634 0645;;;;N;;;;; +FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL; 0633 0647;;;;N;;;;; +FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL; 0634 0647;;;;N;;;;; +FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL; 0637 0645;;;;N;;;;; +FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL; 0633 062C;;;;N;;;;; +FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL; 0633 062D;;;;N;;;;; +FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL; 0633 062E;;;;N;;;;; +FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL; 0634 062C;;;;N;;;;; +FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL; 0634 062D;;;;N;;;;; +FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL; 0634 062E;;;;N;;;;; +FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL; 0637 0645;;;;N;;;;; +FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL; 0638 0645;;;;N;;;;; +FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL; 0627 064B;;;;N;;;;; +FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL; 0627 064B;;;;N;;;;; +FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;; +FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;; +FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062C 0645;;;;N;;;;; +FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; +FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 062A 062D 062C;;;;N;;;;; +FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062D 0645;;;;N;;;;; +FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 062A 062E 0645;;;;N;;;;; +FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 062A 0645 062C;;;;N;;;;; +FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 062A 0645 062D;;;;N;;;;; +FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 062A 0645 062E;;;;N;;;;; +FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 062C 0645 062D;;;;N;;;;; +FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 062C 0645 062D;;;;N;;;;; +FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062D 0645 064A;;;;N;;;;; +FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062D 0645 0649;;;;N;;;;; +FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 0633 062D 062C;;;;N;;;;; +FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0633 062C 062D;;;;N;;;;; +FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 062C 0649;;;;N;;;;; +FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0633 0645 062D;;;;N;;;;; +FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0633 0645 062D;;;;N;;;;; +FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0633 0645 062C;;;;N;;;;; +FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0633 0645 0645;;;;N;;;;; +FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0633 0645 0645;;;;N;;;;; +FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL; 0635 062D 062D;;;;N;;;;; +FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL; 0635 062D 062D;;;;N;;;;; +FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; +FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL; 0634 062D 0645;;;;N;;;;; +FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0634 062D 0645;;;;N;;;;; +FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0634 062C 064A;;;;N;;;;; +FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL; 0634 0645 062E;;;;N;;;;; +FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0634 0645 062E;;;;N;;;;; +FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0634 0645 0645;;;;N;;;;; +FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0634 0645 0645;;;;N;;;;; +FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0636 062D 0649;;;;N;;;;; +FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0636 062E 0645;;;;N;;;;; +FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0636 062E 0645;;;;N;;;;; +FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0637 0645 062D;;;;N;;;;; +FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0637 0645 062D;;;;N;;;;; +FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0637 0645 0645;;;;N;;;;; +FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0637 0645 064A;;;;N;;;;; +FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0639 062C 0645;;;;N;;;;; +FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0639 0645 0645;;;;N;;;;; +FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 0645 0645;;;;N;;;;; +FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0639 0645 0649;;;;N;;;;; +FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 063A 0645 0645;;;;N;;;;; +FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 063A 0645 064A;;;;N;;;;; +FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 063A 0645 0649;;;;N;;;;; +FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0641 062E 0645;;;;N;;;;; +FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0641 062E 0645;;;;N;;;;; +FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0642 0645 062D;;;;N;;;;; +FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0642 0645 0645;;;;N;;;;; +FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL; 0644 062D 0645;;;;N;;;;; +FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0644 062D 064A;;;;N;;;;; +FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0644 062D 0649;;;;N;;;;; +FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0644 062C 062C;;;;N;;;;; +FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL; 0644 062C 062C;;;;N;;;;; +FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL; 0644 062E 0645;;;;N;;;;; +FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062E 0645;;;;N;;;;; +FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL; 0644 0645 062D;;;;N;;;;; +FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0644 0645 062D;;;;N;;;;; +FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062D 062C;;;;N;;;;; +FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062D 0645;;;;N;;;;; +FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0645 062D 064A;;;;N;;;;; +FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645 062C 062D;;;;N;;;;; +FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062C 0645;;;;N;;;;; +FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062E 062C;;;;N;;;;; +FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062E 0645;;;;N;;;;; +FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062C 062E;;;;N;;;;; +FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0647 0645 062C;;;;N;;;;; +FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645 0645;;;;N;;;;; +FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0646 062D 0645;;;;N;;;;; +FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 062D 0649;;;;N;;;;; +FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0646 062C 0645;;;;N;;;;; +FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0646 062C 0645;;;;N;;;;; +FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 062C 0649;;;;N;;;;; +FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 0645 064A;;;;N;;;;; +FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0646 0645 0649;;;;N;;;;; +FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 064A 0645 0645;;;;N;;;;; +FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 064A 0645 0645;;;;N;;;;; +FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0628 062E 064A;;;;N;;;;; +FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 062A 062C 064A;;;;N;;;;; +FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 062C 0649;;;;N;;;;; +FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 062A 062E 064A;;;;N;;;;; +FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 062E 0649;;;;N;;;;; +FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062A 0645 064A;;;;N;;;;; +FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062A 0645 0649;;;;N;;;;; +FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 062C 0645 064A;;;;N;;;;; +FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 062D 0649;;;;N;;;;; +FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 062C 0645 0649;;;;N;;;;; +FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL; 0633 062E 0649;;;;N;;;;; +FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0635 062D 064A;;;;N;;;;; +FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0634 062D 064A;;;;N;;;;; +FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0636 062D 064A;;;;N;;;;; +FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0644 062C 064A;;;;N;;;;; +FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0644 0645 064A;;;;N;;;;; +FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 064A 062D 064A;;;;N;;;;; +FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 064A 062C 064A;;;;N;;;;; +FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 064A 0645 064A;;;;N;;;;; +FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0645 0645 064A;;;;N;;;;; +FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0642 0645 064A;;;;N;;;;; +FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0646 062D 064A;;;;N;;;;; +FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL; 0642 0645 062D;;;;N;;;;; +FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062D 0645;;;;N;;;;; +FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0639 0645 064A;;;;N;;;;; +FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0643 0645 064A;;;;N;;;;; +FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0646 062C 062D;;;;N;;;;; +FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0645 062E 064A;;;;N;;;;; +FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0644 062C 0645;;;;N;;;;; +FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL; 0643 0645 0645;;;;N;;;;; +FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL; 0644 062C 0645;;;;N;;;;; +FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL; 0646 062C 062D;;;;N;;;;; +FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 062C 062D 064A;;;;N;;;;; +FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 062D 062C 064A;;;;N;;;;; +FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0645 062C 064A;;;;N;;;;; +FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL; 0641 0645 064A;;;;N;;;;; +FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL; 0628 062D 064A;;;;N;;;;; +FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0643 0645 0645;;;;N;;;;; +FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639 062C 0645;;;;N;;;;; +FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;; +FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0633 062E 064A;;;;N;;;;; +FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 062C 064A;;;;N;;;;; +FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0635 0644 06D2;;;;N;;;;; +FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0642 0644 06D2;;;;N;;;;; +FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL; 0627 0644 0644 0647;;;;N;;;;; +FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL; 0627 0643 0628 0631;;;;N;;;;; +FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL; 0645 062D 0645 062F;;;;N;;;;; +FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL; 0635 0644 0639 0645;;;;N;;;;; +FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL; 0631 0633 0648 0644;;;;N;;;;; +FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL; 0639 0644 064A 0647;;;;N;;;;; +FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL; 0648 0633 0644 0645;;;;N;;;;; +FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL; 0635 0644 0649;;;;N;;;;; +FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL; 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;; +FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL; 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;; +FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;; +FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;; +FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON; 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;; +FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON; 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;; +FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON; 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;; +FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON; 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;; +FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON; 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;; +FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON; 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;; +FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;; +FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;; +FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;; +FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON; 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;; +FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON; 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;; +FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON; 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;; +FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON; 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;; +FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON; 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;; +FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON; 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;; +FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON; 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;; +FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON; 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;; +FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON; 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;; +FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON; 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;; +FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON; 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;; +FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON; 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;; +FE49;DASHED OVERLINE;Po;0;ON; 203E;;;;N;SPACING DASHED OVERSCORE;;;; +FE4A;CENTRELINE OVERLINE;Po;0;ON; 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;; +FE4B;WAVY OVERLINE;Po;0;ON; 203E;;;;N;SPACING WAVY OVERSCORE;;;; +FE4C;DOUBLE WAVY OVERLINE;Po;0;ON; 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;; +FE4D;DASHED LOW LINE;Pc;0;ON; 005F;;;;N;SPACING DASHED UNDERSCORE;;;; +FE4E;CENTRELINE LOW LINE;Pc;0;ON; 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;; +FE4F;WAVY LOW LINE;Pc;0;ON; 005F;;;;N;SPACING WAVY UNDERSCORE;;;; +FE50;SMALL COMMA;Po;0;CS; 002C;;;;N;;;;; +FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; +FE52;SMALL FULL STOP;Po;0;CS; 002E;;;;N;SMALL PERIOD;;;; +FE54;SMALL SEMICOLON;Po;0;ON; 003B;;;;N;;;;; +FE55;SMALL COLON;Po;0;CS; 003A;;;;N;;;;; +FE56;SMALL QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; +FE57;SMALL EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; +FE58;SMALL EM DASH;Pd;0;ON; 2014;;;;N;;;;; +FE59;SMALL LEFT PARENTHESIS;Ps;0;ON; 0028;;;;N;SMALL OPENING PARENTHESIS;;;; +FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;N;SMALL CLOSING PARENTHESIS;;;; +FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;N;SMALL OPENING CURLY BRACKET;;;; +FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;; +FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON; 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;; +FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON; 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;; +FE5F;SMALL NUMBER SIGN;Po;0;ET; 0023;;;;N;;;;; +FE60;SMALL AMPERSAND;Po;0;ON; 0026;;;;N;;;;; +FE61;SMALL ASTERISK;Po;0;ON; 002A;;;;N;;;;; +FE62;SMALL PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; +FE63;SMALL HYPHEN-MINUS;Pd;0;ET; 002D;;;;N;;;;; +FE64;SMALL LESS-THAN SIGN;Sm;0;ON; 003C;;;;N;;;;; +FE65;SMALL GREATER-THAN SIGN;Sm;0;ON; 003E;;;;N;;;;; +FE66;SMALL EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +FE68;SMALL REVERSE SOLIDUS;Po;0;ON; 005C;;;;N;SMALL BACKSLASH;;;; +FE69;SMALL DOLLAR SIGN;Sc;0;ET; 0024;;;;N;;;;; +FE6A;SMALL PERCENT SIGN;Po;0;ET; 0025;;;;N;;;;; +FE6B;SMALL COMMERCIAL AT;Po;0;ON; 0040;;;;N;;;;; +FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL; 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;; +FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL; 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;; +FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL; 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;; +FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL; 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;; +FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL; 0020 064E;;;;N;ARABIC SPACING FATHAH;;;; +FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL; 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;; +FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL; 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;; +FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL; 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;; +FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL; 0020 0650;;;;N;ARABIC SPACING KASRAH;;;; +FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL; 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;; +FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL; 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;; +FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL; 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;; +FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL; 0020 0652;;;;N;ARABIC SPACING SUKUN;;;; +FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL; 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;; +FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL; 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;; +FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL; 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;; +FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL; 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;; +FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;; +FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;; +FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;; +FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;; +FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL; 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;; +FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL; 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;; +FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;; +FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;; +FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;; +FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL; 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;; +FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL; 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;; +FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL; 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;; +FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;; +FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;; +FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;; +FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL; 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;; +FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL; 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;; +FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL; 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;; +FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;; +FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;; +FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;; +FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL; 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;; +FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;; +FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;; +FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;; +FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL; 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;; +FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;; +FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;; +FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;; +FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL; 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;; +FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;; +FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;; +FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;; +FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL; 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;; +FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;; +FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;; +FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;; +FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL; 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;; +FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL; 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;; +FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL; 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;; +FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL; 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;; +FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL; 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;; +FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL; 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;; +FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL; 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;; +FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL; 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;; +FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL; 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;; +FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;; +FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;; +FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;; +FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL; 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;; +FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;; +FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;; +FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;; +FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL; 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;; +FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;; +FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;; +FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;; +FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL; 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;; +FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;; +FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;; +FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;; +FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL; 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;; +FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;; +FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;; +FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;; +FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL; 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;; +FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;; +FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;; +FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;; +FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL; 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;; +FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;; +FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;; +FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;; +FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL; 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;; +FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;; +FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;; +FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;; +FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL; 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;; +FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;; +FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;; +FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;; +FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL; 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;; +FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;; +FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;; +FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;; +FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL; 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;; +FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;; +FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;; +FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;; +FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL; 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;; +FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;; +FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;; +FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;; +FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL; 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;; +FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;; +FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;; +FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;; +FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL; 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;; +FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;; +FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;; +FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;; +FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL; 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;; +FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;; +FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;; +FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;; +FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL; 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;; +FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL; 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;; +FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL; 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;; +FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL; 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;; +FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL; 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;; +FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;; +FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;; +FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;; +FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL; 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;; +FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL; 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;; +FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL; 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;; +FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL; 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; +FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL; 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;; +FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL; 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; +FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL; 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;; +FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL; 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;; +FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL; 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;; +FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; +FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON; 0021;;;;N;;;;; +FF02;FULLWIDTH QUOTATION MARK;Po;0;ON; 0022;;;;N;;;;; +FF03;FULLWIDTH NUMBER SIGN;Po;0;ET; 0023;;;;N;;;;; +FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET; 0024;;;;N;;;;; +FF05;FULLWIDTH PERCENT SIGN;Po;0;ET; 0025;;;;N;;;;; +FF06;FULLWIDTH AMPERSAND;Po;0;ON; 0026;;;;N;;;;; +FF07;FULLWIDTH APOSTROPHE;Po;0;ON; 0027;;;;N;;;;; +FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON; 0028;;;;N;FULLWIDTH OPENING PARENTHESIS;;;; +FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON; 0029;;;;N;FULLWIDTH CLOSING PARENTHESIS;;;; +FF0A;FULLWIDTH ASTERISK;Po;0;ON; 002A;;;;N;;;;; +FF0B;FULLWIDTH PLUS SIGN;Sm;0;ET; 002B;;;;N;;;;; +FF0C;FULLWIDTH COMMA;Po;0;CS; 002C;;;;N;;;;; +FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ET; 002D;;;;N;;;;; +FF0E;FULLWIDTH FULL STOP;Po;0;CS; 002E;;;;N;FULLWIDTH PERIOD;;;; +FF0F;FULLWIDTH SOLIDUS;Po;0;ES; 002F;;;;N;FULLWIDTH SLASH;;;; +FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +FF11;FULLWIDTH DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +FF12;FULLWIDTH DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +FF13;FULLWIDTH DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +FF16;FULLWIDTH DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +FF19;FULLWIDTH DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +FF1A;FULLWIDTH COLON;Po;0;CS; 003A;;;;N;;;;; +FF1B;FULLWIDTH SEMICOLON;Po;0;ON; 003B;;;;N;;;;; +FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON; 003C;;;;N;;;;; +FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON; 003D;;;;N;;;;; +FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON; 003E;;;;N;;;;; +FF1F;FULLWIDTH QUESTION MARK;Po;0;ON; 003F;;;;N;;;;; +FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON; 0040;;;;N;;;;; +FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L; 0041;;;;N;;;;FF41; +FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L; 0042;;;;N;;;;FF42; +FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L; 0043;;;;N;;;;FF43; +FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L; 0044;;;;N;;;;FF44; +FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L; 0045;;;;N;;;;FF45; +FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L; 0046;;;;N;;;;FF46; +FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L; 0047;;;;N;;;;FF47; +FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L; 0048;;;;N;;;;FF48; +FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L; 0049;;;;N;;;;FF49; +FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L; 004A;;;;N;;;;FF4A; +FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L; 004B;;;;N;;;;FF4B; +FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L; 004C;;;;N;;;;FF4C; +FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L; 004D;;;;N;;;;FF4D; +FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L; 004E;;;;N;;;;FF4E; +FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L; 004F;;;;N;;;;FF4F; +FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L; 0050;;;;N;;;;FF50; +FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L; 0051;;;;N;;;;FF51; +FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L; 0052;;;;N;;;;FF52; +FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L; 0053;;;;N;;;;FF53; +FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L; 0054;;;;N;;;;FF54; +FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L; 0055;;;;N;;;;FF55; +FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L; 0056;;;;N;;;;FF56; +FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L; 0057;;;;N;;;;FF57; +FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L; 0058;;;;N;;;;FF58; +FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L; 0059;;;;N;;;;FF59; +FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L; 005A;;;;N;;;;FF5A; +FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON; 005B;;;;N;FULLWIDTH OPENING SQUARE BRACKET;;;; +FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON; 005C;;;;N;FULLWIDTH BACKSLASH;;;; +FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON; 005D;;;;N;FULLWIDTH CLOSING SQUARE BRACKET;;;; +FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON; 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;; +FF3F;FULLWIDTH LOW LINE;Pc;0;ON; 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;; +FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON; 0060;;;;N;FULLWIDTH SPACING GRAVE;;;; +FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L; 0061;;;;N;;;FF21;;FF21 +FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L; 0062;;;;N;;;FF22;;FF22 +FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L; 0063;;;;N;;;FF23;;FF23 +FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L; 0064;;;;N;;;FF24;;FF24 +FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L; 0065;;;;N;;;FF25;;FF25 +FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L; 0066;;;;N;;;FF26;;FF26 +FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L; 0067;;;;N;;;FF27;;FF27 +FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L; 0068;;;;N;;;FF28;;FF28 +FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L; 0069;;;;N;;;FF29;;FF29 +FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L; 006A;;;;N;;;FF2A;;FF2A +FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L; 006B;;;;N;;;FF2B;;FF2B +FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L; 006C;;;;N;;;FF2C;;FF2C +FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L; 006D;;;;N;;;FF2D;;FF2D +FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L; 006E;;;;N;;;FF2E;;FF2E +FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L; 006F;;;;N;;;FF2F;;FF2F +FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L; 0070;;;;N;;;FF30;;FF30 +FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L; 0071;;;;N;;;FF31;;FF31 +FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L; 0072;;;;N;;;FF32;;FF32 +FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L; 0073;;;;N;;;FF33;;FF33 +FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L; 0074;;;;N;;;FF34;;FF34 +FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L; 0075;;;;N;;;FF35;;FF35 +FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L; 0076;;;;N;;;FF36;;FF36 +FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L; 0077;;;;N;;;FF37;;FF37 +FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L; 0078;;;;N;;;FF38;;FF38 +FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L; 0079;;;;N;;;FF39;;FF39 +FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L; 007A;;;;N;;;FF3A;;FF3A +FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON; 007B;;;;N;FULLWIDTH OPENING CURLY BRACKET;;;; +FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON; 007C;;;;N;FULLWIDTH VERTICAL BAR;;;; +FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON; 007D;;;;N;FULLWIDTH CLOSING CURLY BRACKET;;;; +FF5E;FULLWIDTH TILDE;Sm;0;ON; 007E;;;;N;FULLWIDTH SPACING TILDE;;;; +FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON; 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;; +FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON; 300C;;;;N;HALFWIDTH OPENING CORNER BRACKET;;;; +FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON; 300D;;;;N;HALFWIDTH CLOSING CORNER BRACKET;;;; +FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON; 3001;;;;N;;;;; +FF65;HALFWIDTH KATAKANA MIDDLE DOT;Pc;0;ON; 30FB;;;;N;;;;; +FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L; 30F2;;;;N;;;;; +FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L; 30A1;;;;N;;;;; +FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L; 30A3;;;;N;;;;; +FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L; 30A5;;;;N;;;;; +FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L; 30A7;;;;N;;;;; +FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L; 30A9;;;;N;;;;; +FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L; 30E3;;;;N;;;;; +FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L; 30E5;;;;N;;;;; +FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L; 30E7;;;;N;;;;; +FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L; 30C3;;;;N;;;;; +FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L; 30FC;;;;N;;;;; +FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L; 30A2;;;;N;;;;; +FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L; 30A4;;;;N;;;;; +FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L; 30A6;;;;N;;;;; +FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L; 30A8;;;;N;;;;; +FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L; 30AA;;;;N;;;;; +FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L; 30AB;;;;N;;;;; +FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L; 30AD;;;;N;;;;; +FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L; 30AF;;;;N;;;;; +FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L; 30B1;;;;N;;;;; +FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L; 30B3;;;;N;;;;; +FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L; 30B5;;;;N;;;;; +FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L; 30B7;;;;N;;;;; +FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L; 30B9;;;;N;;;;; +FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L; 30BB;;;;N;;;;; +FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L; 30BD;;;;N;;;;; +FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L; 30BF;;;;N;;;;; +FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L; 30C1;;;;N;;;;; +FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L; 30C4;;;;N;;;;; +FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L; 30C6;;;;N;;;;; +FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L; 30C8;;;;N;;;;; +FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L; 30CA;;;;N;;;;; +FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L; 30CB;;;;N;;;;; +FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L; 30CC;;;;N;;;;; +FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L; 30CD;;;;N;;;;; +FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L; 30CE;;;;N;;;;; +FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L; 30CF;;;;N;;;;; +FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L; 30D2;;;;N;;;;; +FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L; 30D5;;;;N;;;;; +FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L; 30D8;;;;N;;;;; +FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L; 30DB;;;;N;;;;; +FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L; 30DE;;;;N;;;;; +FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L; 30DF;;;;N;;;;; +FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L; 30E0;;;;N;;;;; +FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L; 30E1;;;;N;;;;; +FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L; 30E2;;;;N;;;;; +FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L; 30E4;;;;N;;;;; +FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L; 30E6;;;;N;;;;; +FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L; 30E8;;;;N;;;;; +FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L; 30E9;;;;N;;;;; +FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L; 30EA;;;;N;;;;; +FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L; 30EB;;;;N;;;;; +FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L; 30EC;;;;N;;;;; +FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L; 30ED;;;;N;;;;; +FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L; 30EF;;;;N;;;;; +FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L; 30F3;;;;N;;;;; +FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L; 3099;;;;N;;halfwidth katakana-hiragana voiced sound mark;;; +FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L; 309A;;;;N;;halfwidth katakana-hiragana semi-voiced sound mark;;; +FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L; 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;; +FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L; 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;; +FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L; 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;; +FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L; 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;; +FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L; 3134;;;;N;;;;; +FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L; 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;; +FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L; 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;; +FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L; 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;; +FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L; 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;; +FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L; 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;; +FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L; 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;; +FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L; 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;; +FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L; 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;; +FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L; 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;; +FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L; 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;; +FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L; 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;; +FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L; 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;; +FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L; 3141;;;;N;;;;; +FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L; 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;; +FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L; 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;; +FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L; 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;; +FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L; 3145;;;;N;;;;; +FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L; 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;; +FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L; 3147;;;;N;;;;; +FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L; 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;; +FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L; 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;; +FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L; 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;; +FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L; 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;; +FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L; 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;; +FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L; 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;; +FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L; 314E;;;;N;;;;; +FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L; 314F;;;;N;;;;; +FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L; 3150;;;;N;;;;; +FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L; 3151;;;;N;;;;; +FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L; 3152;;;;N;;;;; +FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L; 3153;;;;N;;;;; +FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L; 3154;;;;N;;;;; +FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L; 3155;;;;N;;;;; +FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L; 3156;;;;N;;;;; +FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L; 3157;;;;N;;;;; +FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L; 3158;;;;N;;;;; +FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L; 3159;;;;N;;;;; +FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L; 315A;;;;N;;;;; +FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L; 315B;;;;N;;;;; +FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L; 315C;;;;N;;;;; +FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L; 315D;;;;N;;;;; +FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L; 315E;;;;N;;;;; +FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L; 315F;;;;N;;;;; +FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L; 3160;;;;N;;;;; +FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L; 3161;;;;N;;;;; +FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L; 3162;;;;N;;;;; +FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L; 3163;;;;N;;;;; +FFE0;FULLWIDTH CENT SIGN;Sc;0;ET; 00A2;;;;N;;;;; +FFE1;FULLWIDTH POUND SIGN;Sc;0;ET; 00A3;;;;N;;;;; +FFE2;FULLWIDTH NOT SIGN;Sm;0;ON; 00AC;;;;N;;;;; +FFE3;FULLWIDTH MACRON;Sk;0;ON; 00AF;;;;N;FULLWIDTH SPACING MACRON;*;;; +FFE4;FULLWIDTH BROKEN BAR;So;0;ON; 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;; +FFE5;FULLWIDTH YEN SIGN;Sc;0;ET; 00A5;;;;N;;;;; +FFE6;FULLWIDTH WON SIGN;Sc;0;ET; 20A9;;;;N;;;;; +FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON; 2502;;;;N;;;;; +FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON; 2190;;;;N;;;;; +FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON; 2191;;;;N;;;;; +FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON; 2192;;;;N;;;;; +FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON; 2193;;;;N;;;;; +FFED;HALFWIDTH BLACK SQUARE;So;0;ON; 25A0;;;;N;;;;; +FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON; 25CB;;;;N;;;;; +FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;BN;;;;;N;;;;; +FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;BN;;;;;N;;;;; +FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;BN;;;;;N;;;;; +FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; +FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; +10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;; +10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;; +10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;; +10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;; +10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;; +10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;; +10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;; +10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;; +10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;; +10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;; +1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;; +1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;; +1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;; +1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;; +1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;; +1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;Faliscan;;; +10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;; +10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;; +10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;; +10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;; +10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;; +10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;; +10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;; +10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;Faliscan;;; +10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;; +10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;; +1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;; +1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;Umbrian;;; +1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;Umbrian;;; +1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;Oscan;;; +1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;Oscan;;; +10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;; +10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; +10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; +10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;; +10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;; +10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;; +10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;; +10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;; +10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;; +10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;; +10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;; +10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;; +10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;; +10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;; +1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;; +1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;; +1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;; +1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;; +1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;; +1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;; +10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;; +10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;; +10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;; +10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;; +10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;; +10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;; +10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;; +10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;; +10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;; +10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;; +1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;;N;;;;; +10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; +10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429; +10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A; +10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B; +10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C; +10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D; +10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E; +10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F; +10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430; +10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431; +1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432; +1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433; +1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434; +1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435; +1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436; +1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437; +10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438; +10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439; +10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A; +10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B; +10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C; +10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D; +10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E; +10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F; +10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440; +10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441; +1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442; +1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443; +1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444; +1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445; +1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446; +1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447; +10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448; +10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449; +10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A; +10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B; +10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C; +10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D; +10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400 +10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401 +1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402 +1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403 +1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404 +1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405 +1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406 +1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407 +10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408 +10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409 +10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A +10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B +10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C +10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D +10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E +10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F +10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410 +10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411 +1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412 +1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413 +1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414 +1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415 +1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416 +1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417 +10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418 +10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419 +10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A +10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B +10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C +10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D +10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E +10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F +10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420 +10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421 +1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422 +1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423 +1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424 +1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425 +1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;; +1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;; +1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;; +1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;; +1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;; +1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;; +1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;; +1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;; +1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;; +1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;; +1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;; +1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;; +1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;; +1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;; +1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;; +1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;; +1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;; +1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;; +1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;; +1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;; +1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;; +1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;; +1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;; +1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;; +1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;; +1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;; +1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;; +1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;; +1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;; +1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;; +1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;; +1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;; +1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;; +1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;; +1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;; +1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;; +1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;; +1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;; +1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;; +1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;; +1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;; +1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;; +1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;; +1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;; +1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;; +1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;; +1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;; +1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;; +1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;; +1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;; +1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;; +1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;; +1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;; +1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;; +1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;; +1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;; +1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;; +1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;; +1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;; +1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;; +1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;; +1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;; +1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;; +1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;; +1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;; +1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;; +1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;; +1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;; +1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;; +1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;; +1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;; +1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;; +1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;; +1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;; +1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;; +1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;; +1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;; +1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;; +1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;; +1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;; +1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;; +1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;; +1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;; +1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;; +1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;; +1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;; +1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;; +1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;; +1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;; +1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;; +1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;; +1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;; +1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;; +1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;; +1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;; +1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;; +1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;; +1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;; +1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;; +1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;; +1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;; +1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;; +1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;; +1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;; +1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;; +1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;; +1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;; +1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;; +1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;; +1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;; +1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;; +1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;; +1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;; +1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;; +1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;; +1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;; +1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;; +1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;; +1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;; +1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;; +1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;; +1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;; +1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;; +1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;; +1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;; +1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;; +1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;; +1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;; +1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;; +1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;; +1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;; +1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;; +1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;; +1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;; +1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;; +1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;; +1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;; +1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;; +1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;; +1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;; +1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;; +1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;; +1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;; +1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;; +1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;; +1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; +1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;; +1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;; +1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;; +1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;; +1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;; +1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;; +1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;; +1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;; +1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;; +1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;; +1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;; +1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;; +1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;; +1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;; +1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;; +1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;; +1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;; +1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;; +1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;; +1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;; +1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;; +1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;; +1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;; +1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;; +1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; +1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;; +1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;; +1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;; +1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;; +1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;; +1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;; +1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;; +1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;; +1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;; +1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;; +1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;; +1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;; +1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;; +1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;; +1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;; +1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;; +1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;; +1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;; +1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;; +1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;; +1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;; +1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;; +1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;; +1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;; +1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;; +1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;; +1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;; +1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;; +1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;; +1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;; +1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;; +1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;; +1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;; +1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;; +1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;; +1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; +1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; +1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; +1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; +1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;; +1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;; +1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;; +1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;; +1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;; +1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;; +1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;; +1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;; +1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;; +1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;; +1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;; +1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;; +1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;; +1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;; +1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;; +1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;; +1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;; +1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;; +1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;; +1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;; +1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;; +1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;; +1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;; +1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;; +1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;; +1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;; +1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;; +1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;; +1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;; +1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;; +1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;; +1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;; +1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;; +1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;; +1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;; +1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;; +1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;; +1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;; +1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;; +1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;; +1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;; +1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;; +1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;; +1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;; +1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;; +1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;; +1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;; +1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;; +1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;; +1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;; +1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;; +1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;; +1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;; +1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;; +1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;; +1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;; +1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;; +1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;; +1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;; +1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;; +1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;; +1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;; +1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;; +1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;; +1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;; +1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;; +1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;; +1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;; +1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;; +1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;; +1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;; +1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;; +1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;; +1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;; +1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;; +1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;; +1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;; +1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;; +1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;; +1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;; +1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;; +1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;; +1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;; +1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;; +1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;; +1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;; +1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;; +1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;; +1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;; +1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;; +1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;; +1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;; +1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;; +1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;; +1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;; +1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;; +1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;; +1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;; +1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;; +1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;; +1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;; +1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;; +1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;; +1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; +1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; +1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;; +1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;; +1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;; +1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;; +1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;; +1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;; +1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;; +1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;; +1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;; +1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;; +1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;; +1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;; +1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;; +1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;; +1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;; +1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;; +1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;; +1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;; +1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;; +1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;; +1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;; +1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;; +1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;; +1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;; +1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;; +1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;; +1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;; +1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;; +1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;; +1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;; +1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;; +1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;; +1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;; +1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;; +1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;; +1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;; +1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;; +1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;; +1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;; +1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;; +1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;; +1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;; +1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;; +1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;; +1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;; +1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;; +1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;; +1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;; +1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;; +1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;; +1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;; +1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;; +1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;; +1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;; +1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;; +1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;; +1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;; +1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;; +1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;; +1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;; +1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;; +1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;; +1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;; +1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;; +1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;; +1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;; +1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;; +1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;; +1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;; +1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;; +1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;; +1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;; +1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;; +1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;; +1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;; +1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;; +1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;; +1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;; +1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;; +1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;; +1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;; +1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;; +1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;; +1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;; +1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;; +1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;; +1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;; +1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;; +1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;; +1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;; +1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;; +1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;; +1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;; +1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;; +1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;; +1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;; +1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;; +1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;; +1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;; +1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;; +1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;; +1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;; +1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;; +1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;; +1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;; +1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;; +1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;; +1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;; +1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;; +1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;; +1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;; +1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;; +1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;; +1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;; +1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;; +1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;; +1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; +1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; +1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; +1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;; +1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;; +1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;; +1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;; +1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;; +1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;; +1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;; +1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;; +1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;; +1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;; +1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;; +1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;; +1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;; +1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;; +1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;; +1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;; +1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;; +1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;; +1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;; +1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;; +1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L; 0041;;;;N;;;;; +1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L; 0042;;;;N;;;;; +1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L; 0043;;;;N;;;;; +1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L; 0044;;;;N;;;;; +1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L; 0045;;;;N;;;;; +1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L; 0046;;;;N;;;;; +1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L; 0047;;;;N;;;;; +1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L; 0048;;;;N;;;;; +1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L; 0049;;;;N;;;;; +1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L; 004A;;;;N;;;;; +1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L; 004B;;;;N;;;;; +1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L; 004C;;;;N;;;;; +1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L; 004D;;;;N;;;;; +1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L; 004E;;;;N;;;;; +1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L; 004F;;;;N;;;;; +1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L; 0050;;;;N;;;;; +1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L; 0051;;;;N;;;;; +1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L; 0052;;;;N;;;;; +1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L; 0053;;;;N;;;;; +1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L; 0054;;;;N;;;;; +1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L; 0055;;;;N;;;;; +1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L; 0056;;;;N;;;;; +1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L; 0057;;;;N;;;;; +1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L; 0058;;;;N;;;;; +1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L; 0059;;;;N;;;;; +1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L; 005A;;;;N;;;;; +1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L; 0061;;;;N;;;;; +1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L; 0062;;;;N;;;;; +1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L; 0063;;;;N;;;;; +1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L; 0064;;;;N;;;;; +1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L; 0065;;;;N;;;;; +1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L; 0066;;;;N;;;;; +1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L; 0067;;;;N;;;;; +1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L; 0068;;;;N;;;;; +1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L; 0069;;;;N;;;;; +1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L; 006A;;;;N;;;;; +1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L; 006B;;;;N;;;;; +1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L; 006C;;;;N;;;;; +1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L; 006D;;;;N;;;;; +1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L; 006E;;;;N;;;;; +1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L; 006F;;;;N;;;;; +1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L; 0070;;;;N;;;;; +1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L; 0071;;;;N;;;;; +1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L; 0072;;;;N;;;;; +1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L; 0073;;;;N;;;;; +1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L; 0074;;;;N;;;;; +1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L; 0075;;;;N;;;;; +1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L; 0076;;;;N;;;;; +1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L; 0077;;;;N;;;;; +1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L; 0078;;;;N;;;;; +1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L; 0079;;;;N;;;;; +1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L; 007A;;;;N;;;;; +1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L; 2207;;;;N;;;;; +1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; +1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L; 2207;;;;N;;;;; +1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; +1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L; 2207;;;;N;;;;; +1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; +1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L; 2207;;;;N;;;;; +1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; +1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L; 0391;;;;N;;;;; +1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L; 0392;;;;N;;;;; +1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L; 0393;;;;N;;;;; +1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L; 0394;;;;N;;;;; +1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L; 0395;;;;N;;;;; +1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L; 0396;;;;N;;;;; +1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L; 0397;;;;N;;;;; +1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L; 0398;;;;N;;;;; +1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L; 0399;;;;N;;;;; +1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L; 039A;;;;N;;;;; +1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L; 039B;;;;N;;;;; +1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L; 039C;;;;N;;;;; +1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L; 039D;;;;N;;;;; +1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L; 039E;;;;N;;;;; +1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L; 039F;;;;N;;;;; +1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L; 03A0;;;;N;;;;; +1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L; 03A1;;;;N;;;;; +1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L; 03F4;;;;N;;;;; +1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L; 03A3;;;;N;;;;; +1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L; 03A4;;;;N;;;;; +1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L; 03A5;;;;N;;;;; +1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L; 03A6;;;;N;;;;; +1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L; 03A7;;;;N;;;;; +1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L; 03A8;;;;N;;;;; +1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L; 03A9;;;;N;;;;; +1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L; 2207;;;;N;;;;; +1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L; 03B1;;;;N;;;;; +1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L; 03B2;;;;N;;;;; +1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L; 03B3;;;;N;;;;; +1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L; 03B4;;;;N;;;;; +1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L; 03B5;;;;N;;;;; +1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L; 03B6;;;;N;;;;; +1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L; 03B7;;;;N;;;;; +1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L; 03B8;;;;N;;;;; +1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L; 03B9;;;;N;;;;; +1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L; 03BA;;;;N;;;;; +1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L; 03BB;;;;N;;;;; +1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L; 03BC;;;;N;;;;; +1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L; 03BD;;;;N;;;;; +1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L; 03BE;;;;N;;;;; +1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L; 03BF;;;;N;;;;; +1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L; 03C0;;;;N;;;;; +1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L; 03C1;;;;N;;;;; +1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L; 03C2;;;;N;;;;; +1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L; 03C3;;;;N;;;;; +1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L; 03C4;;;;N;;;;; +1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L; 03C5;;;;N;;;;; +1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L; 03C6;;;;N;;;;; +1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L; 03C7;;;;N;;;;; +1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L; 03C8;;;;N;;;;; +1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L; 03C9;;;;N;;;;; +1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L; 2202;;;;N;;;;; +1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L; 03F5;;;;N;;;;; +1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L; 03D1;;;;N;;;;; +1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L; 03F0;;;;N;;;;; +1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L; 03D5;;;;N;;;;; +1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L; 03F1;;;;N;;;;; +1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L; 03D6;;;;N;;;;; +1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; +1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; +1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; +1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; +1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; +1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; +1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; +1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; +1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; +1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +20000;;Lo;0;L;;;;;N;;;;; +2A6D6;;Lo;0;L;;;;;N;;;;; +2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; +2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; +2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; +2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;; +2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;; +2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;; +2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;; +2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;; +2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;; +2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;; +2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;; +2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;; +2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;; +2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;; +2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;; +2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;; +2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;; +2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;; +2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;; +2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;; +2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;; +2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;; +2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;; +2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;; +2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;; +2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;; +2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;; +2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;; +2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;; +2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;; +2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;; +2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;; +2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;; +2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;; +2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;; +2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;; +2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;; +2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;; +2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;; +2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;; +2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;; +2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;; +2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;; +2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;; +2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;; +2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;; +2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;; +2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;; +2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;; +2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;; +2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;; +2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;; +2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;; +2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;; +2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;; +2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;; +2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;; +2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;; +2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;; +2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;; +2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;; +2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;; +2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;; +2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;; +2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;; +2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;; +2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;; +2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;; +2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;; +2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;; +2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;; +2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;; +2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;; +2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;; +2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;; +2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;; +2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;; +2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;; +2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;; +2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;; +2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;; +2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;; +2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;; +2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;; +2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;; +2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;; +2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;; +2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;; +2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;; +2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;; +2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;; +2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;; +2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;; +2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;; +2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;; +2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;; +2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;; +2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;; +2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;; +2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;; +2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;; +2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;; +2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;; +2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;; +2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;2136A;;;;N;;;;; +2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;; +2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;; +2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;; +2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;; +2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;; +2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;; +2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;; +2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;; +2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;; +2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;; +2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;; +2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F33;;;;N;;;;; +2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;; +2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;; +2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;; +2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;; +2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;; +2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;; +2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;; +2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;; +2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;; +2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;; +2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;; +2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;; +2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;; +2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;; +2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;; +2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;; +2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;; +2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;; +2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;; +2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;; +2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;; +2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;; +2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;; +2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;; +2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;; +2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;; +2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;; +2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;; +2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;; +2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;; +2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;; +2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;; +2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;; +2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;; +2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;; +2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;; +2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;; +2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;; +2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;; +2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;; +2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;; +2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;; +2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;; +2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;; +2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;; +2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;; +2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;; +2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;; +2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;; +2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;; +2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;; +2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;; +2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;; +2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;; +2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;; +2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;; +2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;; +2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;; +2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;; +2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;; +2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;; +2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;; +2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;; +2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;; +2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;; +2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;; +2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;; +2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;; +2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;; +2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;; +2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;; +2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;; +2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;; +2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;; +2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;; +2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;; +2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;; +2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;; +2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;; +2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;; +2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;; +2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;; +2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;; +2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;; +2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;; +2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;; +2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;; +2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;; +2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;; +2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;; +2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;; +2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;; +2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;; +2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;; +2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;; +2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;; +2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;; +2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;; +2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;; +2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;; +2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;; +2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;; +2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;; +2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;; +2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;; +2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;; +2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;; +2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;; +2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;; +2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;; +2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;; +2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;; +2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;; +2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;; +2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;; +2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;; +2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;; +2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;; +2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;; +2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;; +2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;; +2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;; +2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;; +2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;; +2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;; +2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;; +2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;; +2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;; +2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;; +2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;; +2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;; +2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;; +2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;; +2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;; +2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;; +2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;; +2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;; +2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;; +2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;; +2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;; +2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;; +2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;; +2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;; +2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;; +2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;; +2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;; +2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;; +2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;; +2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;; +2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;; +2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;; +2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;; +2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;; +2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;; +2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;; +2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;; +2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;; +2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;; +2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;; +2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;; +2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;; +2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;; +2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;; +2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;; +2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;; +2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;; +2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;; +2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;; +2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;; +2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;; +2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;43AB;;;;N;;;;; +2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;; +2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;; +2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;; +2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;; +2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;; +2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;; +2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;; +2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;; +2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;; +2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;; +2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;; +2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;; +2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;; +2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;; +2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;; +2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;; +2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;; +2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;; +2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;; +2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;; +2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;; +2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;; +2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;; +2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;; +2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;; +2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;; +2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;; +2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;; +2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;; +2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;; +2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;; +2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;; +2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;; +2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;; +2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;; +2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;; +2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;; +2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;; +2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;; +2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;; +2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;; +2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;; +2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;; +2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;; +2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;; +2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;; +2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;; +2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;; +2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;; +2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;; +2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;; +2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;; +2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;; +2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;; +2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;; +2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;; +2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;; +2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;; +2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;; +2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;; +2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;; +2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;; +2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;; +2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AAE;;;;N;;;;; +2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;; +2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;; +2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;; +2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;; +2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;; +2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;; +2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;; +2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;; +2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;; +2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;; +2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;; +2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;; +2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;; +2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;; +2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;; +2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;; +2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;; +2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;; +2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;; +2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;; +2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;; +2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;; +2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;; +2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;; +2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;; +2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;; +2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;; +2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;; +2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;; +2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;; +2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;; +2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;; +2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;; +2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;; +2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;; +2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;; +2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;; +2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;; +2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;; +2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;; +2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;; +2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;; +2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;; +2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;; +2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;; +2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;; +2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;; +2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;; +2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;; +2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;; +2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;; +2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;; +2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;; +2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;; +2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;; +2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;; +2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;; +2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;; +2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;; +2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;; +2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;; +2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;; +2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;; +2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;; +2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;; +2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;; +2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;; +2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;; +2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;; +2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;; +2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;; +2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;; +2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;; +2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;; +2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;; +2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;; +2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;; +2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;; +2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;; +2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;; +2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;; +2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;; +2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;; +2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;; +2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;; +2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;; +2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;; +2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;; +2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;; +2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;; +2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;; +2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;; +2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;; +2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;; +2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;; +2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;4D57;;;;N;;;;; +2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;; +2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;; +2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;; +2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;; +2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;; +2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;; +2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;; +2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;; +2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;; +2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;; +2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;; +2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;; +2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;; +2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;; +2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;; +2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;; +2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;; +2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;; +2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;; +2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;; +2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;; +2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;; +2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;; +2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;; +2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;; +2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;; +2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;; +2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;; +2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;; +2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;; +2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;; +2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;; +2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;; +2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;; +2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;; +2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;; +2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;; +2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;; +2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;; +2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;; +2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;; +2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;; +2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;; +2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;; +2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;; +2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;; +2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;; +2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;; +2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;; +2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;; +2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;; +2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;; +2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;; +2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;; +2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;; +2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;; +2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;; +2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;; +2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;; +2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;; +2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;; +2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;; +2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;; +2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;; +2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;; +2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;; +2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;; +2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;; +2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;; +2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;; +2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;; +2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;; +2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;; +2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;; +2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;; +2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;; +2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;; +2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;; +2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;; +2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;; +2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;; +2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;; +2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;; +2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;; +2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;; +2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;; +2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;; +2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;; +2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;; +2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;; +2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;; +2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;; +2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;; +2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;; +E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;; +E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;; +E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;; +E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;; +E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;; +E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;; +E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;; +E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;; +E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;; +E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;; +E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;; +E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;; +E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;; +E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;; +E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;; +E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;; +E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;; +E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;; +E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;; +E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;; +E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;; +E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;; +E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;; +E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;; +E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;; +E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;; +E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;; +E003A;TAG COLON;Cf;0;BN;;;;;N;;;;; +E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;; +E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;; +E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;; +E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;; +E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;; +E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;; +E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;; +E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;; +E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;; +E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;; +E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;; +E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;; +E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;; +E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;; +E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;; +E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;; +E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;; +E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;; +E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;; +E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;; +E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;; +E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;; +E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;; +E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;; +E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;; +E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;; +E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;; +E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;; +E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;; +E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;; +E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;; +E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;; +E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; +E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;; +E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;; +E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;; +E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;; +E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;; +E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;; +E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;; +E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;; +E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;; +E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;; +E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;; +E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;; +E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;; +E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;; +E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;; +E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;; +E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;; +E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;; +E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;; +E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;; +E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;; +E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;; +E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;; +E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;; +E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;; +E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;; +E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;; +E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;; +E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;; +E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;; +E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;; +E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; +E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;; +E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;; +E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;; +E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;; +F0000;;Co;0;L;;;;;N;;;;; +FFFFD;;Co;0;L;;;;;N;;;;; +100000;;Co;0;L;;;;;N;;;;; +10FFFD;;Co;0;L;;;;;N;;;;; diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/utf8.cpp b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/utf8.cpp new file mode 100644 index 00000000..a4634187 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/utf8.cpp @@ -0,0 +1,240 @@ +#include +#include "utf8.h" +#include "UnicodeUtils.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + +/* + A little bit about UTF8... + +UTF8 stands for UCS Tranfer Format, while UCS stands for Universal Character Set. In +essence, UTF8 is a way to encode all the characters in the UCS. UTF8 attempts to +describe all the characters in the UCS using from 1 to 6 bytes per character. If the +first byte's high bit is not set, then the character is 1 byte long, and corresponds to +the US-ASCII character of the same number. In this way, all current US-ASCII strings are +already UTF8 compatible. If the the first byte's high bit is set, then the number of +high bits set until the first 0 describes the number of bytes in the character, e.g. a +first byte who's bits are 1110xxxx will be followed by 2 more "data bytes" that look like +10yyyyyy 10zzzzzz, so that the entire character's descriptive ID is x xxxxyyyy yyzzzzzz. + +With this method, all characters in the UCS-4 character space can be mapped to <=6 bytes of +data, and all characters int the UCS-2 character space can be mapped in <=3 bytes +maximum. Since only UCS-2 actually contains character assignments from known languages, +it is expected that a maximum of 3 bytes will be needed for any character encountered +during translation. + +Unfortunately, this method also means that there are sequences of bytes that do not form +valid UTF8 characters/strings. + +In this file, we've placed some string and character validation functions, as well as +replacements for functions where the standard function will not behave +properly on a UTF8 string. + +*/ + +// array of character byte-lengths. Index into the array with the first byte of the character & 0x3C then shift down twice. +// NOTE: this only works for multi-byte characters (up to 6). +static char UTF8_charSizeArray[16] = { 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6 }; + + +// UTF8_charSize returns the length of a UTF8 character in bytes (1-6). +// The array UTF8_size has 0's where an invalid header byte is detected. +// This is a "fast" function, so no error checking is done. +int UTF8_charSize( char * ptr ) +{ + // temp hold of "header" byte + unsigned char ct = *ptr; + // if high bit not set, it's just a normal character, length 1 + if (( ct & 0x80 ) == 0 ) + { + return 1; + } + return UTF8_charSizeArray[ ( ct & 0x3C ) >> 2 ]; +} + + + +// takes a pointer to a UTF8 character and fills the 2nd arg with the 16-bit UTF16 corresponding char. +// return value is the length of the UTF8 char converted. +int UTF8_convertCharToUTF16( char * ptr , UTF16 * ret ) +{ + int len = UTF8_charSize( ptr ); + if ( len == 1 ) + { + *ret = *ptr; + } + else if ( len == 2 ) + { + *ret = (UTF16)(((UTF16)( *ptr & 0x1F ) << 6 ) + ( *(ptr+1) & 0x3F )); + } + else if ( len == 3 ) + { + *ret = (UTF16)(((UTF16)( *ptr & 0x0F ) << 12 ) + ((UTF16)( *(ptr+1) & 0x3F ) << 6 ) + (( *(ptr+2) & 0x3F ))); + } + return len; +} + + +// takes a pointer to a UTF8 String and fills the 2nd array with the corresponding UTF16 string, up to +// the limit number of characters. +// return value is the length of the UTF16 string converted. +int UTF8_convertToUTF16( char * ptr , UTF16 * ret, int limit ) +{ + int len = 0; + while (( *ptr != 0 ) && ( len < ( limit - 1 ) ))//we use limit -1 to leave room for the null terminator + { + int clen = UTF8_convertCharToUTF16( ptr, ret ); + ptr += clen; + ret++; + len++; + } + *ret = 0; + return len; +} + + +// takes a UTF16 character and fills the 2nd arg with the UTF8 corresponding char. +// return value is the size of the UTF8 char converted. +// return value is 0 if the size of the UTF8 char would be bigger than the limit allowed. In this +// case, the return string is not filled. +int UTF16_convertCharToUTF8( UTF16 char16, char * ret, int limit ) +{ + int len = 0; + if ( char16 <= 0x0080 ) + { + if ( limit >= 1 ) + { + *ret = (char)char16; + len = 1; + } + } + else if ( char16 <= 0x07FF ) + { + if ( limit >= 2 ) + { + *(ret) = (char)( 0xC0 + (( char16 & 0x07C0 ) >> 6 )); + *(ret+1) = (char)(0x80 + (char)( char16 & 0x003F )); + len = 2; + } + } + else + { + if ( limit >= 3 ) + { + *ret = (char)(0xE0 + (( char16 & 0xF000 ) >> 12 )); + *(ret+1) = (char)(0x80 + (( char16 & 0x0FC0 ) >> 6 )); + *(ret+2) = (char)(0x80 + ( char16 & 0x003F )); + len = 3; + } + } + return len; +} + +// takes a pointer to a UTF16 String and fills the 2nd array with the corresponding UTF8 string, up to +// the limit number of bytes. +// return value is the size of the UTF8 string converted. +int UTF16_convertToUTF8( UTF16 *ptr, char * ret, int limit ) +{ + int len = 0; + while (( *ptr != 0 ) && ( limit != 0 )) + { + int clen = UTF16_convertCharToUTF8( *ptr, ret, limit ); + if ( clen == 0 ) + { + break; + } + ret += clen; + ptr++; + limit -= clen; + } + *ret = 0; + return len; +} + + +void EnglishToFakeUtf8(char *fakeDestination, char *englishSource, int destinationSize) +{ + UTF16 utf16[8192]; + + UTF16 *d = utf16; + char *s = englishSource; + bool afterPercent = false; + while (*s != 0) + { + if (afterPercent) + { + *d = *s; + + if (*s == ' ') // assuming everthing between % and white-space is formatting and don't shift it, this may not be the case all the time, but the worst that will happen is we won't shift everything we possibly could have + afterPercent = false; + } + else + { + if ((*s >= 'a' && *s <= 'k') || (*s >= 'A' && *s <= 'Z')) + *d = (UTF16)(*s + 0xfee0); + else + *d = *s; + + if (*s == '%') // we can't be shifting formatting tokens or else sprintf won't work + afterPercent = true; + } + d++; + s++; + } + *d = 0; + + UTF16_convertToUTF8(utf16, fakeDestination, destinationSize); +} + +void FakeUtf8ToEnglish(char *englishDestination, char *fakeSource, int destinationSize) +{ + UTF16 utf16[8192]; + UTF8_convertToUTF16(fakeSource, utf16, sizeof(utf16)); + + UTF16 *s = utf16; + char *d = englishDestination; + char *endDest = d + destinationSize - 1; + while (*s != 0 && d < endDest) + { + if (*s >= 0xfee0) + *d = (char)(*s - 0xfee0); + else + *d = (char)*s; + d++; + s++; + } + *d = 0; +} + +Plat_Unicode::String UTF8ToUnicode(const char *source) +{ + Plat_Unicode::String s = narrowToWide(""); + int length = strlen(source) + 1; + UTF16 *buffer = new UTF16[length]; + if (buffer != NULL) + { + UTF8_convertToUTF16(const_cast(source) , buffer, length); + s =buffer; + delete [] buffer; + } + return s; +} + + +void UnicodeToUTF8(Plat_Unicode::String &source, char *dest, int limit) +{ + UTF16_convertToUTF8((UTF16 *)source.c_str(), dest, limit); +} + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/utf8.h b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/utf8.h new file mode 100644 index 00000000..86251e81 --- /dev/null +++ b/external/3rd/library/soePlatform/ChatAPI/utils/Unicode/utf8.h @@ -0,0 +1,38 @@ +#ifndef UTF8_H +#define UTF8_H + +#include +#include "Unicode.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ +#endif + +namespace Plat_Unicode +{ + +typedef char UTF8; +typedef unsigned short int UTF16; + +int UTF8_charSize( char * ); + +int UTF8_convertCharToUTF16( char * ptr , UTF16 * ret ); +int UTF8_convertToUTF16( char * ptr , UTF16 * ret, int limit ); +int UTF16_convertCharToUTF8( UTF16 ret, char * ptr , int limit ); +int UTF16_convertToUTF8( UTF16 * ret, char * ptr , int limit ); + +void EnglishToFakeUtf8(char *fakeDestination, char *englishSource, int destinationSize); +void FakeUtf8ToEnglish(char *englishDestination, char *fakeSource, int destinationSize); + +Plat_Unicode::String UTF8ToUnicode(const char *source); +void UnicodeToUTF8(Plat_Unicode::String &source, char *dest, int limit); + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + + +#endif +