diff --git a/apps/dav/lib/Upload/AssemblyStream.php b/apps/dav/lib/Upload/AssemblyStream.php index b623f717b3..4b327cecaa 100644 --- a/apps/dav/lib/Upload/AssemblyStream.php +++ b/apps/dav/lib/Upload/AssemblyStream.php @@ -20,6 +20,7 @@ * along with this program. If not, see * */ + namespace OCA\DAV\Upload; use Sabre\DAV\IFile; @@ -44,15 +45,15 @@ class AssemblyStream implements \Icewind\Streams\File { /** @var int */ private $pos = 0; - /** @var array */ - private $sortedNodes; - /** @var int */ - private $size; + private $size = 0; /** @var resource */ private $currentStream = null; + /** @var int */ + private $currentNode = 0; + /** * @param string $path * @param string $mode @@ -63,24 +64,18 @@ class AssemblyStream implements \Icewind\Streams\File { public function stream_open($path, $mode, $options, &$opened_path) { $this->loadContext('assembly'); - // sort the nodes $nodes = $this->nodes; // http://stackoverflow.com/a/10985500 - @usort($nodes, function(IFile $a, IFile $b) { + @usort($nodes, function (IFile $a, IFile $b) { return strnatcmp($a->getName(), $b->getName()); }); - $this->nodes = $nodes; - - // build additional information - $this->sortedNodes = []; - $start = 0; - foreach($this->nodes as $node) { - $size = $node->getSize(); - $name = $node->getName(); - $this->sortedNodes[$name] = ['node' => $node, 'start' => $start, 'end' => $start + $size]; - $start += $size; - $this->size = $start; + $this->nodes = array_values($nodes); + if (count($this->nodes) > 0) { + $this->currentStream = $this->getStream($this->nodes[0]); } + $this->size = array_reduce($this->nodes, function ($size, IFile $file) { + return $size + $file->getSize(); + }, 0); return true; } @@ -105,36 +100,27 @@ class AssemblyStream implements \Icewind\Streams\File { * @return string */ public function stream_read($count) { - do { - if ($this->currentStream === null) { - list($node, $posInNode) = $this->getNodeForPosition($this->pos); - if (is_null($node)) { - // reached last node, no more data - return ''; - } - $this->currentStream = $this->getStream($node); - fseek($this->currentStream, $posInNode); - } + if (is_null($this->currentStream)) { + return ''; + } + do { $data = fread($this->currentStream, $count); - // isset is faster than strlen - if (isset($data[$count - 1])) { - // we read the full count - $read = $count; - } else { - // reaching end of stream, which happens less often so strlen is ok - $read = strlen($data); - } + $read = strlen($data); if (feof($this->currentStream)) { fclose($this->currentStream); - $this->currentNode = null; - $this->currentStream = null; + $this->currentNode++; + if ($this->currentNode < count($this->nodes)) { + $this->currentStream = $this->getStream($this->nodes[$this->currentNode]); + } else { + $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); + } while ($read === 0 && !is_null($this->currentStream)); // update position $this->pos += $read; @@ -235,9 +221,10 @@ class AssemblyStream implements \Icewind\Streams\File { public static function wrap(array $nodes) { $context = stream_context_create([ 'assembly' => [ - 'nodes' => $nodes] + 'nodes' => $nodes + ] ]); - stream_wrapper_register('assembly', '\OCA\DAV\Upload\AssemblyStream'); + stream_wrapper_register('assembly', self::class); try { $wrapped = fopen('assembly://', 'r', null, $context); } catch (\BadMethodCallException $e) { @@ -248,19 +235,6 @@ class AssemblyStream implements \Icewind\Streams\File { return $wrapped; } - /** - * @param $pos - * @return IFile | null - */ - private function getNodeForPosition($pos) { - foreach($this->sortedNodes as $node) { - if ($pos >= $node['start'] && $pos < $node['end']) { - return [$node['node'], $pos - $node['start']]; - } - } - return null; - } - /** * @param IFile $node * @return resource @@ -269,9 +243,11 @@ class AssemblyStream implements \Icewind\Streams\File { $data = $node->get(); if (is_resource($data)) { return $data; + } else { + $tmp = fopen('php://temp', 'w+'); + fwrite($tmp, $data); + rewind($tmp); + return $tmp; } - - return fopen('data://text/plain,' . $data,'r'); } - }