Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14841748
D20692.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
20 KB
Referenced Files
None
Subscribers
None
D20692.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D20692: Add very basic support for generating PDF documents
Attached
Detach File
Event Timeline
Log In to Comment