Skip to content

Instantly share code, notes, and snippets.

@take-cheeze
Created November 17, 2012 06:01
Show Gist options
  • Select an option

  • Save take-cheeze/4093703 to your computer and use it in GitHub Desktop.

Select an option

Save take-cheeze/4093703 to your computer and use it in GitHub Desktop.
#include "tiny_reader.hxx"
#include "picojson.hxx"
#include <iconv.h>
namespace LCF {
namespace detail {
template<class F>
static std::string run_iconv(std::string const& target, F func, iconv_t const h) const {
size_t src_left = target.size();
std::vector<char> dst(target.size() * 5 + 10);
size_t dst_left = dst.size();
typedef typename boost::remove_pointer<
typename boost::function_traits<
typename boost::remove_pointer<F>::type
>::arg2_type
>::type src_type;
src_type src = (src_type)target.c_str();
char *dst = &target.front();
BOOST_VERIFY(func(h, &src, &src_left, &dst, &dst_left) != (size_t)-1
&& src_left == 0);
*dst = '\0';
return std::string(&dst.front());
}
struct iconv_wrap: boost::noncopyable {
iconv_wrap(char const* to, char const* from);
~iconv_wrap();
std::string operator()(std::string const& str) const;
static std::string convert(std::string const& target, char const* to, char const* from);
private:
iconv_t handle_;
}; // struct iconv_wrap
std::string iconv_wrap::convert(std::string const& target, char const* to, char const* from) {
typedef boost::container::flat_map<std::pair<std::string, std::string>, iconv_wrap> cache_type;
static cache_type cache_;
cache_type::const_iterator i = cache_.find(std::make_pair(to, from));
if(i == cache_.end()) {
i = cache_.insert(std::make_pair(std::make_pair(to, from), iconv_wrap(to, from))).first;
}
return i->second(target);
}
std::string iconv_wrap::operator()(std::string const& str) {
return run_iconv(str, ::iconv, handle_);
}
iconv_wrap::iconv_wrap(char const* to, char const* from) {
BOOST_VERIFY((handle_ = iconv_open(to, from)) != (iconv_t)-1);
}
iconv_wrap::~iconv_wrap() {
BOOST_VERIFY(iconv_close(handle_) == 0);
}
} // namespace detail
array2d::array2d(picojson const& sch, istream_ref const& is)
: schema_(sch), stream_(is)
, base_(is->tellg())
{
assert(sch.get("type").to<std::string>() == "array2d");
size_t const elem_num = ber(stream_);
for(size_t i = 0; i < elem_num; ++i) {
uint32_t const idx = ber(stream_);
insert(value_type(idx, array1d(schema_, stream_)));
}
}
array1d const& array2d::operator[](uint32_t const k) const {
const_iterator i = find(k);
assert(i != end());
return i->second;
}
array1d::array1d(picojson const& sch, istream_ref const& is)
: stream_(is)
, base_(is->tellg()), schema_(sch);
{
assert(sch.get("type").to<std::string>() == "array1d" ||
sch.get("type").to<std::string>() == "array2d");
while(!is_eof(stream_)) {
uint32_t const idx = ber(stream_);
if(idx == 0) { break; }
size_t const s = ber(stream_);
insert(value_type(idx, element(find_schema(sch, idx), stream_, s)));
stream_->seekg(s, std::istream::cur);
}
size_ = is->tellg() - base_;
picojson::array list = sch["value"].get<picojson::array>();
for(picojson::array::const_iterator i = list.begin() i != list.end(); ++i) {
int const idx = (*i)["index"].to<double>();
if(find(idx) == end()) {
insert(std::make_pair(idx, element(istream_ref(), *i, 0)));
}
}
}
element const& array1d::operator[](char const* const k) const {
const_iterator i = find(find_schema(schema_, k).get("index").to<double>());
assert(i != end());
return i->second;
}
element const& array1d::operator[](uint32_t const k) const {
const_iterator i = find(k);
assert(i != end());
return i->second;
}
int array1d::index() const {
assert(is_a2d());
return index_;
}
bool array1d::is_a2d() const {
return (index_ != 0);
}
array1d element::a1d() const { return to<array1d>(); }
array2d element::a2d() const { return to<array2d>(); }
array1d element::operator[](uint32_t const k) const { return a2d()[k]; }
element element::operator[](char const* const k) const { return a1d()[k]; }
void element::check_type(char const* name) const {
assert(schema_.get("type").get<picojson::string>() == name);
}
std::string const& element::type() const {
return schema_.get("type").get<picojson::string>();
}
template<>
array1d element::to_impl<array1d>() const {
return array1d(schema_, stream_);
}
template<>
array2d element::to_impl<array2d>() const {
return array2d(schema_, stream_);
}
template<>
int element::to_impl<int>() const {
check_type("integer");
if(!exists()) { return schema_.get("value").get<double>(); }
return int32_t(ber(stream_));
}
template<>
bool element::to_impl<bool>() const {
check_type("bool");
if(!exists()) { return schema_.get("value").get<bool>(); }
return bool(ber(stream_));
}
template<>
bool element::to_impl<std::string>() const {
check_type("string");
if(!exists()) { return schema_.get("value").get<std::string>(); }
return read_string(*stream_);
}
template<>
int element::to_impl<double>() const {
check_type("float");
if(!exists()) { return schema_.get("value").get<double>(); }
char data[sizeof(double)];
stream_->read(data, sizeof(double));
#ifdef BOOST_LITTLE_ENDIAN
// don't do anything
#elif defined BOOST_BIG_ENDIAN
// swap endianess
std::swap(data[0], data[7]);
std::swap(data[1], data[6]);
std::swap(data[2], data[5]);
std::swap(data[3], data[4]);
#else
#error unknown endianess
#endif
return *reinterpret_cast<double*>(data);
}
template<>
event element::to_impl<std::vector<event_command> >() const {
check_type("event");
event ret;
while(stream_->tellg() < (base_ + size_)) {
ret.push_back(event_command);
ret.back().code = ber(*stream_);
ret.back().next = ber(*stream_);
ret.back().str = read_string(*stream_);
for(size_t i = 0, len = ber(*stream_); i < len; ++i) {
ret.back().args.push_back(ber(*stream_));
}
}
return ret;
}
bool is_eof(std::istream& is) {
bool const ret = (is->get() == EOF);
is.unget();
is.clear();
return ret;
}
uint32_t ber(std::istream& is) {
uint32_t ret = 0;
do {
int const cur = is->get();
ret = (ret << 7) | (cur & 0x7f);
} while(cur & 0x80);
return ret;
}
size_t ber_size(uint32_t const v) {
size_t ret = 1;
while(v >> (7*ret)) { ++ret; }
return ret;
}
std::ostream& ber(std::ostream& os, uint32_t const v) {
char data[sizeot(uint32_t)*8 / 7 + 1];
size_t const s = ber_size(v);
data[s - 1] = v & 0x7f;
for(size_t i = s - 1; i > 0; --i) {
data[i - 1] = ((v >> (7*(s - i))) & 0x7f) | 0x80;
}
return os.write(data, s);
}
std::string read_string(std::istream& is) {
std::vector<char> ret(read_ber(is));
is.read(&ret.front(), ret.size());
return iconv_wrap::convert(std::string(ret.begin(), ret.end()), "UTF-8", "Shift_JIS");
}
picojson const& find_schema(picojson const& sch, uint32_t const k) {
using picojson::array;
array const& ary = sch.get("value").get<array>();
for(array::const_iterator i = ary.begin(); i < ary.end(); ++i) {
if(i->get("index").to<double>() == k) { return *i; }
}
return picojson();
}
picojson const& find_schema(picojson const& sch, char const* const k) {
using picojson::array;
array const& ary = sch.get("value").get<array>();
for(array::const_iterator i = ary.begin(); i < ary.end(); ++i) {
if(i->get("name").to<std::string>() == k) { return *i; }
}
return picojson();
}
} // namespace LCF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment