1#pragma once
2
3#include <basis/seadRawPrint.h>
4#include <prim/seadBitUtil.h>
5
6namespace agl {
7
8// maybe first parameter is is_le, maybe it is big_endian - different between decomps
9void ModifyEndianU32(bool is_le, void* p_data, size_t size);
10
11template <typename DataType_>
12class ResCommon {
13public:
14 using DataType = DataType_;
15
16 ResCommon() : mpData(nullptr) {}
17
18 ResCommon(const void* data) : mpData(static_cast<const DataType*>(data)) {}
19
20 bool isValid() const { return mpData != nullptr; }
21
22 void verify() const {
23 if (isValidMagic()) {
24 const char* b = reinterpret_cast<const char*>(mpData);
25 SEAD_ASSERT_MSG(false, "Wrong binary. [%c%c%c%c].", b[0], b[1], b[2], b[3]);
26 }
27
28 if (isValidVersion()) {
29 SEAD_ASSERT_MSG(false, "Version error.current:%d binary:%d", DataType::getVersion(),
30 sead::BitUtil::bitCastPtr<u32>(ptr(), 4));
31 }
32 }
33
34 DataType* ptr() {
35 assertValid();
36 return const_cast<DataType*>(mpData);
37 }
38
39 const DataType* ptr() const {
40 assertValid();
41 return mpData;
42 }
43
44 u8* ptrBytes() const { return const_cast<u8*>(reinterpret_cast<const u8*>(mpData)); }
45
46 DataType& ref() {
47 assertValid();
48 return *ptr();
49 }
50
51 const DataType& ref() const {
52 assertValid();
53 return *ptr();
54 }
55
56 bool isValidMagic() const {
57 return sead::BitUtil::bitCastPtr<u32>(ptr(), 0) == DataType::getSignature();
58 }
59
60 bool isValidVersion() const {
61 return sead::BitUtil::bitCastPtr<u32>(ptr(), 4) == DataType::getVersion();
62 }
63
64 void assertValid() const { SEAD_ASSERT(isValid()); }
65
66protected:
67 const DataType* mpData;
68};
69
70#define AGL_RES_FILE_HEADER() \
71public: \
72 bool modifyEndian() const { return ref().mEndian & DataType::cEndianCheckBit; } \
73 \
74 bool isEndianResolved() const { return !modifyEndian(); } \
75 \
76 void setEndianResolved() { ref().mEndian = 1 - ref().mEndian; }
77
78template <typename DataType>
79struct ResArrayData {
80 s32 mSize;
81 u32 mNum;
82 // DataType mData[];
83
84 using ElemType = DataType;
85};
86
87template <typename Type>
88class ResArray : public ResCommon<ResArrayData<typename Type::DataType>> {
89public:
90 using ElemType = Type;
91 using ElemDataType = typename Type::DataType;
92 using DataType = typename ResArray<Type>::DataType;
93 using Base = ResCommon<DataType>;
94
95 using ResCommon<DataType>::ResCommon;
96
97public:
98 class iterator {
99 public:
100 iterator(s32 index, ElemDataType* elem) : mIndex(index), mElem(elem) {}
101
102 friend bool operator==(const iterator& lhs, const iterator& rhs) {
103 return lhs.mIndex == rhs.mIndex;
104 }
105
106 friend bool operator!=(const iterator& lhs, const iterator& rhs) {
107 return lhs.mIndex != rhs.mIndex;
108 }
109
110 iterator& operator++() {
111 ++mIndex;
112 mElem = (ElemDataType*)((uintptr_t)mElem + Type(mElem).ref().mSize);
113 return *this;
114 }
115
116 ElemDataType& operator*() const { return *mElem; }
117 ElemDataType* operator->() const { return mElem; }
118 s32 getIndex() const { return mIndex; }
119
120 private:
121 s32 mIndex;
122 ElemDataType* mElem;
123 };
124
125 class constIterator {
126 public:
127 constIterator(s32 index, const ElemDataType* elem) : mIndex(index), mElem(elem) {}
128
129 friend bool operator==(const constIterator& lhs, const constIterator& rhs) {
130 return lhs.mIndex == rhs.mIndex;
131 }
132
133 friend bool operator!=(const constIterator& lhs, const constIterator& rhs) {
134 return lhs.mIndex != rhs.mIndex;
135 }
136
137 constIterator& operator++() {
138 ++mIndex;
139 mElem = (const ElemDataType*)((uintptr_t)mElem + Type(mElem).ref().mSize);
140 return *this;
141 }
142
143 const ElemDataType& operator*() const { return *mElem; }
144 const ElemDataType* operator->() const { return mElem; }
145 s32 getIndex() const { return mIndex; }
146
147 private:
148 s32 mIndex;
149 const ElemDataType* mElem;
150 };
151
152public:
153 iterator begin() { return iterator(0, (ElemDataType*)(Base::ptr() + 1)); }
154 constIterator begin() const { return constIterator(0, (const ElemDataType*)(Base::ptr() + 1)); }
155 constIterator constBegin() const {
156 return constIterator(0, (const ElemDataType*)(Base::ptr() + 1));
157 }
158
159 iterator end() { return iterator(getNum(), nullptr); }
160 constIterator end() const { return constIterator(getNum(), nullptr); }
161 constIterator constEnd() const { return constIterator(getNum(), nullptr); }
162
163public:
164 u32 getNum() const { return Base::ref().mNum; }
165
166 ElemType get(s32 n) const {
167 // clang-format off
168 SEAD_ASSERT(0 <= n && n <= static_cast< int >( this->getNum() ));
169 // clang-format on
170
171 constIterator itr = constBegin();
172 constIterator itr_end = constIterator(n, nullptr);
173
174 while (itr != itr_end)
175 ++itr;
176
177 return &(*itr);
178 }
179
180 void modifyEndianArray(bool is_le) {
181 ModifyEndianU32(is_le, Base::ptr(), sizeof(DataType));
182
183 for (iterator it = begin(), it_end = end(); it != it_end; ++it)
184 ModifyEndianU32(is_le, &(*it), sizeof(ElemDataType));
185 }
186};
187} // namespace agl
188