Skip to content

Commit ad2dcf0

Browse files
Fix INP1 loading
1 parent 82169fa commit ad2dcf0

File tree

12 files changed

+149
-43
lines changed

12 files changed

+149
-43
lines changed

modules/godot/source/inochi2d/godot/puppet.d

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ public:
8686

8787
// Load puppet into stream
8888
auto mstream = nogc_new!MemoryStream(data_[]);
89-
scope(exit) nogc_delete(mstream);
89+
scope(exit) {
90+
// Yoink the ownership so we don't free the array.
91+
mstream.take();
92+
nogc_delete(mstream);
93+
}
9094

9195
// Parse puppet
9296
auto puppet = Puppet.fromStream(mstream);

modules/inp/source/inp/format/dict.d

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,9 @@ struct KV(TKey, TValue) {
209209

210210
pragma(inline, true)
211211
static void kvassign(T)(ref T dst, ref T src) {
212-
static if (is(T == U[], U)) {
212+
static if (is(T == string)) {
213+
dst = src.nu_dup();
214+
} else static if (is(T == U[], U)) {
213215
dst = src.nu_dup();
214216
} else static if (hasElaborateMove!T) {
215217
dst = src.move();

modules/inp/source/inp/format/inp1/reader.d

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import nulib.io.stream;
1414
import nulib.math;
1515
import numem;
1616
import inp.format.json.reader;
17+
import core.stdc.stdio : printf;
1718

1819
import inp.format :
1920
INP_TAG_PAYLOAD,
@@ -67,7 +68,7 @@ void readINP1Impl()(StreamReader reader, ref DataNode node) {
6768

6869
case INP1_MAGIC:
6970
uint payloadLength = reader.readU32BE();
70-
reader.readJson(node[INP_TAG_PAYLOAD], payloadLength);
71+
auto result = reader.readJson(node[INP_TAG_PAYLOAD], payloadLength);
7172
break;
7273

7374
case INP_TAG_TEXTURES:
@@ -77,9 +78,11 @@ void readINP1Impl()(StreamReader reader, ref DataNode node) {
7778
// Main data
7879
uint dataLength = reader.readU32BE();
7980
ubyte encoding = reader.readU8();
81+
8082
if (dataLength > 0) {
8183
DataNode result = DataNode.createObject();
8284
ubyte[] data = nu_malloca!ubyte(dataLength);
85+
reader.stream.read(data);
8386

8487
result["encoding"] = encoding;
8588
result["data"] = data;
@@ -93,11 +96,16 @@ void readINP1Impl()(StreamReader reader, ref DataNode node) {
9396
case INP_TAG_VENDOR:
9497
uint count = reader.readU32BE();
9598
foreach(i; 0..count) {
96-
auto dataKey = reader.readUTF8(reader.readU32BE());
97-
auto dataValue = nu_malloca!ubyte(reader.readU32BE());
99+
auto keyLength = reader.readU32BE();
100+
auto dataKey = reader.readUTF8(keyLength).take();
101+
auto dataLength = reader.readU32BE();
102+
auto dataValue = nu_malloca!ubyte(dataLength);
103+
98104
reader.stream.read(dataValue);
99105
node[INP_TAG_VENDOR][dataKey] = dataValue;
106+
100107
nu_freea(dataValue);
108+
nu_freea(dataKey);
101109
}
102110
break;
103111
}

modules/inp/source/inp/format/json/reader.d

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import nulib.string;
1414
import nulib.math;
1515
import numem;
1616

17+
import core.stdc.stdio : printf;
18+
1719
@nogc:
1820

1921
/**
@@ -32,6 +34,7 @@ Result!DataNode readJson(Stream stream) @nogc {
3234

3335
if (auto err = reader.readJsonImpl(result, reader.stream.tell, reader.stream.length))
3436
return error!DataNode(err);
37+
printf("Read complete\n");
3538

3639
return ok(result.move());
3740
}
@@ -50,7 +53,7 @@ Result!DataNode readJson(Stream stream) @nogc {
5053
5154
*/
5255
string readJson(StreamReader reader, ref DataNode node, uint length = uint.max) @nogc {
53-
return reader.readJsonImpl(node, reader.stream.tell, min(reader.stream.length-reader.stream.tell, length));
56+
return reader.readJsonImpl(node, reader.stream.tell, min(length, reader.stream.length-reader.stream.tell));
5457
}
5558

5659

@@ -67,6 +70,35 @@ char peekChar(StreamReader reader) {
6770
return c;
6871
}
6972

73+
string peek(StreamReader reader, uint length) {
74+
auto s = reader.read(length);
75+
if (s.length > 0) {
76+
reader.stream.seek(-cast(ptrdiff_t)s.length, SeekOrigin.relative);
77+
}
78+
return s;
79+
}
80+
81+
bool peek(StreamReader reader, string key) {
82+
string read = reader.peek(cast(uint)key.length);
83+
bool same = key == read;
84+
nu_freea(read);
85+
return same;
86+
}
87+
88+
string read(StreamReader reader, uint length) {
89+
return reader.readUTF8(length).take();
90+
}
91+
92+
string popString(StreamReader reader, string key) {
93+
auto read = reader.readUTF8(cast(uint)key.length);
94+
if (read == key) {
95+
return key;
96+
}
97+
98+
reader.stream.seek(-cast(ptrdiff_t)read.length, SeekOrigin.relative);
99+
return null;
100+
}
101+
70102
string readJsonString(StreamReader reader) {
71103

72104
// Skip initial quote.
@@ -89,7 +121,7 @@ string readJsonString(StreamReader reader) {
89121
result ~= c;
90122
}
91123
} while(c != '"');
92-
return result.take()[0..$-1];
124+
return result.take();
93125
}
94126

95127
string readJsonNumber(StreamReader reader) {
@@ -100,6 +132,8 @@ string readJsonNumber(StreamReader reader) {
100132
c = cast(char)reader.readU8();
101133
result ~= c;
102134
} while (isNumberChar(c));
135+
136+
reader.stream.seek(-1, SeekOrigin.relative);
103137
return result.take();
104138
}
105139

@@ -108,48 +142,75 @@ bool isJsonSymbol(char c) {
108142
return isAlphaNumeric(c) ||
109143
c == '"' || c == ':' || c == ',' ||
110144
c == '{' || c == '}' ||
111-
c == '[' || c == ']';
145+
c == '[' || c == ']' || c == '.';
112146
}
113147

114148
void skipWhitespace(StreamReader reader) {
115-
do {} while(!isJsonSymbol(cast(char)reader.readU8()));
149+
do { } while(!isJsonSymbol(cast(char)reader.readU8()));
116150
reader.stream.seek(-1, SeekOrigin.relative);
117151
}
118152

119153
bool isNumberChar(char c) {
120-
return (c >= '0' && c <= '9') || c == '.';
154+
return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+';
121155
}
122156

123157
string readJsonImpl()(StreamReader reader, ref DataNode node, size_t start, size_t length) {
124158
import nulib.conv : to_floating;
125-
reader.skipWhitespace();
126159

127-
if (reader.stream.tell() > start+length)
160+
reader.skipWhitespace();
161+
if (reader.stream.tell() >= start+length)
128162
return "Reached EOF";
129163

164+
130165
char c = cast(char)reader.readU8();
131166
switch(c) {
132167
default:
168+
reader.stream.seek(-1, SeekOrigin.relative);
133169
if (isNumberChar(c)) {
134-
reader.stream.seek(-1, SeekOrigin.relative);
135170

136171
auto valueStr = reader.readJsonNumber();
137172
node = DataNode(to_floating!double(valueStr));
138173
nu_freea(valueStr);
174+
return null;
175+
}
176+
177+
if (reader.peek("true")) {
178+
reader.stream.seek(4, SeekOrigin.relative);
179+
node = DataNode(true);
180+
return null;
181+
}
182+
183+
if (reader.peek("false")) {
184+
reader.stream.seek(5, SeekOrigin.relative);
185+
node = DataNode(false);
186+
return null;
187+
}
188+
189+
// Skip 'null'
190+
if (reader.peek("null")) {
191+
reader.stream.seek(4, SeekOrigin.relative);
192+
return null;
139193
}
140-
return null;
194+
195+
// Okay, no idea what this character is.
196+
return "Unexpected token";
141197

142198
case '[':
143199
node = DataNode.createArray();
200+
201+
// Empty array.
202+
if (reader.peekChar() == ']') {
203+
reader.stream.seek(1, SeekOrigin.relative);
204+
return null;
205+
}
206+
144207
do {
145208
DataNode value;
146209

147210
reader.skipWhitespace();
148-
149211
if (auto error = reader.readJsonImpl(value, start, length))
150212
return error;
151213
node ~= value.move();
152-
153214
reader.skipWhitespace();
154215

155216
c = cast(char)reader.readU8();
@@ -161,6 +222,13 @@ string readJsonImpl()(StreamReader reader, ref DataNode node, size_t start, size
161222

162223
case '{':
163224
node = DataNode.createObject();
225+
226+
// Empty object.
227+
if (reader.peekChar() == '}') {
228+
reader.stream.seek(1, SeekOrigin.relative);
229+
return null;
230+
}
231+
164232
do {
165233
DataNode value;
166234

@@ -169,9 +237,6 @@ string readJsonImpl()(StreamReader reader, ref DataNode node, size_t start, size
169237
string key = reader.readJsonString();
170238
reader.skipWhitespace();
171239

172-
import core.stdc.stdio : printf;
173-
printf("%s\n", key.ptr);
174-
175240
c = cast(char)reader.readU8();
176241
if (c != ':')
177242
return "Invalid key-value pair!";

source/inochi2d/core/math/deform.d

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ public:
7878
struct Deformation {
7979
vec2[] vertexOffsets;
8080

81-
~this() @trusted @nogc nothrow {
82-
nu_freea(vertexOffsets);
81+
this(ref return scope Deformation other) @trusted @nogc nothrow {
82+
this.vertexOffsets = vertexOffsets.nu_dup();
8383
}
8484

8585
this(vec2[] data) @trusted @nogc nothrow {
@@ -246,9 +246,14 @@ struct Deformation {
246246
}
247247

248248
void onDeserialize(ref DataNode data) @nogc {
249-
this.vertexOffsets = nu_malloca!vec2(data.length / 2);
249+
this.vertexOffsets = nu_malloca!vec2(data.length);
250250
foreach (i, ref element; data.array) {
251251
this.vertexOffsets[i / 2] = element.deserialize!vec2();
252252
}
253253
}
254+
255+
void free() @nogc {
256+
if (vertexOffsets)
257+
nu_freea(vertexOffsets);
258+
}
254259
}

source/inochi2d/core/memory.d

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
Memory managment utilities.
3+
4+
Copyright © 2026, Inochi2D Project
5+
Distributed under the 2-Clause BSD License, see LICENSE file.
6+
7+
Authors: Luna Nielsen
8+
*/
9+
module inochi2d.core.memory;
10+
import numem.core.hooks;
11+
import numem;
12+
13+
/**
14+
Clears the given slice without freeing its memory.
15+
16+
Params:
17+
slice = The slice to clear.
18+
*/
19+
void in_clear_slice(T)(ref T[] slice) @nogc {
20+
nu_free(cast(void*)slice.ptr);
21+
slice = null;
22+
}

source/inochi2d/core/package.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public import inochi2d.core.math;
1616
public import inochi2d.core.property;
1717
public import inochi2d.core.sorting;
1818
public import inochi2d.core.registry;
19+
public import inochi2d.core.memory;
1920

2021
import inochi2d.core.math;
2122
import std.stdio;

source/inochi2d/core/serde/package.d

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,6 @@ T deserialize(T)(ref DataNode data) {
3333
return tmp;
3434
}
3535

36-
pragma(inline, true)
37-
void deserialize(T)(ref DataNode data, T[] destination) @nogc {
38-
if (!data.isArray)
39-
return;
40-
41-
foreach (ref ae; data.array) {
42-
foreach (i; 0 .. destination.length) {
43-
ae.deserialize(destination[i]);
44-
}
45-
}
46-
}
47-
4836
pragma(inline, true)
4937
void deserialize(T)(ref DataNode data, ref T destination) @nogc {
5038
import inochi2d.core.serde.deserializers;
@@ -81,8 +69,16 @@ void deserialize(T)(ref DataNode data, ref T destination) @nogc {
8169
return;
8270

8371
destination.resize(data.length);
84-
foreach (ref value; data.array) {
85-
destination ~= value.deserialize!VT();
72+
foreach (i, ref value; data.array) {
73+
destination[i] = value.deserialize!VT();
74+
}
75+
} else static if (is(T == U[], U)) {
76+
if (!data.isArray)
77+
return;
78+
79+
destination = destination.nu_resize(data.length);
80+
foreach (i, ref value; data.array) {
81+
destination[i] = value.deserialize!U();
8682
}
8783
} else static if (is(T == MapImpl!(string, VT, Args), VT, Args...)) {
8884
if (!data.isObject)

source/inochi2d/nodes/package.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -789,8 +789,8 @@ void findNodes(T)(Node root, ref T[] list) @nogc if (is(T : Node)) {
789789
findNodesImpl(child, list);
790790
}
791791
}
792-
793-
nu_freea(list);
792+
793+
in_clear_slice(list);
794794
findNodesImpl(root, list);
795795
}
796796

source/inochi2d/nodes/visual.d

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,12 @@ void findVisuals(Node root, ref Visual[] visuals, bool recurseDelegates = false,
294294
}
295295

296296
if (!append)
297-
nu_freea(visuals);
298-
299-
findVisualsImpl(root, visuals, recurseDelegates);
297+
in_clear_slice(visuals);
298+
299+
// Find all visuals in children.
300+
foreach(child; root.children) {
301+
findVisualsImpl(child, visuals, recurseDelegates);
302+
}
300303
if (sort)
301304
sortNodes(visuals);
302305
}

0 commit comments

Comments
 (0)