/* * libnbt++ - A library for the Minecraft Named Binary Tag format. * Copyright (C) 2013, 2015 ljfa-ag * * This file is part of libnbt++. * * libnbt++ is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * libnbt++ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libnbt++. If not, see . */ #include "tag_list.h" #include "nbt_tags.h" #include "io/stream_reader.h" #include "io/stream_writer.h" #include namespace nbt { tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list il) { init(il); } tag_list::tag_list(std::initializer_list init) { if(init.size() == 0) el_type_ = tag_type::Null; else { el_type_ = init.begin()->get_type(); for(const value& val: init) { if(!val || val.get_type() != el_type_) throw std::invalid_argument("The values are not all the same type"); } tags.assign(init.begin(), init.end()); } } value& tag_list::at(size_t i) { return tags.at(i); } const value& tag_list::at(size_t i) const { return tags.at(i); } void tag_list::set(size_t i, value&& val) { if(val.get_type() != el_type_) throw std::invalid_argument("The tag type does not match the list's content type"); tags.at(i) = std::move(val); } void tag_list::push_back(value_initializer&& val) { if(!val) //don't allow null values throw std::invalid_argument("The value must not be null"); if(el_type_ == tag_type::Null) //set content type if undetermined el_type_ = val.get_type(); else if(el_type_ != val.get_type()) throw std::invalid_argument("The tag type does not match the list's content type"); tags.push_back(std::move(val)); } void tag_list::reset(tag_type type) { clear(); el_type_ = type; } void tag_list::read_payload(io::stream_reader& reader) { tag_type lt = reader.read_type(true); int32_t length; reader.read_num(length); if(length < 0) reader.get_istr().setstate(std::ios::failbit); if(!reader.get_istr()) throw io::input_error("Error reading length of tag_list"); if(lt != tag_type::End) { reset(lt); tags.reserve(length); for(int32_t i = 0; i < length; ++i) tags.emplace_back(reader.read_payload(lt)); } else { //In case of tag_end, ignore the length and leave the type undetermined reset(tag_type::Null); } } void tag_list::write_payload(io::stream_writer& writer) const { if(size() > io::stream_writer::max_array_len) { writer.get_ostr().setstate(std::ios::failbit); throw std::length_error("List is too large for NBT"); } writer.write_type(el_type_ != tag_type::Null ? el_type_ : tag_type::End); writer.write_num(static_cast(size())); for(const auto& val: tags) { //check if the value is of the correct type if(val.get_type() != el_type_) { writer.get_ostr().setstate(std::ios::failbit); throw std::logic_error("The tags in the list do not all match the content type"); } writer.write_payload(val); } } bool operator==(const tag_list& lhs, const tag_list& rhs) { return lhs.el_type_ == rhs.el_type_ && lhs.tags == rhs.tags; } bool operator!=(const tag_list& lhs, const tag_list& rhs) { return !(lhs == rhs); } }