diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 32407404a3..97c19121e0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1795,6 +1795,7 @@ phutil_register_library_map(array( 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', + 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', 'PhabricatorFileChunkQuery' => 'applications/files/query/PhabricatorFileChunkQuery.php', 'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php', 'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php', @@ -5096,6 +5097,10 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), + 'PhabricatorFileChunkIterator' => array( + 'Phobject', + 'Iterator', + ), 'PhabricatorFileChunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileCommentController' => 'PhabricatorFileController', 'PhabricatorFileComposeController' => 'PhabricatorFileController', diff --git a/src/applications/files/engine/PhabricatorChunkedFileStorageEngine.php b/src/applications/files/engine/PhabricatorChunkedFileStorageEngine.php index 641e6658b2..5240dd4630 100644 --- a/src/applications/files/engine/PhabricatorChunkedFileStorageEngine.php +++ b/src/applications/files/engine/PhabricatorChunkedFileStorageEngine.php @@ -177,4 +177,15 @@ final class PhabricatorChunkedFileStorageEngine return 32; } + public function getFileDataIterator(PhabricatorFile $file, $begin, $end) { + $chunks = id(new PhabricatorFileChunkQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withChunkHandles(array($file->getStorageHandle())) + ->withByteRange($begin, $end) + ->needDataFiles(true) + ->execute(); + + return new PhabricatorFileChunkIterator($chunks, $begin, $end); + } + } diff --git a/src/applications/files/engine/PhabricatorFileChunkIterator.php b/src/applications/files/engine/PhabricatorFileChunkIterator.php new file mode 100644 index 0000000000..50b605dc95 --- /dev/null +++ b/src/applications/files/engine/PhabricatorFileChunkIterator.php @@ -0,0 +1,72 @@ +chunks = $chunks; + + if ($begin !== null) { + foreach ($chunks as $key => $chunk) { + if ($chunk->getByteEnd() >= $begin) { + unset($chunks[$key]); + } + break; + } + $this->begin = $begin; + } + + if ($end !== null) { + foreach ($chunks as $key => $chunk) { + if ($chunk->getByteStart() <= $end) { + unset($chunks[$key]); + } + } + $this->end = $end; + } + } + + public function current() { + $chunk = head($this->chunks); + $data = $chunk->getDataFile()->loadFileData(); + + if ($this->end !== null) { + if ($chunk->getByteEnd() > $this->end) { + $data = substr($data, 0, ($this->end - $chunk->getByteStart())); + } + } + + if ($this->begin !== null) { + if ($chunk->getByteStart() < $this->begin) { + $data = substr($data, ($this->begin - $chunk->getByteStart())); + } + } + + return $data; + } + + public function key() { + return head_key($this->chunks); + } + + public function next() { + unset($this->chunks[$this->key()]); + } + + public function rewind() { + return; + } + + public function valid() { + return (count($this->chunks) > 0); + } + +} diff --git a/src/applications/files/engine/PhabricatorFileStorageEngine.php b/src/applications/files/engine/PhabricatorFileStorageEngine.php index f519874a16..8a9749f9dc 100644 --- a/src/applications/files/engine/PhabricatorFileStorageEngine.php +++ b/src/applications/files/engine/PhabricatorFileStorageEngine.php @@ -290,5 +290,20 @@ abstract class PhabricatorFileStorageEngine { return $engine->getChunkSize(); } + public function getFileDataIterator(PhabricatorFile $file, $begin, $end) { + // The default implementation is trivial and just loads the entire file + // upfront. + $data = $file->loadFileData(); + + if ($begin !== null && $end !== null) { + $data = substr($data, $begin, ($end - $begin)); + } else if ($begin !== null) { + $data = substr($data, $begin); + } else if ($end !== null) { + $data = substr($data, 0, $end); + } + + return array($data); + } } diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index 2fbcf3a891..aa681f3233 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -612,19 +612,8 @@ final class PhabricatorFile extends PhabricatorFileDAO * @return Iterable Iterable object which emits requested data. */ public function getFileDataIterator($begin = null, $end = null) { - // The default implementation is trivial and just loads the entire file - // upfront. - $data = $this->loadFileData(); - - if ($begin !== null && $end !== null) { - $data = substr($data, $begin, ($end - $begin)); - } else if ($begin !== null) { - $data = substr($data, $begin); - } else if ($end !== null) { - $data = substr($data, 0, $end); - } - - return array($data); + $engine = $this->instantiateStorageEngine(); + return $engine->getFileDataIterator($this, $begin, $end); }