Page MenuHomePhabricator

D20692.diff
No OneTemporary

D20692.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3878,7 +3878,21 @@
'PhabricatorOwnersPathsSearchEngineAttachment' => 'applications/owners/engineextension/PhabricatorOwnersPathsSearchEngineAttachment.php',
'PhabricatorOwnersSchemaSpec' => 'applications/owners/storage/PhabricatorOwnersSchemaSpec.php',
'PhabricatorOwnersSearchField' => 'applications/owners/searchfield/PhabricatorOwnersSearchField.php',
+ 'PhabricatorPDFCatalogObject' => 'applications/phortune/pdf/PhabricatorPDFCatalogObject.php',
+ 'PhabricatorPDFContentsObject' => 'applications/phortune/pdf/PhabricatorPDFContentsObject.php',
'PhabricatorPDFDocumentEngine' => 'applications/files/document/PhabricatorPDFDocumentEngine.php',
+ 'PhabricatorPDFFontObject' => 'applications/phortune/pdf/PhabricatorPDFFontObject.php',
+ 'PhabricatorPDFFragment' => 'applications/phortune/pdf/PhabricatorPDFFragment.php',
+ 'PhabricatorPDFFragmentOffset' => 'applications/phortune/pdf/PhabricatorPDFFragmentOffset.php',
+ 'PhabricatorPDFGenerator' => 'applications/phortune/pdf/PhabricatorPDFGenerator.php',
+ 'PhabricatorPDFHeadFragment' => 'applications/phortune/pdf/PhabricatorPDFHeadFragment.php',
+ 'PhabricatorPDFInfoObject' => 'applications/phortune/pdf/PhabricatorPDFInfoObject.php',
+ 'PhabricatorPDFIterator' => 'applications/phortune/pdf/PhabricatorPDFIterator.php',
+ 'PhabricatorPDFObject' => 'applications/phortune/pdf/PhabricatorPDFObject.php',
+ 'PhabricatorPDFPageObject' => 'applications/phortune/pdf/PhabricatorPDFPageObject.php',
+ 'PhabricatorPDFPagesObject' => 'applications/phortune/pdf/PhabricatorPDFPagesObject.php',
+ 'PhabricatorPDFResourcesObject' => 'applications/phortune/pdf/PhabricatorPDFResourcesObject.php',
+ 'PhabricatorPDFTailFragment' => 'applications/phortune/pdf/PhabricatorPDFTailFragment.php',
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
@@ -10101,7 +10115,24 @@
'PhabricatorOwnersPathsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorOwnersSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorOwnersSearchField' => 'PhabricatorSearchTokenizerField',
+ 'PhabricatorPDFCatalogObject' => 'PhabricatorPDFObject',
+ 'PhabricatorPDFContentsObject' => 'PhabricatorPDFObject',
'PhabricatorPDFDocumentEngine' => 'PhabricatorDocumentEngine',
+ 'PhabricatorPDFFontObject' => 'PhabricatorPDFObject',
+ 'PhabricatorPDFFragment' => 'Phobject',
+ 'PhabricatorPDFFragmentOffset' => 'Phobject',
+ 'PhabricatorPDFGenerator' => 'Phobject',
+ 'PhabricatorPDFHeadFragment' => 'PhabricatorPDFFragment',
+ 'PhabricatorPDFInfoObject' => 'PhabricatorPDFObject',
+ 'PhabricatorPDFIterator' => array(
+ 'Phobject',
+ 'Iterator',
+ ),
+ 'PhabricatorPDFObject' => 'PhabricatorPDFFragment',
+ 'PhabricatorPDFPageObject' => 'PhabricatorPDFObject',
+ 'PhabricatorPDFPagesObject' => 'PhabricatorPDFObject',
+ 'PhabricatorPDFResourcesObject' => 'PhabricatorPDFObject',
+ 'PhabricatorPDFTailFragment' => 'PhabricatorPDFFragment',
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorPHID' => 'Phobject',
'PhabricatorPHIDConstants' => 'Phobject',
diff --git a/src/applications/phortune/pdf/PhabricatorPDFCatalogObject.php b/src/applications/phortune/pdf/PhabricatorPDFCatalogObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFCatalogObject.php
@@ -0,0 +1,26 @@
+<?php
+
+final class PhabricatorPDFCatalogObject
+ extends PhabricatorPDFObject {
+
+ private $pagesObject;
+
+ public function setPagesObject(PhabricatorPDFPagesObject $pages_object) {
+ $this->pagesObject = $this->newChildObject($pages_object);
+ return $this;
+ }
+
+ public function getPagesObject() {
+ return $this->pagesObject;
+ }
+
+ protected function writeObject() {
+ $this->writeLine('/Type /Catalog');
+
+ $pages_object = $this->getPagesObject();
+ if ($pages_object) {
+ $this->writeLine('/Pages %d 0 R', $pages_object->getObjectIndex());
+ }
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFContentsObject.php b/src/applications/phortune/pdf/PhabricatorPDFContentsObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFContentsObject.php
@@ -0,0 +1,25 @@
+<?php
+
+final class PhabricatorPDFContentsObject
+ extends PhabricatorPDFObject {
+
+ private $rawContent;
+
+ public function setRawContent($raw_content) {
+ $this->rawContent = $raw_content;
+ return $this;
+ }
+
+ public function getRawContent() {
+ return $this->rawContent;
+ }
+
+ protected function writeObject() {
+ $data = $this->getRawContent();
+
+ $stream_length = $this->newStream($data);
+
+ $this->writeLine('/Filter /FlateDecode /Length %d', $stream_length);
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFFontObject.php b/src/applications/phortune/pdf/PhabricatorPDFFontObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFFontObject.php
@@ -0,0 +1,14 @@
+<?php
+
+final class PhabricatorPDFFontObject
+ extends PhabricatorPDFObject {
+
+ protected function writeObject() {
+ $this->writeLine('/Type /Font');
+
+ $this->writeLine('/BaseFont /Helvetica-Bold');
+ $this->writeLine('/Subtype /Type1');
+ $this->writeLine('/Encoding /WinAnsiEncoding');
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFFragment.php b/src/applications/phortune/pdf/PhabricatorPDFFragment.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFFragment.php
@@ -0,0 +1,38 @@
+<?php
+
+abstract class PhabricatorPDFFragment
+ extends Phobject {
+
+ private $rope;
+
+ public function getAsBytes() {
+ $this->rope = new PhutilRope();
+
+ $this->writeFragment();
+
+ $rope = $this->rope;
+ $this->rope = null;
+
+ return $rope->getAsString();
+ }
+
+ public function hasRefTableEntry() {
+ return false;
+ }
+
+ abstract protected function writeFragment();
+
+ final protected function writeLine($pattern) {
+ $pattern = $pattern."\n";
+
+ $argv = func_get_args();
+ $argv[0] = $pattern;
+
+ $line = call_user_func_array('sprintf', $argv);
+
+ $this->rope->append($line);
+
+ return $this;
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFFragmentOffset.php b/src/applications/phortune/pdf/PhabricatorPDFFragmentOffset.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFFragmentOffset.php
@@ -0,0 +1,27 @@
+<?php
+
+final class PhabricatorPDFFragmentOffset
+ extends Phobject {
+
+ private $fragment;
+ private $offset;
+
+ public function setFragment(PhabricatorPDFFragment $fragment) {
+ $this->fragment = $fragment;
+ return $this;
+ }
+
+ public function getFragment() {
+ return $this->fragment;
+ }
+
+ public function setOffset($offset) {
+ $this->offset = $offset;
+ return $this;
+ }
+
+ public function getOffset() {
+ return $this->offset;
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFGenerator.php b/src/applications/phortune/pdf/PhabricatorPDFGenerator.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFGenerator.php
@@ -0,0 +1,59 @@
+<?php
+
+final class PhabricatorPDFGenerator
+ extends Phobject {
+
+ private $objects = array();
+ private $hasIterator = false;
+
+ private $infoObject;
+ private $catalogObject;
+
+ public function addObject(PhabricatorPDFObject $object) {
+ if ($this->hasIterator) {
+ throw new Exception(
+ pht(
+ 'This generator has already emitted an iterator. You can not '.
+ 'modify the PDF document after you begin writing it.'));
+ }
+
+ $this->objects[] = $object;
+ $index = count($this->objects);
+
+ $object->setGenerator($this, $index);
+
+ return $this;
+ }
+
+ public function getObjects() {
+ return $this->objects;
+ }
+
+ public function newIterator() {
+ $this->hasIterator = true;
+ return id(new PhabricatorPDFIterator())
+ ->setGenerator($this);
+ }
+
+ public function setInfoObject(PhabricatorPDFInfoObject $info_object) {
+ $this->addObject($info_object);
+ $this->infoObject = $info_object;
+ return $this;
+ }
+
+ public function getInfoObject() {
+ return $this->infoObject;
+ }
+
+ public function setCatalogObject(
+ PhabricatorPDFCatalogObject $catalog_object) {
+ $this->addObject($catalog_object);
+ $this->catalogObject = $catalog_object;
+ return $this;
+ }
+
+ public function getCatalogObject() {
+ return $this->catalogObject;
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFHeadFragment.php b/src/applications/phortune/pdf/PhabricatorPDFHeadFragment.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFHeadFragment.php
@@ -0,0 +1,10 @@
+<?php
+
+final class PhabricatorPDFHeadFragment
+ extends PhabricatorPDFFragment {
+
+ protected function writeFragment() {
+ $this->writeLine('%s', '%PDF-1.3');
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFInfoObject.php b/src/applications/phortune/pdf/PhabricatorPDFInfoObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFInfoObject.php
@@ -0,0 +1,11 @@
+<?php
+
+final class PhabricatorPDFInfoObject
+ extends PhabricatorPDFObject {
+
+ final protected function writeObject() {
+ $this->writeLine('/Producer (Phabricator 20190801)');
+ $this->writeLine('/CreationDate (D:%s)', date('YmdHis'));
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFIterator.php b/src/applications/phortune/pdf/PhabricatorPDFIterator.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFIterator.php
@@ -0,0 +1,103 @@
+<?php
+
+final class PhabricatorPDFIterator
+ extends Phobject
+ implements Iterator {
+
+ private $generator;
+ private $hasRewound;
+
+ private $fragments;
+ private $fragmentKey;
+ private $fragmentBytes;
+ private $fragmentOffsets = array();
+ private $byteLength;
+
+ public function setGenerator(PhabricatorPDFGenerator $generator) {
+ if ($this->generator) {
+ throw new Exception(
+ pht(
+ 'This iterator already has a generator. You can not modify the '.
+ 'generator for a given iterator.'));
+ }
+
+ $this->generator = $generator;
+
+ return $this;
+ }
+
+ public function getGenerator() {
+ if (!$this->generator) {
+ throw new Exception(
+ pht(
+ 'This PDF iterator has no associated PDF generator.'));
+ }
+
+ return $this->generator;
+ }
+
+ public function getFragmentOffsets() {
+ return $this->fragmentOffsets;
+ }
+
+ public function current() {
+ return $this->fragmentBytes;
+ }
+
+ public function key() {
+ return $this->framgentKey;
+ }
+
+ public function next() {
+ $this->fragmentKey++;
+
+ if (!$this->valid()) {
+ return;
+ }
+
+ $fragment = $this->fragments[$this->fragmentKey];
+
+ $this->fragmentOffsets[] = id(new PhabricatorPDFFragmentOffset())
+ ->setFragment($fragment)
+ ->setOffset($this->byteLength);
+
+ $bytes = $fragment->getAsBytes();
+
+ $this->fragmentBytes = $bytes;
+ $this->byteLength += strlen($bytes);
+ }
+
+ public function rewind() {
+ if ($this->hasRewound) {
+ throw new Exception(
+ pht(
+ 'PDF iterators may not be rewound. Create a new iterator to emit '.
+ 'another PDF.'));
+ }
+
+ $generator = $this->getGenerator();
+ $objects = $generator->getObjects();
+
+ $this->fragments = array();
+ $this->fragments[] = new PhabricatorPDFHeadFragment();
+
+ foreach ($objects as $object) {
+ $this->fragments[] = $object;
+ }
+
+ $this->fragments[] = id(new PhabricatorPDFTailFragment())
+ ->setIterator($this);
+
+ $this->hasRewound = true;
+
+ $this->fragmentKey = -1;
+ $this->byteLength = 0;
+
+ $this->next();
+ }
+
+ public function valid() {
+ return isset($this->fragments[$this->fragmentKey]);
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFObject.php b/src/applications/phortune/pdf/PhabricatorPDFObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFObject.php
@@ -0,0 +1,95 @@
+<?php
+
+abstract class PhabricatorPDFObject
+ extends PhabricatorPDFFragment {
+
+ private $generator;
+ private $objectIndex;
+ private $children = array();
+ private $streams = array();
+
+ final public function hasRefTableEntry() {
+ return true;
+ }
+
+ final protected function writeFragment() {
+ $this->writeLine('%d 0 obj', $this->getObjectIndex());
+ $this->writeLine('<<');
+ $this->writeObject();
+ $this->writeLine('>>');
+
+ $streams = $this->streams;
+ $this->streams = array();
+ foreach ($streams as $stream) {
+ $this->writeLine('stream');
+ $this->writeLine('%s', $stream);
+ $this->writeLine('endstream');
+ }
+
+ $this->writeLine('endobj');
+ }
+
+ final public function setGenerator(
+ PhabricatorPDFGenerator $generator,
+ $index) {
+
+ if ($this->getGenerator()) {
+ throw new Exception(
+ pht(
+ 'This PDF object is already registered with a PDF generator. You '.
+ 'can not register an object with more than one generator.'));
+ }
+
+ $this->generator = $generator;
+ $this->objectIndex = $index;
+
+ foreach ($this->getChildren() as $child) {
+ $generator->addObject($child);
+ }
+
+ return $this;
+ }
+
+ final public function getGenerator() {
+ return $this->generator;
+ }
+
+ final public function getObjectIndex() {
+ if (!$this->objectIndex) {
+ throw new Exception(
+ pht(
+ 'Trying to get index for object ("%s") which has not been '.
+ 'registered with a generator.',
+ get_class($this)));
+ }
+
+ return $this->objectIndex;
+ }
+
+ final protected function newChildObject(PhabricatorPDFObject $object) {
+ if ($this->generator) {
+ throw new Exception(
+ pht(
+ 'Trying to add a new PDF Object child after already registering '.
+ 'the object with a generator.'));
+ }
+
+ $this->children[] = $object;
+ return $object;
+ }
+
+ private function getChildren() {
+ return $this->children;
+ }
+
+ abstract protected function writeObject();
+
+ final protected function newStream($raw_data) {
+ $stream_data = gzcompress($raw_data);
+
+ $this->streams[] = $stream_data;
+
+ return strlen($stream_data);
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFPageObject.php b/src/applications/phortune/pdf/PhabricatorPDFPageObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFPageObject.php
@@ -0,0 +1,48 @@
+<?php
+
+final class PhabricatorPDFPageObject
+ extends PhabricatorPDFObject {
+
+ private $pagesObject;
+ private $contentsObject;
+ private $resourcesObject;
+
+ public function setPagesObject(PhabricatorPDFPagesObject $pages) {
+ $this->pagesObject = $pages;
+ return $this;
+ }
+
+ public function setContentsObject(PhabricatorPDFContentsObject $contents) {
+ $this->contentsObject = $this->newChildObject($contents);
+ return $this;
+ }
+
+ public function setResourcesObject(PhabricatorPDFResourcesObject $resources) {
+ $this->resourcesObject = $this->newChildObject($resources);
+ return $this;
+ }
+
+ protected function writeObject() {
+ $this->writeLine('/Type /Page');
+
+ $pages_object = $this->pagesObject;
+ $contents_object = $this->contentsObject;
+ $resources_object = $this->resourcesObject;
+
+ if ($pages_object) {
+ $pages_index = $pages_object->getObjectIndex();
+ $this->writeLine('/Parent %d 0 R', $pages_index);
+ }
+
+ if ($contents_object) {
+ $contents_index = $contents_object->getObjectIndex();
+ $this->writeLine('/Contents %d 0 R', $contents_index);
+ }
+
+ if ($resources_object) {
+ $resources_index = $resources_object->getObjectIndex();
+ $this->writeLine('/Resources %d 0 R', $resources_index);
+ }
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFPagesObject.php b/src/applications/phortune/pdf/PhabricatorPDFPagesObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFPagesObject.php
@@ -0,0 +1,38 @@
+<?php
+
+final class PhabricatorPDFPagesObject
+ extends PhabricatorPDFObject {
+
+ private $pageObjects = array();
+
+ public function addPageObject(PhabricatorPDFPageObject $page) {
+ $page->setPagesObject($this);
+ $this->pageObjects[] = $this->newChildObject($page);
+ return $this;
+ }
+
+ public function getPageObjects() {
+ return $this->pageObjects;
+ }
+
+ protected function writeObject() {
+ $this->writeLine('/Type /Pages');
+
+ $page_objects = $this->getPageObjects();
+
+ $this->writeLine('/Count %d', count($page_objects));
+ $this->writeLine('/MediaBox [%d %d %0.2f %0.2f]', 0, 0, 595.28, 841.89);
+
+ if ($page_objects) {
+ $kids = array();
+ foreach ($page_objects as $page_object) {
+ $kids[] = sprintf(
+ '%d 0 R',
+ $page_object->getObjectIndex());
+ }
+
+ $this->writeLine('/Kids [%s]', implode(' ', $kids));
+ }
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFResourcesObject.php b/src/applications/phortune/pdf/PhabricatorPDFResourcesObject.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFResourcesObject.php
@@ -0,0 +1,28 @@
+<?php
+
+final class PhabricatorPDFResourcesObject
+ extends PhabricatorPDFObject {
+
+ private $fontObjects = array();
+
+ public function addFontObject(PhabricatorPDFFontObject $font) {
+ $this->fontObjects[] = $this->newChildObject($font);
+ return $this;
+ }
+
+ public function getFontObjects() {
+ return $this->fontObjects;
+ }
+
+ protected function writeObject() {
+ $this->writeLine('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
+
+ $fonts = $this->getFontObjects();
+ foreach ($fonts as $font) {
+ $this->writeLine('/Font <<');
+ $this->writeLine('/F%d %d 0 R', 1, $font->getObjectIndex());
+ $this->writeLine('>>');
+ }
+ }
+
+}
diff --git a/src/applications/phortune/pdf/PhabricatorPDFTailFragment.php b/src/applications/phortune/pdf/PhabricatorPDFTailFragment.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/pdf/PhabricatorPDFTailFragment.php
@@ -0,0 +1,72 @@
+<?php
+
+final class PhabricatorPDFTailFragment
+ extends PhabricatorPDFFragment {
+
+ private $iterator;
+
+ public function setIterator(PhabricatorPDFIterator $iterator) {
+ $this->iterator = $iterator;
+ return $this;
+ }
+
+ public function getIterator() {
+ return $this->iterator;
+ }
+
+ protected function writeFragment() {
+ $iterator = $this->getIterator();
+ $generator = $iterator->getGenerator();
+ $objects = $generator->getObjects();
+
+ $xref_offset = null;
+
+ $this->writeLine('xref');
+ $this->writeLine('0 %d', count($objects) + 1);
+ $this->writeLine('%010d %05d f ', 0, 0xFFFF);
+
+ $offset_map = array();
+
+ $fragment_offsets = $iterator->getFragmentOffsets();
+ foreach ($fragment_offsets as $fragment_offset) {
+ $fragment = $fragment_offset->getFragment();
+ $offset = $fragment_offset->getOffset();
+
+ if ($fragment === $this) {
+ $xref_offset = $offset;
+ }
+
+ if (!$fragment->hasRefTableEntry()) {
+ continue;
+ }
+
+ $offset_map[$fragment->getObjectIndex()] = $offset;
+ }
+
+ ksort($offset_map);
+
+ foreach ($offset_map as $offset) {
+ $this->writeLine('%010d %05d n ', $offset, 0);
+ }
+
+ $this->writeLine('trailer');
+ $this->writeLine('<<');
+ $this->writeLine('/Size %d', count($objects) + 1);
+
+ $info_object = $generator->getInfoObject();
+ if ($info_object) {
+ $this->writeLine('/Info %d 0 R', $info_object->getObjectIndex());
+ }
+
+ $catalog_object = $generator->getCatalogObject();
+ if ($catalog_object) {
+ $this->writeLine('/Root %d 0 R', $catalog_object->getObjectIndex());
+ }
+
+ $this->writeLine('>>');
+ $this->writeLine('startxref');
+ $this->writeLine('%d', $xref_offset);
+ $this->writeLine('%s', '%%EOF');
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 2, 6:07 PM (8 h, 15 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7084951
Default Alt Text
D20692.diff (20 KB)

Event Timeline