fix: improve assembly stream

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2024-11-27 17:29:45 +01:00
parent 6632669157
commit 48640ce155
2 changed files with 33 additions and 11 deletions

View file

@ -75,6 +75,10 @@ class AssemblyStream implements \Icewind\Streams\File {
$offset = $this->size + $offset;
}
if ($offset === $this->pos) {
return true;
}
if ($offset > $this->size) {
return false;
}
@ -95,7 +99,7 @@ class AssemblyStream implements \Icewind\Streams\File {
$stream = $this->getStream($this->nodes[$nodeIndex]);
$nodeOffset = $offset - $nodeStart;
if (fseek($stream, $nodeOffset) === -1) {
if ($nodeOffset > 0 && fseek($stream, $nodeOffset) === -1) {
return false;
}
$this->currentNode = $nodeIndex;
@ -126,9 +130,14 @@ class AssemblyStream implements \Icewind\Streams\File {
}
}
do {
$collectedData = '';
// read data until we either got all the data requested or there is no more stream left
while ($count > 0 && !is_null($this->currentStream)) {
$data = fread($this->currentStream, $count);
$read = strlen($data);
$count -= $read;
$collectedData .= $data;
$this->currentNodeRead += $read;
if (feof($this->currentStream)) {
@ -145,14 +154,11 @@ class AssemblyStream implements \Icewind\Streams\File {
$this->currentStream = null;
}
}
// if no data read, try again with the next node because
// returning empty data can make the caller think there is no more
// data left to read
} while ($read === 0 && !is_null($this->currentStream));
}
// update position
$this->pos += $read;
return $data;
$this->pos += strlen($collectedData);
return $collectedData;
}
/**

View file

@ -24,12 +24,16 @@ class AssemblyStreamTest extends \Test\TestCase {
/**
* @dataProvider providesNodes()
*/
public function testGetContentsFread($expected, $nodes): void {
public function testGetContentsFread($expected, $nodes, $chunkLength = 3): void {
$stream = \OCA\DAV\Upload\AssemblyStream::wrap($nodes);
$content = '';
while (!feof($stream)) {
$content .= fread($stream, 3);
$chunk = fread($stream, $chunkLength);
$content .= $chunk;
if ($chunkLength !== 3) {
$this->assertEquals($chunkLength, strlen($chunk));
}
}
$this->assertEquals($expected, $content);
@ -102,7 +106,19 @@ class AssemblyStreamTest extends \Test\TestCase {
]],
'a ton of nodes' => [
$tonofdata, $tonofnodes
]
],
'one read over multiple nodes' => [
'1234567890', [
$this->buildNode('0', '1234'),
$this->buildNode('1', '5678'),
$this->buildNode('2', '90'),
], 10],
'two reads over multiple nodes' => [
'1234567890', [
$this->buildNode('0', '1234'),
$this->buildNode('1', '5678'),
$this->buildNode('2', '90'),
], 5],
];
}