1#pragma once
2
3#include <array>
4#include <basis/seadRawPrint.h>
5#include <basis/seadTypes.h>
6#include <prim/seadTypedBitFlag.h>
7#include "common/aglResCommon.h"
8
9namespace sead {
10template <typename Key, typename Value>
11class TreeMap;
12}
13
14namespace agl::utl {
15
16struct ResParameterData {
17 constexpr u32 getParameterNameHash() const { return name_hash; }
18 constexpr u32 getOffset() const { return 4 * (offset_and_type & 0xFFFFFF); }
19 constexpr u32 getType() const { return offset_and_type >> 24; }
20
21 u32 name_hash;
22 u32 offset_and_type;
23};
24static_assert(sizeof(ResParameterData) == 0x8);
25
26struct ResParameter {
27 ResParameterData* ptr() const { return mPtr; }
28 u8* ptrBytes() const { return reinterpret_cast<u8*>(mPtr); }
29
30 u32 getParameterNameHash() const { return ptr()->getParameterNameHash(); }
31
32 template <typename T>
33 T* getData() const {
34 return reinterpret_cast<T*>(ptrBytes() + ptr()->getOffset());
35 }
36
37 /// Get the data size in bytes.
38 size_t getDataSize() const;
39
40 template <typename T>
41 bool copyData(T* out) const;
42
43 /// Get the number of elements in the buffer.
44 /// @warning Only valid for buffer types.
45 size_t getBufferSize() const {
46 return *reinterpret_cast<u32*>(ptrBytes() + ptr()->getOffset() - 4);
47 }
48
49 ResParameterData* mPtr;
50};
51
52struct ResParameterObjData {
53 constexpr u32 getParameterObjNameHash() const { return name_hash; }
54 constexpr u32 getParametersOffset() const { return 4 * u16(param_offset_and_num); }
55 constexpr u16 getNumParameters() const { return param_offset_and_num >> 16; }
56 constexpr bool hasParameters() const { return getNumParameters() != 0; }
57
58 u32 name_hash;
59 u32 param_offset_and_num;
60};
61static_assert(sizeof(ResParameterObjData) == 8);
62
63struct ResParameterObj {
64 class Iterator {
65 public:
66 Iterator(ResParameterData* ptr, s32 idx) : mIdx(idx), mPtr(ptr) {}
67 bool operator==(const Iterator& rhs) const { return getIndex() == rhs.getIndex(); }
68 bool operator!=(const Iterator& rhs) const { return !operator==(rhs); }
69 s32 getIndex() const { return mIdx; }
70 ResParameter getParam() const { return {.mPtr: mPtr}; }
71 ResParameter operator*() const { return getParam(); }
72 Iterator& operator++() {
73 ++mIdx;
74 ++mPtr;
75 return *this;
76 }
77
78 private:
79 s32 mIdx;
80 ResParameterData* mPtr;
81 };
82
83 Iterator begin() const {
84 if (!ptr()->hasParameters())
85 return {nullptr, 0};
86 return {reinterpret_cast<ResParameterData*>(ptrBytes() + ptr()->getParametersOffset()), 0};
87 }
88 Iterator end() const { return {nullptr, s32(ptr()->getNumParameters())}; }
89
90 explicit operator bool() const { return ptr() != nullptr; }
91 ResParameterObjData* ptr() const { return mPtr; }
92 u8* ptrBytes() const { return reinterpret_cast<u8*>(mPtr); }
93
94 u32 getParameterObjNameHash() const { return ptr()->getParameterObjNameHash(); }
95 s32 getNum() const { return ptr()->getNumParameters(); }
96
97 /// Get a parameter by index. The index must be valid.
98 ResParameter getResParameter(s32 index) const {
99 SEAD_ASSERT(0 <= index && index < getNum());
100 return getResParameter(index, offset: ptr()->getParametersOffset());
101 }
102
103 ResParameter getResParameter(s32 index, u32 offset) const {
104 return {.mPtr: reinterpret_cast<ResParameterData*>(ptrBytes() + offset +
105 sizeof(ResParameterData) * index)};
106 }
107
108 template <typename T>
109 T* getParameterData(s32 index) const {
110 return getResParameter(index).getData<T>();
111 }
112
113 /// @returns the index of the specified parameter, or -1 if not found.
114 s32 searchIndex(u32 param_hash) const;
115
116 ResParameterObjData* mPtr;
117};
118
119struct ResParameterListData {
120 constexpr u32 getParameterListNameHash() const { return name_hash; }
121 constexpr u32 getListsOffset() const { return 4 * u16(list_offset_and_num); }
122 constexpr u32 getObjectsOffset() const { return 4 * u16(obj_offset_and_num); }
123 constexpr u32 getNumLists() const { return list_offset_and_num >> 16; }
124 constexpr s32 getNumObjects() const { return obj_offset_and_num >> 16; }
125 constexpr bool hasLists() const { return getNumLists() != 0; }
126 constexpr bool hasObjects() const { return getNumObjects() != 0; }
127
128 u32 name_hash;
129 u32 list_offset_and_num;
130 u32 obj_offset_and_num;
131};
132static_assert(sizeof(ResParameterListData) == 0xc);
133
134struct ResParameterList {
135 class ListIterator {
136 public:
137 ListIterator(ResParameterListData* ptr, s32 idx) : mIdx(idx), mPtr(ptr) {}
138 bool operator==(const ListIterator& rhs) const { return getIndex() == rhs.getIndex(); }
139 bool operator!=(const ListIterator& rhs) const { return !operator==(rhs); }
140 s32 getIndex() const { return mIdx; }
141 ResParameterList getList() const { return {.mPtr: mPtr}; }
142 ResParameterList operator*() const { return getList(); }
143 ListIterator& operator++() {
144 ++mIdx;
145 ++mPtr;
146 return *this;
147 }
148
149 private:
150 s32 mIdx;
151 ResParameterListData* mPtr;
152 };
153
154 ListIterator listBegin() const {
155 if (!ptr()->hasLists())
156 return {nullptr, 0};
157 return {reinterpret_cast<ResParameterListData*>(ptrBytes() + ptr()->getListsOffset()), 0};
158 }
159 ListIterator listEnd() const { return {nullptr, s32(ptr()->getNumLists())}; }
160
161 class ObjIterator {
162 public:
163 ObjIterator(ResParameterObjData* ptr, s32 idx) : mIdx(idx), mPtr(ptr) {}
164 bool operator==(const ObjIterator& rhs) const { return getIndex() == rhs.getIndex(); }
165 bool operator!=(const ObjIterator& rhs) const { return !operator==(rhs); }
166 s32 getIndex() const { return mIdx; }
167 ResParameterObj getObj() const { return {.mPtr: mPtr}; }
168 ResParameterObj operator*() const { return getObj(); }
169 ObjIterator& operator++() {
170 ++mIdx;
171 ++mPtr;
172 return *this;
173 }
174
175 private:
176 s32 mIdx;
177 ResParameterObjData* mPtr;
178 };
179
180 ObjIterator objBegin() const {
181 if (!ptr()->hasObjects())
182 return {nullptr, 0};
183 return {reinterpret_cast<ResParameterObjData*>(ptrBytes() + ptr()->getObjectsOffset()), 0};
184 }
185 ObjIterator objEnd() const { return {nullptr, s32(ptr()->getNumObjects())}; }
186
187 explicit operator bool() const { return ptr() != nullptr; }
188 ResParameterListData* ptr() const { return mPtr; }
189 u8* ptrBytes() const { return reinterpret_cast<u8*>(mPtr); }
190
191 u32 getParameterListNameHash() const { return ptr()->getParameterListNameHash(); }
192 s32 getResParameterListNum() const { return ptr()->getNumLists(); }
193 s32 getResParameterObjNum() const { return ptr()->getNumObjects(); }
194
195 /// Get a parameter list by index. The index must be valid.
196 ResParameterList getResParameterList(s32 index) const {
197 SEAD_ASSERT(0 <= index && index < getResParameterListNum());
198 return getResParameterList(index, offset: ptr()->getListsOffset());
199 }
200
201 ResParameterList getResParameterList(s32 index, u32 offset) const {
202 return {.mPtr: reinterpret_cast<ResParameterListData*>(ptrBytes() + offset +
203 sizeof(ResParameterListData) * index)};
204 }
205
206 /// Get a parameter object by index. The index must be valid.
207 ResParameterObj getResParameterObj(s32 index) const {
208 SEAD_ASSERT(0 <= index && index < getResParameterObjNum());
209 return getResParameterObj(index, offset: ptr()->getObjectsOffset());
210 }
211
212 ResParameterObj getResParameterObj(s32 index, u32 offset) const {
213 return {.mPtr: reinterpret_cast<ResParameterObjData*>(ptrBytes() + offset +
214 sizeof(ResParameterObjData) * index)};
215 }
216
217 /// @returns the index of the specified list, or -1 if not found.
218 s32 searchListIndex(u32 list_hash) const;
219
220 /// @returns the index of the specified object, or -1 if not found.
221 s32 searchObjIndex(u32 obj_hash) const;
222
223 void dump(s32, const sead::TreeMap<u32, const char*>* name_table) const;
224
225 ResParameterListData* mPtr;
226};
227
228constexpr std::array<char, 4> HeaderMagic = {{'A', 'A', 'M', 'P'}};
229
230enum class ResParameterArchiveFlag : u32 {
231 LittleEndian = 1 << 0,
232 Utf8 = 1 << 1,
233};
234
235struct ResParameterArchiveData {
236 static u32 getVersion() { return 2; }
237 static u32 getSignature() { return 'AAMP'; }
238
239 std::array<char, 4> magic;
240 u32 version;
241 sead::TypedBitFlag<ResParameterArchiveFlag> flags;
242 u32 file_size;
243 u32 pio_version;
244 /// Offset to parameter IO (relative to 0x30)
245 u32 offset_to_pio;
246 /// Number of lists (including parameter IO)
247 u32 num_lists;
248 u32 num_objects;
249 u32 num_parameters;
250 u32 data_section_size;
251 u32 string_section_size;
252 u32 unk_section_size;
253};
254static_assert(sizeof(ResParameterArchiveData) == 0x30);
255
256struct ResParameterArchive : ResCommon<ResParameterArchiveData> {
257 ResParameterArchive() = default;
258 explicit ResParameterArchive(const void* p_data);
259
260 ResParameterList getRootList() const {
261 return {.mPtr: reinterpret_cast<ResParameterListData*>(
262 ptrBytes() + sizeof(ResParameterArchiveData) + ptr()->offset_to_pio)};
263 }
264};
265
266} // namespace agl::utl
267