string_data.cpp (2041B)
1 #include "string_data.hpp" 2 3 #include "data.hpp" 4 #include "../raw_item.hpp" 5 #include "../../sink.hpp" 6 7 #include <libshit/string_utils.hpp> 8 9 namespace Neptools::Stcm 10 { 11 12 Libshit::RefCountedPtr<StringDataItem> 13 StringDataItem::MaybeCreateAndReplace(DataItem& it) 14 { 15 // string: data(0, x, 1), where x = size/4, size is strlen+1 rounded to 4 bytes 16 // ignore x == 1: it's probably an int32 17 if (it.type != 0 || it.offset_unit <= 1 || it.field_8 != 1 || 18 it.GetChildren().empty() || // only one child 19 &it.GetChildren().front() != &it.GetChildren().back()) return nullptr; 20 auto child = dynamic_cast<RawItem*>(&it.GetChildren().front()); 21 if (!child || child->GetSize() != it.offset_unit * 4) return nullptr; 22 23 auto src = child->GetSource(); 24 auto s = src.ReadCString(); 25 auto padlen = it.offset_unit * 4 - s.size() - 1; 26 if (padlen > 4) return nullptr; 27 char pad[4]; 28 src.Read(pad, padlen); 29 // check padding all zero. I don't think it's required, but in the game 30 // files they're zero filled, + dump will generate zeros, so do not lose 31 // information by discarding a non-null padding... 32 for (size_t i = 0; i < padlen; ++i) 33 if (pad[i] != 0) return nullptr; 34 35 auto sit = it.GetContext()->Create<StringDataItem>(Libshit::Move(s)); 36 it.Replace(sit); 37 return Libshit::Move(sit); 38 } 39 40 FilePosition StringDataItem::GetSize() const noexcept 41 { 42 return sizeof(DataItem::Header) + (string.length() + 1 + 3) / 4 * 4; 43 } 44 45 void StringDataItem::Dump_(Sink& sink) const 46 { 47 auto len = (string.length() + 1 + 3) / 4 * 4; 48 sink.WriteGen(DataItem::Header{0, len/4, 1, len}); 49 sink.Write(string); 50 sink.Pad(len - string.length()); 51 } 52 53 void StringDataItem::Inspect_(std::ostream& os, unsigned indent) const 54 { 55 Item::Inspect_(os, indent); 56 os << "string_data(" << Libshit::Quoted(string) << ')'; 57 } 58 59 static Stcm::DataFactory reg{[](DataItem& it) { 60 return !!StringDataItem::MaybeCreateAndReplace(it); }}; 61 62 } 63 64 #include "string_data.binding.hpp"