Created
November 17, 2012 06:01
-
-
Save take-cheeze/4093703 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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