CP437 support
This commit is contained in:
parent
05e828b9d4
commit
9e638bb054
@ -93,6 +93,7 @@
|
||||
E883191F1792A7CC002ABE6D /* unix.c in Sources */ = {isa = PBXBuildFile; fileRef = E88319161792A7CC002ABE6D /* unix.c */; };
|
||||
E88319201792A7CC002ABE6D /* win32.c in Sources */ = {isa = PBXBuildFile; fileRef = E88319171792A7CC002ABE6D /* win32.c */; };
|
||||
E88EB02F185D9DC500565D07 /* YsrDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E88EB02D185D9DC500565D07 /* YsrDevice.cpp */; };
|
||||
E890F310187046990090AAB8 /* CP437.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E890F30E187046990090AAB8 /* CP437.cpp */; };
|
||||
E89A648E17A11B4F00FDA893 /* GLModelRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E89A648C17A11B4E00FDA893 /* GLModelRenderer.cpp */; };
|
||||
E89A649117A12FF900FDA893 /* GLDynamicLightShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E89A648F17A12FF800FDA893 /* GLDynamicLightShader.cpp */; };
|
||||
E89A649417A1677F00FDA893 /* FallingBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E89A649217A1677F00FDA893 /* FallingBlock.cpp */; };
|
||||
@ -465,6 +466,8 @@
|
||||
E88319171792A7CC002ABE6D /* win32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = win32.c; sourceTree = "<group>"; };
|
||||
E88EB02D185D9DC500565D07 /* YsrDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YsrDevice.cpp; sourceTree = "<group>"; };
|
||||
E88EB02E185D9DC500565D07 /* YsrDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YsrDevice.h; sourceTree = "<group>"; };
|
||||
E890F30E187046990090AAB8 /* CP437.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CP437.cpp; sourceTree = "<group>"; };
|
||||
E890F30F187046990090AAB8 /* CP437.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CP437.h; sourceTree = "<group>"; };
|
||||
E89A648C17A11B4E00FDA893 /* GLModelRenderer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GLModelRenderer.cpp; sourceTree = "<group>"; };
|
||||
E89A648D17A11B4E00FDA893 /* GLModelRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLModelRenderer.h; sourceTree = "<group>"; };
|
||||
E89A648F17A12FF800FDA893 /* GLDynamicLightShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GLDynamicLightShader.cpp; sourceTree = "<group>"; };
|
||||
@ -1377,6 +1380,8 @@
|
||||
E8E0AFB4179BF25B00C6B5A9 /* Settings.h */,
|
||||
E8B6B6EF17E40DA700E35523 /* RefCountedObject.cpp */,
|
||||
E8B6B6F017E40DAA00E35523 /* RefCountedObject.h */,
|
||||
E890F30E187046990090AAB8 /* CP437.cpp */,
|
||||
E890F30F187046990090AAB8 /* CP437.h */,
|
||||
);
|
||||
path = Core;
|
||||
sourceTree = "<group>";
|
||||
@ -1741,6 +1746,7 @@
|
||||
E8CF03FC178FACFF000683D4 /* GameMap.cpp in Sources */,
|
||||
E8CF03FF178FB1E1000683D4 /* IGameMapListener.cpp in Sources */,
|
||||
E8CF0402178FB52F000683D4 /* GLImage.cpp in Sources */,
|
||||
E890F310187046990090AAB8 /* CP437.cpp in Sources */,
|
||||
E8CF0405178FF776000683D4 /* Exception.cpp in Sources */,
|
||||
E8CF04081790455B000683D4 /* GLProgram.cpp in Sources */,
|
||||
E8CF040B1790471E000683D4 /* IFileSystem.cpp in Sources */,
|
||||
|
@ -626,7 +626,9 @@ namespace spades {
|
||||
|
||||
StandardPreferenceLayouter layouter(this);
|
||||
layouter.AddHeading("Player Information");
|
||||
layouter.AddInputField("Player Name", "cg_playerName", not options.GameActive).MaxLength = 15;
|
||||
ConfigField@ nameField = layouter.AddInputField("Player Name", "cg_playerName", not options.GameActive);
|
||||
nameField.MaxLength = 15;
|
||||
nameField.DenyNonAscii = true;
|
||||
|
||||
layouter.AddHeading("Effects");
|
||||
layouter.AddToggleField("Blood", "cg_blood");
|
||||
@ -637,6 +639,9 @@ namespace spades {
|
||||
layouter.AddToggleField("Chat Notify Sounds", "cg_chatBeep");
|
||||
layouter.AddToggleField("Hit Indicator", "cg_hitIndicator");
|
||||
|
||||
//layouter.AddHeading("AoS 0.75/0.76 Compatibility");
|
||||
//layouter.AddToggleField("Compatible Charset", "cg_legacyCharset");
|
||||
|
||||
layouter.AddHeading("Misc");
|
||||
layouter.AddSliderField("Field of View", "cg_fov", 30, 90, 1,
|
||||
ConfigNumberFormatter(0, " deg"));
|
||||
|
@ -258,6 +258,7 @@ namespace spades {
|
||||
int MarkPosition = 0;
|
||||
int CursorPosition = 0;
|
||||
int MaxLength = 255;
|
||||
bool DenyNonAscii = false;
|
||||
|
||||
private string text;
|
||||
private FieldCommand@[] history;
|
||||
@ -291,6 +292,18 @@ namespace spades {
|
||||
historyPos = 0;
|
||||
}
|
||||
|
||||
private bool CheckCharType(string s) {
|
||||
if(DenyNonAscii) {
|
||||
for(uint i = 0, len = s.length; i < len; i++) {
|
||||
int c = s[i];
|
||||
if((c & 0x80) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnChanged() {
|
||||
if(Changed !is null) {
|
||||
Changed(this);
|
||||
@ -327,6 +340,9 @@ namespace spades {
|
||||
return Text.substr(SelectionStart, SelectionLength);
|
||||
}
|
||||
set {
|
||||
if(!CheckCharType(value)) {
|
||||
return;
|
||||
}
|
||||
FieldCommand cmd;
|
||||
cmd.oldString = this.SelectedText;
|
||||
if(cmd.oldString == value) return; // no change
|
||||
@ -458,6 +474,9 @@ namespace spades {
|
||||
}
|
||||
|
||||
void Insert(string text) {
|
||||
if(!CheckCharType(text)) {
|
||||
return;
|
||||
}
|
||||
string oldText = SelectedText;
|
||||
SelectedText = text;
|
||||
|
||||
@ -476,7 +495,8 @@ namespace spades {
|
||||
BackSpace();
|
||||
}else if(key == "Left") {
|
||||
if(Manager.IsShiftPressed) {
|
||||
CursorPosition = ClampCursorPosition(CursorPosition - 1);
|
||||
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||
CursorPosition = ClampCursorPosition(GetByteIndexForString(Text, cIdx - 1));
|
||||
}else {
|
||||
if(SelectionLength == 0) {
|
||||
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||
@ -488,7 +508,8 @@ namespace spades {
|
||||
return;
|
||||
}else if(key == "Right") {
|
||||
if(Manager.IsShiftPressed) {
|
||||
CursorPosition = ClampCursorPosition(CursorPosition + 1);
|
||||
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||
CursorPosition = ClampCursorPosition(GetByteIndexForString(Text, cIdx + 1));
|
||||
}else {
|
||||
if(SelectionLength == 0) {
|
||||
int cIdx = GetCharIndexForString(Text, CursorPosition);
|
||||
|
@ -39,11 +39,16 @@
|
||||
#include "TCGameMode.h"
|
||||
#include <Core/Settings.h>
|
||||
#include <enet/enet.h>
|
||||
#include <Core/CP437.h>
|
||||
|
||||
SPADES_SETTING(cg_protocolVersion, "3");
|
||||
SPADES_SETTING(cg_legacyCharset, "1");
|
||||
|
||||
namespace spades {
|
||||
namespace client {
|
||||
|
||||
static const char UtfSign = -1;
|
||||
|
||||
enum{
|
||||
BLUE_FLAG = 0,
|
||||
GREEN_FLAG = 1,
|
||||
@ -89,6 +94,30 @@ namespace spades {
|
||||
PacketTypeVersionSend = 34, // C2S
|
||||
|
||||
};
|
||||
|
||||
static std::string EncodeString(std::string str) {
|
||||
auto str2 = CP437::Encode(str, -1);
|
||||
if(str2.find(-1) != std::string::npos) {
|
||||
// some fallbacks; always use UTF8
|
||||
str.insert(0, &UtfSign, 1);
|
||||
}else{
|
||||
if(cg_legacyCharset) {
|
||||
str = str2;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string DecodeString(std::string s) {
|
||||
if(s.size() > 0 && s[0] == UtfSign){
|
||||
return s.substr(1);
|
||||
}
|
||||
if(cg_legacyCharset) {
|
||||
return CP437::Decode(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
class NetPacketReader {
|
||||
std::vector<char> data;
|
||||
size_t pos;
|
||||
@ -189,12 +218,16 @@ namespace spades {
|
||||
std::string ReadString(size_t siz){
|
||||
// convert to C string once so that
|
||||
// null-chars are removed
|
||||
return ReadData(siz).c_str(); // TODO: decode
|
||||
std::string s = ReadData(siz).c_str();
|
||||
s = DecodeString(s);
|
||||
return s;
|
||||
}
|
||||
std::string ReadRemainingString() {
|
||||
// convert to C string once so that
|
||||
// null-chars are removed
|
||||
return ReadRemainingData().c_str(); // TODO: decode
|
||||
std::string s = ReadRemainingData().c_str();
|
||||
s = DecodeString(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void DumpDebug() {
|
||||
@ -256,16 +289,15 @@ namespace spades {
|
||||
Write((uint8_t)v.x);
|
||||
}
|
||||
|
||||
//lm: http://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/IBMGRAPH.TXT
|
||||
void Write(std::string str){
|
||||
// TODO: encode from utf-8 to cp437
|
||||
str = EncodeString(str);
|
||||
data.insert(data.end(),
|
||||
str.begin(),
|
||||
str.end());
|
||||
}
|
||||
|
||||
void Write(std::string str, size_t fillLen){
|
||||
// TODO: encode from utf-8 to cp437
|
||||
str = EncodeString(str);
|
||||
Write(str.substr(0, fillLen));
|
||||
size_t sz = str.size();
|
||||
while(sz < fillLen){
|
||||
|
93
Sources/Core/CP437.cpp
Normal file
93
Sources/Core/CP437.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2013 yvt
|
||||
* WTFPL
|
||||
*/
|
||||
|
||||
#include "CP437.h"
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <Core/Debug.h>
|
||||
|
||||
static const uint16_t cp437map[256] = {
|
||||
/*
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,*/
|
||||
|
||||
// graphic symbols
|
||||
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
||||
0x25d8, 0x25cb, 0x000a, 0x2642, 0x2640, 0x000d, 0x266b, 0x263c,
|
||||
0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
|
||||
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
|
||||
|
||||
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
||||
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
||||
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
||||
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
||||
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
|
||||
0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
|
||||
0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
|
||||
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
|
||||
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
|
||||
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
|
||||
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
|
||||
};
|
||||
|
||||
namespace spades {
|
||||
|
||||
class CP437::ReverseMap {
|
||||
public:
|
||||
std::map<uint32_t, char> mp;
|
||||
ReverseMap() {
|
||||
for(int i = 0; i < 256; i++) {
|
||||
mp[cp437map[i]] = static_cast<char>(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CP437::ReverseMap CP437::reverse;
|
||||
|
||||
char CP437::EncodeChar(uint32_t unicode,
|
||||
char fb) {
|
||||
auto it = reverse.mp.find(unicode);
|
||||
if(it == reverse.mp.end()){
|
||||
return fb;
|
||||
}else{
|
||||
SPAssert(cp437map[static_cast<unsigned char>(it->second)] == unicode);
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t CP437::DecodeChar(char c) {
|
||||
auto r = cp437map[static_cast<unsigned char>(c)];
|
||||
SPAssert(reverse.mp.find(r)->second == c);
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string CP437::Encode(const std::string& str,
|
||||
char fallback) {
|
||||
size_t idx = 0;
|
||||
std::string outp;
|
||||
outp.reserve(str.size());
|
||||
while(idx < str.size()){
|
||||
size_t outNumBytes;
|
||||
auto cp = GetCodePointFromUTF8String(str, idx, &outNumBytes);
|
||||
idx += outNumBytes;
|
||||
outp.push_back(EncodeChar(cp, fallback));
|
||||
}
|
||||
return outp;
|
||||
}
|
||||
|
||||
std::string CP437::Decode(const std::string& str) {
|
||||
std::string outp;
|
||||
outp.reserve(str.size() * 3);
|
||||
auto it = std::back_inserter(outp);
|
||||
for(size_t i = 0; i < str.size(); i++) {
|
||||
auto cp = DecodeChar(str[i]);
|
||||
CodePointToUTF8(it, cp);
|
||||
}
|
||||
return outp;
|
||||
}
|
||||
}
|
24
Sources/Core/CP437.h
Normal file
24
Sources/Core/CP437.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2013 yvt
|
||||
* WTFPL
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <Core/Math.h>
|
||||
|
||||
namespace spades {
|
||||
class CP437 {
|
||||
class ReverseMap;
|
||||
static ReverseMap reverse;
|
||||
CP437() {}
|
||||
~CP437() {}
|
||||
public:
|
||||
static char EncodeChar(std::uint32_t unicode,
|
||||
char fallback = 0xff);
|
||||
static std::uint32_t DecodeChar(char c);
|
||||
static std::string Encode(const std::string&,
|
||||
char fallback = 0xff);
|
||||
static std::string Decode(const std::string&);
|
||||
};
|
||||
}
|
@ -846,6 +846,38 @@ namespace spades {
|
||||
std::string EscapeControlCharacters(const std::string& str);
|
||||
|
||||
uint32_t GetCodePointFromUTF8String(const std::string&, size_t start = 0, size_t *outNumBytes = nullptr);
|
||||
template<typename Iterator>
|
||||
static Iterator CodePointToUTF8(Iterator output, uint32_t cp) {
|
||||
if(cp < 0x80) {
|
||||
*(output++) = static_cast<char>(cp);
|
||||
}else if(cp < 0x800) {
|
||||
*(output++) = static_cast<char>((cp>>6) | 0xc0);
|
||||
*(output++) = static_cast<char>((cp&0x3f) | 0x80);
|
||||
}else if(cp < 0x10000) {
|
||||
*(output++) = static_cast<char>((cp>>12) | 0xe0);
|
||||
*(output++) = static_cast<char>(((cp>>6)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>((cp&0x3f) | 0x80);
|
||||
}else if(cp < 0x200000) {
|
||||
*(output++) = static_cast<char>((cp>>18) | 0xf0);
|
||||
*(output++) = static_cast<char>(((cp>>12)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>(((cp>>6)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>((cp&0x3f) | 0x80);
|
||||
}else if(cp < 0x4000000) {
|
||||
*(output++) = static_cast<char>((cp>>24) | 0xf8);
|
||||
*(output++) = static_cast<char>(((cp>>18)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>(((cp>>12)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>(((cp>>6)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>((cp&0x3f) | 0x80);
|
||||
}else{
|
||||
*(output++) = static_cast<char>((cp>>30) | 0xfc);
|
||||
*(output++) = static_cast<char>(((cp>>24)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>(((cp>>18)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>(((cp>>12)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>(((cp>>6)&0x3f) | 0x80);
|
||||
*(output++) = static_cast<char>((cp&0x3f) | 0x80);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string TrimSpaces(const std::string&);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user