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
);
62 int call(lua::state
& L
, lua::parameters
& P
);
63 static int create(lua::state
& L
, lua::parameters
& P
);
74 lua::_class
<lua_iconv
> class_iconv(lua_class_pure
, "ICONV", {
75 {"new", lua_iconv::create
},
77 {"__call", &lua_iconv::call
},
78 }, &lua_iconv::print
);
81 lua_iconv::lua_iconv(lua::state
& L
, const char* from
, const char* to
)
83 spec
= std::string(from
) + "->" + to
;
85 ctx
= iconv_open(to
, from
);
88 (stringfmt() << "Error creating character set converter: " << strerror(err
)).throwex();
92 lua_iconv::~lua_iconv() throw()
97 int lua_iconv::call(lua::state
& L
, lua::parameters
& P
)
104 buffer
input(false, src
);
105 buffer
output(true, dst
);
106 std::string code
= "";
108 auto _input
= input
.get();
109 auto _output
= output
.get();
110 int r
= iconv(ctx
, &_input
.first
, &_input
.second
, &_output
.first
, &_output
.second
);
111 size_t unprocessed
= _input
.second
;
118 continue; //Just retry with new output bufer.
123 if(unprocessed
!= input
.unprocessed())
128 code
= "INTERNALERR";
131 } else if(!input
.unprocessed())
135 L
.pushboolean(!code
.length());
138 L
.pushnumber(input
.left());
141 return code
.length() ? 4 : 2;
144 int lua_iconv::create(lua::state
& L
, lua::parameters
& P
)
146 std::string from
, to
;
150 lua::_class
<lua_iconv
>::create(L
, from
.c_str(), to
.c_str());
154 int _lsnes_string_byteU(lua::state
& L
, lua::parameters
& P
)
159 P(_str
, P
.optional(i
, 1), P
.optional2(j
, i
));
161 std::u32string str
= utf8::to32(_str
);
164 for(size_t k
= i
- 1; k
< j
&& k
< str
.length(); k
++) {
165 L
.pushnumber(str
[k
]);
171 int _lsnes_string_charU(lua::state
& L
, lua::parameters
& P
)
179 //Surrogates are not valid unicode.
180 if((cp
& 0xD800) == 0xD800)
181 throw std::runtime_error("Invalid character");
182 //Explicit noncharacters.
183 if(cp
>= 0xFDD0 && cp
< 0xFDF0)
184 throw std::runtime_error("Invalid character");
185 //The last two characters of each plane are noncharacters.
186 if((cp
& 0xFFFE) == 0xFFFE)
187 throw std::runtime_error("Invalid character");
188 //Last valid plane is plane 16.
190 throw std::runtime_error("Invalid character");
192 str
+= std::u32string(1, cp
);
194 L
.pushlstring(utf8::to8(str
));
198 lua::functions
iconv_fns(lua_func_bit
, "", {
199 {"_lsnes_string_byteU", _lsnes_string_byteU
},
200 {"_lsnes_string_charU", _lsnes_string_charU
},