1#include "Library/Yaml/Writer/ByamlWriter.h"
2
3#include <heap/seadHeapMgr.h>
4#include <stream/seadStream.h>
5
6#include "Library/Yaml/ByamlIter.h"
7#include "Library/Yaml/Writer/ByamlWriterBigDataList.h"
8#include "Library/Yaml/Writer/ByamlWriterData.h"
9#include "Library/Yaml/Writer/ByamlWriterStringTable.h"
10
11namespace al {
12
13ByamlWriter::ByamlWriter(sead::Heap* heap, bool _alwaysFalse)
14 : mHeap(heap), mAlwaysFalse(_alwaysFalse) {
15 sead::ScopedCurrentHeapSetter setter{mHeap};
16 mStringTable1 = new ByamlWriterStringTable();
17 mStringTable2 = new ByamlWriterStringTable();
18 mBigDataList = new ByamlWriterBigDataList();
19 mContainerStack = new ByamlWriterContainer*[mContainerStackSize];
20}
21
22ByamlWriter::~ByamlWriter() {
23 if (mAlwaysFalse) {
24 delete mStringTable1;
25 delete mStringTable2;
26 delete mBigDataList;
27 delete[] mContainerStack;
28
29 for (auto* node : mContainerList)
30 node->deleteData();
31 while (auto* node = mContainerList.popBack()) {
32 node->mList = nullptr;
33 delete node->mData;
34 delete node;
35 }
36 }
37}
38
39void ByamlWriter::addBool(bool value) {
40 sead::ScopedCurrentHeapSetter setter{mHeap};
41 mContainerStack[mCurrentContainerIndex]->addBool(value);
42}
43
44void ByamlWriter::addInt(s32 value) {
45 sead::ScopedCurrentHeapSetter setter{mHeap};
46 mContainerStack[mCurrentContainerIndex]->addInt(value);
47}
48
49void ByamlWriter::addUInt(u32 value) {
50 sead::ScopedCurrentHeapSetter setter{mHeap};
51 mContainerStack[mCurrentContainerIndex]->addUInt(value);
52}
53
54void ByamlWriter::addFloat(f32 value) {
55 sead::ScopedCurrentHeapSetter setter{mHeap};
56 mContainerStack[mCurrentContainerIndex]->addFloat(value);
57}
58
59void ByamlWriter::addInt64(s64 value) {
60 sead::ScopedCurrentHeapSetter setter{mHeap};
61 mContainerStack[mCurrentContainerIndex]->addInt64(value, mBigDataList);
62}
63
64void ByamlWriter::addUInt64(u64 value) {
65 sead::ScopedCurrentHeapSetter setter{mHeap};
66 mContainerStack[mCurrentContainerIndex]->addUInt64(value, mBigDataList);
67}
68
69void ByamlWriter::addDouble(f64 value) {
70 sead::ScopedCurrentHeapSetter setter{mHeap};
71 mContainerStack[mCurrentContainerIndex]->addDouble(value, mBigDataList);
72}
73
74void ByamlWriter::addString(const char* value) {
75 sead::ScopedCurrentHeapSetter setter{mHeap};
76 mContainerStack[mCurrentContainerIndex]->addString(value);
77}
78
79void ByamlWriter::addNull() {
80 sead::ScopedCurrentHeapSetter setter{mHeap};
81 mContainerStack[mCurrentContainerIndex]->addNull();
82}
83
84void ByamlWriter::addBool(const char* key, bool value) {
85 sead::ScopedCurrentHeapSetter setter{mHeap};
86 mContainerStack[mCurrentContainerIndex]->addBool(key, value);
87}
88
89void ByamlWriter::addInt(const char* key, s32 value) {
90 sead::ScopedCurrentHeapSetter setter{mHeap};
91 mContainerStack[mCurrentContainerIndex]->addInt(key, value);
92}
93
94void ByamlWriter::addUInt(const char* key, u32 value) {
95 sead::ScopedCurrentHeapSetter setter{mHeap};
96 mContainerStack[mCurrentContainerIndex]->addUInt(key, value);
97}
98
99void ByamlWriter::addFloat(const char* key, f32 value) {
100 sead::ScopedCurrentHeapSetter setter{mHeap};
101 mContainerStack[mCurrentContainerIndex]->addFloat(key, value);
102}
103
104void ByamlWriter::addInt64(const char* key, s64 value) {
105 sead::ScopedCurrentHeapSetter setter{mHeap};
106 mContainerStack[mCurrentContainerIndex]->addInt64(key, value, mBigDataList);
107}
108
109void ByamlWriter::addUInt64(const char* key, u64 value) {
110 sead::ScopedCurrentHeapSetter setter{mHeap};
111 mContainerStack[mCurrentContainerIndex]->addUInt64(key, value, mBigDataList);
112}
113
114void ByamlWriter::addDouble(const char* key, f64 value) {
115 sead::ScopedCurrentHeapSetter setter{mHeap};
116 mContainerStack[mCurrentContainerIndex]->addDouble(key, value, mBigDataList);
117}
118
119void ByamlWriter::addString(const char* key, const char* value) {
120 sead::ScopedCurrentHeapSetter setter{mHeap};
121 mContainerStack[mCurrentContainerIndex]->addString(key, value);
122}
123
124void ByamlWriter::addNull(const char* key) {
125 sead::ScopedCurrentHeapSetter setter{mHeap};
126 mContainerStack[mCurrentContainerIndex]->addNull(key);
127}
128
129ByamlWriterContainer* ByamlWriter::getCurrentContainer() {
130 return mContainerStack[mCurrentContainerIndex];
131}
132
133ByamlWriterArray* ByamlWriter::getArrayCurrentContainer() {
134 return static_cast<ByamlWriterArray*>(getCurrentContainer());
135}
136
137ByamlWriterHash* ByamlWriter::getHashCurrentContainer() {
138 return static_cast<ByamlWriterHash*>(getCurrentContainer());
139}
140
141void ByamlWriter::pushContainer(ByamlWriterContainer* container) {
142 mCurrentContainerIndex++;
143 mContainerStack[mCurrentContainerIndex] = container;
144 mContainerList.pushBack(item: new sead::TListNode<ByamlWriterContainer*>(container));
145}
146
147void ByamlWriter::pushHash() {
148 sead::ScopedCurrentHeapSetter setter{mHeap};
149 auto* hash = new ByamlWriterHash(mStringTable1, mStringTable2);
150 if (mCurrentContainerIndex >= 0)
151 mContainerStack[mCurrentContainerIndex]->addHash(hash);
152
153 pushContainer(container: hash);
154}
155
156void ByamlWriter::pushArray() {
157 sead::ScopedCurrentHeapSetter setter{mHeap};
158 auto* array = new ByamlWriterArray(mStringTable2);
159 if (mCurrentContainerIndex >= 0)
160 mContainerStack[mCurrentContainerIndex]->addArray(array);
161
162 pushContainer(container: array);
163}
164
165void ByamlWriter::pushHash(const char* key) {
166 sead::ScopedCurrentHeapSetter setter{mHeap};
167 auto* hash = new ByamlWriterHash(mStringTable1, mStringTable2);
168 mContainerStack[mCurrentContainerIndex]->addHash(key, hash);
169
170 pushContainer(container: hash);
171}
172
173void ByamlWriter::pushArray(const char* key) {
174 sead::ScopedCurrentHeapSetter setter{mHeap};
175 auto* array = new ByamlWriterArray(mStringTable2);
176 mContainerStack[mCurrentContainerIndex]->addArray(key, array);
177
178 pushContainer(container: array);
179}
180
181void ByamlWriter::pushIter(const ByamlIter& iter) {
182 pushLocalIter(iter, nullptr);
183}
184
185void ByamlWriter::pushIter(const char* key, const ByamlIter& iter) {
186 pushLocalIter(iter, key);
187}
188
189void ByamlWriter::pushLocalIter(const ByamlIter& iter, const char* iterKey) {
190 if (!iter.isValid())
191 return;
192
193 s32 size = iter.getSize();
194 if (iter.isTypeHash())
195 if (iterKey)
196 pushHash(key: iterKey);
197 else
198 pushHash();
199 else if (iter.isTypeArray())
200 if (iterKey)
201 pushArray(key: iterKey);
202 else
203 pushArray();
204 else
205 return;
206
207 for (s32 i = 0; i < size; i++) {
208 ByamlData data{};
209 const char* key = nullptr;
210 if (iter.isTypeHash())
211 iter.getByamlDataAndKeyName(data: &data, key: &key, index: i);
212 else
213 iter.getByamlDataByIndex(data: &data, index: i);
214
215 if (data.getType() == 0xD0) {
216 bool value;
217 if (iter.tryConvertBool(val: &value, data: &data)) {
218 if (key)
219 addBool(key, value);
220 else
221 addBool(value);
222 }
223 }
224 if (data.getType() == 0xD1) {
225 s32 value;
226 if (iter.tryConvertInt(val: &value, data: &data)) {
227 if (key)
228 addInt(key, value);
229 else
230 addInt(value);
231 }
232 }
233 if (data.getType() == 0xD2) {
234 f32 value;
235 if (iter.tryConvertFloat(val: &value, data: &data)) {
236 if (key)
237 addFloat(key, value);
238 else
239 addFloat(value);
240 }
241 }
242 if (data.getType() == 0xD3) {
243 u32 value;
244 if (iter.tryConvertUInt(val: &value, data: &data)) {
245 if (key)
246 addUInt(key, value);
247 else
248 addUInt(value);
249 }
250 }
251 if (data.getType() == 0xD4) {
252 s64 value;
253 if (iter.tryConvertInt64(val: &value, data: &data)) {
254 if (key)
255 addInt64(key, value);
256 else
257 addInt64(value);
258 }
259 }
260 if (data.getType() == 0xD6) {
261 f64 value;
262 if (iter.tryConvertDouble(val: &value, data: &data)) {
263 if (key)
264 addDouble(key, value);
265 else
266 addDouble(value);
267 }
268 }
269 if (data.getType() == 0xD5) {
270 u64 value;
271 if (iter.tryConvertUInt64(val: &value, data: &data)) {
272 if (key)
273 addUInt64(key, value);
274 else
275 addUInt64(value);
276 }
277 }
278 if (data.getType() == 0xA0) {
279 const char* value;
280 if (iter.tryConvertString(string: &value, data: &data)) {
281 if (key)
282 addString(key, value);
283 else
284 addString(value);
285 }
286 }
287 if (data.getType() == 0x00) {
288 if (key)
289 addNull(key);
290 else
291 addNull();
292 }
293 if (data.getType() == 0xC0 || data.getType() == 0xC1) {
294 ByamlIter value;
295 if (iter.tryConvertIter(iter: &value, data: &data))
296 pushLocalIter(iter: value, iterKey: key);
297 }
298 }
299 pop();
300}
301
302void ByamlWriter::pop() {
303 mCurrentContainerIndex--;
304}
305
306u32 ByamlWriter::calcHeaderSize() const {
307 return 16;
308}
309
310u32 ByamlWriter::calcPackSize() const {
311 u32 size = 16;
312 if (mStringTable1)
313 size += mStringTable1->calcPackSize();
314 if (mStringTable2)
315 size += mStringTable2->calcPackSize();
316 if (mBigDataList)
317 size += mBigDataList->calcPackSize();
318 for (auto* container : mContainerList)
319 size += container->calcPackSize();
320 return size;
321}
322
323// NON_MATCHING: offsetBigDataList increased "too early"
324void ByamlWriter::write(sead::WriteStream* stream) {
325 stream->writeU16(0x4259);
326 stream->writeU16(3);
327
328 s32 sizeStringTable1 = mStringTable1->calcPackSize();
329 stream->writeU32(sizeStringTable1 > 0 ? 16 : 0);
330
331 u32 offsetStringTable2 = sizeStringTable1 + 16;
332 s32 sizeStringTable2 = mStringTable2->calcPackSize();
333 stream->writeU32(sizeStringTable2 > 0 ? offsetStringTable2 : 0);
334
335 u32 offsetBigDataList = mBigDataList->setOffset(offsetStringTable2 + sizeStringTable2);
336 stream->writeU32(mContainerList.size() > 0 ? offsetBigDataList : 0);
337 mStringTable1->write(stream);
338 mStringTable2->write(stream);
339 mBigDataList->write(stream);
340
341 for (auto* container : mContainerList) {
342 container->setOffset(offsetBigDataList);
343 offsetBigDataList += container->calcPackSize();
344 }
345 for (auto* container : mContainerList)
346 container->writeContainer(stream);
347}
348
349void ByamlWriter::print() const {
350 if (mStringTable1)
351 mStringTable1->print();
352 if (mStringTable2)
353 mStringTable2->print();
354 if (mCurrentContainerIndex >= 0)
355 mContainerStack[0]->print(1);
356}
357
358} // namespace al
359