]> git.immae.eu Git - github/wallabag/wallabag.git/blame - inc/3rdparty/libraries/PHPePub/EPub.NCX.php
phinx for database migration
[github/wallabag/wallabag.git] / inc / 3rdparty / libraries / PHPePub / EPub.NCX.php
CommitLineData
87090d8a 1<?php
2/**
3 * ePub NCX file structure
4 *
5 * @author A. Grandt <php@grandt.com>
6 * @copyright 2009-2014 A. Grandt
7 * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
8 * @version 3.20
9 */
10class Ncx {
11 const _VERSION = 3.20;
12
13 const MIMETYPE = "application/x-dtbncx+xml";
14
15 private $bookVersion = EPub::BOOK_VERSION_EPUB2;
16
17 private $navMap = NULL;
18 private $uid = NULL;
19 private $meta = array();
20 private $docTitle = NULL;
21 private $docAuthor = NULL;
22
23 private $currentLevel = NULL;
24 private $lastLevel = NULL;
25
26 private $languageCode = "en";
27 private $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT;
28
29 public $chapterList = array();
30 public $referencesTitle = "Guide";
31 public $referencesClass = "references";
32 public $referencesId = "references";
33 public $referencesList = array();
34 public $referencesName = array();
35 public $referencesOrder = NULL;
36
37 /**
38 * Class constructor.
39 *
40 * @param string $uid
41 * @param string $docTitle
42 * @param string $docAuthor
43 * @param string $languageCode
44 * @param string $writingDirection
45 */
46 function __construct($uid = NULL, $docTitle = NULL, $docAuthor = NULL, $languageCode = "en", $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT) {
47 $this->navMap = new NavMap($writingDirection);
48 $this->currentLevel = $this->navMap;
49 $this->setUid($uid);
50 $this->setDocTitle($docTitle);
51 $this->setDocAuthor($docAuthor);
52 $this->setLanguageCode($languageCode);
53 $this->setWritingDirection($writingDirection);
54 }
55
56 /**
57 * Class destructor
58 *
59 * @return void
60 */
61 function __destruct() {
62 unset($this->bookVersion, $this->navMap, $this->uid, $this->meta);
63 unset($this->docTitle, $this->docAuthor, $this->currentLevel, $this->lastLevel);
64 unset($this->languageCode, $this->writingDirection, $this->chapterList, $this->referencesTitle);
65 unset($this->referencesClass, $this->referencesId, $this->referencesList, $this->referencesName);
66 unset($this->referencesOrder);
67 }
68
69 /**
70 *
71 * Enter description here ...
72 *
73 * @param string $bookVersion
74 */
75 function setVersion($bookVersion) {
76 $this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2;
77 }
78
79 /**
80 *
81 * @return bool TRUE if the book is set to type ePub 2
82 */
83 function isEPubVersion2() {
84 return $this->bookVersion === EPub::BOOK_VERSION_EPUB2;
85 }
86
87 /**
88 *
89 * Enter description here ...
90 *
91 * @param string $uid
92 */
93 function setUid($uid) {
94 $this->uid = is_string($uid) ? trim($uid) : NULL;
95 }
96
97 /**
98 *
99 * Enter description here ...
100 *
101 * @param string $docTitle
102 */
103 function setDocTitle($docTitle) {
104 $this->docTitle = is_string($docTitle) ? trim($docTitle) : NULL;
105 }
106
107 /**
108 *
109 * Enter description here ...
110 *
111 * @param string $docAuthor
112 */
113 function setDocAuthor($docAuthor) {
114 $this->docAuthor = is_string($docAuthor) ? trim($docAuthor) : NULL;
115 }
116
117 /**
118 *
119 * Enter description here ...
120 *
121 * @param string $languageCode
122 */
123 function setLanguageCode($languageCode) {
124 $this->languageCode = is_string($languageCode) ? trim($languageCode) : "en";
125 }
126
127 /**
128 *
129 * Enter description here ...
130 *
131 * @param string $writingDirection
132 */
133 function setWritingDirection($writingDirection) {
134 $this->writingDirection = is_string($writingDirection) ? trim($writingDirection) : EPub::DIRECTION_LEFT_TO_RIGHT;
135 }
136
137 /**
138 *
139 * Enter description here ...
140 *
141 * @param NavMap $navMap
142 */
143 function setNavMap($navMap) {
144 if ($navMap != NULL && is_object($navMap) && get_class($navMap) === "NavMap") {
145 $this->navMap = $navMap;
146 }
147 }
148
149 /**
150 * Add one chapter level.
151 *
152 * Subsequent chapters will be added to this level.
153 *
154 * @param string $navTitle
155 * @param string $navId
156 * @param string $navClass
157 * @param string $isNavHidden
158 * @param string $writingDirection
159 * @return NavPoint
160 */
161 function subLevel($navTitle = NULL, $navId = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
162 $navPoint = FALSE;
163 if (isset($navTitle) && isset($navClass)) {
164 $navPoint = new NavPoint($navTitle, NULL, $navId, $navClass, $isNavHidden, $writingDirection);
165 $this->addNavPoint($navPoint);
166 }
167 if ($this->lastLevel !== NULL) {
168 $this->currentLevel = $this->lastLevel;
169 }
170 return $navPoint;
171 }
172
173 /**
174 * Step back one chapter level.
175 *
176 * Subsequent chapters will be added to this chapters parent level.
177 */
178 function backLevel() {
179 $this->lastLevel = $this->currentLevel;
180 $this->currentLevel = $this->currentLevel->getParent();
181 }
182
183 /**
184 * Step back to the root level.
185 *
186 * Subsequent chapters will be added to the rooot NavMap.
187 */
188 function rootLevel() {
189 $this->lastLevel = $this->currentLevel;
190 $this->currentLevel = $this->navMap;
191 }
192
193 /**
194 * Step back to the given level.
195 * Useful for returning to a previous level from deep within the structure.
196 * Values below 2 will have the same effect as rootLevel()
197 *
198 * @param int $newLevel
199 */
200 function setCurrentLevel($newLevel) {
201 if ($newLevel <= 1) {
202 $this->rootLevel();
203 } else {
204 while ($this->currentLevel->getLevel() > $newLevel) {
205 $this->backLevel();
206 }
207 }
208 }
209
210 /**
211 * Get current level count.
212 * The indentation of the current structure point.
213 *
214 * @return current level count;
215 */
216 function getCurrentLevel() {
217 return $this->currentLevel->getLevel();
218 }
219
220 /**
221 * Add child NavPoints to current level.
222 *
223 * @param NavPoint $navPoint
224 */
225 function addNavPoint($navPoint) {
226 $this->lastLevel = $this->currentLevel->addNavPoint($navPoint);
227 }
228
229 /**
230 *
231 * Enter description here ...
232 *
233 * @return NavMap
234 */
235 function getNavMap() {
236 return $this->navMap;
237 }
238
239 /**
240 *
241 * Enter description here ...
242 *
243 * @param string $name
244 * @param string $content
245 */
246 function addMetaEntry($name, $content) {
247 $name = is_string($name) ? trim($name) : NULL;
248 $content = is_string($content) ? trim($content) : NULL;
249
250 if ($name != NULL && $content != NULL) {
251 $this->meta[] = array($name => $content);
252 }
253 }
254
255 /**
256 *
257 * Enter description here ...
258 *
259 * @return string
260 */
261 function finalize() {
262 $nav = $this->navMap->finalize();
263
264 $ncx = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
265 if ($this->isEPubVersion2()) {
266 $ncx .= "<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\"\n"
267 . " \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n";
268 }
269 $ncx .= "<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\" xml:lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n"
270 . "\t<head>\n"
271 . "\t\t<meta name=\"dtb:uid\" content=\"" . $this->uid . "\" />\n"
272 . "\t\t<meta name=\"dtb:depth\" content=\"" . $this->navMap->getNavLevels() . "\" />\n"
273 . "\t\t<meta name=\"dtb:totalPageCount\" content=\"0\" />\n"
274 . "\t\t<meta name=\"dtb:maxPageNumber\" content=\"0\" />\n";
275
276 if (sizeof($this->meta)) {
277 foreach ($this->meta as $metaEntry) {
278 list($name, $content) = each($metaEntry);
279 $ncx .= "\t\t<meta name=\"" . $name . "\" content=\"" . $content . "\" />\n";
280 }
281 }
282
283 $ncx .= "\t</head>\n\n\t<docTitle>\n\t\t<text>"
284 . $this->docTitle
285 . "</text>\n\t</docTitle>\n\n\t<docAuthor>\n\t\t<text>"
286 . $this->docAuthor
287 . "</text>\n\t</docAuthor>\n\n"
288 . $nav;
289
290 return $ncx . "</ncx>\n";
291 }
292
293 /**
294 *
295 * @param string $title
296 * @param string $cssFileName
297 * @return string
298 */
299 function finalizeEPub3($title = "Table of Contents", $cssFileName = NULL) {
300 $end = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
301 . "<html xmlns=\"http://www.w3.org/1999/xhtml\"\n"
302 . " xmlns:epub=\"http://www.idpf.org/2007/ops\"\n"
303 . " xml:lang=\"" . $this->languageCode . "\" lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n"
304 . "\t<head>\n"
305 . "\t\t<title>" . $this->docTitle . "</title>\n"
306 . "\t\t<meta http-equiv=\"default-style\" content=\"text/html; charset=utf-8\"/>\n";
307 if ($cssFileName !== NULL) {
308 $end .= "\t\t<link rel=\"stylesheet\" href=\"" . $cssFileName . "\" type=\"text/css\"/>\n";
309 }
310 $end .= "\t</head>\n"
311 . "\t<body epub:type=\"frontmatter toc\">\n"
312 . "\t\t<header>\n"
313 . "\t\t\t<h1>" . $title . "</h1>\n"
314 . "\t\t</header>\n"
315 . $this->navMap->finalizeEPub3()
316 . $this->finalizeEPub3Landmarks()
317 . "\t</body>\n"
318 . "</html>\n";
319
320 return $end;
321 }
322
323 /**
324 * Build the references for the ePub 2 toc.
325 * These are merely reference pages added to the end of the navMap though.
326 *
327 * @return string
328 */
329 function finalizeReferences() {
330 if (isset($this->referencesList) && sizeof($this->referencesList) > 0) {
331 $this->rootLevel();
332 $this->subLevel($this->referencesTitle, $this->referencesId, $this->referencesClass);
333 $refId = 1;
334 while (list($item, $descriptive) = each($this->referencesOrder)) {
335 if (array_key_exists($item, $this->referencesList)) {
336 $name = (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item]);
337 $navPoint = new NavPoint($name, $this->referencesList[$item], "ref-" . $refId++);
338 $this->addNavPoint($navPoint);
339 }
340 }
341 }
342 }
343
344 /**
345 * Build the landmarks for the ePub 3 toc.
346 * @return string
347 */
348 function finalizeEPub3Landmarks() {
349 $lm = "";
350 if (isset($this->referencesList) && sizeof($this->referencesList) > 0) {
351 $lm = "\t\t\t<nav epub:type=\"landmarks\">\n"
352 . "\t\t\t\t<h2"
353 . ($this->writingDirection === EPub::DIRECTION_RIGHT_TO_LEFT ? " dir=\"rtl\"" : "")
354 . ">" . $this->referencesTitle . "</h2>\n"
355 . "\t\t\t\t<ol>\n";
356
357 $li = "";
358 while (list($item, $descriptive) = each($this->referencesOrder)) {
359 if (array_key_exists($item, $this->referencesList)) {
360 $li .= "\t\t\t\t\t<li><a epub:type=\""
361 . $item
362 . "\" href=\"" . $this->referencesList[$item] . "\">"
363 . (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item])
364 . "</a></li>\n";
365 }
366 }
367 if (empty($li)) {
368 return "";
369 }
370
371 $lm .= $li
372 . "\t\t\t\t</ol>\n"
373 . "\t\t\t</nav>\n";
374 }
375 return $lm;
376 }
377}
378
379/**
380 * ePub NavMap class
381 */
382class NavMap {
383 const _VERSION = 3.00;
384
385 private $navPoints = array();
386 private $navLevels = 0;
387 private $writingDirection = NULL;
388
389 /**
390 * Class constructor.
391 *
392 * @return void
393 */
394 function __construct($writingDirection = NULL) {
395 $this->setWritingDirection($writingDirection);
396 }
397
398 /**
399 * Class destructor
400 *
401 * @return void
402 */
403 function __destruct() {
404 unset($this->navPoints, $this->navLevels, $this->writingDirection);
405 }
406
407 /**
408 * Set the writing direction to be used for this NavPoint.
409 *
410 * @param string $writingDirection
411 */
412 function setWritingDirection($writingDirection) {
413 $this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
414 }
415
416 function getWritingDirection() {
417 return $this->writingDirection;
418 }
419
420 /**
421 * Add a navPoint to the root of the NavMap.
422 *
423 * @param NavPoint $navPoint
424 * @return NavMap
425 */
426 function addNavPoint($navPoint) {
427 if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
428 $navPoint->setParent($this);
429 if ($navPoint->getWritingDirection() == NULL) {
430 $navPoint->setWritingDirection($this->writingDirection);
431 }
432 $this->navPoints[] = $navPoint;
433 return $navPoint;
434 }
435 return $this;
436 }
437
438 /**
439 * The final max depth for the "dtb:depth" meta attribute
440 * Only available after finalize have been called.
441 *
442 * @return number
443 */
444 function getNavLevels() {
445 return $this->navLevels+1;
446 }
447
448 function getLevel() {
449 return 1;
450 }
451
452 function getParent() {
453 return $this;
454 }
455
456 /**
457 * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
458 *
459 */
460 function finalize() {
461 $playOrder = 0;
462 $this->navLevels = 0;
463
464 $nav = "\t<navMap>\n";
465 if (sizeof($this->navPoints) > 0) {
466 $this->navLevels++;
467 foreach ($this->navPoints as $navPoint) {
468 $retLevel = $navPoint->finalize($nav, $playOrder, 0);
469 if ($retLevel > $this->navLevels) {
470 $this->navLevels = $retLevel;
471 }
472 }
473 }
474 return $nav . "\t</navMap>\n";
475 }
476
477 /**
478 * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
479 *
480 */
481 function finalizeEPub3() {
482 $playOrder = 0;
483 $level = 0;
484 $this->navLevels = 0;
485
486 $nav = "\t\t<nav epub:type=\"toc\" id=\"toc\">\n";
487
488 if (sizeof($this->navPoints) > 0) {
489 $this->navLevels++;
490
491 $nav .= str_repeat("\t", $level) . "\t\t\t<ol epub:type=\"list\">\n";
492 foreach ($this->navPoints as $navPoint) {
493 $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, 0);
494 if ($retLevel > $this->navLevels) {
495 $this->navLevels = $retLevel;
496 }
497 }
498 $nav .= str_repeat("\t", $level) . "\t\t\t</ol>\n";
499 }
500
501 return $nav . "\t\t</nav>\n";
502 }
503}
504
505/**
506 * ePub NavPoint class
507 */
508class NavPoint {
509 const _VERSION = 3.00;
510
511 private $label = NULL;
512 private $contentSrc = NULL;
513 private $id = NULL;
514 private $navClass = NULL;
515 private $isNavHidden = FALSE;
516 private $navPoints = array();
517 private $parent = NULL;
518
519 /**
520 * Class constructor.
521 *
522 * All three attributes are mandatory, though if ID is set to null (default) the value will be generated.
523 *
524 * @param string $label
525 * @param string $contentSrc
526 * @param string $id
527 * @param string $navClass
528 * @param bool $isNavHidden
529 * @param string $writingDirection
530 */
531 function __construct($label, $contentSrc = NULL, $id = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
532 $this->setLabel($label);
533 $this->setContentSrc($contentSrc);
534 $this->setId($id);
535 $this->setNavClass($navClass);
536 $this->setNavHidden($isNavHidden);
537 $this->setWritingDirection($writingDirection);
538 }
539
540 /**
541 * Class destructor
542 *
543 * @return void
544 */
545 function __destruct() {
546 unset($this->label, $this->contentSrc, $this->id, $this->navClass);
547 unset($this->isNavHidden, $this->navPoints, $this->parent);
548 }
549
550 /**
551 * Set the Text label for the NavPoint.
552 *
553 * The label is mandatory.
554 *
555 * @param string $label
556 */
557 function setLabel($label) {
558 $this->label = is_string($label) ? trim($label) : NULL;
559 }
560
561 /**
562 * Get the Text label for the NavPoint.
563 *
564 * @return string Label
565 */
566 function getLabel() {
567 return $this->label;
568 }
569
570 /**
571 * Set the src reference for the NavPoint.
572 *
573 * The src is mandatory for ePub 2.
574 *
575 * @param string $contentSrc
576 */
577 function setContentSrc($contentSrc) {
578 $this->contentSrc = isset($contentSrc) && is_string($contentSrc) ? trim($contentSrc) : NULL;
579 }
580
581 /**
582 * Get the src reference for the NavPoint.
583 *
584 * @return string content src url.
585 */
586 function getContentSrc() {
587 return $this->contentSrc;
588 }
589 /**
590 * Set the parent for this NavPoint.
591 *
592 * @param NavPoint or NavMap $parent
593 */
594 function setParent($parent) {
595 if ($parent != NULL && is_object($parent) &&
596 (get_class($parent) === "NavPoint" || get_class($parent) === "NavMap") ) {
597 $this->parent = $parent;
598 }
599 }
600
601 /**
602 * Get the parent to this NavPoint.
603 *
604 * @return NavPoint, or NavMap if the parent is the root.
605 */
606 function getParent() {
607 return $this->parent;
608 }
609
610 /**
611 * Get the current level. 1 = document root.
612 *
613 * @return int level
614 */
615 function getLevel() {
616 return $this->parent === NULL ? 1 : $this->parent->getLevel()+1;
617 }
618
619 /**
620 * Set the id for the NavPoint.
621 *
622 * The id must be unique, and is mandatory.
623 *
624 * @param string $id
625 */
626 function setId($id) {
627 $this->id = is_string($id) ? trim($id) : NULL;
628 }
629
630 /**
631 * Set the class to be used for this NavPoint.
632 *
633 * @param string $navClass
634 */
635 function setNavClass($navClass) {
636 $this->navClass = isset($navClass) && is_string($navClass) ? trim($navClass) : NULL;
637 }
638
639 /**
640 * Set the class to be used for this NavPoint.
641 *
642 * @param string $navClass
643 */
644 function setNavHidden($isNavHidden) {
645 $this->isNavHidden = $isNavHidden === TRUE;
646 }
647
648 /**
649 * Set the writing direction to be used for this NavPoint.
650 *
651 * @param string $writingDirection
652 */
653 function setWritingDirection($writingDirection) {
654 $this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
655 }
656
657 function getWritingDirection() {
658 return $this->writingDirection;
659 }
660
661 /**
662 * Add child NavPoints for multi level NavMaps.
663 *
664 * @param NavPoint $navPoint
665 */
666 function addNavPoint($navPoint) {
667 if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
668 $navPoint->setParent($this);
669 if ($navPoint->getWritingDirection() == NULL) {
670 $navPoint->setWritingDirection($this->writingDirection);
671 }
672 $this->navPoints[] = $navPoint;
673 return $navPoint;
674 }
675 return $this;
676 }
677
678 /**
679 *
680 * Enter description here ...
681 *
682 * @param string $nav
683 * @param int $playOrder
684 * @param int $level
685 * @return int
686 */
687 function finalize(&$nav = "", &$playOrder = 0, $level = 0) {
688 $maxLevel = $level;
689 $levelAdjust = 0;
690
691 if ($this->isNavHidden) {
692 return $maxLevel;
693 }
694
695 if (isset($this->contentSrc)) {
696 $playOrder++;
697
698 if ($this->id == NULL) {
699 $this->id = "navpoint-" . $playOrder;
700 }
701 $nav .= str_repeat("\t", $level) . "\t\t<navPoint id=\"" . $this->id . "\" playOrder=\"" . $playOrder . "\">\n"
702 . str_repeat("\t", $level) . "\t\t\t<navLabel>\n"
703 . str_repeat("\t", $level) . "\t\t\t\t<text>" . $this->label . "</text>\n"
704 . str_repeat("\t", $level) . "\t\t\t</navLabel>\n"
705 . str_repeat("\t", $level) . "\t\t\t<content src=\"" . $this->contentSrc . "\" />\n";
706 } else {
707 $levelAdjust++;
708 }
709
710 if (sizeof($this->navPoints) > 0) {
711 $maxLevel++;
712 foreach ($this->navPoints as $navPoint) {
713 $retLevel = $navPoint->finalize($nav, $playOrder, ($level+1+$levelAdjust));
714 if ($retLevel > $maxLevel) {
715 $maxLevel = $retLevel;
716 }
717 }
718 }
719
720 if (isset($this->contentSrc)) {
721 $nav .= str_repeat("\t", $level) . "\t\t</navPoint>\n";
722 }
723
724 return $maxLevel;
725 }
726
727 /**
728 *
729 * Enter description here ...
730 *
731 * @param string $nav
732 * @param int $playOrder
733 * @param int $level
734 * @return int
735 */
736 function finalizeEPub3(&$nav = "", &$playOrder = 0, $level = 0, $subLevelClass = NULL, $subLevelHidden = FALSE) {
737 $maxLevel = $level;
738
739 if ($this->id == NULL) {
740 $this->id = "navpoint-" . $playOrder;
741 }
742 $indent = str_repeat("\t", $level) . "\t\t\t\t";
743
744 $nav .= $indent . "<li id=\"" . $this->id . "\"";
745 if (isset($this->writingDirection)) {
746 $nav .= " dir=\"" . $this->writingDirection . "\"";
747 }
748 $nav .= ">\n";
749
750 if (isset($this->contentSrc)) {
751 $nav .= $indent . "\t<a href=\"" . $this->contentSrc . "\">" . $this->label . "</a>\n";
752 } else {
753 $nav .= $indent . "\t<span>" . $this->label . "</span>\n";
754 }
755
756 if (sizeof($this->navPoints) > 0) {
757 $maxLevel++;
758
759 $nav .= $indent . "\t<ol epub:type=\"list\"";
760 if (isset($subLevelClass)) {
761 $nav .= " class=\"" . $subLevelClass . "\"";
762 }
763 if ($subLevelHidden) {
764 $nav .= " hidden=\"hidden\"";
765 }
766 $nav .= ">\n";
767
768 foreach ($this->navPoints as $navPoint) {
769 $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, ($level+2), $subLevelClass, $subLevelHidden);
770 if ($retLevel > $maxLevel) {
771 $maxLevel = $retLevel;
772 }
773 }
774 $nav .= $indent . "\t</ol>\n";
775 }
776
777 $nav .= $indent . "</li>\n";
778
779 return $maxLevel;
780 }
781}
782?>