Skip to content

Commit 03ab2a6

Browse files
committed
fix: Implement better read functionality
fix: Use resource as reference for callbacks
1 parent b2d90b5 commit 03ab2a6

6 files changed

+60
-71
lines changed

Diff for: src/FFI.php

-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,6 @@ private static function init(): void
484484
*/
485485
};
486486
long g_signal_connect_closure(GObject* object, const char* detailed_signal, GClosure *closure, bool after);
487-
GClosure* g_closure_ref(GClosure* closure);
488487
GClosure* g_closure_new_simple (int sizeof_closure, void* data);
489488
EOS;
490489

Diff for: src/GObject.php

+51-44
Original file line numberDiff line numberDiff line change
@@ -97,110 +97,117 @@ public function unref(): void
9797
FFI::gobject()->g_object_unref($this->pointer);
9898
}
9999

100+
/**
101+
* @throws Exception
102+
*/
100103
public function signalConnect(string $name, Closure $callback): void
101104
{
102105
$imageProgressCb = static function (
103-
CData $gClosure,
106+
CData $gClosure,
104107
?CData $returnValue,
105-
int $numberOfParams,
106-
CData $params,
107-
CData $hint,
108+
int $numberOfParams,
109+
CData $params,
110+
CData $hint,
108111
?CData $data
109-
) use ($callback) {
112+
) use (&$callback) {
110113
assert($numberOfParams === 3);
111114
/**
112-
* Marshal-Signature: void(VipsImage*, void*, void*)
115+
* Marshal-Signature: void(VipsImage* image, void* progress, void* handle)
113116
*/
114-
$vi = \FFI::cast(FFI::ctypes('GObject'), FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1])));
117+
$vi = \FFI::cast(FFI::ctypes('GObject'), FFI::gobject()->g_value_get_pointer(\FFI::addr($params[0])));
115118
FFI::gobject()->g_object_ref($vi);
116119
$image = new Image($vi);
117-
$pr = \FFI::cast(FFI::ctypes('VipsProgress'), FFI::gobject()->g_value_get_pointer(\FFI::addr($params[2])));
120+
$pr = \FFI::cast(FFI::ctypes('VipsProgress'), FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1])));
118121
$callback($image, $pr);
119122
};
120123
$marshalers = ['preeval' => $imageProgressCb, 'eval' => $imageProgressCb, 'posteval' => $imageProgressCb];
121124

122125
if (FFI::atLeast(8, 9)) {
123126
$marshalers['read'] = static function (
124-
CData $gClosure,
125-
CData $returnValue,
126-
int $numberOfParams,
127-
CData $params,
128-
CData $hint,
127+
CData $gClosure,
128+
CData $returnValue,
129+
int $numberOfParams,
130+
CData $params,
131+
CData $hint,
129132
?CData $data
130133
) use (&$callback): void {
131134
assert($numberOfParams === 4);
132135
/*
133-
* Marshal-Signature: gint64(VipsSourceCustom*, void*, gint64, void*)
136+
* Marshal-Signature: gint64(VipsSourceCustom* source, void* buffer, gint64 length, void* handle)
134137
*/
135138
$bufferPointer = FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1]));
136-
$bufferLength = (int) FFI::gobject()->g_value_get_int64(\FFI::addr($params[2]));
137-
$buffer = \FFI::string($bufferPointer, $bufferLength);
138-
$returnBufferLength = $callback($buffer);
139-
\FFI::memcpy($bufferPointer, $buffer, $returnBufferLength);
139+
$bufferLength = (int)FFI::gobject()->g_value_get_int64(\FFI::addr($params[2]));
140+
$returnBuffer = $callback($bufferLength);
141+
$returnBufferLength = 0;
142+
143+
if ($returnBuffer !== null) {
144+
$returnBufferLength = strlen($returnBuffer);
145+
\FFI::memcpy($bufferPointer, $returnBuffer, $returnBufferLength);
146+
}
140147
FFI::gobject()->g_value_set_int64($returnValue, $returnBufferLength);
141148
};
142149
$marshalers['seek'] = static function (
143-
CData $gClosure,
144-
CData $returnValue,
145-
int $numberOfParams,
146-
CData $params,
147-
CData $hint,
150+
CData $gClosure,
151+
CData $returnValue,
152+
int $numberOfParams,
153+
CData $params,
154+
CData $hint,
148155
?CData $data
149156
) use (&$callback): void {
150157
assert($numberOfParams === 4);
151158
/*
152-
* Marshal-Signature: gint64(VipsSourceCustom*, gint64, int, void*)
159+
* Marshal-Signature: gint64(VipsSourceCustom* source, gint64 offset, int whence, void* handle)
153160
*/
154-
$offset = (int) FFI::gobject()->g_value_get_int64(\FFI::addr($params[1]));
155-
$whence = (int) FFI::gobject()->g_value_get_int(\FFI::addr($params[2]));
161+
$offset = (int)FFI::gobject()->g_value_get_int64(\FFI::addr($params[1]));
162+
$whence = (int)FFI::gobject()->g_value_get_int(\FFI::addr($params[2]));
156163
FFI::gobject()->g_value_set_int64($returnValue, $callback($offset, $whence));
157164
};
158165
$marshalers['write'] = static function (
159-
CData $gClosure,
160-
CData $returnValue,
161-
int $numberOfParams,
162-
CData $params,
163-
CData $hint,
166+
CData $gClosure,
167+
CData $returnValue,
168+
int $numberOfParams,
169+
CData $params,
170+
CData $hint,
164171
?CData $data
165172
) use (&$callback): void {
166173
assert($numberOfParams === 4);
167174
/*
168-
* Marshal-Signature: gint64(VipsTargetCustom*, void*, gint64, void*)
175+
* Marshal-Signature: gint64(VipsTargetCustom* target, void* buffer, gint64 length, void* handle)
169176
*/
170177
$bufferPointer = FFI::gobject()->g_value_get_pointer(\FFI::addr($params[1]));
171-
$bufferLength = (int) FFI::gobject()->g_value_get_int64(\FFI::addr($params[2]));
178+
$bufferLength = (int)FFI::gobject()->g_value_get_int64(\FFI::addr($params[2]));
172179
$buffer = \FFI::string($bufferPointer, $bufferLength);
173180
$returnBufferLength = $callback($buffer);
174181
FFI::gobject()->g_value_set_int64($returnValue, $returnBufferLength);
175182
};
176183
$marshalers['finish'] = static function (
177-
CData $gClosure,
184+
CData $gClosure,
178185
?CData $returnValue,
179-
int $numberOfParams,
180-
CData $params,
181-
CData $hint,
186+
int $numberOfParams,
187+
CData $params,
188+
CData $hint,
182189
?CData $data
183190
) use (&$callback): void {
184191
assert($numberOfParams === 2);
185192
/**
186-
* Marshal-Signature: void(VipsTargetCustom*, void*)
193+
* Marshal-Signature: void(VipsTargetCustom* target, void* handle)
187194
*/
188195
$callback();
189196
};
190197
}
191198

192199
if (FFI::atLeast(8, 13)) {
193200
$marshalers['end'] = static function (
194-
CData $gClosure,
195-
CData $returnValue,
196-
int $numberOfParams,
197-
CData $params,
198-
CData $hint,
201+
CData $gClosure,
202+
CData $returnValue,
203+
int $numberOfParams,
204+
CData $params,
205+
CData $hint,
199206
?CData $data
200207
) use (&$callback): void {
201208
assert($numberOfParams === 2);
202209
/**
203-
* Marshal-Signature: int(VipsTargetCustom*, void*)
210+
* Marshal-Signature: int(VipsTargetCustom* target, void* handle)
204211
*/
205212
FFI::gobject()->g_value_set_int($returnValue, $callback());
206213
};

Diff for: src/VipsSourceCustom.php

+2-11
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,14 @@ public function __construct()
2222

2323
/**
2424
* Attach a read handler.
25-
* The interface is exactly as io.read() in Python. The handler is given a number
25+
* The interface is similar to fread. The handler is given a number
2626
* of bytes to fetch, and should return a bytes-like object containing up
2727
* to that number of bytes. If there is no more data available, it should
2828
* return None.
2929
*/
3030
public function onRead(Closure $callback): void
3131
{
32-
$this->signalConnect('read', static function (string &$buffer) use ($callback): int {
33-
$chunk = $callback(strlen($buffer));
34-
35-
if ($chunk === null) {
36-
return 0;
37-
}
38-
39-
$buffer = substr_replace($buffer, $chunk, 0);
40-
return strlen($chunk);
41-
});
32+
$this->signalConnect('read', $callback);
4233
}
4334

4435
/**

Diff for: src/VipsSourceResource.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ public function __construct($resource)
2222
$this->resource = $resource;
2323
parent::__construct();
2424

25-
$this->onRead(static function (int $length) use ($resource): ?string {
25+
$this->onRead(static function (int $length) use (&$resource): ?string {
2626
return fread($resource, $length) ?: null;
2727
});
2828

2929
if (stream_get_meta_data($resource)['seekable']) {
30-
$this->onSeek(static function (int $offset, int $whence) use ($resource): int {
30+
$this->onSeek(static function (int $offset, int $whence) use (&$resource): int {
3131
fseek($resource, $offset, $whence);
3232
return ftell($resource);
3333
});

Diff for: src/VipsTargetCustom.php

+1-9
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,7 @@ public function onWrite(Closure $callback): void
2828
public function onRead(Closure $callback): void
2929
{
3030
if (FFI::atLeast(8, 13)) {
31-
$this->signalConnect('read', static function (string &$buffer) use ($callback): int {
32-
$chunk = $callback(strlen($buffer));
33-
34-
if ($chunk === null) {
35-
return 0;
36-
}
37-
$buffer = substr_replace($buffer, $chunk, 0);
38-
return strlen($chunk);
39-
});
31+
$this->signalConnect('read', $callback);
4032
}
4133
}
4234

Diff for: src/VipsTargetResource.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,24 @@ public function __construct($resource)
2020
$this->resource = $resource;
2121
parent::__construct();
2222

23-
$this->onWrite(static function (string $buffer) use ($resource): int {
23+
$this->onWrite(static function (string $buffer) use (&$resource): int {
2424
return fwrite($resource, $buffer) ?: 0;
2525
});
2626

27-
$this->onEnd(static function () use ($resource): void {
27+
$this->onEnd(static function () use (&$resource): void {
2828
fclose($resource);
2929
});
3030

3131
$meta = stream_get_meta_data($resource);
3232
// See: https://www.php.net/manual/en/function.fopen.php
3333
if (substr($meta['mode'], -1) === '+') {
34-
$this->onRead(static function (int $length) use ($resource): ?string {
34+
$this->onRead(static function (int $length) use (&$resource): ?string {
3535
return fread($resource, $length) ?: null;
3636
});
3737
}
3838

3939
if ($meta['seekable']) {
40-
$this->onSeek(static function (int $offset, int $whence) use ($resource): int {
40+
$this->onSeek(static function (int $offset, int $whence) use (&$resource): int {
4141
fseek($resource, $offset, $whence);
4242
return ftell($resource);
4343
});

0 commit comments

Comments
 (0)