2 #include "lua/internal.hpp"
3 #include "library/string.hpp"
4 #include "library/utf8.hpp"
12 buffer(bool _is_out
, std::string
& _str
)
13 : str(_str
), is_out(_is_out
)
18 while(buffer_size
< sizeof(buf
) && char_count
< str
.length())
19 buf
[buffer_size
++] = str
[char_count
++];
22 std::pair
<char*,size_t> get()
24 return std::make_pair(buf
, is_out
? sizeof(buf
) : buffer_size
);
26 void set(std::pair
<char*,size_t> pos
)
29 size_t emitted
= sizeof(buf
) - pos
.second
;
30 str
.resize(str
.length() + emitted
);
31 std::copy(pos
.first
- emitted
, pos
.first
, str
.begin() + char_count
);
32 char_count
+= emitted
;
34 size_t eaten
= buffer_size
- pos
.second
;
35 memmove(buf
, buf
+ eaten
, buffer_size
- eaten
);
37 while(buffer_size
< sizeof(buf
) && char_count
< str
.length())
38 buf
[buffer_size
++] = str
[char_count
++];
43 return buffer_size
+ str
.length() - char_count
;
60 lua_iconv(lua::state
& L
, const char* from
, const char* to
);
61 static size_t overcommit(const char* from
, const char* to
) { return 0; }
63 int call(lua::state
& L
, lua::parameters
& P
);
64 static int create(lua::state
& L
, lua::parameters
& P
);
75 lua::_class
<lua_iconv
> class_iconv(lua_class_pure
, "ICONV", {
76 {"new", lua_iconv::create
},
78 {"__call", &lua_iconv::call
},
79 }, &lua_iconv::print
);
82 lua_iconv::lua_iconv(lua::state
& L
, const char* from
, const char* to
)
84 spec
= std::string(from
) + "->" + to
;
86 ctx
= iconv_open(to
, from
);
89 (stringfmt() << "Error creating character set converter: " << strerror(err
)).throwex();
93 lua_iconv::~lua_iconv() throw()
98 int lua_iconv::call(lua::state
& L
, lua::parameters
& P
)
105 buffer
input(false, src
);
106 buffer
output(true, dst
);
107 std::string code
= "";
109 auto _input
= input
.get();
110 auto _output
= output
.get();
111 int r
= iconv(ctx
, &_input
.first
, &_input
.second
, &_output
.first
, &_output
.second
);
112 size_t unprocessed
= _input
.second
;
119 continue; //Just retry with new output bufer.
124 if(unprocessed
!= input
.unprocessed())
129 code
= "INTERNALERR";
132 } else if(!input
.unprocessed())
136 L
.pushboolean(!code
.length());
139 L
.pushnumber(input
.left());
142 return code
.length() ? 4 : 2;
145 int lua_iconv::create(lua::state
& L
, lua::parameters
& P
)
147 std::string from
, to
;
151 lua::_class
<lua_iconv
>::create(L
, from
.c_str(), to
.c_str());
155 int _lsnes_string_byteU(lua::state
& L
, lua::parameters
& P
)
160 P(_str
, P
.optional(i
, 1), P
.optional2(j
, i
));
162 std::u32string str
= utf8::to32(_str
);
165 for(size_t k
= i
- 1; k
< j
&& k
< str
.length(); k
++) {
166 L
.pushnumber(str
[k
]);
172 int _lsnes_string_charU(lua::state
& L
, lua::parameters
& P
)
180 //Surrogates are not valid unicode.
181 if((cp
& 0xD800) == 0xD800)
182 throw std::runtime_error("Invalid character");
183 //Explicit noncharacters.
184 if(cp
>= 0xFDD0 && cp
< 0xFDF0)
185 throw std::runtime_error("Invalid character");
186 //The last two characters of each plane are noncharacters.
187 if((cp
& 0xFFFE) == 0xFFFE)
188 throw std::runtime_error("Invalid character");
189 //Last valid plane is plane 16.
191 throw std::runtime_error("Invalid character");
193 str
+= std::u32string(1, cp
);
195 L
.pushlstring(utf8::to8(str
));
199 lua::functions
iconv_fns(lua_func_bit
, "", {
200 {"_lsnes_string_byteU", _lsnes_string_byteU
},
201 {"_lsnes_string_charU", _lsnes_string_charU
},