Răsfoiți Sursa

Mid-Init, going to "restart" by now

Moritz Schmidt 10 ani în urmă
părinte
comite
123e59ede1
100 a modificat fișierele cu 23405 adăugiri și 7 ștergeri
  1. 31 7
      ajax.php
  2. BIN
      drafts/Rechnung.docx
  3. BIN
      drafts/Rechnung.odt
  4. 58 0
      includes/PhpWord/Autoloader.php
  5. 96 0
      includes/PhpWord/Collection/AbstractCollection.php
  6. 27 0
      includes/PhpWord/Collection/Bookmarks.php
  7. 27 0
      includes/PhpWord/Collection/Charts.php
  8. 27 0
      includes/PhpWord/Collection/Endnotes.php
  9. 27 0
      includes/PhpWord/Collection/Footnotes.php
  10. 27 0
      includes/PhpWord/Collection/Titles.php
  11. 286 0
      includes/PhpWord/Element/AbstractContainer.php
  12. 395 0
      includes/PhpWord/Element/AbstractElement.php
  13. 63 0
      includes/PhpWord/Element/Bookmark.php
  14. 77 0
      includes/PhpWord/Element/Cell.php
  15. 125 0
      includes/PhpWord/Element/Chart.php
  16. 73 0
      includes/PhpWord/Element/CheckBox.php
  17. 43 0
      includes/PhpWord/Element/Endnote.php
  18. 181 0
      includes/PhpWord/Element/Field.php
  19. 117 0
      includes/PhpWord/Element/Footer.php
  20. 90 0
      includes/PhpWord/Element/Footnote.php
  21. 195 0
      includes/PhpWord/Element/FormField.php
  22. 41 0
      includes/PhpWord/Element/Header.php
  23. 537 0
      includes/PhpWord/Element/Image.php
  24. 53 0
      includes/PhpWord/Element/Line.php
  25. 174 0
      includes/PhpWord/Element/Link.php
  26. 111 0
      includes/PhpWord/Element/ListItem.php
  27. 86 0
      includes/PhpWord/Element/ListItemRun.php
  28. 165 0
      includes/PhpWord/Element/Object.php
  29. 31 0
      includes/PhpWord/Element/PageBreak.php
  30. 102 0
      includes/PhpWord/Element/PreserveText.php
  31. 107 0
      includes/PhpWord/Element/Row.php
  32. 130 0
      includes/PhpWord/Element/SDT.php
  33. 246 0
      includes/PhpWord/Element/Section.php
  34. 88 0
      includes/PhpWord/Element/Shape.php
  35. 172 0
      includes/PhpWord/Element/TOC.php
  36. 153 0
      includes/PhpWord/Element/Table.php
  37. 153 0
      includes/PhpWord/Element/Text.php
  38. 60 0
      includes/PhpWord/Element/TextBox.php
  39. 128 0
      includes/PhpWord/Element/TextBreak.php
  40. 58 0
      includes/PhpWord/Element/TextRun.php
  41. 102 0
      includes/PhpWord/Element/Title.php
  42. 39 0
      includes/PhpWord/Exception/CopyFileException.php
  43. 37 0
      includes/PhpWord/Exception/CreateTemporaryFileException.php
  44. 25 0
      includes/PhpWord/Exception/Exception.php
  45. 25 0
      includes/PhpWord/Exception/InvalidImageException.php
  46. 25 0
      includes/PhpWord/Exception/InvalidObjectException.php
  47. 27 0
      includes/PhpWord/Exception/InvalidStyleException.php
  48. 25 0
      includes/PhpWord/Exception/UnsupportedImageTypeException.php
  49. 91 0
      includes/PhpWord/IOFactory.php
  50. 332 0
      includes/PhpWord/Media.php
  51. 62 0
      includes/PhpWord/Metadata/Compatibility.php
  52. 578 0
      includes/PhpWord/Metadata/DocInfo.php
  53. 69 0
      includes/PhpWord/Metadata/Protection.php
  54. 358 0
      includes/PhpWord/PhpWord.php
  55. 119 0
      includes/PhpWord/Reader/AbstractReader.php
  56. 50 0
      includes/PhpWord/Reader/HTML.php
  57. 2341 0
      includes/PhpWord/Reader/MsDoc.php
  58. 95 0
      includes/PhpWord/Reader/ODText.php
  59. 30 0
      includes/PhpWord/Reader/ODText/AbstractPart.php
  60. 68 0
      includes/PhpWord/Reader/ODText/Content.php
  61. 80 0
      includes/PhpWord/Reader/ODText/Meta.php
  62. 51 0
      includes/PhpWord/Reader/RTF.php
  63. 414 0
      includes/PhpWord/Reader/RTF/Document.php
  64. 41 0
      includes/PhpWord/Reader/ReaderInterface.php
  65. 169 0
      includes/PhpWord/Reader/Word2007.php
  66. 515 0
      includes/PhpWord/Reader/Word2007/AbstractPart.php
  67. 40 0
      includes/PhpWord/Reader/Word2007/DocPropsApp.php
  68. 84 0
      includes/PhpWord/Reader/Word2007/DocPropsCore.php
  69. 56 0
      includes/PhpWord/Reader/Word2007/DocPropsCustom.php
  70. 186 0
      includes/PhpWord/Reader/Word2007/Document.php
  71. 40 0
      includes/PhpWord/Reader/Word2007/Endnotes.php
  72. 77 0
      includes/PhpWord/Reader/Word2007/Footnotes.php
  73. 123 0
      includes/PhpWord/Reader/Word2007/Numbering.php
  74. 86 0
      includes/PhpWord/Reader/Word2007/Styles.php
  75. 416 0
      includes/PhpWord/Settings.php
  76. 278 0
      includes/PhpWord/Shared/Converter.php
  77. 217 0
      includes/PhpWord/Shared/Drawing.php
  78. 104 0
      includes/PhpWord/Shared/Font.php
  79. 377 0
      includes/PhpWord/Shared/Html.php
  80. 313 0
      includes/PhpWord/Shared/OLERead.php
  81. 5691 0
      includes/PhpWord/Shared/PCLZip/pclzip.lib.php
  82. 195 0
      includes/PhpWord/Shared/String.php
  83. 192 0
      includes/PhpWord/Shared/XMLReader.php
  84. 202 0
      includes/PhpWord/Shared/XMLWriter.php
  85. 389 0
      includes/PhpWord/Shared/ZipArchive.php
  86. 202 0
      includes/PhpWord/Style.php
  87. 349 0
      includes/PhpWord/Style/AbstractStyle.php
  88. 78 0
      includes/PhpWord/Style/Alignment.php
  89. 338 0
      includes/PhpWord/Style/Border.php
  90. 249 0
      includes/PhpWord/Style/Cell.php
  91. 127 0
      includes/PhpWord/Style/Chart.php
  92. 106 0
      includes/PhpWord/Style/Extrusion.php
  93. 69 0
      includes/PhpWord/Style/Fill.php
  94. 851 0
      includes/PhpWord/Style/Font.php
  95. 513 0
      includes/PhpWord/Style/Frame.php
  96. 265 0
      includes/PhpWord/Style/Image.php
  97. 157 0
      includes/PhpWord/Style/Indentation.php
  98. 280 0
      includes/PhpWord/Style/Line.php
  99. 164 0
      includes/PhpWord/Style/LineNumbering.php
  100. 263 0
      includes/PhpWord/Style/ListItem.php

+ 31 - 7
ajax.php

@@ -2,13 +2,14 @@
 // AJAX handling
 
 // Includes
-include('includes/config.inc.php');
-include('includes/database.inc.php');
-include('includes/functions.inc.php');
-include('includes/document.inc.php');
-include('includes/label.inc.php');
-include('includes/imap.inc.php');
-include('includes/mailboxfolder.inc.php');
+require('includes/config.inc.php');
+require('includes/database.inc.php');
+require('includes/functions.inc.php');
+require('includes/document.inc.php');
+require('includes/label.inc.php');
+require('includes/imap.inc.php');
+require('includes/mailboxfolder.inc.php');
+require('includes/documenthandler.inc.php');
 
 $db = new Database($CONFIG['dbHost'], $CONFIG['dbUser'], $CONFIG['dbPassword'], $CONFIG['dbDatabase']);
 
@@ -79,6 +80,10 @@ switch($_REQUEST['action']) {
         header("Status: 200 OK");
         $db->removeQuery("DELETE FROM `mailboxes` WHERE `id` = " . $_POST['id'] . ";");
         break;
+    case 'removeMailboxFolder':
+        header("Status: 200 OK");
+        $db->removeQuery("DELETE FROM `mailbox-folders` WHERE `id` = " . $_POST['id'] . ";");
+        break;
     case 'manageMailboxFolder':
         header("Status: 200 OK");
         $boxHtml = 'Account: ';
@@ -97,6 +102,25 @@ switch($_REQUEST['action']) {
         $jsonOut = json_encode($mbArray);
         echo $jsonOut;
         break;
+    case 'getNewDocumentBox':
+        $boxHtml = 'Vorlage: ';
+        $boxHtml .= getEditableLink('document-draft', 'select', 0, 'Click to change', 'Rechnung.odt');
+        $boxHtml .= '<br>Dateiname: ';
+        $boxHtml .= getEditableLink('document-filename', 'text', 0, 'Click to change', 'Neue-Rechnung-09.04.2015.odt');
+        $documentHandler = new DocumentHandler('NeueRechnung.docx', 'Rechnung.docx');
+        $valueKeys = $documentHandler->getVariables();
+        foreach($valueKeys as $key=>$value) {
+            $boxHtml .= '<br>' . getEditableLink('template-value-' . $key, 'text', 0, 'Click to change', $value) . $value;
+        }
+        $documentHandler->setVal('ADRESSE', 'Moritz Schmidt' . PHP_EOL . 'Fr.-Weinbrenner-Str. 13' . PHP_EOL . '69126 Heidelberg');
+        $documentHandler->setVal('RECHNUNGSNUMMER', '2015.1');
+        $documentHandler->setVal('BESCHREIBUNG', 'eine kleine rechnung lol');
+        $documentHandler->setVal('RECHNUNGTABELLE', 'tabelle idk ollo todo implement!');
+        $documentHandler->setVal('GESAMTBETRAG', '7€');
+        $documentHandler->setVal('JAHR', '2015');
+        //$documentHandler->saveFile();
+        echo $boxHtml;
+        break;
     default:
         header("Status: 400 No Action Defined");
         echo 'error';

BIN
drafts/Rechnung.docx


BIN
drafts/Rechnung.odt


+ 58 - 0
includes/PhpWord/Autoloader.php

@@ -0,0 +1,58 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord;
+
+/**
+ * Autoloader
+ */
+class Autoloader
+{
+    /** @const string */
+    const NAMESPACE_PREFIX = 'PhpOffice\\PhpWord\\';
+
+    /**
+     * Register
+     *
+     * @param bool $throw
+     * @param bool $prepend
+     * @return void
+     */
+    public static function register($throw = true, $prepend = false)
+    {
+        spl_autoload_register(array(new self, 'autoload'), $throw, $prepend);
+    }
+
+    /**
+     * Autoload
+     *
+     * @param string $class
+     * @return void
+     */
+    public static function autoload($class)
+    {
+        $prefixLength = strlen(self::NAMESPACE_PREFIX);
+        if (0 === strncmp(self::NAMESPACE_PREFIX, $class, $prefixLength)) {
+            $file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength));
+            $file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');
+            if (file_exists($file)) {
+                /** @noinspection PhpIncludeInspection Dynamic includes */
+                require_once $file;
+            }
+        }
+    }
+}

+ 96 - 0
includes/PhpWord/Collection/AbstractCollection.php

@@ -0,0 +1,96 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Collection;
+
+/**
+ * Collection abstract class
+ *
+ * @since 0.10.0
+ */
+abstract class AbstractCollection
+{
+    /**
+     * Items
+     *
+     * @var array
+     */
+    private $items = array();
+
+    /**
+     * Get items
+     *
+     * @return array
+     */
+    public function getItems()
+    {
+        return $this->items;
+    }
+
+    /**
+     * Get item by index
+     *
+     * @param int $index
+     * @return mixed
+     */
+    public function getItem($index)
+    {
+        if (array_key_exists($index, $this->items)) {
+            return $this->items[$index];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set item.
+     *
+     * @param int $index
+     * @param mixed $item
+     * @return void
+     */
+    public function setItem($index, $item)
+    {
+        if (array_key_exists($index, $this->items)) {
+            $this->items[$index] = $item;
+        }
+    }
+
+    /**
+     * Add new item
+     *
+     * @param mixed $item
+     * @return int
+     */
+    public function addItem($item)
+    {
+        $index = $this->countItems() + 1;
+        $this->items[$index] = $item;
+
+        return $index;
+    }
+
+    /**
+     * Get item count
+     *
+     * @return int
+     */
+    public function countItems()
+    {
+        return count($this->items);
+    }
+}

+ 27 - 0
includes/PhpWord/Collection/Bookmarks.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Collection;
+
+/**
+ * Bookmarks collection
+ *
+ * @since 0.12.0
+ */
+class Bookmarks extends AbstractCollection
+{
+}

+ 27 - 0
includes/PhpWord/Collection/Charts.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Collection;
+
+/**
+ * Charts collection
+ *
+ * @since 0.12.0
+ */
+class Charts extends AbstractCollection
+{
+}

+ 27 - 0
includes/PhpWord/Collection/Endnotes.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Collection;
+
+/**
+ * Endnotes collection
+ *
+ * @since 0.10.0
+ */
+class Endnotes extends AbstractCollection
+{
+}

+ 27 - 0
includes/PhpWord/Collection/Footnotes.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Collection;
+
+/**
+ * Footnotes collection
+ *
+ * @since 0.10.0
+ */
+class Footnotes extends AbstractCollection
+{
+}

+ 27 - 0
includes/PhpWord/Collection/Titles.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Collection;
+
+/**
+ * Titles collection
+ *
+ * @since 0.10.0
+ */
+class Titles extends AbstractCollection
+{
+}

+ 286 - 0
includes/PhpWord/Element/AbstractContainer.php

@@ -0,0 +1,286 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Container abstract class
+ *
+ * @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null)
+ * @method TextRun addTextRun(mixed $pStyle = null)
+ * @method Bookmark addBookmark(string $name)
+ * @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null)
+ * @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null)
+ * @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null)
+ * @method ListItem addListItem(string $txt, int $depth = 0, mixed $font = null, mixed $list = null, mixed $para = null)
+ * @method ListItemRun addListItemRun(int $depth = 0, mixed $listStyle = null, mixed $pStyle = null)
+ * @method Footnote addFootnote(mixed $pStyle = null)
+ * @method Endnote addEndnote(mixed $pStyle = null)
+ * @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null)
+ * @method Title addTitle(string $text, int $depth = 1)
+ * @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9)
+ *
+ * @method PageBreak addPageBreak()
+ * @method Table addTable(mixed $style = null)
+ * @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false)
+ * @method Object addObject(string $source, mixed $style = null)
+ * @method TextBox addTextBox(mixed $style = null)
+ * @method Field addField(string $type = null, array $properties = array(), array $options = array())
+ * @method Line addLine(mixed $lineStyle = null)
+ * @method Shape addShape(string $type, mixed $style = null)
+ * @method Chart addChart(string $type, array $categories, array $values, array $style = null)
+ * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)
+ * @method SDT addSDT(string $type)
+ *
+ * @since 0.10.0
+ */
+abstract class AbstractContainer extends AbstractElement
+{
+    /**
+     * Elements collection
+     *
+     * @var array
+     */
+    protected $elements = array();
+
+    /**
+     * Container type Section|Header|Footer|Footnote|Endnote|Cell|TextRun|TextBox|ListItemRun
+     *
+     * @var string
+     */
+    protected $container;
+
+    /**
+     * Magic method to catch all 'addElement' variation
+     *
+     * This removes addText, addTextRun, etc. When adding new element, we have to
+     * add the model in the class docblock with `@method`.
+     *
+     * Warning: This makes capitalization matters, e.g. addCheckbox or addcheckbox won't work.
+     *
+     * @param mixed $function
+     * @param mixed $args
+     * @return \PhpOffice\PhpWord\Element\AbstractElement
+     */
+    public function __call($function, $args)
+    {
+        $elements = array(
+            'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak',
+            'ListItem', 'ListItemRun', 'Table', 'Image', 'Object',
+            'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
+            'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
+            'Chart', 'FormField', 'SDT'
+        );
+        $functions = array();
+        foreach ($elements as $element) {
+            $functions['add' . strtolower($element)] = $element;
+        }
+
+        // Run valid `add` command
+        $function = strtolower($function);
+        if (isset($functions[$function])) {
+            $element = $functions[$function];
+
+            // Special case for TextBreak
+            // @todo Remove the `$count` parameter in 1.0.0 to make this element similiar to other elements?
+            if ($element == 'TextBreak') {
+                @list($count, $fontStyle, $paragraphStyle) = $args; // Suppress error
+                if ($count === null) {
+                    $count = 1;
+                }
+                for ($i = 1; $i <= $count; $i++) {
+                    $this->addElement($element, $fontStyle, $paragraphStyle);
+                }
+
+            // All other elements
+            } else {
+                array_unshift($args, $element); // Prepend element name to the beginning of args array
+                return call_user_func_array(array($this, 'addElement'), $args);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Add element
+     *
+     * Each element has different number of parameters passed
+     *
+     * @param string $elementName
+     * @return \PhpOffice\PhpWord\Element\AbstractElement
+     */
+    protected function addElement($elementName)
+    {
+        $elementClass = __NAMESPACE__ . '\\' . $elementName;
+        $this->checkValidity($elementName);
+
+        // Get arguments
+        $args = func_get_args();
+        $withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field'));
+        if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) {
+            $args[3] = null; // Remove paragraph style for texts in textrun
+        }
+
+        // Create element using reflection
+        $reflection = new \ReflectionClass($elementClass);
+        $elementArgs = $args;
+        array_shift($elementArgs); // Shift the $elementName off the beginning of array
+
+        /** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */
+        $element = $reflection->newInstanceArgs($elementArgs);
+
+        // Set parent container
+        $element->setParentContainer($this);
+        $element->setElementIndex($this->countElements() + 1);
+        $element->setElementId();
+
+        $this->elements[] = $element;
+
+        return $element;
+    }
+
+    /**
+     * Get all elements
+     *
+     * @return array
+     */
+    public function getElements()
+    {
+        return $this->elements;
+    }
+
+    /**
+     * Count elements
+     *
+     * @return int
+     */
+    public function countElements()
+    {
+        return count($this->elements);
+    }
+
+    /**
+     * Check if a method is allowed for the current container
+     *
+     * @param string $method
+     * @return bool
+     * @throws \BadMethodCallException
+     */
+    private function checkValidity($method)
+    {
+        $generalContainers = array(
+            'Section', 'Header', 'Footer', 'Footnote', 'Endnote', 'Cell', 'TextRun', 'TextBox', 'ListItemRun',
+        );
+
+        $validContainers = array(
+            'Text'          => $generalContainers,
+            'Bookmark'      => $generalContainers,
+            'Link'          => $generalContainers,
+            'TextBreak'     => $generalContainers,
+            'Image'         => $generalContainers,
+            'Object'        => $generalContainers,
+            'Field'         => $generalContainers,
+            'Line'          => $generalContainers,
+            'Shape'         => $generalContainers,
+            'FormField'     => $generalContainers,
+            'SDT'           => $generalContainers,
+            'TextRun'       => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
+            'ListItem'      => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
+            'ListItemRun'   => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
+            'Table'         => array('Section', 'Header', 'Footer', 'Cell', 'TextBox'),
+            'CheckBox'      => array('Section', 'Header', 'Footer', 'Cell'),
+            'TextBox'       => array('Section', 'Header', 'Footer', 'Cell'),
+            'Footnote'      => array('Section', 'TextRun', 'Cell'),
+            'Endnote'       => array('Section', 'TextRun', 'Cell'),
+            'PreserveText'  => array('Header', 'Footer', 'Cell'),
+            'Title'         => array('Section'),
+            'TOC'           => array('Section'),
+            'PageBreak'     => array('Section'),
+            'Chart'         => array('Section'),
+        );
+
+        // Special condition, e.g. preservetext can only exists in cell when
+        // the cell is located in header or footer
+        $validSubcontainers = array(
+            'PreserveText'  => array(array('Cell'), array('Header', 'Footer')),
+            'Footnote'      => array(array('Cell', 'TextRun'), array('Section')),
+            'Endnote'       => array(array('Cell', 'TextRun'), array('Section')),
+        );
+
+        // Check if a method is valid for current container
+        if (isset($validContainers[$method])) {
+            if (!in_array($this->container, $validContainers[$method])) {
+                throw new \BadMethodCallException("Cannot add {$method} in {$this->container}.");
+            }
+        }
+
+        // Check if a method is valid for current container, located in other container
+        if (isset($validSubcontainers[$method])) {
+            $rules = $validSubcontainers[$method];
+            $containers = $rules[0];
+            $allowedDocParts = $rules[1];
+            foreach ($containers as $container) {
+                if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) {
+                    throw new \BadMethodCallException("Cannot add {$method} in {$this->container}.");
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Add memory image element
+     *
+     * @param string $src
+     * @param mixed $style
+     * @return \PhpOffice\PhpWord\Element\Image
+     * @deprecated 0.9.0
+     * @codeCoverageIgnore
+     */
+    public function addMemoryImage($src, $style = null)
+    {
+        return $this->addImage($src, $style);
+    }
+
+    /**
+     * Create textrun element
+     *
+     * @param mixed $paragraphStyle
+     * @return \PhpOffice\PhpWord\Element\TextRun
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function createTextRun($paragraphStyle = null)
+    {
+        return $this->addTextRun($paragraphStyle);
+    }
+
+    /**
+     * Create footnote element
+     *
+     * @param mixed $paragraphStyle
+     * @return \PhpOffice\PhpWord\Element\Footnote
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function createFootnote($paragraphStyle = null)
+    {
+        return $this->addFootnote($paragraphStyle);
+    }
+}

+ 395 - 0
includes/PhpWord/Element/AbstractElement.php

@@ -0,0 +1,395 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Media;
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Style;
+
+/**
+ * Element abstract class
+ *
+ * @since 0.10.0
+ */
+abstract class AbstractElement
+{
+    /**
+     * PhpWord object
+     *
+     * @var \PhpOffice\PhpWord\PhpWord
+     */
+    protected $phpWord;
+
+    /**
+     * Section Id
+     *
+     * @var int
+     */
+    protected $sectionId;
+
+    /**
+     * Document part type: Section|Header|Footer|Footnote|Endnote
+     *
+     * Used by textrun and cell container to determine where the element is
+     * located because it will affect the availability of other element,
+     * e.g. footnote will not be available when $docPart is header or footer.
+     *
+     * @var string
+     */
+    protected $docPart = 'Section';
+
+    /**
+     * Document part Id
+     *
+     * For header and footer, this will be = ($sectionId - 1) * 3 + $index
+     * because the max number of header/footer in every page is 3, i.e.
+     * AUTO, FIRST, and EVEN (AUTO = ODD)
+     *
+     * @var int
+     */
+    protected $docPartId = 1;
+
+    /**
+     * Index of element in the elements collection (start with 1)
+     *
+     * @var int
+     */
+    protected $elementIndex = 1;
+
+    /**
+     * Unique Id for element
+     *
+     * @var int
+     */
+    protected $elementId;
+
+    /**
+     * Relation Id
+     *
+     * @var int
+     */
+    protected $relationId;
+
+    /**
+     * Depth of table container nested level; Primarily used for RTF writer/reader
+     *
+     * 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc.
+     *
+     * @var int
+     */
+    private $nestedLevel = 0;
+
+    /**
+     * Parent container type
+     *
+     * @var string
+     */
+    private $parentContainer;
+
+    /**
+     * Has media relation flag; true for Link, Image, and Object
+     *
+     * @var bool
+     */
+    protected $mediaRelation = false;
+
+    /**
+     * Is part of collection; true for Title, Footnote, Endnote, and Chart
+     *
+     * @var bool
+     */
+    protected $collectionRelation = false;
+
+    /**
+     * Get PhpWord
+     *
+     * @return \PhpOffice\PhpWord\PhpWord
+     */
+    public function getPhpWord()
+    {
+        return $this->phpWord;
+    }
+
+    /**
+     * Set PhpWord as reference.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function setPhpWord(PhpWord $phpWord = null)
+    {
+        $this->phpWord = $phpWord;
+    }
+
+    /**
+     * Get section number
+     *
+     * @return int
+     */
+    public function getSectionId()
+    {
+        return $this->sectionId;
+    }
+
+    /**
+     * Set doc part.
+     *
+     * @param string $docPart
+     * @param int $docPartId
+     * @return void
+     */
+    public function setDocPart($docPart, $docPartId = 1)
+    {
+        $this->docPart = $docPart;
+        $this->docPartId = $docPartId;
+    }
+
+    /**
+     * Get doc part
+     *
+     * @return string
+     */
+    public function getDocPart()
+    {
+        return $this->docPart;
+    }
+
+    /**
+     * Get doc part Id
+     *
+     * @return int
+     */
+    public function getDocPartId()
+    {
+        return $this->docPartId;
+    }
+
+    /**
+     * Return media element (image, object, link) container name
+     *
+     * @return string section|headerx|footerx|footnote|endnote
+     */
+    private function getMediaPart()
+    {
+        $mediaPart = $this->docPart;
+        if ($mediaPart == 'Header' || $mediaPart == 'Footer') {
+            $mediaPart .= $this->docPartId;
+        }
+
+        return strtolower($mediaPart);
+    }
+
+    /**
+     * Get element index
+     *
+     * @return int
+     */
+    public function getElementIndex()
+    {
+        return $this->elementIndex;
+    }
+
+    /**
+     * Set element index.
+     *
+     * @param int $value
+     * @return void
+     */
+    public function setElementIndex($value)
+    {
+        $this->elementIndex = $value;
+    }
+
+    /**
+     * Get element unique ID
+     *
+     * @return string
+     */
+    public function getElementId()
+    {
+        return $this->elementId;
+    }
+
+    /**
+     * Set element unique ID from 6 first digit of md5.
+     *
+     * @return void
+     */
+    public function setElementId()
+    {
+        $this->elementId = substr(md5(rand()), 0, 6);
+    }
+
+    /**
+     * Get relation Id
+     *
+     * @return int
+     */
+    public function getRelationId()
+    {
+        return $this->relationId;
+    }
+
+    /**
+     * Set relation Id.
+     *
+     * @param int $value
+     * @return void
+     */
+    public function setRelationId($value)
+    {
+        $this->relationId = $value;
+    }
+
+    /**
+     * Get nested level
+     *
+     * @return int
+     */
+    public function getNestedLevel()
+    {
+        return $this->nestedLevel;
+    }
+
+    /**
+     * Set parent container
+     *
+     * Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell)
+     *
+     * @param \PhpOffice\PhpWord\Element\AbstractElement $container
+     * @return void
+     */
+    public function setParentContainer(AbstractElement $container)
+    {
+        $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1);
+
+        // Set nested level
+        $this->nestedLevel = $container->getNestedLevel();
+        if ($this->parentContainer == 'Cell') {
+            $this->nestedLevel++;
+        }
+
+        // Set phpword
+        $this->setPhpWord($container->getPhpWord());
+
+        // Set doc part
+        if (!$this instanceof Footnote) {
+            $this->setDocPart($container->getDocPart(), $container->getDocPartId());
+        }
+
+        $this->setMediaRelation();
+        $this->setCollectionRelation();
+    }
+
+    /**
+     * Set relation Id for media elements (link, image, object; legacy of OOXML)
+     *
+     * - Image element needs to be passed to Media object
+     * - Icon needs to be set for Object element
+     *
+     * @return void
+     */
+    private function setMediaRelation()
+    {
+        if (!$this instanceof Link && !$this instanceof Image && !$this instanceof Object) {
+            return;
+        }
+
+        $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1);
+        $mediaPart = $this->getMediaPart();
+        $source = $this->getSource();
+        $image = null;
+        if ($this instanceof Image) {
+            $image = $this;
+        }
+        $rId = Media::addElement($mediaPart, strtolower($elementName), $source, $image);
+        $this->setRelationId($rId);
+
+        if ($this instanceof Object) {
+            $icon = $this->getIcon();
+            $rId = Media::addElement($mediaPart, 'image', $icon, new Image($icon));
+            $this->setImageRelationId($rId);
+        }
+    }
+
+    /**
+     * Set relation Id for elements that will be registered in the Collection subnamespaces.
+     *
+     * @return void
+     */
+    private function setCollectionRelation()
+    {
+        if ($this->collectionRelation === true && $this->phpWord instanceof PhpWord) {
+            $elementName = substr(get_class($this), strrpos(get_class($this), '\\') + 1);
+            $addMethod = "add{$elementName}";
+            $rId = $this->phpWord->$addMethod($this);
+            $this->setRelationId($rId);
+        }
+    }
+
+    /**
+     * Check if element is located in Section doc part (as opposed to Header/Footer)
+     *
+     * @return bool
+     */
+    public function isInSection()
+    {
+        return ($this->docPart == 'Section');
+    }
+
+    /**
+     * Set new style value
+     *
+     * @param mixed $styleObject Style object
+     * @param mixed $styleValue Style value
+     * @param bool $returnObject Always return object
+     * @return mixed
+     */
+    protected function setNewStyle($styleObject, $styleValue = null, $returnObject = false)
+    {
+        if (!is_null($styleValue) && is_array($styleValue)) {
+            $styleObject->setStyleByArray($styleValue);
+            $style = $styleObject;
+        } else {
+            $style = $returnObject ? $styleObject : $styleValue;
+        }
+
+        return $style;
+    }
+
+    /**
+     * Set enum value
+     *
+     * @param mixed $value
+     * @param array $enum
+     * @param mixed $default
+     * @return mixed
+     * @throws \InvalidArgumentException
+     * @todo Merge with the same method in AbstractStyle
+     */
+    protected function setEnumVal($value = null, $enum = array(), $default = null)
+    {
+        if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {
+            throw new \InvalidArgumentException("Invalid style value: {$value}");
+        } elseif ($value === null || trim($value) == '') {
+            $value = $default;
+        }
+
+        return $value;
+    }
+}

+ 63 - 0
includes/PhpWord/Element/Bookmark.php

@@ -0,0 +1,63 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+use PhpOffice\PhpWord\Style;
+
+/**
+ * Bookmark element
+ */
+class Bookmark extends AbstractElement
+{
+    /**
+     * Bookmark Name
+     *
+     * @var string
+     */
+    private $name;
+
+    /**
+     * Is part of collection
+     *
+     * @var bool
+     */
+    protected $collectionRelation = true;
+
+    /**
+     * Create a new Bookmark Element
+     *
+     * @param string $name
+     */
+    public function __construct($name)
+    {
+
+        $this->name = String::toUTF8($name);
+        return $this;
+    }
+
+    /**
+     * Get Bookmark name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+}

+ 77 - 0
includes/PhpWord/Element/Cell.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Cell as CellStyle;
+
+/**
+ * Table cell element
+ */
+class Cell extends AbstractContainer
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'Cell';
+
+    /**
+     * Cell width
+     *
+     * @var int
+     */
+    private $width = null;
+
+    /**
+     * Cell style
+     *
+     * @var \PhpOffice\PhpWord\Style\Cell
+     */
+    private $style;
+
+    /**
+     * Create new instance
+     *
+     * @param int $width
+     * @param array|\PhpOffice\PhpWord\Style\Cell $style
+     */
+    public function __construct($width = null, $style = null)
+    {
+        $this->width = $width;
+        $this->style = $this->setNewStyle(new CellStyle(), $style, true);
+    }
+
+    /**
+     * Get cell style
+     *
+     * @return \PhpOffice\PhpWord\Style\Cell
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Get cell width
+     *
+     * @return int
+     */
+    public function getWidth()
+    {
+        return $this->width;
+    }
+}

+ 125 - 0
includes/PhpWord/Element/Chart.php

@@ -0,0 +1,125 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Chart as ChartStyle;
+
+/**
+ * Chart element
+ *
+ * @since 0.12.0
+ */
+class Chart extends AbstractElement
+{
+    /**
+     * Is part of collection
+     *
+     * @var bool
+     */
+    protected $collectionRelation = true;
+
+    /**
+     * Type
+     *
+     * @var string
+     */
+    private $type = 'pie';
+
+    /**
+     * Series
+     *
+     * @var array
+     */
+    private $series = array();
+
+    /**
+     * Chart style
+     *
+     * @var \PhpOffice\PhpWord\Style\Chart
+     */
+    private $style;
+
+    /**
+     * Create new instance
+     *
+     * @param string $type
+     * @param array $categories
+     * @param array $values
+     * @param array $style
+     */
+    public function __construct($type, $categories, $values, $style = null)
+    {
+        $this->setType($type);
+        $this->addSeries($categories, $values);
+        $this->style = $this->setNewStyle(new ChartStyle(), $style, true);
+    }
+
+    /**
+     * Get type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set type.
+     *
+     * @param string $value
+     * @return void
+     */
+    public function setType($value)
+    {
+        $enum = array('pie', 'doughnut', 'line', 'bar', 'column', 'area', 'radar', 'scatter');
+        $this->type = $this->setEnumVal($value, $enum, 'pie');
+    }
+
+    /**
+     * Add series
+     *
+     * @param array $categories
+     * @param array $values
+     * @return void
+     */
+    public function addSeries($categories, $values)
+    {
+        $this->series[] = array('categories' => $categories, 'values' => $values);
+    }
+
+    /**
+     * Get series
+     *
+     * @return array
+     */
+    public function getSeries()
+    {
+        return $this->series;
+    }
+
+    /**
+     * Get chart style
+     *
+     * @return \PhpOffice\PhpWord\Style\Chart
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+}

+ 73 - 0
includes/PhpWord/Element/CheckBox.php

@@ -0,0 +1,73 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+
+/**
+ * Check box element
+ *
+ * @since 0.10.0
+ */
+class CheckBox extends Text
+{
+    /**
+     * Name content
+     *
+     * @var string
+     */
+    private $name;
+
+    /**
+     * Create new instance
+     *
+     * @param string $name
+     * @param string $text
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     * @return self
+     */
+    public function __construct($name = null, $text = null, $fontStyle = null, $paragraphStyle = null)
+    {
+        $this->setName($name);
+        parent::__construct($text, $fontStyle, $paragraphStyle);
+    }
+
+    /**
+     * Set name content
+     *
+     * @param string $name
+     * @return self
+     */
+    public function setName($name)
+    {
+        $this->name = String::toUTF8($name);
+
+        return $this;
+    }
+
+    /**
+     * Get name content
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+}

+ 43 - 0
includes/PhpWord/Element/Endnote.php

@@ -0,0 +1,43 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Endnote element
+ *
+ * @since 0.10.0
+ */
+class Endnote extends Footnote
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'Endnote';
+
+    /**
+     * Create new instance
+     *
+     * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle
+     */
+    public function __construct($paragraphStyle = null)
+    {
+        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
+    }
+}

+ 181 - 0
includes/PhpWord/Element/Field.php

@@ -0,0 +1,181 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Field element
+ *
+ * @since 0.11.0
+ * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html
+ */
+class Field extends AbstractElement
+{
+    /**
+     * Field properties and options. Depending on type, a field can have different properties
+     * and options
+     *
+     * @var array
+     */
+    protected $fieldsArray = array(
+        'PAGE'=>array(
+           'properties'=>array(
+               'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'),
+           ),
+           'options'=>array('PreserveFormat')
+        ),
+        'NUMPAGES'=>array(
+           'properties'=>array(
+               'format' => array('Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'),
+               'numformat' => array('0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%')
+           ),
+           'options'=>array('PreserveFormat')
+        ),
+        'DATE'=>array(
+            'properties'=> array(
+               'dateformat' =>array('d-M-yyyy', 'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-M-yy', 'yyyy-MM-dd',
+                    'd-MMM-yy', 'd/M/yyyy', 'd MMM. yy', 'd/M/yy', 'MMM-yy', 'd-M-yyy H:mm', 'd-M-yyyy H:mm:ss',
+                    'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss')
+            ),
+            'options'=>array('PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat')
+        )
+    );
+
+    /**
+     * Field type
+     *
+     * @var string
+     */
+    protected $type;
+
+    /**
+     * Field properties
+     *
+     * @var array
+     */
+    protected $properties = array();
+
+    /**
+     * Field options
+     *
+     * @var array
+     */
+    protected $options = array();
+
+    /**
+     * Create a new Field Element
+     *
+     * @param string $type
+     * @param array $properties
+     * @param array $options
+     */
+    public function __construct($type = null, $properties = array(), $options = array())
+    {
+        $this->setType($type);
+        $this->setProperties($properties);
+        $this->setOptions($options);
+    }
+
+    /**
+     * Set Field type
+     *
+     * @param string $type
+     * @return string
+     * @throws \InvalidArgumentException
+     */
+    public function setType($type = null)
+    {
+        if (isset($type)) {
+            if (isset($this->fieldsArray[$type])) {
+                $this->type = $type;
+            } else {
+                throw new \InvalidArgumentException("Invalid type");
+            }
+        }
+        return $this->type;
+    }
+
+    /**
+     * Get Field type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set Field properties
+     *
+     * @param array $properties
+     * @return self
+     * @throws \InvalidArgumentException
+     */
+    public function setProperties($properties = array())
+    {
+        if (is_array($properties)) {
+            foreach (array_keys($properties) as $propkey) {
+                if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) {
+                    throw new \InvalidArgumentException("Invalid property");
+                }
+            }
+            $this->properties = array_merge($this->properties, $properties);
+        }
+        return $this->properties;
+    }
+
+    /**
+     * Get Field properties
+     *
+     * @return array
+     */
+    public function getProperties()
+    {
+        return $this->properties;
+    }
+
+    /**
+     * Set Field options
+     *
+     * @param array $options
+     * @return self
+     * @throws \InvalidArgumentException
+     */
+    public function setOptions($options = array())
+    {
+        if (is_array($options)) {
+            foreach (array_keys($options) as $optionkey) {
+                if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey]))) {
+                    throw new \InvalidArgumentException("Invalid option");
+                }
+            }
+            $this->options = array_merge($this->options, $options);
+        }
+        return $this->options;
+    }
+
+    /**
+     * Get Field properties
+     *
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->options;
+    }
+}

+ 117 - 0
includes/PhpWord/Element/Footer.php

@@ -0,0 +1,117 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Footer element
+ */
+class Footer extends AbstractContainer
+{
+    /**
+     * Header/footer types constants
+     *
+     * @var string
+     * @link http://www.schemacentral.com/sc/ooxml/a-wtype-4.html Header or Footer Type
+     */
+    const AUTO  = 'default';  // default and odd pages
+    const FIRST = 'first';
+    const EVEN  = 'even';
+
+    /**
+     * @var string Container type
+     */
+    protected $container = 'Footer';
+
+    /**
+     * Header type
+     *
+     * @var string
+     */
+    protected $type = self::AUTO;
+
+    /**
+     * Create new instance
+     *
+     * @param int $sectionId
+     * @param int $containerId
+     * @param string $type
+     */
+    public function __construct($sectionId, $containerId = 1, $type = self::AUTO)
+    {
+        $this->sectionId = $sectionId;
+        $this->setType($type);
+        $this->setDocPart($this->container, ($sectionId - 1) * 3 + $containerId);
+    }
+
+    /**
+     * Set type.
+     *
+     * @since 0.10.0
+     *
+     * @param string $value
+     * @return void
+     */
+    public function setType($value = self::AUTO)
+    {
+        if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) {
+            $value = self::AUTO;
+        }
+        $this->type = $value;
+    }
+
+    /**
+     * Get type
+     *
+     * @return string
+     * @since 0.10.0
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Reset type to default
+     *
+     * @return string
+     */
+    public function resetType()
+    {
+        return $this->type = self::AUTO;
+    }
+
+    /**
+     * First page only header
+     *
+     * @return string
+     */
+    public function firstPage()
+    {
+        return $this->type = self::FIRST;
+    }
+
+    /**
+     * Even numbered pages only
+     *
+     * @return string
+     */
+    public function evenPage()
+    {
+        return $this->type = self::EVEN;
+    }
+}

+ 90 - 0
includes/PhpWord/Element/Footnote.php

@@ -0,0 +1,90 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Footnote element
+ */
+class Footnote extends AbstractContainer
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'Footnote';
+
+    /**
+     * Paragraph style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    protected $paragraphStyle;
+
+    /**
+     * Is part of collection
+     *
+     * @var bool
+     */
+    protected $collectionRelation = true;
+
+    /**
+     * Create new instance
+     *
+     * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle
+     */
+    public function __construct($paragraphStyle = null)
+    {
+        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
+        $this->setDocPart($this->container);
+    }
+
+    /**
+     * Get paragraph style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraphStyle()
+    {
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Get Footnote Reference ID
+     *
+     * @return int
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getReferenceId()
+    {
+        return $this->getRelationId();
+    }
+
+    /**
+     * Set Footnote Reference ID
+     *
+     * @param int $rId
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function setReferenceId($rId)
+    {
+        $this->setRelationId($rId);
+    }
+}

+ 195 - 0
includes/PhpWord/Element/FormField.php

@@ -0,0 +1,195 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Form field element
+ *
+ * @since 0.12.0
+ * @link http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html
+ */
+class FormField extends Text
+{
+    /**
+     * Form field type: textinput|checkbox|dropdown
+     *
+     * @var string
+     */
+    private $type = 'textinput';
+
+    /**
+     * Form field name
+     *
+     * @var string
+     */
+    private $name;
+
+    /**
+     * Default value
+     *
+     * - TextInput: string
+     * - CheckBox: bool
+     * - DropDown: int Index of entries (zero based)
+     *
+     * @var string|bool|int
+     */
+    private $default;
+
+    /**
+     * Value
+     *
+     * @var string|bool|int
+     */
+    private $value;
+
+    /**
+     * Dropdown entries
+     *
+     * @var array
+     */
+    private $entries = array();
+
+    /**
+     * Create new instance
+     *
+     * @param string $type
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     * @return self
+     */
+    public function __construct($type, $fontStyle = null, $paragraphStyle = null)
+    {
+        $this->setType($type);
+    }
+
+    /**
+     * Get type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set type
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setType($value)
+    {
+        $enum = array('textinput', 'checkbox', 'dropdown');
+        $this->type = $this->setEnumVal($value, $enum, $this->type);
+
+        return $this;
+    }
+
+    /**
+     * Get name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Set name
+     *
+     * @param string|bool|int $value
+     * @return self
+     */
+    public function setName($value)
+    {
+        $this->name = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get default
+     *
+     * @return string|bool|int
+     */
+    public function getDefault()
+    {
+        return $this->default;
+    }
+
+    /**
+     * Set default
+     *
+     * @param string|bool|int $value
+     * @return self
+     */
+    public function setDefault($value)
+    {
+        $this->default = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get value
+     *
+     * @return string|bool|int
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Set value
+     *
+     * @param string|bool|int $value
+     * @return self
+     */
+    public function setValue($value)
+    {
+        $this->value = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get entries
+     *
+     * @return array
+     */
+    public function getEntries()
+    {
+        return $this->entries;
+    }
+
+    /**
+     * Set entries
+     *
+     * @param array $value
+     * @return self
+     */
+    public function setEntries($value)
+    {
+        $this->entries = $value;
+
+        return $this;
+    }
+}

+ 41 - 0
includes/PhpWord/Element/Header.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Header element
+ */
+class Header extends Footer
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'Header';
+
+    /**
+     * Add a Watermark Element
+     *
+     * @param string $src
+     * @param mixed $style
+     * @return Image
+     */
+    public function addWatermark($src, $style = null)
+    {
+        return $this->addImage($src, $style, true);
+    }
+}

+ 537 - 0
includes/PhpWord/Element/Image.php

@@ -0,0 +1,537 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Exception\CreateTemporaryFileException;
+use PhpOffice\PhpWord\Exception\InvalidImageException;
+use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException;
+use PhpOffice\PhpWord\Settings;
+use PhpOffice\PhpWord\Shared\ZipArchive;
+use PhpOffice\PhpWord\Style\Image as ImageStyle;
+
+/**
+ * Image element
+ */
+class Image extends AbstractElement
+{
+    /**
+     * Image source type constants
+     */
+    const SOURCE_LOCAL = 'local'; // Local images
+    const SOURCE_GD = 'gd'; // Generated using GD
+    const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image
+
+    /**
+     * Image source
+     *
+     * @var string
+     */
+    private $source;
+
+    /**
+     * Source type: local|gd|archive
+     *
+     * @var string
+     */
+    private $sourceType;
+
+    /**
+     * Image style
+     *
+     * @var ImageStyle
+     */
+    private $style;
+
+    /**
+     * Is watermark
+     *
+     * @var boolean
+     */
+    private $watermark;
+
+    /**
+     * Image type
+     *
+     * @var string
+     */
+    private $imageType;
+
+    /**
+     * Image create function
+     *
+     * @var string
+     */
+    private $imageCreateFunc;
+
+    /**
+     * Image function
+     *
+     * @var string
+     */
+    private $imageFunc;
+
+    /**
+     * Image extension
+     *
+     * @var string
+     */
+    private $imageExtension;
+
+    /**
+     * Is memory image
+     *
+     * @var boolean
+     */
+    private $memoryImage;
+
+    /**
+     * Image target file name
+     *
+     * @var string
+     */
+    private $target;
+
+    /**
+     * Image media index
+     *
+     * @var integer
+     */
+    private $mediaIndex;
+
+    /**
+     * Has media relation flag; true for Link, Image, and Object
+     *
+     * @var bool
+     */
+    protected $mediaRelation = true;
+
+    /**
+     * Create new image element
+     *
+     * @param string $source
+     * @param mixed $style
+     * @param boolean $watermark
+     * @throws \PhpOffice\PhpWord\Exception\InvalidImageException
+     * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
+     */
+    public function __construct($source, $style = null, $watermark = false)
+    {
+        $this->source = $source;
+        $this->setIsWatermark($watermark);
+        $this->style = $this->setNewStyle(new ImageStyle(), $style, true);
+
+        $this->checkImage($source);
+    }
+
+    /**
+     * Get Image style
+     *
+     * @return ImageStyle
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Get image source
+     *
+     * @return string
+     */
+    public function getSource()
+    {
+        return $this->source;
+    }
+
+    /**
+     * Get image source type
+     *
+     * @return string
+     */
+    public function getSourceType()
+    {
+        return $this->sourceType;
+    }
+
+    /**
+     * Get image media ID
+     *
+     * @return string
+     */
+    public function getMediaId()
+    {
+        return md5($this->source);
+    }
+
+    /**
+     * Get is watermark
+     *
+     * @return boolean
+     */
+    public function isWatermark()
+    {
+        return $this->watermark;
+    }
+
+    /**
+     * Set is watermark
+     *
+     * @param boolean $value
+     */
+    public function setIsWatermark($value)
+    {
+        $this->watermark = $value;
+    }
+
+    /**
+     * Get image type
+     *
+     * @return string
+     */
+    public function getImageType()
+    {
+        return $this->imageType;
+    }
+
+    /**
+     * Get image create function
+     *
+     * @return string
+     */
+    public function getImageCreateFunction()
+    {
+        return $this->imageCreateFunc;
+    }
+
+    /**
+     * Get image function
+     *
+     * @return string
+     */
+    public function getImageFunction()
+    {
+        return $this->imageFunc;
+    }
+
+    /**
+     * Get image extension
+     *
+     * @return string
+     */
+    public function getImageExtension()
+    {
+        return $this->imageExtension;
+    }
+
+    /**
+     * Get is memory image
+     *
+     * @return boolean
+     */
+    public function isMemImage()
+    {
+        return $this->memoryImage;
+    }
+
+    /**
+     * Get target file name
+     *
+     * @return string
+     */
+    public function getTarget()
+    {
+        return $this->target;
+    }
+
+    /**
+     * Set target file name.
+     *
+     * @param string $value
+     * @return void
+     */
+    public function setTarget($value)
+    {
+        $this->target = $value;
+    }
+
+    /**
+     * Get media index
+     *
+     * @return integer
+     */
+    public function getMediaIndex()
+    {
+        return $this->mediaIndex;
+    }
+
+    /**
+     * Set media index.
+     *
+     * @param integer $value
+     * @return void
+     */
+    public function setMediaIndex($value)
+    {
+        $this->mediaIndex = $value;
+    }
+
+    /**
+     * Get image string data
+     *
+     * @param bool $base64
+     * @return string|null
+     * @since 0.11.0
+     */
+    public function getImageStringData($base64 = false)
+    {
+        $source = $this->source;
+        $actualSource = null;
+        $imageBinary = null;
+        $imageData = null;
+        $isTemp = false;
+
+        // Get actual source from archive image or other source
+        // Return null if not found
+        if ($this->sourceType == self::SOURCE_ARCHIVE) {
+            $source = substr($source, 6);
+            list($zipFilename, $imageFilename) = explode('#', $source);
+
+            $zip = new ZipArchive();
+            if ($zip->open($zipFilename) !== false) {
+                if ($zip->locateName($imageFilename)) {
+                    $isTemp = true;
+                    $zip->extractTo(Settings::getTempDir(), $imageFilename);
+                    $actualSource = Settings::getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;
+                }
+            }
+            $zip->close();
+        } else {
+            $actualSource = $source;
+        }
+
+        // Can't find any case where $actualSource = null hasn't captured by
+        // preceding exceptions. Please uncomment when you find the case and
+        // put the case into Element\ImageTest.
+        // if ($actualSource === null) {
+        //     return null;
+        // }
+
+        // Read image binary data and convert to hex/base64 string
+        if ($this->sourceType == self::SOURCE_GD) {
+            $imageResource = call_user_func($this->imageCreateFunc, $actualSource);
+            ob_start();
+            call_user_func($this->imageFunc, $imageResource);
+            $imageBinary = ob_get_contents();
+            ob_end_clean();
+        } else {
+            $fileHandle = fopen($actualSource, 'rb', false);
+            if ($fileHandle !== false) {
+                $imageBinary = fread($fileHandle, filesize($actualSource));
+                fclose($fileHandle);
+            }
+        }
+        if ($imageBinary !== null) {
+            if ($base64) {
+                $imageData = chunk_split(base64_encode($imageBinary));
+            } else {
+                $imageData = chunk_split(bin2hex($imageBinary));
+            }
+        }
+
+        // Delete temporary file if necessary
+        if ($isTemp === true) {
+            @unlink($actualSource);
+        }
+
+        return $imageData;
+    }
+
+    /**
+     * Check memory image, supported type, image functions, and proportional width/height.
+     *
+     * @param string $source
+     * @return void
+     * @throws \PhpOffice\PhpWord\Exception\InvalidImageException
+     * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException
+     */
+    private function checkImage($source)
+    {
+        $this->setSourceType($source);
+
+        // Check image data
+        if ($this->sourceType == self::SOURCE_ARCHIVE) {
+            $imageData = $this->getArchiveImageSize($source);
+        } else {
+            $imageData = @getimagesize($source);
+        }
+        if (!is_array($imageData)) {
+            throw new InvalidImageException();
+        }
+        list($actualWidth, $actualHeight, $imageType) = $imageData;
+
+        // Check image type support
+        $supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG);
+        if ($this->sourceType != self::SOURCE_GD) {
+            $supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM));
+        }
+        if (!in_array($imageType, $supportedTypes)) {
+            throw new UnsupportedImageTypeException();
+        }
+
+        // Define image functions
+        $this->imageType = image_type_to_mime_type($imageType);
+        $this->setFunctions();
+        $this->setProportionalSize($actualWidth, $actualHeight);
+    }
+
+    /**
+     * Set source type.
+     *
+     * @param string $source
+     * @return void
+     */
+    private function setSourceType($source)
+    {
+        if (stripos(strrev($source), strrev('.php')) === 0) {
+            $this->memoryImage = true;
+            $this->sourceType = self::SOURCE_GD;
+        } elseif (strpos($source, 'zip://') !== false) {
+            $this->memoryImage = false;
+            $this->sourceType = self::SOURCE_ARCHIVE;
+        } else {
+            $this->memoryImage = (filter_var($source, FILTER_VALIDATE_URL) !== false);
+            $this->sourceType = $this->memoryImage ? self::SOURCE_GD : self::SOURCE_LOCAL;
+        }
+    }
+
+    /**
+     * Get image size from archive
+     *
+     * @since 0.12.0 Throws CreateTemporaryFileException.
+     *
+     * @param string $source
+     * @return array|null
+     * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException
+     */
+    private function getArchiveImageSize($source)
+    {
+        $imageData = null;
+        $source = substr($source, 6);
+        list($zipFilename, $imageFilename) = explode('#', $source);
+
+        $tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage');
+        if (false === $tempFilename) {
+            throw new CreateTemporaryFileException();
+        }
+
+        $zip = new ZipArchive();
+        if ($zip->open($zipFilename) !== false) {
+            if ($zip->locateName($imageFilename)) {
+                $imageContent = $zip->getFromName($imageFilename);
+                if ($imageContent !== false) {
+                    file_put_contents($tempFilename, $imageContent);
+                    $imageData = getimagesize($tempFilename);
+                    unlink($tempFilename);
+                }
+            }
+            $zip->close();
+        }
+
+        return $imageData;
+    }
+
+    /**
+     * Set image functions and extensions.
+     *
+     * @return void
+     */
+    private function setFunctions()
+    {
+        switch ($this->imageType) {
+            case 'image/png':
+                $this->imageCreateFunc = 'imagecreatefrompng';
+                $this->imageFunc = 'imagepng';
+                $this->imageExtension = 'png';
+                break;
+            case 'image/gif':
+                $this->imageCreateFunc = 'imagecreatefromgif';
+                $this->imageFunc = 'imagegif';
+                $this->imageExtension = 'gif';
+                break;
+            case 'image/jpeg':
+            case 'image/jpg':
+                $this->imageCreateFunc = 'imagecreatefromjpeg';
+                $this->imageFunc = 'imagejpeg';
+                $this->imageExtension = 'jpg';
+                break;
+            case 'image/bmp':
+            case 'image/x-ms-bmp':
+                $this->imageType = 'image/bmp';
+                $this->imageExtension = 'bmp';
+                break;
+            case 'image/tiff':
+                $this->imageExtension = 'tif';
+                break;
+        }
+    }
+
+    /**
+     * Set proportional width/height if one dimension not available.
+     *
+     * @param integer $actualWidth
+     * @param integer $actualHeight
+     * @return void
+     */
+    private function setProportionalSize($actualWidth, $actualHeight)
+    {
+        $styleWidth = $this->style->getWidth();
+        $styleHeight = $this->style->getHeight();
+        if (!($styleWidth && $styleHeight)) {
+            if ($styleWidth == null && $styleHeight == null) {
+                $this->style->setWidth($actualWidth);
+                $this->style->setHeight($actualHeight);
+            } elseif ($styleWidth) {
+                $this->style->setHeight($actualHeight * ($styleWidth / $actualWidth));
+            } else {
+                $this->style->setWidth($actualWidth * ($styleHeight / $actualHeight));
+            }
+        }
+    }
+
+    /**
+     * Get is watermark
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getIsWatermark()
+    {
+        return $this->isWatermark();
+    }
+
+    /**
+     * Get is memory image
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getIsMemImage()
+    {
+        return $this->isMemImage();
+    }
+}

+ 53 - 0
includes/PhpWord/Element/Line.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Line as LineStyle;
+
+/**
+ * Line element
+ */
+class Line extends AbstractElement
+{
+    /**
+     * Line style
+     *
+     * @var \PhpOffice\PhpWord\Style\Line
+     */
+    private $style;
+
+    /**
+     * Create new line element
+     *
+     * @param mixed $style
+     */
+    public function __construct($style = null)
+    {
+        $this->style = $this->setNewStyle(new LineStyle(), $style);
+    }
+
+    /**
+     * Get line style
+     *
+     * @return \PhpOffice\PhpWord\Style\Line
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+}

+ 174 - 0
includes/PhpWord/Element/Link.php

@@ -0,0 +1,174 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+use PhpOffice\PhpWord\Style\Font;
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Link element
+ */
+class Link extends AbstractElement
+{
+    /**
+     * Link source
+     *
+     * @var string
+     */
+    private $source;
+
+    /**
+     * Link text
+     *
+     * @var string
+     */
+    private $text;
+
+    /**
+     * Font style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Font
+     */
+    private $fontStyle;
+
+    /**
+     * Paragraph style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    private $paragraphStyle;
+
+    /**
+     * Has media relation flag; true for Link, Image, and Object
+     *
+     * @var bool
+     */
+    protected $mediaRelation = true;
+
+    /**
+     * Has internal flag - anchor to internal bookmark
+     *
+     * @var bool
+     */
+    protected $internal = false;
+
+    /**
+     * Create a new Link Element
+     *
+     * @param string $source
+     * @param string $text
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     */
+    public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false)
+    {
+        $this->source = String::toUTF8($source);
+        $this->text = is_null($text) ? $this->source : String::toUTF8($text);
+        $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);
+        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
+        $this->internal = $internal;
+        return $this;
+    }
+
+    /**
+     * Get link source
+     *
+     * @return string
+     */
+    public function getSource()
+    {
+        return $this->source;
+    }
+
+    /**
+     * Get link text
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+
+    /**
+     * Get Text style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Font
+     */
+    public function getFontStyle()
+    {
+        return $this->fontStyle;
+    }
+
+    /**
+     * Get Paragraph style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraphStyle()
+    {
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Get link target
+     *
+     * @return string
+     * @deprecated 0.12.0
+     * @codeCoverageIgnore
+     */
+    public function getTarget()
+    {
+        return $this->source;
+    }
+
+    /**
+     * Get Link source
+     *
+     * @return string
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getLinkSrc()
+    {
+        return $this->getSource();
+    }
+
+    /**
+     * Get Link name
+     *
+     * @return string
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getLinkName()
+    {
+        return $this->getText();
+    }
+
+    /**
+     * is internal
+     *
+     * @return bool
+     */
+    public function isInternal()
+    {
+        return $this->internal;
+    }
+}

+ 111 - 0
includes/PhpWord/Element/ListItem.php

@@ -0,0 +1,111 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+use PhpOffice\PhpWord\Style\ListItem as ListItemStyle;
+
+/**
+ * List item element
+ */
+class ListItem extends AbstractElement
+{
+    /**
+     * Element style
+     *
+     * @var \PhpOffice\PhpWord\Style\ListItem
+     */
+    private $style;
+
+    /**
+     * Text object
+     *
+     * @var \PhpOffice\PhpWord\Element\Text
+     */
+    private $textObject;
+
+    /**
+     * Depth
+     *
+     * @var int
+     */
+    private $depth;
+
+    /**
+     * Create a new ListItem
+     *
+     * @param string $text
+     * @param int $depth
+     * @param mixed $fontStyle
+     * @param array|string|null $listStyle
+     * @param mixed $paragraphStyle
+     */
+    public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null)
+    {
+        $this->textObject = new Text(String::toUTF8($text), $fontStyle, $paragraphStyle);
+        $this->depth = $depth;
+
+        // Version >= 0.10.0 will pass numbering style name. Older version will use old method
+        if (!is_null($listStyle) && is_string($listStyle)) {
+            $this->style = new ListItemStyle($listStyle);
+        } else {
+            $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true);
+        }
+    }
+
+    /**
+     * Get style
+     *
+     * @return \PhpOffice\PhpWord\Style\ListItem
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Get Text object
+     *
+     * @return \PhpOffice\PhpWord\Element\Text
+     */
+    public function getTextObject()
+    {
+        return $this->textObject;
+    }
+
+    /**
+     * Get depth
+     *
+     * @return int
+     */
+    public function getDepth()
+    {
+        return $this->depth;
+    }
+
+    /**
+     * Get text
+     *
+     * @return string
+     * @since 0.11.0
+     */
+    public function getText()
+    {
+        return $this->textObject->getText();
+    }
+}

+ 86 - 0
includes/PhpWord/Element/ListItemRun.php

@@ -0,0 +1,86 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+* word processing documents.
+*
+* PHPWord is free software distributed under the terms of the GNU Lesser
+* General Public License version 3 as published by the Free Software Foundation.
+*
+* For the full copyright and license information, please read the LICENSE
+* file that was distributed with this source code. For the full list of
+* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+*
+* @link        https://github.com/PHPOffice/PHPWord
+* @copyright   2010-2014 PHPWord contributors
+* @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+*/
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\ListItem as ListItemStyle;
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * List item element
+ */
+class ListItemRun extends TextRun
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'ListItemRun';
+
+    /**
+     * ListItem Style
+     *
+     * @var \PhpOffice\PhpWord\Style\ListItem
+     */
+    private $style;
+
+    /**
+     * ListItem Depth
+     *
+     * @var int
+     */
+    private $depth;
+
+    /**
+     * Create a new ListItem
+     *
+     * @param int $depth
+     * @param array|string|null $listStyle
+     * @param mixed $paragraphStyle
+     */
+    public function __construct($depth = 0, $listStyle = null, $paragraphStyle = null)
+    {
+        $this->depth = $depth;
+
+        // Version >= 0.10.0 will pass numbering style name. Older version will use old method
+        if (!is_null($listStyle) && is_string($listStyle)) {
+            $this->style = new ListItemStyle($listStyle);
+        } else {
+            $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true);
+        }
+        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
+    }
+
+    /**
+     * Get ListItem style.
+     *
+     * @return \PhpOffice\PhpWord\Style\ListItem
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+     /**
+     * Get ListItem depth.
+      *
+      * @return int
+     */
+    public function getDepth()
+    {
+        return $this->depth;
+    }
+}

+ 165 - 0
includes/PhpWord/Element/Object.php

@@ -0,0 +1,165 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Exception\InvalidObjectException;
+use PhpOffice\PhpWord\Style\Image as ImageStyle;
+
+/**
+ * Object element
+ */
+class Object extends AbstractElement
+{
+    /**
+     * Ole-Object Src
+     *
+     * @var string
+     */
+    private $source;
+
+    /**
+     * Image Style
+     *
+     * @var \PhpOffice\PhpWord\Style\Image
+     */
+    private $style;
+
+    /**
+     * Icon
+     *
+     * @var string
+     */
+    private $icon;
+
+    /**
+     * Image Relation ID
+     *
+     * @var int
+     */
+    private $imageRelationId;
+
+    /**
+     * Has media relation flag; true for Link, Image, and Object
+     *
+     * @var bool
+     */
+    protected $mediaRelation = true;
+
+    /**
+     * Create a new Ole-Object Element
+     *
+     * @param string $source
+     * @param mixed $style
+     * @throws \PhpOffice\PhpWord\Exception\InvalidObjectException
+     */
+    public function __construct($source, $style = null)
+    {
+        $supportedTypes = array('xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx');
+        $pathInfo = pathinfo($source);
+
+        if (file_exists($source) && in_array($pathInfo['extension'], $supportedTypes)) {
+            $ext = $pathInfo['extension'];
+            if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') {
+                $ext = substr($ext, 0, -1);
+            }
+
+            $this->source = $source;
+            $this->style = $this->setNewStyle(new ImageStyle(), $style, true);
+            $this->icon = realpath(__DIR__ . "/../resources/{$ext}.png");
+
+            return $this;
+        } else {
+            throw new InvalidObjectException();
+        }
+    }
+
+    /**
+     * Get object source
+     *
+     * @return string
+     */
+    public function getSource()
+    {
+        return $this->source;
+    }
+
+    /**
+     * Get object style
+     *
+     * @return \PhpOffice\PhpWord\Style\Image
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Get object icon
+     *
+     * @return string
+     */
+    public function getIcon()
+    {
+        return $this->icon;
+    }
+
+    /**
+     * Get image relation ID
+     *
+     * @return int
+     */
+    public function getImageRelationId()
+    {
+        return $this->imageRelationId;
+    }
+
+    /**
+     * Set Image Relation ID.
+     *
+     * @param int $rId
+     * @return void
+     */
+    public function setImageRelationId($rId)
+    {
+        $this->imageRelationId = $rId;
+    }
+
+    /**
+     * Get Object ID
+     *
+     * @return int
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getObjectId()
+    {
+        return $this->relationId + 1325353440;
+    }
+
+    /**
+     * Set Object ID
+     *
+     * @param int $objId
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function setObjectId($objId)
+    {
+        $this->relationId = $objId;
+    }
+}

+ 31 - 0
includes/PhpWord/Element/PageBreak.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Page break element
+ */
+class PageBreak extends AbstractElement
+{
+    /**
+     * Create new page break
+     */
+    public function __construct()
+    {
+    }
+}

+ 102 - 0
includes/PhpWord/Element/PreserveText.php

@@ -0,0 +1,102 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+use PhpOffice\PhpWord\Style\Font;
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Preserve text/field element
+ */
+class PreserveText extends AbstractElement
+{
+    /**
+     * Text content
+     *
+     * @var string
+     */
+    private $text;
+
+    /**
+     * Text style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Font
+     */
+    private $fontStyle;
+
+    /**
+     * Paragraph style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    private $paragraphStyle;
+
+
+    /**
+     * Create a new Preserve Text Element
+     *
+     * @param string $text
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     * @return self
+     */
+    public function __construct($text = null, $fontStyle = null, $paragraphStyle = null)
+    {
+        $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);
+        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
+
+        $this->text = String::toUTF8($text);
+        $matches = preg_split('/({.*?})/', $this->text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+        if (isset($matches[0])) {
+            $this->text = $matches;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Text style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Font
+     */
+    public function getFontStyle()
+    {
+        return $this->fontStyle;
+    }
+
+    /**
+     * Get Paragraph style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraphStyle()
+    {
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Get Text content
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+}

+ 107 - 0
includes/PhpWord/Element/Row.php

@@ -0,0 +1,107 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Row as RowStyle;
+
+/**
+ * Table row element
+ *
+ * @since 0.8.0
+ */
+class Row extends AbstractElement
+{
+    /**
+     * Row height
+     *
+     * @var int
+     */
+    private $height = null;
+
+    /**
+     * Row style
+     *
+     * @var \PhpOffice\PhpWord\Style\Row
+     */
+    private $style;
+
+    /**
+     * Row cells
+     *
+     * @var \PhpOffice\PhpWord\Element\Cell[]
+     */
+    private $cells = array();
+
+    /**
+     * Create a new table row
+     *
+     * @param int $height
+     * @param mixed $style
+     */
+    public function __construct($height = null, $style = null)
+    {
+        $this->height = $height;
+        $this->style = $this->setNewStyle(new RowStyle(), $style, true);
+    }
+
+    /**
+     * Add a cell
+     *
+     * @param int $width
+     * @param mixed $style
+     * @return \PhpOffice\PhpWord\Element\Cell
+     */
+    public function addCell($width = null, $style = null)
+    {
+        $cell = new Cell($width, $style);
+        $cell->setParentContainer($this);
+        $this->cells[] = $cell;
+
+        return $cell;
+    }
+
+    /**
+     * Get all cells
+     *
+     * @return \PhpOffice\PhpWord\Element\Cell[]
+     */
+    public function getCells()
+    {
+        return $this->cells;
+    }
+
+    /**
+     * Get row style
+     *
+     * @return \PhpOffice\PhpWord\Style\Row
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Get row height
+     *
+     * @return int
+     */
+    public function getHeight()
+    {
+        return $this->height;
+    }
+}

+ 130 - 0
includes/PhpWord/Element/SDT.php

@@ -0,0 +1,130 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+/**
+ * Structured document tag (SDT) element
+ *
+ * @since 0.12.0
+ */
+class SDT extends Text
+{
+    /**
+     * Form field type: comboBox|dropDownList|date
+     *
+     * @var string
+     */
+    private $type;
+
+    /**
+     * Value
+     *
+     * @var string|bool|int
+     */
+    private $value;
+
+    /**
+     * CheckBox/DropDown list entries
+     *
+     * @var array
+     */
+    private $listItems = array();
+
+    /**
+     * Create new instance
+     *
+     * @param string $type
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     * @return self
+     */
+    public function __construct($type, $fontStyle = null, $paragraphStyle = null)
+    {
+        $this->setType($type);
+    }
+
+    /**
+     * Get type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set type
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setType($value)
+    {
+        $enum = array('comboBox', 'dropDownList', 'date');
+        $this->type = $this->setEnumVal($value, $enum, 'comboBox');
+
+        return $this;
+    }
+
+    /**
+     * Get value
+     *
+     * @return string|bool|int
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Set value
+     *
+     * @param string|bool|int $value
+     * @return self
+     */
+    public function setValue($value)
+    {
+        $this->value = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get listItems
+     *
+     * @return array
+     */
+    public function getListItems()
+    {
+        return $this->listItems;
+    }
+
+    /**
+     * Set listItems
+     *
+     * @param array $value
+     * @return self
+     */
+    public function setListItems($value)
+    {
+        $this->listItems = $value;
+
+        return $this;
+    }
+}

+ 246 - 0
includes/PhpWord/Element/Section.php

@@ -0,0 +1,246 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Exception\Exception;
+use PhpOffice\PhpWord\Style\Section as SectionStyle;
+
+/**
+ * Section
+ */
+class Section extends AbstractContainer
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'Section';
+
+    /**
+     * Section style
+     *
+     * @var \PhpOffice\PhpWord\Style\Section
+     */
+    private $style;
+
+    /**
+     * Section headers, indexed from 1, not zero
+     *
+     * @var Header[]
+     */
+    private $headers = array();
+
+    /**
+     * Section footers, indexed from 1, not zero
+     *
+     * @var Footer[]
+     */
+    private $footers = array();
+
+    /**
+     * Create new instance
+     *
+     * @param int $sectionCount
+     * @param array $style
+     */
+    public function __construct($sectionCount, $style = null)
+    {
+        $this->sectionId = $sectionCount;
+        $this->setDocPart($this->container, $this->sectionId);
+        $this->style = new SectionStyle();
+        $this->setStyle($style);
+    }
+
+    /**
+     * Set section style.
+     *
+     * @param array $style
+     * @return void
+     */
+    public function setStyle($style = null)
+    {
+        if (!is_null($style) && is_array($style)) {
+            $this->style->setStyleByArray($style);
+        }
+    }
+
+    /**
+     * Get section style
+     *
+     * @return \PhpOffice\PhpWord\Style\Section
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Add header
+     *
+     * @param string $type
+     * @return Header
+     * @since 0.10.0
+     */
+    public function addHeader($type = Header::AUTO)
+    {
+        return $this->addHeaderFooter($type, true);
+    }
+
+    /**
+     * Add footer
+     *
+     * @param string $type
+     * @return Footer
+     * @since 0.10.0
+     */
+    public function addFooter($type = Header::AUTO)
+    {
+        return $this->addHeaderFooter($type, false);
+    }
+
+    /**
+     * Get header elements
+     *
+     * @return Header[]
+     */
+    public function getHeaders()
+    {
+        return $this->headers;
+    }
+
+    /**
+     * Get footer elements
+     *
+     * @return Footer[]
+     */
+    public function getFooters()
+    {
+        return $this->footers;
+    }
+
+    /**
+     * Is there a header for this section that is for the first page only?
+     *
+     * If any of the Header instances have a type of Header::FIRST then this method returns true.
+     * False otherwise.
+     *
+     * @return boolean
+     */
+    public function hasDifferentFirstPage()
+    {
+        foreach ($this->headers as $header) {
+            if ($header->getType() == Header::FIRST) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Add header/footer
+     *
+     * @param string $type
+     * @param boolean $header
+     * @return Header|Footer
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     * @since 0.10.0
+     */
+    private function addHeaderFooter($type = Header::AUTO, $header = true)
+    {
+        $containerClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' .
+            ($header ? 'Header' : 'Footer');
+        $collectionArray = $header ? 'headers' : 'footers';
+        $collection = &$this->$collectionArray;
+
+        if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) {
+            $index = count($collection);
+            /** @var \PhpOffice\PhpWord\Element\AbstractContainer $container Type hint */
+            $container = new $containerClass($this->sectionId, ++$index, $type);
+            $container->setPhpWord($this->phpWord);
+
+            $collection[$index] = $container;
+            return $container;
+        } else {
+            throw new Exception('Invalid header/footer type.');
+        }
+
+    }
+
+    /**
+     * Set section style
+     *
+     * @param array $settings
+     * @deprecated 0.12.0
+     * @codeCoverageIgnore
+     */
+    public function setSettings($settings = null)
+    {
+        $this->setStyle($settings);
+    }
+
+    /**
+     * Get section style
+     *
+     * @return \PhpOffice\PhpWord\Style\Section
+     * @deprecated 0.12.0
+     * @codeCoverageIgnore
+     */
+    public function getSettings()
+    {
+        return $this->getStyle();
+    }
+
+    /**
+     * Create header
+     *
+     * @return Header
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function createHeader()
+    {
+        return $this->addHeader();
+    }
+
+    /**
+     * Create footer
+     *
+     * @return Footer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function createFooter()
+    {
+        return $this->addFooter();
+    }
+
+    /**
+     * Get footer
+     *
+     * @return Footer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getFooter()
+    {
+        if (empty($this->footers)) {
+            return null;
+        } else {
+            return $this->footers[1];
+        }
+    }
+}

+ 88 - 0
includes/PhpWord/Element/Shape.php

@@ -0,0 +1,88 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Shape as ShapeStyle;
+
+/**
+ * Shape element
+ *
+ * @since 0.12.0
+ */
+class Shape extends AbstractElement
+{
+    /**
+     * Shape type arc|curve|line|polyline|rect|oval
+     *
+     * @var string
+     */
+    private $type;
+
+    /**
+     * Shape style
+     *
+     * @var \PhpOffice\PhpWord\Style\Shape
+     */
+    private $style;
+
+    /**
+     * Create new instance
+     *
+     * @param string $type
+     * @param mixed $style
+     */
+    public function __construct($type, $style = null)
+    {
+        $this->setType($type);
+        $this->style = $this->setNewStyle(new ShapeStyle(), $style);
+    }
+
+    /**
+     * Get type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set pattern
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setType($value = null)
+    {
+        $enum = array('arc', 'curve', 'line', 'polyline', 'rect', 'oval');
+        $this->type = $this->setEnumVal($value, $enum, null);
+
+        return $this;
+    }
+
+    /**
+     * Get shape style
+     *
+     * @return \PhpOffice\PhpWord\Style\Shape
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+}

+ 172 - 0
includes/PhpWord/Element/TOC.php

@@ -0,0 +1,172 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Style\Font;
+use PhpOffice\PhpWord\Style\TOC as TOCStyle;
+
+/**
+ * Table of contents
+ */
+class TOC extends AbstractElement
+{
+    /**
+     * TOC style
+     *
+     * @var \PhpOffice\PhpWord\Style\TOC
+     */
+    private $TOCStyle;
+
+    /**
+     * Font style
+     *
+     * @var \PhpOffice\PhpWord\Style\Font|array|string
+     */
+    private $fontStyle;
+
+    /**
+     * Min title depth to show
+     *
+     * @var int
+     */
+    private $minDepth = 1;
+
+    /**
+     * Max title depth to show
+     *
+     * @var int
+     */
+    private $maxDepth = 9;
+
+
+    /**
+     * Create a new Table-of-Contents Element
+     *
+     * @param mixed $fontStyle
+     * @param array $tocStyle
+     * @param integer $minDepth
+     * @param integer $maxDepth
+     */
+    public function __construct($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9)
+    {
+        $this->TOCStyle = new TOCStyle();
+
+        if (!is_null($tocStyle) && is_array($tocStyle)) {
+            $this->TOCStyle->setStyleByArray($tocStyle);
+        }
+
+        if (!is_null($fontStyle) && is_array($fontStyle)) {
+            $this->fontStyle = new Font();
+            $this->fontStyle->setStyleByArray($fontStyle);
+        } else {
+            $this->fontStyle = $fontStyle;
+        }
+
+        $this->minDepth = $minDepth;
+        $this->maxDepth = $maxDepth;
+    }
+
+    /**
+     * Get all titles
+     *
+     * @return array
+     */
+    public function getTitles()
+    {
+        if (!$this->phpWord instanceof PhpWord) {
+            return array();
+        }
+
+        $titles = $this->phpWord->getTitles()->getItems();
+        foreach ($titles as $i => $title) {
+            /** @var \PhpOffice\PhpWord\Element\Title $title Type hint */
+            $depth = $title->getDepth();
+            if ($this->minDepth > $depth) {
+                unset($titles[$i]);
+            }
+            if (($this->maxDepth != 0) && ($this->maxDepth < $depth)) {
+                unset($titles[$i]);
+            }
+        }
+
+        return $titles;
+    }
+
+    /**
+     * Get TOC Style
+     *
+     * @return \PhpOffice\PhpWord\Style\TOC
+     */
+    public function getStyleTOC()
+    {
+        return $this->TOCStyle;
+    }
+
+    /**
+     * Get Font Style
+     *
+     * @return \PhpOffice\PhpWord\Style\Font
+     */
+    public function getStyleFont()
+    {
+        return $this->fontStyle;
+    }
+
+    /**
+     * Set max depth.
+     *
+     * @param int $value
+     * @return void
+     */
+    public function setMaxDepth($value)
+    {
+        $this->maxDepth = $value;
+    }
+
+    /**
+     * Get Max Depth
+     *
+     * @return int Max depth of titles
+     */
+    public function getMaxDepth()
+    {
+        return $this->maxDepth;
+    }
+
+    /**
+     * Set min depth.
+     *
+     * @param int $value
+     * @return void
+     */
+    public function setMinDepth($value)
+    {
+        $this->minDepth = $value;
+    }
+
+    /**
+     * Get Min Depth
+     *
+     * @return int Min depth of titles
+     */
+    public function getMinDepth()
+    {
+        return $this->minDepth;
+    }
+}

+ 153 - 0
includes/PhpWord/Element/Table.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Table as TableStyle;
+
+/**
+ * Table element
+ */
+class Table extends AbstractElement
+{
+    /**
+     * Table style
+     *
+     * @var \PhpOffice\PhpWord\Style\Table
+     */
+    private $style;
+
+    /**
+     * Table rows
+     *
+     * @var \PhpOffice\PhpWord\Element\Row[]
+     */
+    private $rows = array();
+
+    /**
+     * Table width
+     *
+     * @var int
+     */
+    private $width = null;
+
+    /**
+     * Create a new table
+     *
+     * @param mixed $style
+     */
+    public function __construct($style = null)
+    {
+        $this->style = $this->setNewStyle(new TableStyle(), $style);
+    }
+
+    /**
+     * Add a row
+     *
+     * @param int $height
+     * @param mixed $style
+     * @return \PhpOffice\PhpWord\Element\Row
+     */
+    public function addRow($height = null, $style = null)
+    {
+        $row = new Row($height, $style);
+        $row->setParentContainer($this);
+        $this->rows[] = $row;
+
+        return $row;
+    }
+
+    /**
+     * Add a cell
+     *
+     * @param int $width
+     * @param mixed $style
+     * @return \PhpOffice\PhpWord\Element\Cell
+     */
+    public function addCell($width = null, $style = null)
+    {
+        $index = count($this->rows) - 1;
+        $row = $this->rows[$index];
+        $cell = $row->addCell($width, $style);
+
+        return $cell;
+    }
+
+    /**
+     * Get all rows
+     *
+     * @return \PhpOffice\PhpWord\Element\Row[]
+     */
+    public function getRows()
+    {
+        return $this->rows;
+    }
+
+    /**
+     * Get table style
+     *
+     * @return \PhpOffice\PhpWord\Style\Table
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+
+    /**
+     * Get table width
+     *
+     * @return int
+     */
+    public function getWidth()
+    {
+        return $this->width;
+    }
+
+    /**
+     * Set table width.
+     *
+     * @param int $width
+     * @return void
+     */
+    public function setWidth($width)
+    {
+        $this->width = $width;
+    }
+
+    /**
+     * Get column count
+     *
+     * @return int
+     */
+    public function countColumns()
+    {
+        $columnCount = 0;
+        if (is_array($this->rows)) {
+            $rowCount = count($this->rows);
+            for ($i = 0; $i < $rowCount; $i++) {
+                /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */
+                $row = $this->rows[$i];
+                $cellCount = count($row->getCells());
+                if ($columnCount < $cellCount) {
+                    $columnCount = $cellCount;
+                }
+            }
+        }
+
+        return $columnCount;
+    }
+}

+ 153 - 0
includes/PhpWord/Element/Text.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+use PhpOffice\PhpWord\Style\Font;
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Text element
+ */
+class Text extends AbstractElement
+{
+    /**
+     * Text content
+     *
+     * @var string
+     */
+    protected $text;
+
+    /**
+     * Text style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Font
+     */
+    protected $fontStyle;
+
+    /**
+     * Paragraph style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    protected $paragraphStyle;
+
+    /**
+     * Create a new Text Element
+     *
+     * @param string $text
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     */
+    public function __construct($text = null, $fontStyle = null, $paragraphStyle = null)
+    {
+        $this->setText($text);
+        $paragraphStyle = $this->setParagraphStyle($paragraphStyle);
+        $this->setFontStyle($fontStyle, $paragraphStyle);
+    }
+
+    /**
+     * Set Text style
+     *
+     * @param string|array|\PhpOffice\PhpWord\Style\Font $style
+     * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle
+     * @return string|\PhpOffice\PhpWord\Style\Font
+     */
+    public function setFontStyle($style = null, $paragraphStyle = null)
+    {
+        if ($style instanceof Font) {
+            $this->fontStyle = $style;
+            $this->setParagraphStyle($paragraphStyle);
+        } elseif (is_array($style)) {
+            $this->fontStyle = new Font('text', $paragraphStyle);
+            $this->fontStyle->setStyleByArray($style);
+        } elseif (null === $style) {
+            $this->fontStyle = new Font('text', $paragraphStyle);
+        } else {
+            $this->fontStyle = $style;
+            $this->setParagraphStyle($paragraphStyle);
+        }
+
+        return $this->fontStyle;
+    }
+
+    /**
+     * Get Text style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Font
+     */
+    public function getFontStyle()
+    {
+        return $this->fontStyle;
+    }
+
+    /**
+     * Set Paragraph style
+     *
+     * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function setParagraphStyle($style = null)
+    {
+        if (is_array($style)) {
+            $this->paragraphStyle = new Paragraph;
+            $this->paragraphStyle->setStyleByArray($style);
+        } elseif ($style instanceof Paragraph) {
+            $this->paragraphStyle = $style;
+        } elseif (null === $style) {
+            $this->paragraphStyle = new Paragraph;
+        } else {
+            $this->paragraphStyle = $style;
+        }
+
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Get Paragraph style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraphStyle()
+    {
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Set text content
+     *
+     * @param string $text
+     * @return self
+     */
+    public function setText($text)
+    {
+        $this->text = String::toUTF8($text);
+
+        return $this;
+    }
+
+    /**
+     * Get Text content
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+}

+ 60 - 0
includes/PhpWord/Element/TextBox.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\TextBox as TextBoxStyle;
+
+/**
+ * TextBox element
+ *
+ * @since 0.11.0
+ */
+class TextBox extends AbstractContainer
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'TextBox';
+
+    /**
+     * TextBox style
+     *
+     * @var \PhpOffice\PhpWord\Style\TextBox
+     */
+    private $style;
+
+    /**
+     * Create a new textbox
+     *
+     * @param mixed $style
+     */
+    public function __construct($style = null)
+    {
+        $this->style = $this->setNewStyle(new TextBoxStyle(), $style);
+    }
+
+    /**
+     * Get textbox style
+     *
+     * @return \PhpOffice\PhpWord\Style\TextBox
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+}

+ 128 - 0
includes/PhpWord/Element/TextBreak.php

@@ -0,0 +1,128 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Font;
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Text break element
+ */
+class TextBreak extends AbstractElement
+{
+    /**
+     * Paragraph style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    private $paragraphStyle = null;
+
+    /**
+     * Text style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Font
+     */
+    private $fontStyle = null;
+
+    /**
+     * Create a new TextBreak Element
+     *
+     * @param mixed $fontStyle
+     * @param mixed $paragraphStyle
+     */
+    public function __construct($fontStyle = null, $paragraphStyle = null)
+    {
+        if (!is_null($paragraphStyle)) {
+            $paragraphStyle = $this->setParagraphStyle($paragraphStyle);
+        }
+        if (!is_null($fontStyle)) {
+            $this->setFontStyle($fontStyle, $paragraphStyle);
+        }
+    }
+
+    /**
+     * Set Text style
+     *
+     * @param mixed $style
+     * @param mixed $paragraphStyle
+     * @return string|\PhpOffice\PhpWord\Style\Font
+     */
+    public function setFontStyle($style = null, $paragraphStyle = null)
+    {
+        if ($style instanceof Font) {
+            $this->fontStyle = $style;
+            $this->setParagraphStyle($paragraphStyle);
+        } elseif (is_array($style)) {
+            $this->fontStyle = new Font('text', $paragraphStyle);
+            $this->fontStyle->setStyleByArray($style);
+        } else {
+            $this->fontStyle = $style;
+            $this->setParagraphStyle($paragraphStyle);
+        }
+        return $this->fontStyle;
+    }
+
+    /**
+     * Get Text style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Font
+     */
+    public function getFontStyle()
+    {
+        return $this->fontStyle;
+    }
+
+    /**
+     * Set Paragraph style
+     *
+     * @param   string|array|\PhpOffice\PhpWord\Style\Paragraph $style
+     * @return  string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function setParagraphStyle($style = null)
+    {
+        if (is_array($style)) {
+            $this->paragraphStyle = new Paragraph;
+            $this->paragraphStyle->setStyleByArray($style);
+        } elseif ($style instanceof Paragraph) {
+            $this->paragraphStyle = $style;
+        } else {
+            $this->paragraphStyle = $style;
+        }
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Get Paragraph style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraphStyle()
+    {
+        return $this->paragraphStyle;
+    }
+
+    /**
+     * Has font/paragraph style defined
+     *
+     * @return bool
+     */
+    public function hasStyle()
+    {
+        return !is_null($this->fontStyle) || !is_null($this->paragraphStyle);
+    }
+}

+ 58 - 0
includes/PhpWord/Element/TextRun.php

@@ -0,0 +1,58 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Style\Paragraph;
+
+/**
+ * Textrun/paragraph element
+ */
+class TextRun extends AbstractContainer
+{
+    /**
+     * @var string Container type
+     */
+    protected $container = 'TextRun';
+
+    /**
+     * Paragraph style
+     *
+     * @var string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    protected $paragraphStyle;
+
+    /**
+     * Create new instance
+     *
+     * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle
+     */
+    public function __construct($paragraphStyle = null)
+    {
+        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);
+    }
+
+    /**
+     * Get Paragraph style
+     *
+     * @return string|\PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraphStyle()
+    {
+        return $this->paragraphStyle;
+    }
+}

+ 102 - 0
includes/PhpWord/Element/Title.php

@@ -0,0 +1,102 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Element;
+
+use PhpOffice\PhpWord\Shared\String;
+use PhpOffice\PhpWord\Style;
+
+/**
+ * Title element
+ */
+class Title extends AbstractElement
+{
+    /**
+     * Title Text content
+     *
+     * @var string
+     */
+    private $text;
+
+    /**
+     * Title depth
+     *
+     * @var int
+     */
+    private $depth = 1;
+
+    /**
+     * Name of the heading style, e.g. 'Heading1'
+     *
+     * @var string
+     */
+    private $style;
+
+    /**
+     * Is part of collection
+     *
+     * @var bool
+     */
+    protected $collectionRelation = true;
+
+    /**
+     * Create a new Title Element
+     *
+     * @param string $text
+     * @param int $depth
+     */
+    public function __construct($text, $depth = 1)
+    {
+        $this->text = String::toUTF8($text);
+        $this->depth = $depth;
+        if (array_key_exists("Heading_{$this->depth}", Style::getStyles())) {
+            $this->style = "Heading{$this->depth}";
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get Title Text content
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        return $this->text;
+    }
+
+    /**
+     * Get depth
+     *
+     * @return integer
+     */
+    public function getDepth()
+    {
+        return $this->depth;
+    }
+
+    /**
+     * Get Title style
+     *
+     * @return string
+     */
+    public function getStyle()
+    {
+        return $this->style;
+    }
+}

+ 39 - 0
includes/PhpWord/Exception/CopyFileException.php

@@ -0,0 +1,39 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+/**
+ * @since 0.12.0
+ */
+final class CopyFileException extends Exception
+{
+    /**
+     * @param string $source The fully qualified source file name.
+     * @param string $destination The fully qualified destination file name.
+     * @param integer $code The user defined exception code.
+     * @param \Exception $previous The previous exception used for the exception chaining.
+     */
+    final public function __construct($source, $destination, $code = 0, \Exception $previous = null)
+    {
+        parent::__construct(
+            sprintf('Could not copy \'%s\' file to \'%s\'.', $source, $destination),
+            $code,
+            $previous
+        );
+    }
+}

+ 37 - 0
includes/PhpWord/Exception/CreateTemporaryFileException.php

@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+/**
+ * @since 0.12.0
+ */
+final class CreateTemporaryFileException extends Exception
+{
+    /**
+     * @param integer $code The user defined exception code.
+     * @param \Exception $previous The previous exception used for the exception chaining.
+     */
+    final public function __construct($code = 0, \Exception $previous = null)
+    {
+        parent::__construct(
+            'Could not create a temporary file with unique name in the specified directory.',
+            $code,
+            $previous
+        );
+    }
+}

+ 25 - 0
includes/PhpWord/Exception/Exception.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+/**
+ * General exception
+ */
+class Exception extends \Exception
+{
+}

+ 25 - 0
includes/PhpWord/Exception/InvalidImageException.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+/**
+ * Exception used for when an image is not found
+ */
+class InvalidImageException extends Exception
+{
+}

+ 25 - 0
includes/PhpWord/Exception/InvalidObjectException.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+/**
+ * Exception used for when an image is not found
+ */
+class InvalidObjectException extends Exception
+{
+}

+ 27 - 0
includes/PhpWord/Exception/InvalidStyleException.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+use InvalidArgumentException;
+
+/**
+ * Exception used for when a style value is invalid
+ */
+class InvalidStyleException extends InvalidArgumentException
+{
+}

+ 25 - 0
includes/PhpWord/Exception/UnsupportedImageTypeException.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Exception;
+
+/**
+ * Exception used for when an image type is unsupported
+ */
+class UnsupportedImageTypeException extends Exception
+{
+}

+ 91 - 0
includes/PhpWord/IOFactory.php

@@ -0,0 +1,91 @@
+<?php
+/**
+ * PHPWord
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2014 PHPWord
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord;
+
+use PhpOffice\PhpWord\Exception\Exception;
+use PhpOffice\PhpWord\Reader\ReaderInterface;
+use PhpOffice\PhpWord\Writer\WriterInterface;
+
+abstract class IOFactory
+{
+    /**
+     * Create new writer
+     *
+     * @param PhpWord $phpWord
+     * @param string $name
+     * @return WriterInterface
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     */
+    public static function createWriter(PhpWord $phpWord, $name = 'Word2007')
+    {
+        if ($name !== 'WriterInterface' && !in_array($name, array('ODText', 'RTF', 'Word2007', 'HTML', 'PDF'), true)) {
+            throw new Exception("\"{$name}\" is not a valid writer.");
+        }
+
+        $fqName = "PhpOffice\\PhpWord\\Writer\\{$name}";
+
+        return new $fqName($phpWord);
+    }
+
+    /**
+     * Create new reader
+     *
+     * @param string $name
+     * @return ReaderInterface
+     * @throws Exception
+     */
+    public static function createReader($name = 'Word2007')
+    {
+        return self::createObject('Reader', $name);
+    }
+
+    /**
+     * Create new object
+     *
+     * @param string $type
+     * @param string $name
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return \PhpOffice\PhpWord\Writer\WriterInterface|\PhpOffice\PhpWord\Reader\ReaderInterface
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     */
+    private static function createObject($type, $name, $phpWord = null)
+    {
+        $class = "PhpOffice\\PhpWord\\{$type}\\{$name}";
+        if (class_exists($class) && self::isConcreteClass($class)) {
+            return new $class($phpWord);
+        } else {
+            throw new Exception("\"{$name}\" is not a valid {$type}.");
+        }
+    }
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $filename The name of the file
+     * @param string $readerName
+     * @return \PhpOffice\PhpWord\PhpWord $phpWord
+     */
+    public static function load($filename, $readerName = 'Word2007')
+    {
+        /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */
+        $reader = self::createReader($readerName);
+        return $reader->load($filename);
+    }
+    /**
+     * Check if it's a concrete class (not abstract nor interface)
+     *
+     * @param string $class
+     * @return bool
+     */
+    private static function isConcreteClass($class)
+    {
+        $reflection = new \ReflectionClass($class);
+        return !$reflection->isAbstract() && !$reflection->isInterface();
+    }
+}

+ 332 - 0
includes/PhpWord/Media.php

@@ -0,0 +1,332 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord;
+
+use PhpOffice\PhpWord\Element\Image;
+use PhpOffice\PhpWord\Exception\Exception;
+
+/**
+ * Media collection
+ */
+class Media
+{
+    /**
+     * Media elements
+     *
+     * @var array
+     */
+    private static $elements = array();
+
+    /**
+     * Add new media element
+     *
+     * @param string $container section|headerx|footerx|footnote|endnote
+     * @param string $mediaType image|object|link
+     * @param string $source
+     * @param \PhpOffice\PhpWord\Element\Image $image
+     * @return integer
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     * @since 0.9.2
+     * @since 0.10.0
+     */
+    public static function addElement($container, $mediaType, $source, Image $image = null)
+    {
+        // Assign unique media Id and initiate media container if none exists
+        $mediaId = md5($container . $source);
+        if (!isset(self::$elements[$container])) {
+            self::$elements[$container] = array();
+        }
+
+        // Add media if not exists or point to existing media
+        if (!isset(self::$elements[$container][$mediaId])) {
+            $mediaCount = self::countElements($container);
+            $mediaTypeCount = self::countElements($container, $mediaType);
+            $mediaTypeCount++;
+            $rId = ++$mediaCount;
+            $target = null;
+            $mediaData = array('mediaIndex' => $mediaTypeCount);
+
+            switch ($mediaType) {
+                // Images
+                case 'image':
+                    if (is_null($image)) {
+                        throw new Exception('Image object not assigned.');
+                    }
+                    $isMemImage = $image->isMemImage();
+                    $extension = $image->getImageExtension();
+                    $mediaData['imageExtension'] = $extension;
+                    $mediaData['imageType'] = $image->getImageType();
+                    if ($isMemImage) {
+                        $mediaData['isMemImage'] = true;
+                        $mediaData['createFunction'] = $image->getImageCreateFunction();
+                        $mediaData['imageFunction'] = $image->getImageFunction();
+                    }
+                    $target = "{$container}_image{$mediaTypeCount}.{$extension}";
+                    $image->setTarget($target);
+                    $image->setMediaIndex($mediaTypeCount);
+                    break;
+
+                // Objects
+                case 'object':
+                    $target = "{$container}_oleObject{$mediaTypeCount}.bin";
+                    break;
+
+                // Links
+                case 'link':
+                    $target = $source;
+                    break;
+            }
+
+            $mediaData['source'] = $source;
+            $mediaData['target'] = $target;
+            $mediaData['type'] = $mediaType;
+            $mediaData['rID'] = $rId;
+            self::$elements[$container][$mediaId] = $mediaData;
+            return $rId;
+        } else {
+            $mediaData = self::$elements[$container][$mediaId];
+            if (!is_null($image)) {
+                $image->setTarget($mediaData['target']);
+                $image->setMediaIndex($mediaData['mediaIndex']);
+            }
+            return $mediaData['rID'];
+        }
+    }
+
+    /**
+     * Get media elements count
+     *
+     * @param string $container section|headerx|footerx|footnote|endnote
+     * @param string $mediaType image|object|link
+     * @return integer
+     * @since 0.10.0
+     */
+    public static function countElements($container, $mediaType = null)
+    {
+        $mediaCount = 0;
+
+        if (isset(self::$elements[$container])) {
+            foreach (self::$elements[$container] as $mediaData) {
+                if (!is_null($mediaType)) {
+                    if ($mediaType == $mediaData['type']) {
+                        $mediaCount++;
+                    }
+                } else {
+                    $mediaCount++;
+                }
+            }
+        }
+
+        return $mediaCount;
+    }
+
+    /**
+     * Get media elements
+     *
+     * @param string $container section|headerx|footerx|footnote|endnote
+     * @param string $type image|object|link
+     * @return array
+     * @since 0.10.0
+     */
+    public static function getElements($container, $type = null)
+    {
+        $elements = array();
+
+        // If header/footer, search for headerx and footerx where x is number
+        if ($container == 'header' || $container == 'footer') {
+            foreach (self::$elements as $key => $val) {
+                if (substr($key, 0, 6) == $container) {
+                    $elements[$key] = $val;
+                }
+            }
+            return $elements;
+        } else {
+            if (!isset(self::$elements[$container])) {
+                return $elements;
+            }
+            return self::getElementsByType($container, $type);
+        }
+    }
+
+    /**
+     * Get elements by media type
+     *
+     * @param string $container section|footnote|endnote
+     * @param string $type image|object|link
+     * @return array
+     * @since 0.11.0 Splitted from `getElements` to reduce complexity
+     */
+    private static function getElementsByType($container, $type = null)
+    {
+        $elements = array();
+
+        foreach (self::$elements[$container] as $key => $data) {
+            if ($type !== null) {
+                if ($type == $data['type']) {
+                    $elements[$key] = $data;
+                }
+            } else {
+                $elements[$key] = $data;
+            }
+        }
+
+        return $elements;
+    }
+
+    /**
+     * Reset media elements
+     */
+    public static function resetElements()
+    {
+        self::$elements = array();
+    }
+
+    /**
+     * Add new Section Media Element
+     *
+     * @param  string $src
+     * @param  string $type
+     * @param  \PhpOffice\PhpWord\Element\Image $image
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function addSectionMediaElement($src, $type, Image $image = null)
+    {
+        return self::addElement('section', $type, $src, $image);
+    }
+
+    /**
+     * Add new Section Link Element
+     *
+     * @param string $linkSrc
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function addSectionLinkElement($linkSrc)
+    {
+        return self::addElement('section', 'link', $linkSrc);
+    }
+
+    /**
+     * Get Section Media Elements
+     *
+     * @param string $key
+     * @return array
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function getSectionMediaElements($key = null)
+    {
+        return self::getElements('section', $key);
+    }
+
+    /**
+     * Get Section Media Elements Count
+     *
+     * @param string $key
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function countSectionMediaElements($key = null)
+    {
+        return self::countElements('section', $key);
+    }
+
+    /**
+     * Add new Header Media Element
+     *
+     * @param  integer $headerCount
+     * @param  string $src
+     * @param  \PhpOffice\PhpWord\Element\Image $image
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function addHeaderMediaElement($headerCount, $src, Image $image = null)
+    {
+        return self::addElement("header{$headerCount}", 'image', $src, $image);
+    }
+
+    /**
+     * Get Header Media Elements Count
+     *
+     * @param string $key
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function countHeaderMediaElements($key)
+    {
+        return self::countElements($key);
+    }
+
+    /**
+     * Get Header Media Elements
+     *
+     * @return array
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function getHeaderMediaElements()
+    {
+        return self::getElements('header');
+    }
+
+    /**
+     * Add new Footer Media Element
+     *
+     * @param  integer $footerCount
+     * @param  string $src
+     * @param  \PhpOffice\PhpWord\Element\Image $image
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function addFooterMediaElement($footerCount, $src, Image $image = null)
+    {
+        return self::addElement("footer{$footerCount}", 'image', $src, $image);
+    }
+
+    /**
+     * Get Footer Media Elements Count
+     *
+     * @param string $key
+     * @return integer
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function countFooterMediaElements($key)
+    {
+        return self::countElements($key);
+    }
+
+    /**
+     * Get Footer Media Elements
+     *
+     * @return array
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function getFooterMediaElements()
+    {
+        return self::getElements('footer');
+    }
+}

+ 62 - 0
includes/PhpWord/Metadata/Compatibility.php

@@ -0,0 +1,62 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Metadata;
+
+/**
+ * Compatibility setting class
+ *
+ * @since 0.12.0
+ * @link http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html
+ */
+class Compatibility
+{
+    /**
+     * OOXML version
+     *
+     * 12 = 2007
+     * 14 = 2010
+     * 15 = 2013
+     *
+     * @var int
+     * @link http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx
+     */
+    private $ooxmlVersion = 12;
+
+    /**
+     * Get OOXML version
+     *
+     * @return int
+     */
+    public function getOoxmlVersion()
+    {
+        return $this->ooxmlVersion;
+    }
+
+    /**
+     * Set OOXML version
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setOoxmlVersion($value)
+    {
+        $this->ooxmlVersion = $value;
+
+        return $this;
+    }
+}

+ 578 - 0
includes/PhpWord/Metadata/DocInfo.php

@@ -0,0 +1,578 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Metadata;
+
+/**
+ * Document information
+ */
+class DocInfo
+{
+    /** @const string Property type constants */
+    const PROPERTY_TYPE_BOOLEAN = 'b';
+    const PROPERTY_TYPE_INTEGER = 'i';
+    const PROPERTY_TYPE_FLOAT = 'f';
+    const PROPERTY_TYPE_DATE = 'd';
+    const PROPERTY_TYPE_STRING = 's';
+    const PROPERTY_TYPE_UNKNOWN = 'u';
+
+    /**
+     * Creator
+     *
+     * @var string
+     */
+    private $creator;
+
+    /**
+     * LastModifiedBy
+     *
+     * @var string
+     */
+    private $lastModifiedBy;
+
+    /**
+     * Created
+     *
+     * @var int
+     */
+    private $created;
+
+    /**
+     * Modified
+     *
+     * @var int
+     */
+    private $modified;
+
+    /**
+     * Title
+     *
+     * @var string
+     */
+    private $title;
+
+    /**
+     * Description
+     *
+     * @var string
+     */
+    private $description;
+
+    /**
+     * Subject
+     *
+     * @var string
+     */
+    private $subject;
+
+    /**
+     * Keywords
+     *
+     * @var string
+     */
+    private $keywords;
+
+    /**
+     * Category
+     *
+     * @var string
+     */
+    private $category;
+
+    /**
+     * Company
+     *
+     * @var string
+     */
+    private $company;
+
+    /**
+     * Manager
+     *
+     * @var string
+     */
+    private $manager;
+
+    /**
+     * Custom Properties
+     *
+     * @var array
+     */
+    private $customProperties = array();
+
+    /**
+     * Create new instance
+     */
+    public function __construct()
+    {
+        $this->creator        = '';
+        $this->lastModifiedBy = $this->creator;
+        $this->created        = time();
+        $this->modified       = time();
+        $this->title          = '';
+        $this->subject        = '';
+        $this->description    = '';
+        $this->keywords       = '';
+        $this->category       = '';
+        $this->company        = '';
+        $this->manager        = '';
+    }
+
+    /**
+     * Get Creator
+     *
+     * @return string
+     */
+    public function getCreator()
+    {
+        return $this->creator;
+    }
+
+    /**
+     * Set Creator
+     *
+     * @param  string $value
+     * @return self
+     */
+    public function setCreator($value = '')
+    {
+        $this->creator = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Last Modified By
+     *
+     * @return string
+     */
+    public function getLastModifiedBy()
+    {
+        return $this->lastModifiedBy;
+    }
+
+    /**
+     * Set Last Modified By
+     *
+     * @param  string $value
+     * @return self
+     */
+    public function setLastModifiedBy($value = '')
+    {
+        $this->lastModifiedBy = $this->setValue($value, $this->creator);
+
+        return $this;
+    }
+
+    /**
+     * Get Created
+     *
+     * @return int
+     */
+    public function getCreated()
+    {
+        return $this->created;
+    }
+
+    /**
+     * Set Created
+     *
+     * @param  int $value
+     * @return self
+     */
+    public function setCreated($value = null)
+    {
+        $this->created = $this->setValue($value, time());
+
+        return $this;
+    }
+
+    /**
+     * Get Modified
+     *
+     * @return int
+     */
+    public function getModified()
+    {
+        return $this->modified;
+    }
+
+    /**
+     * Set Modified
+     *
+     * @param  int $value
+     * @return self
+     */
+    public function setModified($value = null)
+    {
+        $this->modified = $this->setValue($value, time());
+
+        return $this;
+    }
+
+    /**
+     * Get Title
+     *
+     * @return string
+     */
+    public function getTitle()
+    {
+        return $this->title;
+    }
+
+    /**
+     * Set Title
+     *
+     * @param  string $value
+     * @return self
+     */
+    public function setTitle($value = '')
+    {
+        $this->title = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Description
+     *
+     * @return string
+     */
+    public function getDescription()
+    {
+        return $this->description;
+    }
+
+    /**
+     * Set Description
+     *
+     * @param  string $value
+     * @return self
+     */
+    public function setDescription($value = '')
+    {
+        $this->description = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Subject
+     *
+     * @return string
+     */
+    public function getSubject()
+    {
+        return $this->subject;
+    }
+
+    /**
+     * Set Subject
+     *
+     * @param  string $value
+     * @return self
+     */
+    public function setSubject($value = '')
+    {
+        $this->subject = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Keywords
+     *
+     * @return string
+     */
+    public function getKeywords()
+    {
+        return $this->keywords;
+    }
+
+    /**
+     * Set Keywords
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setKeywords($value = '')
+    {
+        $this->keywords = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Category
+     *
+     * @return string
+     */
+    public function getCategory()
+    {
+        return $this->category;
+    }
+
+    /**
+     * Set Category
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setCategory($value = '')
+    {
+        $this->category = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Company
+     *
+     * @return string
+     */
+    public function getCompany()
+    {
+        return $this->company;
+    }
+
+    /**
+     * Set Company
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setCompany($value = '')
+    {
+        $this->company = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get Manager
+     *
+     * @return string
+     */
+    public function getManager()
+    {
+        return $this->manager;
+    }
+
+    /**
+     * Set Manager
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setManager($value = '')
+    {
+        $this->manager = $this->setValue($value, '');
+
+        return $this;
+    }
+
+    /**
+     * Get a List of Custom Property Names
+     *
+     * @return array of string
+     */
+    public function getCustomProperties()
+    {
+        return array_keys($this->customProperties);
+    }
+
+    /**
+     * Check if a Custom Property is defined
+     *
+     * @param string $propertyName
+     * @return boolean
+     */
+    public function isCustomPropertySet($propertyName)
+    {
+        return isset($this->customProperties[$propertyName]);
+    }
+
+    /**
+     * Get a Custom Property Value
+     *
+     * @param string $propertyName
+     * @return string
+     */
+    public function getCustomPropertyValue($propertyName)
+    {
+        if ($this->isCustomPropertySet($propertyName)) {
+            return $this->customProperties[$propertyName]['value'];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get a Custom Property Type
+     *
+     * @param string $propertyName
+     * @return string
+     */
+    public function getCustomPropertyType($propertyName)
+    {
+        if ($this->isCustomPropertySet($propertyName)) {
+            return $this->customProperties[$propertyName]['type'];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set a Custom Property
+     *
+     * @param string $propertyName
+     * @param mixed $propertyValue
+     * @param string $propertyType
+     *   'i': Integer
+     *   'f': Floating Point
+     *   's': String
+     *   'd': Date/Time
+     *   'b': Boolean
+     * @return self
+     */
+    public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)
+    {
+        $propertyTypes = array(
+            self::PROPERTY_TYPE_INTEGER,
+            self::PROPERTY_TYPE_FLOAT,
+            self::PROPERTY_TYPE_STRING,
+            self::PROPERTY_TYPE_DATE,
+            self::PROPERTY_TYPE_BOOLEAN
+        );
+        if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) {
+            if ($propertyValue === null) {
+                $propertyType = self::PROPERTY_TYPE_STRING;
+            } elseif (is_float($propertyValue)) {
+                $propertyType = self::PROPERTY_TYPE_FLOAT;
+            } elseif (is_int($propertyValue)) {
+                $propertyType = self::PROPERTY_TYPE_INTEGER;
+            } elseif (is_bool($propertyValue)) {
+                $propertyType = self::PROPERTY_TYPE_BOOLEAN;
+            } else {
+                $propertyType = self::PROPERTY_TYPE_STRING;
+            }
+        }
+
+        $this->customProperties[$propertyName] = array(
+            'value' => $propertyValue,
+            'type' => $propertyType
+        );
+        return $this;
+    }
+
+    /**
+     * Convert document property based on type
+     *
+     * @param string $propertyValue
+     * @param string $propertyType
+     * @return mixed
+     */
+    public static function convertProperty($propertyValue, $propertyType)
+    {
+        $conversion = self::getConversion($propertyType);
+
+        switch ($conversion) {
+            case 'empty': // Empty
+                return '';
+            case 'null': // Null
+                return null;
+            case 'int': // Signed integer
+                return (int) $propertyValue;
+            case 'uint': // Unsigned integer
+                return abs((int) $propertyValue);
+            case 'float': // Float
+                return (float) $propertyValue;
+            case 'date': // Date
+                return strtotime($propertyValue);
+            case 'bool': // Boolean
+                return ($propertyValue == 'true') ? true : false;
+        }
+
+        return $propertyValue;
+    }
+
+    /**
+     * Convert document property type
+     *
+     * @param string $propertyType
+     * @return string
+     */
+    public static function convertPropertyType($propertyType)
+    {
+        $typeGroups = array(
+            self::PROPERTY_TYPE_INTEGER => array('i1', 'i2', 'i4', 'i8', 'int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint'),
+            self::PROPERTY_TYPE_FLOAT   => array('r4', 'r8', 'decimal'),
+            self::PROPERTY_TYPE_STRING  => array('empty', 'null', 'lpstr', 'lpwstr', 'bstr'),
+            self::PROPERTY_TYPE_DATE    => array('date', 'filetime'),
+            self::PROPERTY_TYPE_BOOLEAN => array('bool'),
+        );
+        foreach ($typeGroups as $groupId => $groupMembers) {
+            if (in_array($propertyType, $groupMembers)) {
+                return $groupId;
+            }
+        }
+
+        return self::PROPERTY_TYPE_UNKNOWN;
+    }
+
+    /**
+     * Set default for null and empty value
+     *
+     * @param mixed $value
+     * @param mixed $default
+     * @return mixed
+     */
+    private function setValue($value, $default)
+    {
+        if ($value === null || $value == '') {
+            $value = $default;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Get conversion model depending on property type
+     *
+     * @param string $propertyType
+     * @return string
+     */
+    private static function getConversion($propertyType)
+    {
+        $conversions = array(
+            'empty' => array('empty'),
+            'null'  => array('null'),
+            'int'   => array('i1', 'i2', 'i4', 'i8', 'int'),
+            'uint'  => array('ui1', 'ui2', 'ui4', 'ui8', 'uint'),
+            'float' => array('r4', 'r8', 'decimal'),
+            'bool'  => array('bool'),
+            'date'  => array('date', 'filetime'),
+        );
+        foreach ($conversions as $conversion => $types) {
+            if (in_array($propertyType, $types)) {
+                return $conversion;
+            }
+        }
+
+        return 'string';
+    }
+}

+ 69 - 0
includes/PhpWord/Metadata/Protection.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Metadata;
+
+/**
+ * Document protection class
+ *
+ * @since 0.12.0
+ * @link http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html
+ * @todo Password!
+ */
+class Protection
+{
+    /**
+     * Editing restriction readOnly|comments|trackedChanges|forms
+     *
+     * @var string
+     * @link http://www.datypic.com/sc/ooxml/a-w_edit-1.html
+     */
+    private $editing;
+
+    /**
+     * Create a new instance
+     *
+     * @param string $editing
+     */
+    public function __construct($editing = null)
+    {
+        $this->setEditing($editing);
+    }
+
+    /**
+     * Get editing protection
+     *
+     * @return string
+     */
+    public function getEditing()
+    {
+        return $this->editing;
+    }
+
+    /**
+     * Set editing protection
+     *
+     * @param string $editing
+     * @return self
+     */
+    public function setEditing($editing = null)
+    {
+        $this->editing = $editing;
+
+        return $this;
+    }
+}

+ 358 - 0
includes/PhpWord/PhpWord.php

@@ -0,0 +1,358 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord;
+
+use PhpOffice\PhpWord\Element\Section;
+use PhpOffice\PhpWord\Exception\Exception;
+
+/**
+ * PHPWord main class
+ *
+ * @method Collection\Titles getTitles()
+ * @method Collection\Footnotes getFootnotes()
+ * @method Collection\Endnotes getEndnotes()
+ * @method Collection\Charts getCharts()
+ * @method int addBookmark(Element\Bookmark $bookmark)
+ * @method int addTitle(Element\Title $title)
+ * @method int addFootnote(Element\Footnote $footnote)
+ * @method int addEndnote(Element\Endnote $endnote)
+ * @method int addChart(Element\Chart $chart)
+ *
+ * @method Style\Paragraph addParagraphStyle(string $styleName, array $styles)
+ * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null)
+ * @method Style\Font addLinkStyle(string $styleName, mixed $styles)
+ * @method Style\Font addTitleStyle(int $depth, mixed $fontStyle, mixed $paragraphStyle = null)
+ * @method Style\Table addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null)
+ * @method Style\Numbering addNumberingStyle(string $styleName, mixed $styles)
+ */
+class PhpWord
+{
+    /**
+     * Default font settings
+     *
+     * @const string|int
+     * @deprecated 0.11.0 Use Settings constants
+     */
+    const DEFAULT_FONT_NAME = Settings::DEFAULT_FONT_NAME;
+    const DEFAULT_FONT_SIZE = Settings::DEFAULT_FONT_SIZE;
+    const DEFAULT_FONT_COLOR = Settings::DEFAULT_FONT_COLOR;
+    const DEFAULT_FONT_CONTENT_TYPE = Settings::DEFAULT_FONT_CONTENT_TYPE;
+
+    /**
+     * Collection of sections
+     *
+     * @var \PhpOffice\PhpWord\Element\Section[]
+     */
+    private $sections = array();
+
+    /**
+     * Collections
+     *
+     * @var array
+     */
+    private $collections = array();
+
+    /**
+     * Metadata
+     *
+     * @var array
+     * @since 0.12.0
+     */
+    private $metadata = array();
+
+    /**
+     * Create new instance
+     *
+     * Collections are created dynamically
+     */
+    public function __construct()
+    {
+        // Collection
+        $collections = array('Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts');
+        foreach ($collections as $collection) {
+            $class = 'PhpOffice\\PhpWord\\Collection\\' . $collection;
+            $this->collections[$collection] = new $class();
+        }
+
+        // Metadata
+        $metadata = array('DocInfo', 'Protection', 'Compatibility');
+        foreach ($metadata as $meta) {
+            $class = 'PhpOffice\\PhpWord\\Metadata\\' . $meta;
+            $this->metadata[$meta] = new $class();
+        }
+    }
+
+    /**
+     * Dynamic function call to reduce static dependency
+     *
+     * @param mixed $function
+     * @param mixed $args
+     * @throws \BadMethodCallException
+     * @return mixed
+     * @since 0.12.0
+     */
+    public function __call($function, $args)
+    {
+        $function = strtolower($function);
+
+        $getCollection = array();
+        $addCollection = array();
+        $addStyle = array();
+
+        $collections = array('Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart');
+        foreach ($collections as $collection) {
+            $getCollection[] = strtolower("get{$collection}s");
+            $addCollection[] = strtolower("add{$collection}");
+        }
+
+        $styles = array('Paragraph', 'Font', 'Table', 'Numbering', 'Link', 'Title');
+        foreach ($styles as $style) {
+            $addStyle[] = strtolower("add{$style}Style");
+        }
+
+        // Run get collection method
+        if (in_array($function, $getCollection)) {
+            $key = ucfirst(str_replace('get', '', $function));
+
+            return $this->collections[$key];
+        }
+
+        // Run add collection item method
+        if (in_array($function, $addCollection)) {
+            $key = ucfirst(str_replace('add', '', $function) . 's');
+
+            /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collectionObject */
+            $collectionObject = $this->collections[$key];
+
+            return $collectionObject->addItem(isset($args[0]) ? $args[0] : null);
+        }
+
+        // Run add style method
+        if (in_array($function, $addStyle)) {
+            return forward_static_call_array(array('PhpOffice\\PhpWord\\Style', $function), $args);
+        }
+
+        // Exception
+        throw new \BadMethodCallException("Method $function is not defined.");
+    }
+
+    /**
+     * Get document properties object
+     *
+     * @return \PhpOffice\PhpWord\Metadata\DocInfo
+     */
+    public function getDocInfo()
+    {
+        return $this->metadata['DocInfo'];
+    }
+
+    /**
+     * Get protection
+     *
+     * @return \PhpOffice\PhpWord\Metadata\Protection
+     * @since 0.12.0
+     */
+    public function getProtection()
+    {
+        return $this->metadata['Protection'];
+    }
+
+    /**
+     * Get compatibility
+     *
+     * @return \PhpOffice\PhpWord\Metadata\Compatibility
+     * @since 0.12.0
+     */
+    public function getCompatibility()
+    {
+        return $this->metadata['Compatibility'];
+    }
+
+    /**
+     * Get all sections
+     *
+     * @return \PhpOffice\PhpWord\Element\Section[]
+     */
+    public function getSections()
+    {
+        return $this->sections;
+    }
+
+    /**
+     * Create new section
+     *
+     * @param array $style
+     * @return \PhpOffice\PhpWord\Element\Section
+     */
+    public function addSection($style = null)
+    {
+        $section = new Section(count($this->sections) + 1, $style);
+        $section->setPhpWord($this);
+        $this->sections[] = $section;
+
+        return $section;
+    }
+
+    /**
+     * Get default font name
+     *
+     * @return string
+     */
+    public function getDefaultFontName()
+    {
+        return Settings::getDefaultFontName();
+    }
+
+    /**
+     * Set default font name.
+     *
+     * @param string $fontName
+     * @return void
+     */
+    public function setDefaultFontName($fontName)
+    {
+        Settings::setDefaultFontName($fontName);
+    }
+
+    /**
+     * Get default font size
+     *
+     * @return integer
+     */
+    public function getDefaultFontSize()
+    {
+        return Settings::getDefaultFontSize();
+    }
+
+    /**
+     * Set default font size.
+     *
+     * @param int $fontSize
+     * @return void
+     */
+    public function setDefaultFontSize($fontSize)
+    {
+        Settings::setDefaultFontSize($fontSize);
+    }
+
+    /**
+     * Set default paragraph style definition to styles.xml
+     *
+     * @param array $styles Paragraph style definition
+     * @return \PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function setDefaultParagraphStyle($styles)
+    {
+        return Style::setDefaultParagraphStyle($styles);
+    }
+
+    /**
+     * Load template by filename
+     *
+     * @deprecated 0.12.0 Use `new TemplateProcessor($documentTemplate)` instead.
+     *
+     * @param  string $filename Fully qualified filename.
+     * @return TemplateProcessor
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     */
+    public function loadTemplate($filename)
+    {
+        if (file_exists($filename)) {
+            return new TemplateProcessor($filename);
+        } else {
+            throw new Exception("Template file {$filename} not found.");
+        }
+    }
+
+    /**
+     * Save to file or download
+     *
+     * All exceptions should already been handled by the writers
+     *
+     * @param string $filename
+     * @param string $format
+     * @param bool $download
+     * @return bool
+     */
+    public function save($filename, $format = 'Word2007', $download = false)
+    {
+        $mime = array(
+            'Word2007'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+            'ODText'    => 'application/vnd.oasis.opendocument.text',
+            'RTF'       => 'application/rtf',
+            'HTML'      => 'text/html',
+            'PDF'       => 'application/pdf',
+        );
+
+        $writer = IOFactory::createWriter($this, $format);
+
+        if ($download === true) {
+            header("Content-Description: File Transfer");
+            header('Content-Disposition: attachment; filename="' . $filename . '"');
+            header('Content-Type: ' . $mime[$format]);
+            header('Content-Transfer-Encoding: binary');
+            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+            header('Expires: 0');
+            $filename = 'php://output'; // Change filename to force download
+        }
+
+        $writer->save($filename);
+
+        return true;
+    }
+
+    /**
+     * Create new section
+     *
+     * @param array $settings
+     * @return \PhpOffice\PhpWord\Element\Section
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function createSection($settings = null)
+    {
+        return $this->addSection($settings);
+    }
+
+    /**
+     * Get document properties object
+     *
+     * @return \PhpOffice\PhpWord\Metadata\DocInfo
+     * @deprecated 0.12.0
+     * @codeCoverageIgnore
+     */
+    public function getDocumentProperties()
+    {
+        return $this->getDocInfo();
+    }
+
+    /**
+     * Set document properties object
+     *
+     * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties
+     * @return self
+     * @deprecated 0.12.0
+     * @codeCoverageIgnore
+     */
+    public function setDocumentProperties($documentProperties)
+    {
+        $this->metadata['Document'] = $documentProperties;
+
+        return $this;
+    }
+}

+ 119 - 0
includes/PhpWord/Reader/AbstractReader.php

@@ -0,0 +1,119 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+use PhpOffice\PhpWord\Exception\Exception;
+
+/**
+ * Reader abstract class
+ *
+ * @since 0.8.0
+ * @codeCoverageIgnore Abstract class
+ */
+abstract class AbstractReader implements ReaderInterface
+{
+    /**
+     * Read data only?
+     *
+     * @var bool
+     */
+    protected $readDataOnly = true;
+
+    /**
+     * File pointer
+     *
+     * @var bool|resource
+     */
+    protected $fileHandle;
+
+    /**
+     * Read data only?
+     *
+     * @return bool
+     */
+    public function isReadDataOnly()
+    {
+        // return $this->readDataOnly;
+        return true;
+    }
+
+    /**
+     * Set read data only
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setReadDataOnly($value = true)
+    {
+        $this->readDataOnly = $value;
+        return $this;
+    }
+
+    /**
+     * Open file for reading
+     *
+     * @param string $filename
+     * @return resource
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     */
+    protected function openFile($filename)
+    {
+        // Check if file exists
+        if (!file_exists($filename) || !is_readable($filename)) {
+            throw new Exception("Could not open " . $filename . " for reading! File does not exist.");
+        }
+
+        // Open file
+        $this->fileHandle = fopen($filename, 'r');
+        if ($this->fileHandle === false) {
+            throw new Exception("Could not open file " . $filename . " for reading.");
+        }
+    }
+
+    /**
+     * Can the current ReaderInterface read the file?
+     *
+     * @param string $filename
+     * @return bool
+     */
+    public function canRead($filename)
+    {
+        // Check if file exists
+        try {
+            $this->openFile($filename);
+        } catch (Exception $e) {
+            return false;
+        }
+        if (is_resource($this->fileHandle)) {
+            fclose($this->fileHandle);
+        }
+
+        return true;
+    }
+
+    /**
+     * Read data only?
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getReadDataOnly()
+    {
+        return $this->isReadDataOnly();
+    }
+}

+ 50 - 0
includes/PhpWord/Reader/HTML.php

@@ -0,0 +1,50 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\Html as HTMLParser;
+
+/**
+ * HTML Reader class
+ *
+ * @since 0.11.0
+ */
+class HTML extends AbstractReader implements ReaderInterface
+{
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $docFile
+     * @throws \Exception
+     * @return \PhpOffice\PhpWord\PhpWord
+     */
+    public function load($docFile)
+    {
+        $phpWord = new PhpWord();
+
+        if ($this->canRead($docFile)) {
+            $section = $phpWord->addSection();
+            HTMLParser::addHtml($section, file_get_contents($docFile), true);
+        } else {
+            throw new \Exception("Cannot read {$docFile}.");
+        }
+
+        return $phpWord;
+    }
+}

+ 2341 - 0
includes/PhpWord/Reader/MsDoc.php

@@ -0,0 +1,2341 @@
+<?php
+/**
+ * PHPWord
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2014 PHPWord
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\Drawing;
+use PhpOffice\PhpWord\Shared\OLERead;
+use PhpOffice\PhpWord\Style;
+
+/**
+ * Reader for Word97
+ *
+ * @since 0.10.0
+ */
+class MsDoc extends AbstractReader implements ReaderInterface
+{
+    /**
+     * PhpWord object
+     *
+     * @var PhpWord
+     */
+    private $phpWord;
+
+    /**
+     * WordDocument Stream
+     *
+     * @var
+     */
+    private $dataWorkDocument;
+    /**
+     * 1Table Stream
+     *
+     * @var
+     */
+    private $data1Table;
+    /**
+     * Data Stream
+     *
+     * @var
+     */
+    private $dataData;
+    /**
+     * Object Pool Stream
+     *
+     * @var
+     */
+    private $dataObjectPool;
+    /**
+     * @var \stdClass[]
+     */
+    private $arrayCharacters = array();
+    /**
+     * @var array
+     */
+    private $arrayFib = array();
+    /**
+     * @var string[]
+     */
+    private $arrayFonts = array();
+    /**
+     * @var string[]
+     */
+    private $arrayParagraphs = array();
+    /**
+     * @var \stdClass[]
+     */
+    private $arraySections = array();
+
+    const VERSION_97 = '97';
+    const VERSION_2000 = '2000';
+    const VERSION_2002 = '2002';
+    const VERSION_2003 = '2003';
+    const VERSION_2007 = '2007';
+
+    const SPRA_VALUE = 10;
+    const SPRA_VALUE_OPPOSITE = 20;
+
+    const OFFICEARTBLIPEMF = 0xF01A;
+    const OFFICEARTBLIPWMF = 0xF01B;
+    const OFFICEARTBLIPPICT = 0xF01C;
+    const OFFICEARTBLIPJPG = 0xF01D;
+    const OFFICEARTBLIPPNG = 0xF01E;
+    const OFFICEARTBLIPDIB = 0xF01F;
+    const OFFICEARTBLIPTIFF = 0xF029;
+    const OFFICEARTBLIPJPEG = 0xF02A;
+
+    const MSOBLIPERROR = 0x00;
+    const MSOBLIPUNKNOWN = 0x01;
+    const MSOBLIPEMF = 0x02;
+    const MSOBLIPWMF = 0x03;
+    const MSOBLIPPICT = 0x04;
+    const MSOBLIPJPEG = 0x05;
+    const MSOBLIPPNG = 0x06;
+    const MSOBLIPDIB = 0x07;
+    const MSOBLIPTIFF = 0x11;
+    const MSOBLIPCMYKJPEG = 0x12;
+
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $filename
+     * @return PhpWord
+     */
+    public function load($filename)
+    {
+        $this->phpWord = new PhpWord();
+
+        $this->loadOLE($filename);
+
+        $this->readFib($this->dataWorkDocument);
+        $this->readFibContent();
+
+        return $this->phpWord;
+    }
+
+    /**
+     * Load an OLE Document
+     * @param string $filename
+     */
+    private function loadOLE($filename)
+    {
+        // OLE reader
+        $ole = new OLERead();
+        $ole->read($filename);
+
+        // Get WorkDocument stream
+        $this->dataWorkDocument = $ole->getStream($ole->wrkdocument);
+        // Get 1Table stream
+        $this->data1Table = $ole->getStream($ole->wrk1Table);
+        // Get Data stream
+        $this->dataData = $ole->getStream($ole->wrkData);
+        // Get Data stream
+        $this->dataObjectPool = $ole->getStream($ole->wrkObjectPool);
+        // Get Summary Information data
+        $this->_SummaryInformation = $ole->getStream($ole->summaryInformation);
+        // Get Document Summary Information data
+        $this->_DocumentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
+    }
+
+    private function getNumInLcb($lcb, $iSize)
+    {
+        return ($lcb - 4) / (4 + $iSize);
+    }
+
+    private function getArrayCP($data, $posMem, $iNum)
+    {
+        $arrayCP = array();
+        for ($inc = 0; $inc < $iNum; $inc++) {
+            $arrayCP[$inc] = self::getInt4d($data, $posMem);
+            $posMem += 4;
+        }
+        return $arrayCP;
+    }
+
+    /**
+     *
+     * @link http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx
+     * @link https://igor.io/2012/09/24/binary-parsing.html
+     */
+    private function readFib($data)
+    {
+        $pos = 0;
+        //----- FibBase
+        // wIdent
+        $pos += 2;
+        // nFib
+        $pos += 2;
+        // unused
+        $pos += 2;
+        // lid : Language Identifier
+        $pos += 2;
+        // pnNext
+        $pos += 2;
+
+        // $mem = self::getInt2d($data, $pos);
+        // $fDot = ($mem >> 15) & 1;
+        // $fGlsy = ($mem >> 14) & 1;
+        // $fComplex = ($mem >> 13) & 1;
+        // $fHasPic = ($mem >> 12) & 1;
+        // $cQuickSaves = ($mem >> 8) & bindec('1111');
+        // $fEncrypted = ($mem >> 7) & 1;
+        // $fWhichTblStm = ($mem >> 6) & 1;
+        // $fReadOnlyRecommended = ($mem >> 5) & 1;
+        // $fWriteReservation = ($mem >> 4) & 1;
+        // $fExtChar = ($mem >> 3) & 1;
+        // $fLoadOverride = ($mem >> 2) & 1;
+        // $fFarEast = ($mem >> 1) & 1;
+        // $fObfuscated = ($mem >> 0) & 1;
+        $pos += 2;
+        // nFibBack
+        $pos += 2;
+        // lKey
+        $pos += 4;
+        // envr
+        $pos += 1;
+
+        // $mem = self::getInt1d($data, $pos);
+        // $fMac = ($mem >> 7) & 1;
+        // $fEmptySpecial = ($mem >> 6) & 1;
+        // $fLoadOverridePage = ($mem >> 5) & 1;
+        // $reserved1 = ($mem >> 4) & 1;
+        // $reserved2 = ($mem >> 3) & 1;
+        // $fSpare0 = ($mem >> 0) & bindec('111');
+        $pos += 1;
+
+        // reserved3
+        $pos += 2;
+        // reserved4
+        $pos += 2;
+        // reserved5
+        $pos += 4;
+        // reserved6
+        $pos += 4;
+
+        //----- csw
+        $pos += 2;
+
+        //----- fibRgW
+        // reserved1
+        $pos += 2;
+        // reserved2
+        $pos += 2;
+        // reserved3
+        $pos += 2;
+        // reserved4
+        $pos += 2;
+        // reserved5
+        $pos += 2;
+        // reserved6
+        $pos += 2;
+        // reserved7
+        $pos += 2;
+        // reserved8
+        $pos += 2;
+        // reserved9
+        $pos += 2;
+        // reserved10
+        $pos += 2;
+        // reserved11
+        $pos += 2;
+        // reserved12
+        $pos += 2;
+        // reserved13
+        $pos += 2;
+        // lidFE
+        $pos += 2;
+
+        //----- cslw
+        $pos += 2;
+
+        //----- fibRgLw
+        // cbMac
+        $pos += 4;
+        // reserved1
+        $pos += 4;
+        // reserved2
+        $pos += 4;
+        $this->arrayFib['ccpText'] = self::getInt4d($data, $pos);
+        $pos += 4;
+        $this->arrayFib['ccpFtn'] = self::getInt4d($data, $pos);
+        $pos += 4;
+        $this->arrayFib['ccpHdd'] = self::getInt4d($data, $pos);
+        $pos += 4;
+        // reserved3
+        $pos += 4;
+        // ccpAtn
+        $pos += 4;
+        // ccpEdn
+        $pos += 4;
+        // ccpTxbx
+        $pos += 4;
+        // ccpHdrTxbx
+        $pos += 4;
+        // reserved4
+        $pos += 4;
+        // reserved5
+        $pos += 4;
+        // reserved6
+        $pos += 4;
+        // reserved7
+        $pos += 4;
+        // reserved8
+        $pos += 4;
+        // reserved9
+        $pos += 4;
+        // reserved10
+        $pos += 4;
+        // reserved11
+        $pos += 4;
+        // reserved12
+        $pos += 4;
+        // reserved13
+        $pos += 4;
+        // reserved14
+        $pos += 4;
+
+        //----- cbRgFcLcb
+        $cbRgFcLcb = self::getInt2d($data, $pos);
+        $pos += 2;
+        //----- fibRgFcLcbBlob
+        switch ($cbRgFcLcb) {
+            case 0x005D:
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);
+                break;
+            case 0x006C:
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);
+                break;
+            case 0x0088:
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002);
+                break;
+            case 0x00A4:
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2003);
+                break;
+            case 0x00B7:
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2003);
+                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2007);
+                break;
+        }
+        //----- cswNew
+        $this->arrayFib['cswNew'] = self::getInt2d($data, $pos);
+        $pos += 2;
+
+        if ($this->arrayFib['cswNew'] != 0) {
+            //@todo : fibRgCswNew
+        }
+
+        return $pos;
+    }
+
+    private function readBlockFibRgFcLcb($data, $pos, $version)
+    {
+        if ($version == self::VERSION_97) {
+            $this->arrayFib['fcStshfOrig'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbStshfOrig'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcStshf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbStshf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcffndRef'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcffndRef'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcffndTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcffndTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfandRef'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfandRef'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfandTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfandTxt '] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfSed'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfSed'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcPad'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcPad'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfPhe'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfPhe'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfGlsy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfGlsy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfGlsy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfGlsy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfHdd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfHdd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBteChpx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBteChpx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBtePapx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBtePapx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfSea'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfSea'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfFfn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfFfn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldMom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldMom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldHdr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldHdr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldAtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldAtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldMcr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldMcr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmk'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmk'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcCmds'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbCmds'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused1'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused1'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfMcr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfMcr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPrDrvr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPrDrvr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPrEnvPort'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPrEnvPort'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPrEnvLand'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPrEnvLand'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcWss'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbWss'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcDop'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbDop'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfAssoc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfAssoc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcClx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbClx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfPgdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfPgdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcAutosaveSource'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbAutosaveSource'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcGrpXstAtnOwners'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbGrpXstAtnOwners'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfAtnBkmk'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfAtnBkmk'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused2'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused2'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused3'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused3'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcSpaMom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcSpaMom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcSpaHdr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcSpaHdr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfAtnBkf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfAtnBkf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfAtnBkl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfAtnBkl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPms'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPms'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcFormFldSttbs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbFormFldSttbs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfendRef'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfendRef'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfendTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfendTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused4'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused4'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcDggInfo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbDggInfo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfRMark'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfRMark'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfCaption'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfCaption'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfAutoCaption'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfAutoCaption'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfWkb'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfWkb'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfSpl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfSpl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcftxbxTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcftxbxTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfFldTxbx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfFldTxbx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfHdrtxbxTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfHdrtxbxTxt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcffldHdrTxbx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcffldHdrTxbx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcStwUser'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbStwUser'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbTtmbd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbTtmbd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcCookieData'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbCookieData'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdMotherOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdMotherOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdMotherOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdMotherOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdFtnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdFtnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdFtnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdFtnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdEdnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdEdnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdEdnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdEdnOldOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfIntlFld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfIntlFld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcRouteSlip'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbRouteSlip'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbSavedBy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbSavedBy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbFnm'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbFnm'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlfLst'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlfLst'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlfLfo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlfLfo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfTxbxBkd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfTxbxBkd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfTxbxHdrBkd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfTxbxHdrBkd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcDocUndoWord9'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbDocUndoWord9'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcRgbUse'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbRgbUse'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUsp'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUsp'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUskf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUskf'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcupcRgbUse'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcupcRgbUse'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcupcUsp'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcupcUsp'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbGlsyStyle'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbGlsyStyle'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlgosl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlgosl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcocx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcocx'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBteLvc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBteLvc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['dwLowDateTime'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['dwHighDateTime'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfLvcPre10'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfLvcPre10'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfAsumy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfAsumy'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfGram'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfGram'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbListNames'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbListNames'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfUssr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfUssr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+        }
+        if ($version == self::VERSION_2000) {
+            $this->arrayFib['fcPlcfTch'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfTch'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcRmdThreading'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbRmdThreading'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcMid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbMid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbRgtplc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbRgtplc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcMsoEnvelope'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbMsoEnvelope'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfLad'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfLad'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcRgDofr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbRgDofr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcosl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcosl'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfCookieOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfCookieOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdMotherOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdMotherOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdMotherOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdMotherOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdFtnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdFtnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdFtnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdFtnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdEdnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdEdnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdEdnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdEdnOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+        }
+        if ($version == self::VERSION_2002) {
+            $this->arrayFib['fcUnused1'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused1'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfPgp'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfPgp'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfuim'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfuim'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlfguidUim'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlfguidUim'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcAtrdExtra'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbAtrdExtra'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlrsid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlrsid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkFactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkFactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfFactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfFactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfcookie'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfcookie'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklFactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklFactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcFactoidData'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbFactoidData'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcDocUndo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbDocUndo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkFcc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkFcc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfFcc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfFcc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklFcc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklFcc'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfbkmkBPRepairs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfbkmkBPRepairs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfbkfBPRepairs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfbkfBPRepairs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfbklBPRepairs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfbklBPRepairs'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPmsNew'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPmsNew'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcODSO'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbODSO'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiOldXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiOldXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiNewXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiNewXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiMixedXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiMixedXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused2'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused2'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcffactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcffactoid'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcOldXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcOldXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcNewXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcNewXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcMixedXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcMixedXP'] = self::getInt4d($data, $pos);
+            $pos += 4;
+        }
+        if ($version == self::VERSION_2003) {
+            $this->arrayFib['fcHplxsdr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbHplxsdr'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkSdt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkSdt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfSdt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfSdt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklSdt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklSdt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcCustomXForm'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbCustomXForm'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkProt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkProt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfProt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfProt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklProt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklProt'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbProtUser'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbProtUser'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiOldInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiOldInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiNew'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiNew'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfpmiNewInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfpmiNewInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcOld'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcOldInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcOldInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcNew'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcNew'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcflvcNewInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcflvcNewInline'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdMother'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdMother'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdMother'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdMother'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcAfdMother'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbAfdMother'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcAfdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbAfdFtn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPgdEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPgdEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcBkdEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbBkdEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcAfdEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbAfdEdn'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcAfd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbAfd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+        }
+        if ($version == self::VERSION_2007) {
+            $this->arrayFib['fcPlcfmthd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfmthd'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkMoveFrom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkMoveFrom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfMoveFrom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfMoveFrom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklMoveFrom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklMoveFrom'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkMoveTo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkMoveTo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfMoveTo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfMoveTo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklMoveTo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklMoveTo'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused1'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused1'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused2'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused2'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused3'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused3'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcSttbfBkmkArto'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbSttbfBkmkArto'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBkfArto'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBkfArto'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcPlcfBklArto'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbPlcfBklArto'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcArtoData'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbArtoData'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused4'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused4'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused5'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused5'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcUnused6'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbUnused6'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcOssTheme'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbOssTheme'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['fcColorSchemeMapping'] = self::getInt4d($data, $pos);
+            $pos += 4;
+            $this->arrayFib['lcbColorSchemeMapping'] = self::getInt4d($data, $pos);
+            $pos += 4;
+        }
+        return $pos;
+    }
+
+    private function readFibContent()
+    {
+        // Informations about Font
+        $this->readRecordSttbfFfn();
+
+        // Informations about page
+        $this->readRecordPlcfSed();
+
+        // reading paragraphs
+        //@link https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L86
+        $this->readRecordPlcfBtePapx();
+
+        // reading character formattings
+        //@link https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L94
+        $this->readRecordPlcfBteChpx();
+
+        $this->generatePhpWord();
+    }
+
+    /**
+     * Section and information about them
+     * @link : http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx
+     */
+    private function readRecordPlcfSed()
+    {
+        $posMem = $this->arrayFib['fcPlcfSed'];
+        // PlcfSed
+        // PlcfSed : aCP
+        $aCP = array();
+        $aCP[0] = self::getInt4d($this->data1Table, $posMem);
+        $posMem += 4;
+        $aCP[1] = self::getInt4d($this->data1Table, $posMem);
+        $posMem += 4;
+
+        // PlcfSed : aSed
+        //@link : http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx
+        $numSed = $this->getNumInLcb($this->arrayFib['lcbPlcfSed'], 12);
+
+        $aSed = array();
+        for ($iInc = 0; $iInc < $numSed; ++$iInc) {
+            // Sed : http://msdn.microsoft.com/en-us/library/dd950982%28v=office.12%29.aspx
+            // fn
+            $posMem += 2;
+            // fnMpr
+            $aSed[$iInc] = self::getInt4d($this->data1Table, $posMem);
+            $posMem += 4;
+            // fnMpr
+            $posMem += 2;
+            // fcMpr
+            $posMem += 4;
+        }
+
+        foreach ($aSed as $offsetSed) {
+            // Sepx : http://msdn.microsoft.com/en-us/library/dd921348%28v=office.12%29.aspx
+            $cb = self::getInt2d($this->dataWorkDocument, $offsetSed);
+            $offsetSed += 2;
+
+            $oStylePrl = $this->readPrl($this->dataWorkDocument, $offsetSed, $cb);
+            $offsetSed += $oStylePrl->length;
+
+            $this->arraySections[] = $oStylePrl;
+        }
+    }
+
+    /**
+     * Specifies the fonts that are used in the document
+     * @link : http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx
+     */
+    private function readRecordSttbfFfn()
+    {
+        $posMem = $this->arrayFib['fcSttbfFfn'];
+
+        $cData = self::getInt2d($this->data1Table, $posMem);
+        $posMem += 2;
+        $cbExtra = self::getInt2d($this->data1Table, $posMem);
+        $posMem += 2;
+
+        if ($cData < 0x7FF0 && $cbExtra == 0) {
+            for ($inc = 0; $inc < $cData; $inc++) {
+                // len
+                $posMem += 1;
+                // ffid
+                $posMem += 1;
+                // wWeight (400 : Normal - 700 bold)
+                $posMem += 2;
+                // chs
+                $posMem += 1;
+                // ixchSzAlt
+                $ixchSzAlt = self::getInt1d($this->data1Table, $posMem);
+                $posMem += 1;
+                // panose
+                $posMem += 10;
+                // fs
+                $posMem += 24;
+                // xszFfn
+                $xszFfn = '';
+                do {
+                    $char = self::getInt2d($this->data1Table, $posMem);
+                    $posMem += 2;
+                    if ($char > 0) {
+                        $xszFfn .= chr($char);
+                    }
+                } while ($char != 0);
+                // xszAlt
+                $xszAlt = '';
+                if ($ixchSzAlt > 0) {
+                    do {
+                        $char = self::getInt2d($this->data1Table, $posMem);
+                        $posMem += 2;
+                        if ($char == 0) {
+                            break;
+                        }
+                        $xszAlt .= chr($char);
+                    } while ($char != 0);
+                }
+                $this->arrayFonts[] = array(
+                    'main' => $xszFfn,
+                    'alt' => $xszAlt,
+                );
+            }
+        }
+    }
+
+    /**
+     * Paragraph and information about them
+     * @link http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx
+     */
+    private function readRecordPlcfBtePapx()
+    {
+        $posMem = $this->arrayFib['fcPlcfBtePapx'];
+        $num = $this->getNumInLcb($this->arrayFib['lcbPlcfBtePapx'], 4);
+        $posMem += 4 * ($num + 1);
+        $arrAPnBtePapx = $this->getArrayCP($this->data1Table, $posMem, $num);
+        $posMem += 4 * $num;
+
+        foreach ($arrAPnBtePapx as $aPnBtePapx) {
+            $offsetBase = $aPnBtePapx * 512;
+            $offset = $offsetBase;
+
+            $string = '';
+
+            $numRun = self::getInt1d($this->dataWorkDocument, $offset + 511);
+            $arrayRGFC = array();
+            for ($inc = 0; $inc <= $numRun; $inc++) {
+                $arrayRGFC[$inc] = self::getInt4d($this->dataWorkDocument, $offset);
+                $offset += 4;
+            }
+            $arrayRGB = array();
+            for ($inc = 1; $inc <= $numRun; $inc++) {
+                // @link http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx
+                $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset);
+                $offset += 1;
+                // reserved
+                $offset += 12;
+            }
+
+            foreach (array_keys($arrayRGFC) as $key) {
+                if (!isset($arrayRGFC[$key + 1])) {
+                    break;
+                }
+                $strLen = $arrayRGFC[$key + 1] - $arrayRGFC[$key] - 1;
+                for ($inc = 0; $inc < $strLen; $inc++) {
+                    $byte = self::getInt1d($this->dataWorkDocument, $arrayRGFC[$key] + $inc);
+                    if ($byte > 0) {
+                        $string .= chr($byte);
+                    }
+                }
+            }
+            $this->arrayParagraphs[] = $string;
+
+            //@todo readPrl for paragraphs
+            /*// use $this->readPrl()
+            foreach ($arrayRGB as $key => $rgb) {
+                $offset = $offsetBase + ($rgb * 2);
+
+                $cb = self::getInt1d($this->dataWorkDocument, $offset);
+                $offset += 1;
+                print_r('$cb : '.$cb.PHP_EOL);
+                if ($cb == 0) {
+                    $cb = self::getInt1d($this->dataWorkDocument, $offset);
+                    $cb = $cb * 2;
+                    $offset += 1;
+                    print_r('$cb0 : '.$cb.PHP_EOL);
+                } else {
+                    $cb = $cb * 2 - 1;
+                    print_r('$cbD : '.$cb.PHP_EOL);
+                }
+                $istd = self::getInt2d($this->dataWorkDocument, $offset);
+                $offset += 2;
+                $cb -= 2;
+                print_r('$istd : '.$istd.($istd == 0 ? ' (Normal)' : '').PHP_EOL);
+                if ($cb > 0) {
+                    do{
+                        $sprm = self::getInt2d($this->dataWorkDocument, $offset);
+                        $offset += 2;
+                        $cb -= 2;
+                        $sprm_IsPmd = $sprm & 0x01FF;
+                        $sprm_F = ($sprm/512) & 0x0001;
+                        $sprm_Sgc = ($sprm/1024) & 0x0007;
+                        $sprm_Spra = ($sprm/8192);
+
+                        print_r('$sprm : 0x'.dechex($sprm).PHP_EOL);
+                        print_r('$sprm.ispmd : 0x'.dechex($sprm_IsPmd).PHP_EOL);
+                        print_r('$sprm.f : 0x'.dechex($sprm_F).PHP_EOL);
+                        print_r('$sprm.sgc : 0x'.dechex($sprm_Sgc));
+                        switch(dechex($sprm_Sgc)) {
+                            case 0x01:
+                                print_r(' (Paragraph property)');
+                                break;
+                            case 0x02:
+                                print_r(' (Character property)');
+                                break;
+                            case 0x03:
+                                print_r(' (Picture property)');
+                                break;
+                            case 0x04:
+                                print_r(' (Section property)');
+                                break;
+                            case 0x05:
+                                print_r(' (Table property)');
+                                break;
+                        }
+                        print_r(PHP_EOL);
+                        print_r('$sprm.spra : 0x'.dechex($sprm_Spra).PHP_EOL);
+                        switch(dechex($sprm_Spra)) {
+                            case 0x0:
+                                $operand = self::getInt1d($this->dataWorkDocument, $offset);
+                                $offset += 1;
+                                $cb -= 1;
+                                switch(dechex($operand)) {
+                                    case 0x00:
+                                        $operand = 'OFF';
+                                        break;
+                                    case 0x01:
+                                        $operand = 'ON';
+                                        break;
+                                    case 0x80:
+                                        $operand = 'CURRENT VALUE';
+                                        print_r(''.PHP_EOL.PHP_EOL);
+                                        break;
+                                    case 0x81:
+                                        $operand = 'OPPOSITE OF THE CURRENT VALUE';
+                                        break;
+                                }
+                                break;
+                            case 0x1:
+                                $operand = self::getInt1d($this->dataWorkDocument, $offset);
+                                $offset += 1;
+                                $cb -= 1;
+                                print_r('$operand : 0x'.dechex($operand).PHP_EOL);
+                                break;
+                            case 0x2:
+                            case 0x4:
+                            case 0x5:
+                                $operand = self::getInt2d($this->dataWorkDocument, $offset);
+                                $offset += 2;
+                                $cb -= 2;
+                                print_r('$operand : 0x'.dechex($operand).PHP_EOL);
+                                break;
+                            case 0x3:
+                                if ($sprm_IsPmd != 0x70) {
+                                    $operand = self::getInt4d($this->dataWorkDocument, $offset);
+                                    $offset += 4;
+                                    $cb -= 4;
+                                    print_r('$operand : 0x'.dechex($operand).PHP_EOL);
+                                }
+                                break;
+                            case 0x7:
+                                $operand = self::getInt3d($this->dataWorkDocument, $offset);
+                                $offset += 3;
+                                $cb -= 3;
+                                print_r('$operand : 0x'.dechex($operand).PHP_EOL);
+                                break;
+                            default:
+                                print_r('YO YO YO : '.PHP_EOL);
+                        }
+
+                        //
+                        switch(dechex($sprm_Sgc)) {
+                            case 0x01: // Sprm is modifying a paragraph property.
+                                switch($sprm_IsPmd) {
+                                    case 0x0A: // sprmPIlvl
+                                        print_r('sprmPIlvl : '.$operand.PHP_EOL.PHP_EOL);
+                                        break;
+                                    case 0x0B: // sprmPIlfo
+                                        print_r('sprmPIlfo : '.$operand.PHP_EOL.PHP_EOL);
+                                        break;
+                                    default:
+                                        print_r('$sprm_IsPmd(1) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);
+                                        break;
+                                }
+                                break;
+                            case 0x02: // Sprm is modifying a character property.
+                                switch($sprm_IsPmd) {
+                                    default:
+                                        print_r('$sprm_IsPmd(2) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);
+                                        break;
+                                }
+                                break;
+                            case 0x03: // Sprm is modifying a picture property.
+                                switch($sprm_IsPmd) {
+                                    default:
+                                        print_r('$sprm_IsPmd(3) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);
+                                        break;
+                                }
+                                break;
+                            case 0x04: // Sprm is modifying a section property.
+                                switch($sprm_IsPmd) {
+                                    default:
+                                        print_r('$sprm_IsPmd(4) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);
+                                        break;
+                                }
+                                break;
+                            case 0x05: // Sprm is modifying a table property.
+                                switch($sprm_IsPmd) {
+                                    default:
+                                        print_r('$sprm_IsPmd(4) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);
+                                        break;
+                                }
+                                break;
+                            default:
+                                print_r('$sprm_Sgc : '.dechex($sprm_Sgc).PHP_EOL.PHP_EOL);
+                                break;
+                        }
+                    } while ($cb > 0);
+                } else {
+                    if ($istd > 0) {
+                        // @todo : Determining Properties of a Paragraph Style
+                        # @link http://msdn.microsoft.com/en-us/library/dd948631%28v=office.12%29.aspx
+                    }
+                }
+            }*/
+        }
+    }
+
+    /**
+     * Character formatting properties to text in a document
+     * @link http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx
+     */
+    private function readRecordPlcfBteChpx()
+    {
+        $posMem = $this->arrayFib['fcPlcfBteChpx'];
+        $num = $this->getNumInLcb($this->arrayFib['lcbPlcfBteChpx'], 4);
+        $aPnBteChpx = array();
+        for ($inc = 0; $inc <= $num; $inc++) {
+            $aPnBteChpx[$inc] = self::getInt4d($this->data1Table, $posMem);
+            $posMem += 4;
+        }
+        $pnFkpChpx = self::getInt4d($this->data1Table, $posMem);
+        $posMem += 4;
+
+        $offsetBase = $pnFkpChpx * 512;
+        $offset = $offsetBase;
+
+        // ChpxFkp
+        // @link : http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx
+        $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511);
+        $arrayRGFC = array();
+        for ($inc = 0; $inc <= $numRGFC; $inc++) {
+            $arrayRGFC[$inc] = self::getInt4d($this->dataWorkDocument, $offset);
+            $offset += 4;
+        }
+
+        $arrayRGB = array();
+        for ($inc = 1; $inc <= $numRGFC; $inc++) {
+            $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset);
+            $offset += 1;
+        }
+
+        $start = 0;
+        foreach ($arrayRGB as $keyRGB => $rgb) {
+            $oStyle = new \stdClass();
+            $oStyle->pos_start = $start;
+            $oStyle->pos_len = (int)ceil((($arrayRGFC[$keyRGB] -1) - $arrayRGFC[$keyRGB -1]) / 2);
+            $start += $oStyle->pos_len;
+
+            if ($rgb > 0) {
+                // Chp Structure
+                // @link : http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx
+                $posRGB = $offsetBase + $rgb * 2;
+
+                $cb = self::getInt1d($this->dataWorkDocument, $posRGB);
+                $posRGB += 1;
+
+                $oStyle->style = $this->readPrl($this->dataWorkDocument, $posRGB, $cb);
+                $posRGB += $oStyle->style->length;
+            }
+            $this->arrayCharacters[] = $oStyle;
+        }
+    }
+
+    /**
+     * @param $sprm
+     * @return \stdClass
+     */
+    private function readSprm($sprm)
+    {
+        $oSprm = new \stdClass();
+        $oSprm->isPmd = $sprm & 0x01FF;
+        $oSprm->f = ($sprm / 512) & 0x0001;
+        $oSprm->sgc = ($sprm / 1024) & 0x0007;
+        $oSprm->spra = ($sprm / 8192);
+        return $oSprm;
+    }
+
+    /**
+     * @param string $data
+     * @param integer $pos
+     * @param \stdClass $oSprm
+     * @return array
+     */
+    private function readSprmSpra($data, $pos, $oSprm)
+    {
+        $length = 0;
+        $operand = null;
+
+        switch(dechex($oSprm->spra)) {
+            case 0x0:
+                $operand = self::getInt1d($data, $pos);
+                $length = 1;
+                switch(dechex($operand)) {
+                    case 0x00:
+                        $operand = false;
+                        break;
+                    case 0x01:
+                        $operand = true;
+                        break;
+                    case 0x80:
+                        $operand = self::SPRA_VALUE;
+                        break;
+                    case 0x81:
+                        $operand = self::SPRA_VALUE_OPPOSITE;
+                        break;
+                }
+                break;
+            case 0x1:
+                $operand = self::getInt1d($data, $pos);
+                $length = 1;
+                break;
+            case 0x2:
+            case 0x4:
+            case 0x5:
+                $operand = self::getInt2d($data, $pos);
+                $length = 2;
+                break;
+            case 0x3:
+                if ($oSprm->isPmd != 0x70) {
+                    $operand = self::getInt4d($data, $pos);
+                    $length = 4;
+                }
+                break;
+            case 0x7:
+                $operand = self::getInt3d($data, $pos);
+                $length = 3;
+                break;
+            default:
+                // print_r('YO YO YO : '.PHP_EOL);
+        }
+
+        return array(
+            'length' => $length,
+            'operand' => $operand,
+        );
+    }
+
+    /**
+     * @param $data integer
+     * @param $pos integer
+     * @return \stdClass
+     * @link http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx
+     */
+    private function readPrl($data, $pos, $cbNum)
+    {
+        $posStart = $pos;
+        $oStylePrl = new \stdClass();
+
+        // Variables
+        $sprmCPicLocation = null;
+        $sprmCFData = null;
+        $sprmCFSpec = null;
+
+        do {
+            // Variables
+            $operand = null;
+
+            $sprm = self::getInt2d($data, $pos);
+            $oSprm = $this->readSprm($sprm);
+            $pos += 2;
+            $cbNum -= 2;
+
+            $arrayReturn = $this->readSprmSpra($data, $pos, $oSprm);
+            $pos += $arrayReturn['length'];
+            $cbNum -= $arrayReturn['length'];
+            $operand = $arrayReturn['operand'];
+
+            switch(dechex($oSprm->sgc)) {
+                // Paragraph property
+                case 0x01:
+                    break;
+                // Character property
+                case 0x02:
+                    if (!isset($oStylePrl->styleFont)) {
+                        $oStylePrl->styleFont = array();
+                    }
+                    switch($oSprm->isPmd) {
+                        // sprmCFRMarkIns
+                        case 0x01:
+                            break;
+                        // sprmCFFldVanish
+                        case 0x02:
+                            break;
+                        // sprmCPicLocation
+                        case 0x03:
+                            $sprmCPicLocation = $operand;
+                            break;
+                        // sprmCFData
+                        case 0x06:
+                            $sprmCFData = dechex($operand) == 0x00 ? false : true;
+                            break;
+                        // sprmCFItalic
+                        case 0x36:
+                            // By default, text is not italicized.
+                            switch($operand) {
+                                case false:
+                                case true:
+                                    $oStylePrl->styleFont['italic'] = $operand;
+                                    break;
+                                case self::SPRA_VALUE:
+                                    $oStylePrl->styleFont['italic'] = false;
+                                    break;
+                                case self::SPRA_VALUE_OPPOSITE:
+                                    $oStylePrl->styleFont['italic'] = true;
+                                    break;
+                            }
+                            break;
+                        // sprmCIstd
+                        case 0x30:
+                            //print_r('sprmCIstd : '.dechex($operand).PHP_EOL.PHP_EOL);
+                            break;
+                        // sprmCFBold
+                        case 0x35:
+                            // By default, text is not bold.
+                            switch($operand) {
+                                case false:
+                                case true:
+                                    $oStylePrl->styleFont['bold'] = $operand;
+                                    break;
+                                case self::SPRA_VALUE:
+                                    $oStylePrl->styleFont['bold'] = false;
+                                    break;
+                                case self::SPRA_VALUE_OPPOSITE:
+                                    $oStylePrl->styleFont['bold'] = true;
+                                    break;
+                            }
+                            break;
+                        // sprmCFStrike
+                        case 0x37:
+                            // By default, text is not struck through.
+                            switch($operand) {
+                                case false:
+                                case true:
+                                    $oStylePrl->styleFont['strikethrough'] = $operand;
+                                    break;
+                                case self::SPRA_VALUE:
+                                    $oStylePrl->styleFont['strikethrough'] = false;
+                                    break;
+                                case self::SPRA_VALUE_OPPOSITE:
+                                    $oStylePrl->styleFont['strikethrough'] = true;
+                                    break;
+                            }
+                            break;
+                        // sprmCKul
+                        case 0x3E:
+                            switch(dechex($operand)) {
+                                case 0x00:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_NONE;
+                                    break;
+                                case 0x01:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_SINGLE;
+                                    break;
+                                case 0x02:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WORDS;
+                                    break;
+                                case 0x03:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOUBLE;
+                                    break;
+                                case 0x04:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTTED;
+                                    break;
+                                case 0x06:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_HEAVY;
+                                    break;
+                                case 0x07:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASH;
+                                    break;
+                                case 0x09:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTHASH;
+                                    break;
+                                case 0x0A:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDOTDASH;
+                                    break;
+                                case 0x0B:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WAVY;
+                                    break;
+                                case 0x14:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTTEDHEAVY;
+                                    break;
+                                case 0x17:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHHEAVY;
+                                    break;
+                                case 0x19:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTHASHHEAVY;
+                                    break;
+                                case 0x1A:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DOTDOTDASHHEAVY;
+                                    break;
+                                case 0x1B:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WAVYHEAVY;
+                                    break;
+                                case 0x27:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHLONG;
+                                    break;
+                                case 0x2B:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_WAVYDOUBLE;
+                                    break;
+                                case 0x37:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_DASHLONGHEAVY;
+                                    break;
+                                default:
+                                    $oStylePrl->styleFont['underline'] = Style\Font::UNDERLINE_NONE;
+                                    break;
+                            }
+                            break;
+                        // sprmCIco
+                        //@link http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx
+                        case 0x42:
+                            switch(dechex($operand)) {
+                                case 0x00:
+                                case 0x01:
+                                    $oStylePrl->styleFont['color'] = '000000';
+                                    break;
+                                case 0x02:
+                                    $oStylePrl->styleFont['color'] = '0000FF';
+                                    break;
+                                case 0x03:
+                                    $oStylePrl->styleFont['color'] = '00FFFF';
+                                    break;
+                                case 0x04:
+                                    $oStylePrl->styleFont['color'] = '00FF00';
+                                    break;
+                                case 0x05:
+                                    $oStylePrl->styleFont['color'] = 'FF00FF';
+                                    break;
+                                case 0x06:
+                                    $oStylePrl->styleFont['color'] = 'FF0000';
+                                    break;
+                                case 0x07:
+                                    $oStylePrl->styleFont['color'] = 'FFFF00';
+                                    break;
+                                case 0x08:
+                                    $oStylePrl->styleFont['color'] = 'FFFFFF';
+                                    break;
+                                case 0x09:
+                                    $oStylePrl->styleFont['color'] = '000080';
+                                    break;
+                                case 0x0A:
+                                    $oStylePrl->styleFont['color'] = '008080';
+                                    break;
+                                case 0x0B:
+                                    $oStylePrl->styleFont['color'] = '008000';
+                                    break;
+                                case 0x0C:
+                                    $oStylePrl->styleFont['color'] = '800080';
+                                    break;
+                                case 0x0D:
+                                    $oStylePrl->styleFont['color'] = '800080';
+                                    break;
+                                case 0x0E:
+                                    $oStylePrl->styleFont['color'] = '808000';
+                                    break;
+                                case 0x0F:
+                                    $oStylePrl->styleFont['color'] = '808080';
+                                    break;
+                                case 0x10:
+                                    $oStylePrl->styleFont['color'] = 'C0C0C0';
+                            }
+                            break;
+                        // sprmCHps
+                        case 0x43:
+                            $oStylePrl->styleFont['size'] = dechex($operand/2);
+                            break;
+                        // sprmCIss
+                        case 0x48:
+                            if (!isset($oStylePrl->styleFont['superScript'])) {
+                                $oStylePrl->styleFont['superScript'] = false;
+                            }
+                            if (!isset($oStylePrl->styleFont['subScript'])) {
+                                $oStylePrl->styleFont['subScript'] = false;
+                            }
+                            switch (dechex($operand)) {
+                                case 0x00:
+                                    // Normal text
+                                    break;
+                                case 0x01:
+                                    $oStylePrl->styleFont['superScript'] = true;
+                                    break;
+                                case 0x02:
+                                    $oStylePrl->styleFont['subScript'] = true;
+                                    break;
+                            }
+                            break;
+                        // sprmCRgFtc0
+                        case 0x4F:
+                            $oStylePrl->styleFont['name'] = '';
+                            if (isset($this->arrayFonts[$operand])) {
+                                $oStylePrl->styleFont['name'] = $this->arrayFonts[$operand]['main'];
+                            }
+                            break;
+                        // sprmCRgFtc1
+                        case 0x50:
+                            // if the language for the text is an East Asian language
+                            break;
+                        // sprmCRgFtc2
+                        case 0x51:
+                            // if the character falls outside the Unicode character range
+                            break;
+                        // sprmCFSpec
+                        case 0x55:
+                            $sprmCFSpec = $operand;
+                            break;
+                        // sprmCFtcBi
+                        case 0x5E:
+                            break;
+                        // sprmCFItalicBi
+                        case 0x5D:
+                            break;
+                        // sprmCHpsBi
+                        case 0x61:
+                            break;
+                        // sprmCShd80
+                        //@link http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx
+                        case 0x66:
+                            // $operand = self::getInt2d($data, $pos);
+                            $pos += 2;
+                            $cbNum -= 2;
+                            // $ipat = ($operand >> 0) && bindec('111111');
+                            // $icoBack = ($operand >> 6) && bindec('11111');
+                            // $icoFore = ($operand >> 11) && bindec('11111');
+                            break;
+                        // sprmCCv
+                        //@link : http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx
+                        case 0x70:
+                            $red = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT);
+                            $pos += 1;
+                            $green = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT);
+                            $pos += 1;
+                            $blue = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT);
+                            $pos += 1;
+                            $pos += 1;
+                            $oStylePrl->styleFont['color'] = $red.$green.$blue;
+                            $cbNum -= 4;
+                            break;
+                        default:
+                            // print_r('@todo Character : 0x'.dechex($oSprm->isPmd));
+                            // print_r(PHP_EOL);
+                    }
+                    break;
+                // Picture property
+                case 0x03:
+                    break;
+                // Section property
+                case 0x04:
+                    if (!isset($oStylePrl->styleSection)) {
+                        $oStylePrl->styleSection = array();
+                    }
+                    switch($oSprm->isPmd) {
+                        // sprmSNfcPgn
+                        case 0x0E:
+                            // numbering format used for page numbers
+                            break;
+                        // sprmSXaPage
+                        case 0x1F:
+                            $oStylePrl->styleSection['pageSizeW'] = $operand;
+                            break;
+                        // sprmSYaPage
+                        case 0x20:
+                            $oStylePrl->styleSection['pageSizeH'] = $operand;
+                            break;
+                        // sprmSDxaLeft
+                        case 0x21:
+                            $oStylePrl->styleSection['marginLeft'] = $operand;
+                            break;
+                        // sprmSDxaRight
+                        case 0x22:
+                            $oStylePrl->styleSection['marginRight'] = $operand;
+                            break;
+                        // sprmSDyaTop
+                        case 0x23:
+                            $oStylePrl->styleSection['marginTop'] = $operand;
+                            break;
+                        // sprmSDyaBottom
+                        case 0x24:
+                            $oStylePrl->styleSection['marginBottom'] = $operand;
+                            break;
+                        // sprmSFBiDi
+                        case 0x28:
+                            // RTL layout
+                            break;
+                        // sprmSDxtCharSpace
+                        case 0x30:
+                            // characpter pitch
+                            break;
+                        // sprmSDyaLinePitch
+                        case 0x31:
+                            // line height
+                            break;
+                        // sprmSClm
+                        case 0x32:
+                            // document grid mode
+                            break;
+                        // sprmSTextFlow
+                        case 0x33:
+                            // text flow
+                            break;
+                        default:
+                            // print_r('@todo Section : 0x'.dechex($oSprm->isPmd));
+                            // print_r(PHP_EOL);
+
+                    }
+                    break;
+                // Table property
+                case 0x05:
+                    break;
+            }
+        } while ($cbNum > 0);
+
+        if (!is_null($sprmCPicLocation)) {
+            if (!is_null($sprmCFData) && $sprmCFData == 0x01) {
+                // NilPICFAndBinData
+                //@todo Read Hyperlink structure
+                /*$lcb = self::getInt4d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 4;
+                $cbHeader = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // ignored
+                $sprmCPicLocation += 62;
+                // depending of the element
+                // Hyperlink => HFD
+                // HFD > bits
+                $sprmCPicLocation += 1;
+                // HFD > clsid
+                $sprmCPicLocation += 16;
+                // HFD > hyperlink
+                //@link : http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx
+                $streamVersion = self::getInt4d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 4;
+                $data = self::getInt4d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 4;
+                $hlstmfAbsFromGetdataRel = ($data >> 9) & bindec('1');
+                $hlstmfMonikerSavedAsStr = ($data >> 8) & bindec('1');
+                $hlstmfHasFrameName = ($data >> 7) & bindec('1');
+                $hlstmfHasCreationTime = ($data >> 6) & bindec('1');
+                $hlstmfHasGUID = ($data >> 5) & bindec('1');
+                $hlstmfHasDisplayName = ($data >> 4) & bindec('1');
+                $hlstmfHasLocationStr = ($data >> 3) & bindec('1');
+                $hlstmfSiteGaveDisplayName = ($data >> 2) & bindec('1');
+                $hlstmfIsAbsolute = ($data >> 1) & bindec('1');
+                $hlstmfHasMoniker = ($data >> 0) & bindec('1');
+                for ($inc = 0; $inc <= 32; $inc++) {
+                    echo ($data >> $inc) & bindec('1');
+                }
+
+                print_r('$hlstmfHasMoniker > '.$hlstmfHasMoniker.PHP_EOL);
+                print_r('$hlstmfIsAbsolute > '.$hlstmfIsAbsolute.PHP_EOL);
+                print_r('$hlstmfSiteGaveDisplayName > '.$hlstmfSiteGaveDisplayName.PHP_EOL);
+                print_r('$hlstmfHasLocationStr > '.$hlstmfHasLocationStr.PHP_EOL);
+                print_r('$hlstmfHasDisplayName > '.$hlstmfHasDisplayName.PHP_EOL);
+                print_r('$hlstmfHasGUID > '.$hlstmfHasGUID.PHP_EOL);
+                print_r('$hlstmfHasCreationTime > '.$hlstmfHasCreationTime.PHP_EOL);
+                print_r('$hlstmfHasFrameName > '.$hlstmfHasFrameName.PHP_EOL);
+                print_r('$hlstmfMonikerSavedAsStr > '.$hlstmfMonikerSavedAsStr.PHP_EOL);
+                print_r('$hlstmfAbsFromGetdataRel > '.$hlstmfAbsFromGetdataRel.PHP_EOL);
+                if ($streamVersion == 2) {
+                    $AAA = self::getInt4d($this->dataData, $sprmCPicLocation);
+                    echo 'AAAA : '.$AAA.PHP_EOL;
+                    if ($hlstmfHasDisplayName == 1) {
+                        echo 'displayName'.PHP_EOL;
+                    }
+                    if ($hlstmfHasFrameName == 1) {
+                        echo 'targetFrameName'.PHP_EOL;
+                    }
+                    if ($hlstmfHasMoniker == 1 || $hlstmfMonikerSavedAsStr == 1) {
+                        $sprmCPicLocation += 16;
+                        $length = self::getInt4d($this->dataData, $sprmCPicLocation);
+                        $sprmCPicLocation += 4;
+                        for ($inc = 0; $inc < ($length / 2); $inc++) {
+                            $chr = self::getInt2d($this->dataData, $sprmCPicLocation);
+                            $sprmCPicLocation += 2;
+                            print_r(chr($chr));
+                        }
+                        echo PHP_EOL;
+                        echo 'moniker : '.$length.PHP_EOL;
+                    }
+                    if ($hlstmfHasMoniker == 1 || $hlstmfMonikerSavedAsStr == 1) {
+                        echo 'oleMoniker'.PHP_EOL;
+                    }
+                    if ($hlstmfHasLocationStr == 1) {
+                        echo 'location'.PHP_EOL;
+                    }
+                    if ($hlstmfHasGUID == 1) {
+                        echo 'guid'.PHP_EOL;
+                        $sprmCPicLocation += 16;
+                    }
+                    if ($hlstmfHasCreationTime == 1) {
+                        echo 'fileTime'.PHP_EOL;
+                        $sprmCPicLocation += 4;
+                    }
+                    echo 'HYPERLINK'.PHP_EOL;
+                }*/
+            } else {
+                // Pictures
+                //@link : http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx
+                //@link : http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx
+                // PICF : lcb
+                $sprmCPicLocation += 4;
+                // PICF : cbHeader
+                $sprmCPicLocation += 2;
+                // PICF : mfpf : mm
+                $mfpfMm = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : mfpf : xExt
+                $sprmCPicLocation += 2;
+                // PICF : mfpf : yExt
+                $sprmCPicLocation += 2;
+                // PICF : mfpf : swHMF
+                $sprmCPicLocation += 2;
+                // PICF : innerHeader : grf
+                $sprmCPicLocation += 4;
+                // PICF : innerHeader : padding1
+                $sprmCPicLocation += 4;
+                // PICF : innerHeader : mmPM
+                $sprmCPicLocation += 2;
+                // PICF : innerHeader : padding2
+                $sprmCPicLocation += 4;
+                // PICF : picmid : dxaGoal
+                $picmidDxaGoal = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : dyaGoal
+                $picmidDyaGoal = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : mx
+                $picmidMx = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : my
+                $picmidMy = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : dxaReserved1
+                $picmidDxaCropLeft = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : dyaReserved1
+                $picmidDxaCropTop = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : dxaReserved2
+                $picmidDxaCropRight = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : dyaReserved2
+                $picmidDxaCropBottom = self::getInt2d($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 2;
+                // PICF : picmid : fReserved
+                $sprmCPicLocation += 1;
+                // PICF : picmid : bpp
+                $sprmCPicLocation += 1;
+                // PICF : picmid : brcTop80
+                $sprmCPicLocation += 4;
+                // PICF : picmid : brcLeft80
+                $sprmCPicLocation += 4;
+                // PICF : picmid : brcBottom80
+                $sprmCPicLocation += 4;
+                // PICF : picmid : brcRight80
+                $sprmCPicLocation += 4;
+                // PICF : picmid : dxaReserved3
+                $sprmCPicLocation += 2;
+                // PICF : picmid : dyaReserved3
+                $sprmCPicLocation += 2;
+                // PICF : cProps
+                $sprmCPicLocation += 2;
+
+                if ($mfpfMm == 0x0066) {
+                    // cchPicName
+                    $cchPicName = self::getInt1d($this->dataData, $sprmCPicLocation);
+                    $sprmCPicLocation += 1;
+
+                    // stPicName
+                    $stPicName = '';
+                    for ($inc = 0; $inc <= $cchPicName; $inc++) {
+                        $chr = self::getInt1d($this->dataData, $sprmCPicLocation);
+                        $sprmCPicLocation += 1;
+                        $stPicName .= chr($chr);
+                    }
+                }
+
+                // picture (OfficeArtInlineSpContainer)
+                // picture : shape
+                $shapeRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);
+                $sprmCPicLocation += 8;
+                if ($shapeRH['recVer'] == 0xF && $shapeRH['recInstance'] == 0x000 && $shapeRH['recType'] == 0xF004) {
+                    $sprmCPicLocation += $shapeRH['recLen'];
+                }
+                // picture : rgfb
+                //@link : http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx
+                $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);
+                while ($fileBlockRH['recType'] == 0xF007 || ($fileBlockRH['recType'] >= 0xF018 && $fileBlockRH['recType'] <= 0xF117)) {
+                    $sprmCPicLocation += 8;
+                    switch ($fileBlockRH['recType']) {
+                        // OfficeArtFBSE
+                        //@link : http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx
+                        case 0xF007:
+                            // btWin32
+                            $sprmCPicLocation += 1;
+                            // btMacOS
+                            $sprmCPicLocation += 1;
+                            // rgbUid
+                            $sprmCPicLocation += 16;
+                            // tag
+                            $sprmCPicLocation += 2;
+                            // size
+                            $sprmCPicLocation += 4;
+                            // cRef
+                            $sprmCPicLocation += 4;
+                            // foDelay
+                            $sprmCPicLocation += 4;
+                            // unused1
+                            $sprmCPicLocation += 1;
+                            // cbName
+                            $cbName = self::getInt1d($this->dataData, $sprmCPicLocation);
+                            $sprmCPicLocation += 1;
+                            // unused2
+                            $sprmCPicLocation += 1;
+                            // unused3
+                            $sprmCPicLocation += 1;
+                            // nameData
+                            if ($cbName > 0) {
+                                $nameData = '';
+                                for ($inc = 0; $inc <= ($cbName / 2); $inc++) {
+                                    $chr = self::getInt2d($this->dataData, $sprmCPicLocation);
+                                    $sprmCPicLocation += 2;
+                                    $nameData .= chr($chr);
+                                }
+                            }
+                            // embeddedBlip
+                            //@link : http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx
+                            $embeddedBlipRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);
+                            switch ($embeddedBlipRH['recType']) {
+                                case self::OFFICEARTBLIPJPG:
+                                case self::OFFICEARTBLIPJPEG:
+                                    if (!isset($oStylePrl->image)) {
+                                        $oStylePrl->image = array();
+                                    }
+                                    $sprmCPicLocation += 8;
+                                    // embeddedBlip : rgbUid1
+                                    $sprmCPicLocation += 16;
+                                    if ($embeddedBlipRH['recInstance'] == 0x6E1) {
+                                        // rgbUid2
+                                        $sprmCPicLocation += 16;
+                                    }
+                                    // embeddedBlip : tag
+                                    $sprmCPicLocation += 1;
+                                    // embeddedBlip : BLIPFileData
+                                    $oStylePrl->image['data'] = substr($this->dataData, $sprmCPicLocation, $embeddedBlipRH['recLen']);
+                                    $oStylePrl->image['format'] = 'jpg';
+                                    // Image Size
+                                    $iCropWidth = $picmidDxaGoal - ($picmidDxaCropLeft + $picmidDxaCropRight);
+                                    $iCropHeight = $picmidDyaGoal - ($picmidDxaCropTop + $picmidDxaCropBottom);
+                                    if (!$iCropWidth) {
+                                        $iCropWidth = 1;
+                                    }
+                                    if (!$iCropHeight) {
+                                        $iCropHeight = 1;
+                                    }
+                                    $oStylePrl->image['width'] = Drawing::twipsToPixels($iCropWidth * $picmidMx / 1000);
+                                    $oStylePrl->image['height'] = Drawing::twipsToPixels($iCropHeight * $picmidMy / 1000);
+
+                                    $sprmCPicLocation += $embeddedBlipRH['recLen'];
+                                    break;
+                                default:
+                                    // print_r(dechex($embeddedBlipRH['recType']));
+                            }
+                            break;
+                    }
+                    $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);
+                }
+            }
+        }
+
+        $oStylePrl->length = $pos - $posStart;
+        return $oStylePrl;
+    }
+
+    /**
+     * Read a record header
+     * @param string $stream
+     * @param integer $pos
+     * @return array
+     */
+    private function loadRecordHeader($stream, $pos)
+    {
+        $rec = self::getInt2d($stream, $pos);
+        $recType = self::getInt2d($stream, $pos + 2);
+        $recLen = self::getInt4d($stream, $pos + 4);
+        return array(
+            'recVer' => ($rec >> 0) & bindec('1111'),
+            'recInstance' => ($rec >> 4) & bindec('111111111111'),
+            'recType' => $recType,
+            'recLen' => $recLen,
+        );
+    }
+
+    private function generatePhpWord()
+    {
+        foreach ($this->arraySections as $itmSection) {
+            $oSection = $this->phpWord->addSection();
+            $oSection->setSettings($itmSection->styleSection);
+
+            $sHYPERLINK = '';
+            foreach ($this->arrayParagraphs as $itmParagraph) {
+                $textPara = $itmParagraph;
+                foreach ($this->arrayCharacters as $oCharacters) {
+                    $subText = substr($textPara, $oCharacters->pos_start, $oCharacters->pos_len);
+                    $subText = str_replace(chr(13), PHP_EOL, $subText);
+                    $arrayText = explode(PHP_EOL, $subText);
+                    if (end($arrayText) == '') {
+                        array_pop($arrayText);
+                    }
+                    if (reset($arrayText) == '') {
+                        array_shift($arrayText);
+                    }
+
+                    // Style Character
+                    $styleFont = array();
+                    if (isset($oCharacters->style)) {
+                        if (isset($oCharacters->style->styleFont)) {
+                            $styleFont = $oCharacters->style->styleFont;
+                        }
+                    }
+
+                    foreach ($arrayText as $sText) {
+                        // HyperLink
+                        if (empty($sText) && !empty($sHYPERLINK)) {
+                            $arrHYPERLINK = explode('"', $sHYPERLINK);
+                            $oSection->addLink($arrHYPERLINK[1], null);
+                            // print_r('>addHyperLink<'.$sHYPERLINK.'>'.ord($sHYPERLINK[0]).EOL);
+                            $sHYPERLINK = '';
+                        }
+
+                        // TextBreak
+                        if (empty($sText)) {
+                            $oSection->addTextBreak();
+                            $sHYPERLINK = '';
+                            // print_r('>addTextBreak<' . EOL);
+                        }
+
+                        if (!empty($sText)) {
+                            if (!empty($sHYPERLINK) && ord($sText[0]) > 20) {
+                                $sHYPERLINK .= $sText;
+                            }
+                            if (empty($sHYPERLINK)) {
+                                if (ord($sText[0]) > 20) {
+                                    if (strpos(trim($sText), 'HYPERLINK "') === 0) {
+                                        $sHYPERLINK = $sText;
+                                    } else {
+                                        $oSection->addText($sText, $styleFont);
+                                        // print_r('>addText<'.$sText.'>'.ord($sText[0]).EOL);
+                                    }
+                                }
+                                if (ord($sText[0]) == 1) {
+                                    if (isset($oCharacters->style->image)) {
+                                        $fileImage = tempnam(sys_get_temp_dir(), 'PHPWord_MsDoc').'.'.$oCharacters->style->image['format'];
+                                        file_put_contents($fileImage, $oCharacters->style->image['data']);
+                                        $oSection->addImage($fileImage, array('width' => $oCharacters->style->image['width'], 'height' => $oCharacters->style->image['height']));
+                                        // print_r('>addImage<'.$fileImage.'>'.EOL);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+        }
+    }
+
+    /**
+     * Read 8-bit unsigned integer
+     *
+     * @param string $data
+     * @param int $pos
+     * @return int
+     */
+    public static function getInt1d($data, $pos)
+    {
+        return ord($data[$pos]);
+    }
+
+    /**
+     * Read 16-bit unsigned integer
+     *
+     * @param string $data
+     * @param int $pos
+     * @return int
+     */
+    public static function getInt2d($data, $pos)
+    {
+        return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
+    }
+
+    /**
+     * Read 24-bit signed integer
+     *
+     * @param string $data
+     * @param int $pos
+     * @return int
+     */
+    public static function getInt3d($data, $pos)
+    {
+        return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16);
+    }
+
+    /**
+     * Read 32-bit signed integer
+     *
+     * @param string $data
+     * @param int $pos
+     * @return int
+     */
+    public static function getInt4d($data, $pos)
+    {
+        // FIX: represent numbers correctly on 64-bit system
+        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
+        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
+        $or24 = ord($data[$pos + 3]);
+        if ($or24 >= 128) {
+            // negative number
+            $ord24 = -abs((256 - $or24) << 24);
+        } else {
+            $ord24 = ($or24 & 127) << 24;
+        }
+        return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $ord24;
+    }
+}

+ 95 - 0
includes/PhpWord/Reader/ODText.php

@@ -0,0 +1,95 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Reader for ODText
+ *
+ * @since 0.10.0
+ */
+class ODText extends AbstractReader implements ReaderInterface
+{
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $docFile
+     * @return \PhpOffice\PhpWord\PhpWord
+     */
+    public function load($docFile)
+    {
+        $phpWord = new PhpWord();
+        $relationships = $this->readRelationships($docFile);
+
+        $readerParts = array(
+            'content.xml' => 'Content',
+            'meta.xml' => 'Meta',
+        );
+
+        foreach ($readerParts as $xmlFile => $partName) {
+            $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile);
+        }
+
+        return $phpWord;
+    }
+
+    /**
+     * Read document part.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @param array $relationships
+     * @param string $partName
+     * @param string $docFile
+     * @param string $xmlFile
+     * @return void
+     */
+    private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile)
+    {
+        $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}";
+        if (class_exists($partClass)) {
+            /** @var \PhpOffice\PhpWord\Reader\ODText\AbstractPart $part Type hint */
+            $part = new $partClass($docFile, $xmlFile);
+            $part->setRels($relationships);
+            $part->read($phpWord);
+        }
+    }
+
+    /**
+     * Read all relationship files
+     *
+     * @param string $docFile
+     * @return array
+     */
+    private function readRelationships($docFile)
+    {
+        $rels = array();
+        $xmlFile = 'META-INF/manifest.xml';
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($docFile, $xmlFile);
+        $nodes = $xmlReader->getElements('manifest:file-entry');
+        foreach ($nodes as $node) {
+            $type = $xmlReader->getAttribute('manifest:media-type', $node);
+            $target = $xmlReader->getAttribute('manifest:full-path', $node);
+            $rels[] = array('type' => $type, 'target' => $target);
+        }
+
+        return $rels;
+    }
+}

+ 30 - 0
includes/PhpWord/Reader/ODText/AbstractPart.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\ODText;
+
+use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart;
+
+/**
+ * Abstract part reader
+ *
+ * @since 0.10.0
+ * @codeCoverageIgnore
+ */
+abstract class AbstractPart extends Word2007AbstractPart
+{
+}

+ 68 - 0
includes/PhpWord/Reader/ODText/Content.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\ODText;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Content reader
+ *
+ * @since 0.10.0
+ */
+class Content extends AbstractPart
+{
+    /**
+     * Read content.xml.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+
+        $nodes = $xmlReader->getElements('office:body/office:text/*');
+        if ($nodes->length > 0) {
+            $section = $phpWord->addSection();
+            foreach ($nodes as $node) {
+                // $styleName = $xmlReader->getAttribute('text:style-name', $node);
+                switch ($node->nodeName) {
+
+                    case 'text:h': // Heading
+                        $depth = $xmlReader->getAttribute('text:outline-level', $node);
+                        $section->addTitle($node->nodeValue, $depth);
+                        break;
+
+                    case 'text:p': // Paragraph
+                        $section->addText($node->nodeValue);
+                        break;
+
+                    case 'text:list': // List
+                        $listItems = $xmlReader->getElements('text:list-item/text:p', $node);
+                        foreach ($listItems as $listItem) {
+                            // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem);
+                            $section->addListItem($listItem->nodeValue, 0);
+                        }
+                        break;
+                }
+            }
+        }
+    }
+}

+ 80 - 0
includes/PhpWord/Reader/ODText/Meta.php

@@ -0,0 +1,80 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\ODText;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Meta reader
+ *
+ * @since 0.11.0
+ */
+class Meta extends AbstractPart
+{
+    /**
+     * Read meta.xml.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     * @todo Process property type
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+        $docProps = $phpWord->getDocInfo();
+
+        $metaNode = $xmlReader->getElement('office:meta');
+
+        // Standard properties
+        $properties = array(
+            'title'          => 'dc:title',
+            'subject'        => 'dc:subject',
+            'description'    => 'dc:description',
+            'keywords'       => 'meta:keyword',
+            'creator'        => 'meta:initial-creator',
+            'lastModifiedBy' => 'dc:creator',
+            // 'created'        => 'meta:creation-date',
+            // 'modified'       => 'dc:date',
+        );
+        foreach ($properties as $property => $path) {
+            $method = "set{$property}";
+            $propertyNode = $xmlReader->getElement($path, $metaNode);
+            if ($propertyNode !== null && method_exists($docProps, $method)) {
+                $docProps->$method($propertyNode->nodeValue);
+            }
+        }
+
+        // Custom properties
+        $propertyNodes = $xmlReader->getElements('meta:user-defined', $metaNode);
+        foreach ($propertyNodes as $propertyNode) {
+            $property = $xmlReader->getAttribute('meta:name', $propertyNode);
+
+            // Set category, company, and manager property
+            if (in_array($property, array('Category', 'Company', 'Manager'))) {
+                $method = "set{$property}";
+                $docProps->$method($propertyNode->nodeValue);
+
+            // Set other custom properties
+            } else {
+                $docProps->setCustomProperty($property, $propertyNode->nodeValue);
+            }
+        }
+    }
+}

+ 51 - 0
includes/PhpWord/Reader/RTF.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Reader\RTF\Document;
+
+/**
+ * RTF Reader class
+ *
+ * @since 0.11.0
+ */
+class RTF extends AbstractReader implements ReaderInterface
+{
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $docFile
+     * @throws \Exception
+     * @return \PhpOffice\PhpWord\PhpWord
+     */
+    public function load($docFile)
+    {
+        $phpWord = new PhpWord();
+
+        if ($this->canRead($docFile)) {
+            $doc = new Document();
+            $doc->rtf = file_get_contents($docFile);
+            $doc->read($phpWord);
+        } else {
+            throw new \Exception("Cannot read {$docFile}.");
+        }
+
+        return $phpWord;
+    }
+}

+ 414 - 0
includes/PhpWord/Reader/RTF/Document.php

@@ -0,0 +1,414 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\RTF;
+
+use PhpOffice\PhpWord\PhpWord;
+
+/**
+ * RTF document reader
+ *
+ * References:
+ * - How to Write an RTF Reader http://latex2rtf.sourceforge.net/rtfspec_45.html
+ * - PHP rtfclass by Markus Fischer https://github.com/mfn/rtfclass
+ * - JavaScript RTF-parser by LazyGyu https://github.com/lazygyu/RTF-parser
+ *
+ * @since 0.11.0
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
+ */
+class Document
+{
+    /** @const int */
+    const PARA = 'readParagraph';
+    const STYL = 'readStyle';
+    const SKIP = 'readSkip';
+
+    /**
+     * PhpWord object
+     *
+     * @var \PhpOffice\PhpWord\PhpWord
+     */
+    private $phpWord;
+
+    /**
+     * Section object
+     *
+     * @var \PhpOffice\PhpWord\Element\Section
+     */
+    private $section;
+
+    /**
+     * Textrun object
+     *
+     * @var \PhpOffice\PhpWord\Element\TextRun
+     */
+    private $textrun;
+
+    /**
+     * RTF content
+     *
+     * @var string
+     */
+    public $rtf;
+
+    /**
+     * Content length
+     *
+     * @var int
+     */
+    private $length = 0;
+
+    /**
+     * Character index
+     *
+     * @var int
+     */
+    private $offset = 0;
+
+    /**
+     * Current control word
+     *
+     * @var string
+     */
+    private $control = '';
+
+    /**
+     * Text content
+     *
+     * @var string
+     */
+    private $text = '';
+
+    /**
+     * Parsing a control word flag
+     *
+     * @var bool
+     */
+    private $isControl = false;
+
+    /**
+     * First character flag: watch out for control symbols
+     *
+     * @var bool
+     */
+    private $isFirst = false;
+
+    /**
+     * Group groups
+     *
+     * @var array
+     */
+    private $groups = array();
+
+    /**
+     * Parser flags; not used
+     *
+     * @var array
+     */
+    private $flags = array();
+
+    /**
+     * Parse RTF content
+     *
+     * - Marks controlling characters `{`, `}`, and `\`
+     * - Removes line endings
+     * - Builds control words and control symbols
+     * - Pushes every other character into the text queue
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     * @todo Use `fread` stream for scalability
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $markers = array(
+            123 => 'markOpening',   // {
+            125 => 'markClosing',   // }
+            92  => 'markBackslash', // \
+            10  => 'markNewline',   // LF
+            13  => 'markNewline'    // CR
+        );
+
+        $this->phpWord = $phpWord;
+        $this->section = $phpWord->addSection();
+        $this->textrun = $this->section->addTextRun();
+        $this->length = strlen($this->rtf);
+
+        $this->flags['paragraph'] = true; // Set paragraph flag from the beginning
+
+        // Walk each characters
+        while ($this->offset < $this->length) {
+            $char  = $this->rtf[$this->offset];
+            $ascii = ord($char);
+
+            if (isset($markers[$ascii])) { // Marker found: {, }, \, LF, or CR
+                $markerFunction = $markers[$ascii];
+                $this->$markerFunction();
+            } else {
+                if ($this->isControl === false) { // Non control word: Push character
+                    $this->pushText($char);
+                } else {
+                    if (preg_match("/^[a-zA-Z0-9-]?$/", $char)) { // No delimiter: Buffer control
+                        $this->control .= $char;
+                        $this->isFirst = false;
+                    } else { // Delimiter found: Parse buffered control
+                        if ($this->isFirst) {
+                            $this->isFirst = false;
+                        } else {
+                            if ($char == ' ') { // Discard space as a control word delimiter
+                                $this->flushControl(true);
+                            }
+                        }
+                    }
+                }
+            }
+            $this->offset++;
+        }
+        $this->flushText();
+    }
+
+    /**
+     * Mark opening braket `{` character.
+     *
+     * @return void
+     */
+    private function markOpening()
+    {
+        $this->flush(true);
+        array_push($this->groups, $this->flags);
+    }
+
+    /**
+     * Mark closing braket `}` character.
+     *
+     * @return void
+     */
+    private function markClosing()
+    {
+        $this->flush(true);
+        $this->flags = array_pop($this->groups);
+    }
+
+    /**
+     * Mark backslash `\` character.
+     *
+     * @return void
+     */
+    private function markBackslash()
+    {
+        if ($this->isFirst) {
+            $this->setControl(false);
+            $this->text .= '\\';
+        } else {
+            $this->flush();
+            $this->setControl(true);
+            $this->control = '';
+        }
+    }
+
+    /**
+     * Mark newline character: Flush control word because it's not possible to span multiline.
+     *
+     * @return void
+     */
+    private function markNewline()
+    {
+        if ($this->isControl) {
+            $this->flushControl(true);
+        }
+    }
+
+    /**
+     * Flush control word or text.
+     *
+     * @param bool $isControl
+     * @return void
+     */
+    private function flush($isControl = false)
+    {
+        if ($this->isControl) {
+            $this->flushControl($isControl);
+        } else {
+            $this->flushText();
+        }
+    }
+
+    /**
+     * Flush control word.
+     *
+     * @param bool $isControl
+     * @return void
+     */
+    private function flushControl($isControl = false)
+    {
+        if (preg_match("/^([A-Za-z]+)(-?[0-9]*) ?$/", $this->control, $match) === 1) {
+            list(, $control, $parameter) = $match;
+            $this->parseControl($control, $parameter);
+        }
+
+        if ($isControl === true) {
+            $this->setControl(false);
+        }
+    }
+
+    /**
+     * Flush text in queue.
+     *
+     * @return void
+     */
+    private function flushText()
+    {
+        if ($this->text != '') {
+            if (isset($this->flags['property'])) { // Set property
+                $this->flags['value'] = $this->text;
+            } else { // Set text
+                if ($this->flags['paragraph'] === true) {
+                    $this->flags['paragraph'] = false;
+                    $this->flags['text'] = $this->text;
+                }
+            }
+
+            // Add text if it's not flagged as skipped
+            if (!isset($this->flags['skipped'])) {
+                $this->readText();
+            }
+
+            $this->text = '';
+        }
+    }
+
+    /**
+     * Reset control word and first char state.
+     *
+     * @param bool $value
+     * @return void
+     */
+    private function setControl($value)
+    {
+        $this->isControl = $value;
+        $this->isFirst = $value;
+    }
+
+    /**
+     * Push text into queue.
+     *
+     * @param string $char
+     * @return void
+     */
+    private function pushText($char)
+    {
+        if ($char == '<') {
+            $this->text .= "&lt;";
+        } elseif ($char == '>') {
+            $this->text .= "&gt;";
+        } else {
+            $this->text .= $char;
+        }
+    }
+
+    /**
+     * Parse control.
+     *
+     * @param string $control
+     * @param string $parameter
+     * @return void
+     */
+    private function parseControl($control, $parameter)
+    {
+        $controls = array(
+            'par'       => array(self::PARA,    'paragraph',    true),
+            'b'         => array(self::STYL,    'font',         'bold',         true),
+            'i'         => array(self::STYL,    'font',         'italic',       true),
+            'u'         => array(self::STYL,    'font',         'underline',    true),
+            'strike'    => array(self::STYL,    'font',         'strikethrough',true),
+            'fs'        => array(self::STYL,    'font',         'size',         $parameter),
+            'qc'        => array(self::STYL,    'paragraph',    'align',        'center'),
+            'sa'        => array(self::STYL,    'paragraph',    'spaceAfter',   $parameter),
+            'fonttbl'   => array(self::SKIP,    'fonttbl',      null),
+            'colortbl'  => array(self::SKIP,    'colortbl',     null),
+            'info'      => array(self::SKIP,    'info',         null),
+            'generator' => array(self::SKIP,    'generator',    null),
+            'title'     => array(self::SKIP,    'title',        null),
+            'subject'   => array(self::SKIP,    'subject',      null),
+            'category'  => array(self::SKIP,    'category',     null),
+            'keywords'  => array(self::SKIP,    'keywords',     null),
+            'comment'   => array(self::SKIP,    'comment',      null),
+            'shppict'   => array(self::SKIP,    'pic',          null),
+            'fldinst'   => array(self::SKIP,    'link',         null),
+        );
+
+        if (isset($controls[$control])) {
+            list($function) = $controls[$control];
+            if (method_exists($this, $function)) {
+                $directives = $controls[$control];
+                array_shift($directives); // remove the function variable; we won't need it
+                $this->$function($directives);
+            }
+        }
+    }
+
+    /**
+     * Read paragraph.
+     *
+     * @param array $directives
+     * @return void
+     */
+    private function readParagraph($directives)
+    {
+        list($property, $value) = $directives;
+        $this->textrun = $this->section->addTextRun();
+        $this->flags[$property] = $value;
+    }
+
+    /**
+     * Read style.
+     *
+     * @param array $directives
+     * @return void
+     */
+    private function readStyle($directives)
+    {
+        list($style, $property, $value) = $directives;
+        $this->flags['styles'][$style][$property] = $value;
+    }
+
+    /**
+     * Read skip.
+     *
+     * @param array $directives
+     * @return void
+     */
+    private function readSkip($directives)
+    {
+        list($property) = $directives;
+        $this->flags['property'] = $property;
+        $this->flags['skipped'] = true;
+    }
+
+    /**
+     * Read text.
+     *
+     * @return void
+     */
+    private function readText()
+    {
+        $text = $this->textrun->addText($this->text);
+        if (isset($this->flags['styles']['font'])) {
+            $text->getFontStyle()->setStyleByArray($this->flags['styles']['font']);
+        }
+    }
+}

+ 41 - 0
includes/PhpWord/Reader/ReaderInterface.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+/**
+ * Reader interface
+ *
+ * @since 0.8.0
+ */
+interface ReaderInterface
+{
+    /**
+     * Can the current ReaderInterface read the file?
+     *
+     * @param  string $filename
+     * @return boolean
+     */
+    public function canRead($filename);
+
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $filename
+     */
+    public function load($filename);
+}

+ 169 - 0
includes/PhpWord/Reader/Word2007.php

@@ -0,0 +1,169 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+use PhpOffice\PhpWord\Shared\ZipArchive;
+
+/**
+ * Reader for Word2007
+ *
+ * @since 0.8.0
+ * @todo watermark, checkbox, toc
+ * @todo Partly done: image, object
+ */
+class Word2007 extends AbstractReader implements ReaderInterface
+{
+    /**
+     * Loads PhpWord from file
+     *
+     * @param string $docFile
+     * @return \PhpOffice\PhpWord\PhpWord
+     */
+    public function load($docFile)
+    {
+        $phpWord = new PhpWord();
+        $relationships = $this->readRelationships($docFile);
+
+        $steps = array(
+            array('stepPart' => 'document', 'stepItems' => array(
+                'styles'    => 'Styles',
+                'numbering' => 'Numbering',
+            )),
+            array('stepPart' => 'main', 'stepItems' => array(
+                'officeDocument'      => 'Document',
+                'core-properties'     => 'DocPropsCore',
+                'extended-properties' => 'DocPropsApp',
+                'custom-properties'   => 'DocPropsCustom',
+            )),
+            array('stepPart' => 'document', 'stepItems' => array(
+                'endnotes'  => 'Endnotes',
+                'footnotes' => 'Footnotes',
+            )),
+        );
+
+        foreach ($steps as $step) {
+            $stepPart = $step['stepPart'];
+            $stepItems = $step['stepItems'];
+            foreach ($relationships[$stepPart] as $relItem) {
+                $relType = $relItem['type'];
+                if (isset($stepItems[$relType])) {
+                    $partName = $stepItems[$relType];
+                    $xmlFile = $relItem['target'];
+                    $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile);
+                }
+            }
+        }
+
+        return $phpWord;
+    }
+
+    /**
+     * Read document part.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @param array $relationships
+     * @param string $partName
+     * @param string $docFile
+     * @param string $xmlFile
+     * @return void
+     */
+    private function readPart(PhpWord $phpWord, $relationships, $partName, $docFile, $xmlFile)
+    {
+        $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}";
+        if (class_exists($partClass)) {
+            /** @var \PhpOffice\PhpWord\Reader\Word2007\AbstractPart $part Type hint */
+            $part = new $partClass($docFile, $xmlFile);
+            $part->setRels($relationships);
+            $part->read($phpWord);
+        }
+
+    }
+
+    /**
+     * Read all relationship files
+     *
+     * @param string $docFile
+     * @return array
+     */
+    private function readRelationships($docFile)
+    {
+        $relationships = array();
+
+        // _rels/.rels
+        $relationships['main'] = $this->getRels($docFile, '_rels/.rels');
+
+        // word/_rels/*.xml.rels
+        $wordRelsPath = 'word/_rels/';
+        $zip = new ZipArchive();
+        if ($zip->open($docFile) === true) {
+            for ($i = 0; $i < $zip->numFiles; $i++) {
+                $xmlFile = $zip->getNameIndex($i);
+                if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') {
+                    $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile));
+                    $relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/');
+                }
+            }
+            $zip->close();
+        }
+
+        return $relationships;
+    }
+
+    /**
+     * Get relationship array
+     *
+     * @param string $docFile
+     * @param string $xmlFile
+     * @param string $targetPrefix
+     * @return array
+     */
+    private function getRels($docFile, $xmlFile, $targetPrefix = '')
+    {
+        $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/';
+        $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
+
+        $rels = array();
+
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($docFile, $xmlFile);
+        $nodes = $xmlReader->getElements('*');
+        foreach ($nodes as $node) {
+            $rId = $xmlReader->getAttribute('Id', $node);
+            $type = $xmlReader->getAttribute('Type', $node);
+            $target = $xmlReader->getAttribute('Target', $node);
+
+            // Remove URL prefixes from $type to make it easier to read
+            $type = str_replace($metaPrefix, '', $type);
+            $type = str_replace($officePrefix, '', $type);
+            $docPart = str_replace('.xml', '', $target);
+
+            // Do not add prefix to link source
+            if (!in_array($type, array('hyperlink'))) {
+                $target = $targetPrefix . $target;
+            }
+
+            // Push to return array
+            $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart);
+        }
+        ksort($rels);
+
+        return $rels;
+    }
+}

+ 515 - 0
includes/PhpWord/Reader/Word2007/AbstractPart.php

@@ -0,0 +1,515 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Abstract part reader
+ *
+ * This class is inherited by ODText reader
+ *
+ * @since 0.10.0
+ */
+abstract class AbstractPart
+{
+    /**
+     * Conversion method
+     *
+     * @const int
+     */
+    const READ_VALUE = 'attributeValue';            // Read attribute value
+    const READ_EQUAL = 'attributeEquals';           // Read `true` when attribute value equals specified value
+    const READ_TRUE  = 'attributeTrue';             // Read `true` when element exists
+    const READ_FALSE = 'attributeFalse';            // Read `false` when element exists
+    const READ_SIZE  = 'attributeMultiplyByTwo';    // Read special attribute value for Font::$size
+
+    /**
+     * Document file
+     *
+     * @var string
+     */
+    protected $docFile;
+
+    /**
+     * XML file
+     *
+     * @var string
+     */
+    protected $xmlFile;
+
+    /**
+     * Part relationships
+     *
+     * @var array
+     */
+    protected $rels = array();
+
+    /**
+     * Read part.
+     */
+    abstract public function read(PhpWord $phpWord);
+
+    /**
+     * Create new instance
+     *
+     * @param string $docFile
+     * @param string $xmlFile
+     */
+    public function __construct($docFile, $xmlFile)
+    {
+        $this->docFile = $docFile;
+        $this->xmlFile = $xmlFile;
+    }
+
+    /**
+     * Set relationships.
+     *
+     * @param array $value
+     * @return void
+     */
+    public function setRels($value)
+    {
+        $this->rels = $value;
+    }
+
+    /**
+     * Read w:p.
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @param mixed $parent
+     * @param string $docPart
+     * @return void
+     *
+     * @todo Get font style for preserve text
+     */
+    protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document')
+    {
+        // Paragraph style
+        $paragraphStyle = null;
+        $headingMatches = array();
+        if ($xmlReader->elementExists('w:pPr', $domNode)) {
+            $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode);
+            if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) {
+                preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches);
+            }
+        }
+
+        // PreserveText
+        if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) {
+            $ignoreText = false;
+            $textContent = '';
+            $fontStyle = $this->readFontStyle($xmlReader, $domNode);
+            $nodes = $xmlReader->getElements('w:r', $domNode);
+            foreach ($nodes as $node) {
+                $instrText = $xmlReader->getValue('w:instrText', $node);
+                if ($xmlReader->elementExists('w:fldChar', $node)) {
+                    $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar');
+                    if ($fldCharType == 'begin') {
+                        $ignoreText = true;
+                    } elseif ($fldCharType == 'end') {
+                        $ignoreText = false;
+                    }
+                }
+                if (!is_null($instrText)) {
+                    $textContent .= '{' . $instrText . '}';
+                } else {
+                    if ($ignoreText === false) {
+                        $textContent .= $xmlReader->getValue('w:t', $node);
+                    }
+                }
+            }
+            $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle);
+
+        // List item
+        } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) {
+            $textContent = '';
+            $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId');
+            $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl');
+            $nodes = $xmlReader->getElements('w:r', $domNode);
+            foreach ($nodes as $node) {
+                $textContent .= $xmlReader->getValue('w:t', $node);
+            }
+            $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $paragraphStyle);
+
+        // Heading
+        } elseif (!empty($headingMatches)) {
+            $textContent = '';
+            $nodes = $xmlReader->getElements('w:r', $domNode);
+            foreach ($nodes as $node) {
+                $textContent .= $xmlReader->getValue('w:t', $node);
+            }
+            $parent->addTitle($textContent, $headingMatches[1]);
+
+        // Text and TextRun
+        } else {
+            $runCount = $xmlReader->countElements('w:r', $domNode);
+            $linkCount = $xmlReader->countElements('w:hyperlink', $domNode);
+            $runLinkCount = $runCount + $linkCount;
+            if ($runLinkCount == 0) {
+                $parent->addTextBreak(null, $paragraphStyle);
+            } else {
+                $nodes = $xmlReader->getElements('*', $domNode);
+                foreach ($nodes as $node) {
+                    $this->readRun(
+                        $xmlReader,
+                        $node,
+                        ($runLinkCount > 1) ? $parent->addTextRun($paragraphStyle) : $parent,
+                        $docPart,
+                        $paragraphStyle
+                    );
+                }
+            }
+        }
+    }
+
+    /**
+     * Read w:r.
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @param mixed $parent
+     * @param string $docPart
+     * @param mixed $paragraphStyle
+     * @return void
+     *
+     * @todo Footnote paragraph style
+     */
+    protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart, $paragraphStyle = null)
+    {
+        if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) {
+            return;
+        }
+        $fontStyle = $this->readFontStyle($xmlReader, $domNode);
+
+        // Link
+        if ($domNode->nodeName == 'w:hyperlink') {
+            $rId = $xmlReader->getAttribute('r:id', $domNode);
+            $textContent = $xmlReader->getValue('w:r/w:t', $domNode);
+            $target = $this->getMediaTarget($docPart, $rId);
+            if (!is_null($target)) {
+                $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle);
+            }
+        } else {
+            // Footnote
+            if ($xmlReader->elementExists('w:footnoteReference', $domNode)) {
+                $parent->addFootnote();
+
+            // Endnote
+            } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) {
+                $parent->addEndnote();
+
+            // Image
+            } elseif ($xmlReader->elementExists('w:pict', $domNode)) {
+                $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata');
+                $target = $this->getMediaTarget($docPart, $rId);
+                if (!is_null($target)) {
+                    $imageSource = "zip://{$this->docFile}#{$target}";
+                    $parent->addImage($imageSource);
+                }
+
+            // Object
+            } elseif ($xmlReader->elementExists('w:object', $domNode)) {
+                $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:object/o:OLEObject');
+                // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata');
+                $target = $this->getMediaTarget($docPart, $rId);
+                if (!is_null($target)) {
+                    $textContent = "<Object: {$target}>";
+                    $parent->addText($textContent, $fontStyle, $paragraphStyle);
+                }
+
+            // TextRun
+            } else {
+                $textContent = $xmlReader->getValue('w:t', $domNode);
+                $parent->addText($textContent, $fontStyle, $paragraphStyle);
+            }
+        }
+    }
+
+    /**
+     * Read w:tbl.
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @param mixed $parent
+     * @param string $docPart
+     * @return void
+     */
+    protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart = 'document')
+    {
+        // Table style
+        $tblStyle = null;
+        if ($xmlReader->elementExists('w:tblPr', $domNode)) {
+            $tblStyle = $this->readTableStyle($xmlReader, $domNode);
+        }
+
+        /** @var \PhpOffice\PhpWord\Element\Table $table Type hint */
+        $table = $parent->addTable($tblStyle);
+        $tblNodes = $xmlReader->getElements('*', $domNode);
+        foreach ($tblNodes as $tblNode) {
+            if ($tblNode->nodeName == 'w:tblGrid') { // Column
+                // @todo Do something with table columns
+
+            } elseif ($tblNode->nodeName == 'w:tr') { // Row
+                $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight');
+                $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight');
+                $rowHRule = $rowHRule == 'exact' ? true : false;
+                $rowStyle = array(
+                    'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode),
+                    'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode),
+                    'exactHeight' => $rowHRule,
+                );
+
+                $row = $table->addRow($rowHeight, $rowStyle);
+                $rowNodes = $xmlReader->getElements('*', $tblNode);
+                foreach ($rowNodes as $rowNode) {
+                    if ($rowNode->nodeName == 'w:trPr') { // Row style
+                        // @todo Do something with row style
+
+                    } elseif ($rowNode->nodeName == 'w:tc') { // Cell
+                        $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW');
+                        $cellStyle = null;
+                        $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode);
+                        if (!is_null($cellStyleNode)) {
+                            $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode);
+                        }
+
+                        $cell = $row->addCell($cellWidth, $cellStyle);
+                        $cellNodes = $xmlReader->getElements('*', $rowNode);
+                        foreach ($cellNodes as $cellNode) {
+                            if ($cellNode->nodeName == 'w:p') { // Paragraph
+                                $this->readParagraph($xmlReader, $cellNode, $cell, $docPart);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Read w:pPr.
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @return array|null
+     */
+    protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode)
+    {
+        if (!$xmlReader->elementExists('w:pPr', $domNode)) {
+            return null;
+        }
+
+        $styleNode = $xmlReader->getElement('w:pPr', $domNode);
+        $styleDefs = array(
+            'styleName'       => array(self::READ_VALUE, 'w:pStyle'),
+            'align'           => array(self::READ_VALUE, 'w:jc'),
+            'basedOn'         => array(self::READ_VALUE, 'w:basedOn'),
+            'next'            => array(self::READ_VALUE, 'w:next'),
+            'indent'          => array(self::READ_VALUE, 'w:ind', 'w:left'),
+            'hanging'         => array(self::READ_VALUE, 'w:ind', 'w:hanging'),
+            'spaceAfter'      => array(self::READ_VALUE, 'w:spacing', 'w:after'),
+            'spaceBefore'     => array(self::READ_VALUE, 'w:spacing', 'w:before'),
+            'widowControl'    => array(self::READ_FALSE, 'w:widowControl'),
+            'keepNext'        => array(self::READ_TRUE,  'w:keepNext'),
+            'keepLines'       => array(self::READ_TRUE,  'w:keepLines'),
+            'pageBreakBefore' => array(self::READ_TRUE,  'w:pageBreakBefore'),
+        );
+
+        return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
+    }
+
+    /**
+     * Read w:rPr
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @return array|null
+     */
+    protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode)
+    {
+        if (is_null($domNode)) {
+            return null;
+        }
+        // Hyperlink has an extra w:r child
+        if ($domNode->nodeName == 'w:hyperlink') {
+            $domNode = $xmlReader->getElement('w:r', $domNode);
+        }
+        if (!$xmlReader->elementExists('w:rPr', $domNode)) {
+            return null;
+        }
+
+        $styleNode = $xmlReader->getElement('w:rPr', $domNode);
+        $styleDefs = array(
+            'styleName'           => array(self::READ_VALUE, 'w:rStyle'),
+            'name'                => array(self::READ_VALUE, 'w:rFonts', 'w:ascii'),
+            'hint'                => array(self::READ_VALUE, 'w:rFonts', 'w:hint'),
+            'size'                => array(self::READ_SIZE,  'w:sz'),
+            'color'               => array(self::READ_VALUE, 'w:color'),
+            'underline'           => array(self::READ_VALUE, 'w:u'),
+            'bold'                => array(self::READ_TRUE,  'w:b'),
+            'italic'              => array(self::READ_TRUE,  'w:i'),
+            'strikethrough'       => array(self::READ_TRUE,  'w:strike'),
+            'doubleStrikethrough' => array(self::READ_TRUE,  'w:dstrike'),
+            'smallCaps'           => array(self::READ_TRUE,  'w:smallCaps'),
+            'allCaps'             => array(self::READ_TRUE,  'w:caps'),
+            'superScript'         => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'superscript'),
+            'subScript'           => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'),
+            'fgColor'             => array(self::READ_VALUE, 'w:highlight'),
+            'rtl'                 => array(self::READ_TRUE,  'w:rtl'),
+        );
+
+        return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
+    }
+
+    /**
+     * Read w:tblPr
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @return string|array|null
+     * @todo Capture w:tblStylePr w:type="firstRow"
+     */
+    protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode)
+    {
+        $style = null;
+        $margins = array('top', 'left', 'bottom', 'right');
+        $borders = $margins + array('insideH', 'insideV');
+
+        if ($xmlReader->elementExists('w:tblPr', $domNode)) {
+            if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) {
+                $style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle');
+            } else {
+                $styleNode = $xmlReader->getElement('w:tblPr', $domNode);
+                $styleDefs = array();
+                // $styleDefs['styleName'] = array(self::READ_VALUE, 'w:tblStyle');
+                foreach ($margins as $side) {
+                    $ucfSide = ucfirst($side);
+                    $styleDefs["cellMargin$ucfSide"] = array(self::READ_VALUE, "w:tblCellMar/w:$side", 'w:w');
+                }
+                foreach ($borders as $side) {
+                    $ucfSide = ucfirst($side);
+                    $styleDefs["border{$ucfSide}Size"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz');
+                    $styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color');
+                }
+                $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);
+            }
+        }
+
+        return $style;
+    }
+
+    /**
+     * Read w:tcPr
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @return array
+     */
+    private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode)
+    {
+        $styleDefs = array(
+            'valign'        => array(self::READ_VALUE, 'w:vAlign'),
+            'textDirection' => array(self::READ_VALUE, 'w:textDirection'),
+            'gridSpan'      => array(self::READ_VALUE, 'w:gridSpan'),
+            'vMerge'        => array(self::READ_VALUE, 'w:vMerge'),
+            'bgColor'       => array(self::READ_VALUE, 'w:shd/w:fill'),
+        );
+
+        return $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
+    }
+
+    /**
+     * Read style definition
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $parentNode
+     * @param array $styleDefs
+     * @ignoreScrutinizerPatch
+     * @return array
+     */
+    protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = null, $styleDefs = array())
+    {
+        $styles = array();
+
+        foreach ($styleDefs as $styleProp => $styleVal) {
+            @list($method, $element, $attribute, $expected) = $styleVal;
+
+            if ($xmlReader->elementExists($element, $parentNode)) {
+                $node = $xmlReader->getElement($element, $parentNode);
+
+                // Use w:val as default if no attribute assigned
+                $attribute = ($attribute === null) ? 'w:val' : $attribute;
+                $attributeValue = $xmlReader->getAttribute($attribute, $node);
+
+                $styleValue = $this->readStyleDef($method, $attributeValue, $expected);
+                if ($styleValue !== null) {
+                    $styles[$styleProp] = $styleValue;
+                }
+            }
+        }
+
+        return $styles;
+    }
+
+    /**
+     * Return style definition based on conversion method
+     *
+     * @param string $method
+     * @ignoreScrutinizerPatch
+     * @param mixed $attributeValue
+     * @param mixed $expected
+     * @return mixed
+     */
+    private function readStyleDef($method, $attributeValue, $expected)
+    {
+        $style = $attributeValue;
+
+        if ($method == self::READ_SIZE) {
+            $style = $attributeValue / 2;
+        } elseif ($method == self::READ_TRUE) {
+            $style = true;
+        } elseif ($method == self::READ_FALSE) {
+            $style = false;
+        } elseif ($method == self::READ_EQUAL) {
+            $style = $attributeValue == $expected;
+        }
+
+        return $style;
+    }
+
+    /**
+     * Returns the target of image, object, or link as stored in ::readMainRels
+     *
+     * @param string $docPart
+     * @param string $rId
+     * @return string|null
+     */
+    private function getMediaTarget($docPart, $rId)
+    {
+        $target = null;
+
+        if (isset($this->rels[$docPart]) && isset($this->rels[$docPart][$rId])) {
+            $target = $this->rels[$docPart][$rId]['target'];
+        }
+
+        return $target;
+    }
+}

+ 40 - 0
includes/PhpWord/Reader/Word2007/DocPropsApp.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+/**
+ * Extended properties reader
+ *
+ * @since 0.10.0
+ */
+class DocPropsApp extends DocPropsCore
+{
+    /**
+     * Property mapping
+     *
+     * @var array
+     */
+    protected $mapping = array('Company' => 'setCompany', 'Manager' => 'setManager');
+
+    /**
+     * Callback functions
+     *
+     * @var array
+     */
+    protected $callbacks = array();
+}

+ 84 - 0
includes/PhpWord/Reader/Word2007/DocPropsCore.php

@@ -0,0 +1,84 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Core properties reader
+ *
+ * @since 0.10.0
+ */
+class DocPropsCore extends AbstractPart
+{
+    /**
+     * Property mapping
+     *
+     * @var array
+     */
+    protected $mapping = array(
+        'dc:creator' => 'setCreator',
+        'dc:title' => 'setTitle',
+        'dc:description' => 'setDescription',
+        'dc:subject' => 'setSubject',
+        'cp:keywords' => 'setKeywords',
+        'cp:category' => 'setCategory',
+        'cp:lastModifiedBy' => 'setLastModifiedBy',
+        'dcterms:created' => 'setCreated',
+        'dcterms:modified' => 'setModified',
+    );
+
+    /**
+     * Callback functions
+     *
+     * @var array
+     */
+    protected $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime');
+
+    /**
+     * Read core/extended document properties.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+
+        $docProps = $phpWord->getDocInfo();
+
+        $nodes = $xmlReader->getElements('*');
+        if ($nodes->length > 0) {
+            foreach ($nodes as $node) {
+                if (!isset($this->mapping[$node->nodeName])) {
+                    continue;
+                }
+                $method = $this->mapping[$node->nodeName];
+                $value = $node->nodeValue == '' ? null : $node->nodeValue;
+                if (isset($this->callbacks[$node->nodeName])) {
+                    $value = $this->callbacks[$node->nodeName]($value);
+                }
+                if (method_exists($docProps, $method)) {
+                    $docProps->$method($value);
+                }
+            }
+        }
+    }
+}

+ 56 - 0
includes/PhpWord/Reader/Word2007/DocPropsCustom.php

@@ -0,0 +1,56 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\Metadata\DocInfo;
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Custom properties reader
+ *
+ * @since 0.11.0
+ */
+class DocPropsCustom extends AbstractPart
+{
+    /**
+     * Read custom document properties.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+        $docProps = $phpWord->getDocInfo();
+
+        $nodes = $xmlReader->getElements('*');
+        if ($nodes->length > 0) {
+            foreach ($nodes as $node) {
+                $propertyName = $xmlReader->getAttribute('name', $node);
+                $attributeNode = $xmlReader->getElement('*', $node);
+                $attributeType = $attributeNode->nodeName;
+                $attributeValue = $attributeNode->nodeValue;
+                $attributeValue = DocInfo::convertProperty($attributeValue, $attributeType);
+                $attributeType = DocInfo::convertPropertyType($attributeType);
+                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);
+            }
+        }
+    }
+}

+ 186 - 0
includes/PhpWord/Reader/Word2007/Document.php

@@ -0,0 +1,186 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\Element\Section;
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Document reader
+ *
+ * @since 0.10.0
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
+ */
+class Document extends AbstractPart
+{
+    /**
+     * PhpWord object
+     *
+     * @var \PhpOffice\PhpWord\PhpWord
+     */
+    private $phpWord;
+
+    /**
+     * Read document.xml.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $this->phpWord = $phpWord;
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+        $readMethods = array('w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode');
+
+        $nodes = $xmlReader->getElements('w:body/*');
+        if ($nodes->length > 0) {
+            $section = $this->phpWord->addSection();
+            foreach ($nodes as $node) {
+                if (isset($readMethods[$node->nodeName])) {
+                    $readMethod = $readMethods[$node->nodeName];
+                    $this->$readMethod($xmlReader, $node, $section);
+                }
+            }
+        }
+    }
+
+    /**
+     * Read header footer.
+     *
+     * @param array $settings
+     * @param \PhpOffice\PhpWord\Element\Section &$section
+     * @return void
+     */
+    private function readHeaderFooter($settings, Section &$section)
+    {
+        $readMethods = array('w:p' => 'readParagraph', 'w:tbl' => 'readTable');
+
+        if (is_array($settings) && isset($settings['hf'])) {
+            foreach ($settings['hf'] as $rId => $hfSetting) {
+                if (isset($this->rels['document'][$rId])) {
+                    list($hfType, $xmlFile, $docPart) = array_values($this->rels['document'][$rId]);
+                    $addMethod = "add{$hfType}";
+                    $hfObject = $section->$addMethod($hfSetting['type']);
+
+                    // Read header/footer content
+                    $xmlReader = new XMLReader();
+                    $xmlReader->getDomFromZip($this->docFile, $xmlFile);
+                    $nodes = $xmlReader->getElements('*');
+                    if ($nodes->length > 0) {
+                        foreach ($nodes as $node) {
+                            if (isset($readMethods[$node->nodeName])) {
+                                $readMethod = $readMethods[$node->nodeName];
+                                $this->$readMethod($xmlReader, $node, $hfObject, $docPart);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Read w:sectPr
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $domNode
+     * @ignoreScrutinizerPatch
+     * @return array
+     */
+    private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode)
+    {
+        $styleDefs = array(
+            'breakType'     => array(self::READ_VALUE, 'w:type'),
+            'pageSizeW'     => array(self::READ_VALUE, 'w:pgSz', 'w:w'),
+            'pageSizeH'     => array(self::READ_VALUE, 'w:pgSz', 'w:h'),
+            'orientation'   => array(self::READ_VALUE, 'w:pgSz', 'w:orient'),
+            'colsNum'       => array(self::READ_VALUE, 'w:cols', 'w:num'),
+            'colsSpace'     => array(self::READ_VALUE, 'w:cols', 'w:space'),
+            'topMargin'     => array(self::READ_VALUE, 'w:pgMar', 'w:top'),
+            'leftMargin'    => array(self::READ_VALUE, 'w:pgMar', 'w:left'),
+            'bottomMargin'  => array(self::READ_VALUE, 'w:pgMar', 'w:bottom'),
+            'rightMargin'   => array(self::READ_VALUE, 'w:pgMar', 'w:right'),
+            'headerHeight'  => array(self::READ_VALUE, 'w:pgMar', 'w:header'),
+            'footerHeight'  => array(self::READ_VALUE, 'w:pgMar', 'w:footer'),
+            'gutter'        => array(self::READ_VALUE, 'w:pgMar', 'w:gutter'),
+        );
+        $styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
+
+        // Header and footer
+        // @todo Cleanup this part
+        $nodes = $xmlReader->getElements('*', $domNode);
+        foreach ($nodes as $node) {
+            if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') {
+                $id = $xmlReader->getAttribute('r:id', $node);
+                $styles['hf'][$id] = array(
+                    'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)),
+                    'type' => $xmlReader->getAttribute('w:type', $node),
+                );
+            }
+        }
+
+        return $styles;
+    }
+
+    /**
+     * Read w:p node.
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $node
+     * @param \PhpOffice\PhpWord\Element\Section &$section
+     * @return void
+     *
+     * @todo <w:lastRenderedPageBreak>
+     */
+    private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$section)
+    {
+        // Page break
+        if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') {
+            $section->addPageBreak(); // PageBreak
+        }
+
+        // Paragraph
+        $this->readParagraph($xmlReader, $node, $section);
+
+        // Section properties
+        if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) {
+            $sectPrNode = $xmlReader->getElement('w:pPr/w:sectPr', $node);
+            if ($sectPrNode !== null) {
+                $this->readWSectPrNode($xmlReader, $sectPrNode, $section);
+            }
+            $section = $this->phpWord->addSection();
+        }
+    }
+
+    /**
+     * Read w:sectPr node.
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $node
+     * @param \PhpOffice\PhpWord\Element\Section &$section
+     * @return void
+     */
+    private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section)
+    {
+        $style = $this->readSectionStyle($xmlReader, $node);
+        $section->setStyle($style);
+        $this->readHeaderFooter($style, $section);
+    }
+}

+ 40 - 0
includes/PhpWord/Reader/Word2007/Endnotes.php

@@ -0,0 +1,40 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+/**
+ * Endnotes reader
+ *
+ * @since 0.10.0
+ */
+class Endnotes extends Footnotes
+{
+    /**
+     * Collection name
+     *
+     * @var string
+     */
+    protected $collection = 'endnotes';
+
+    /**
+     * Element name
+     *
+     * @var string
+     */
+    protected $element = 'endnote';
+}

+ 77 - 0
includes/PhpWord/Reader/Word2007/Footnotes.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Footnotes reader
+ *
+ * @since 0.10.0
+ */
+class Footnotes extends AbstractPart
+{
+    /**
+     * Collection name footnotes|endnotes
+     *
+     * @var string
+     */
+    protected $collection = 'footnotes';
+
+    /**
+     * Element name footnote|endnote
+     *
+     * @var string
+     */
+    protected $element = 'footnote';
+
+    /**
+     * Read (footnotes|endnotes).xml.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $getMethod = "get{$this->collection}";
+        $collection = $phpWord->$getMethod()->getItems();
+
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+        $nodes = $xmlReader->getElements('*');
+        if ($nodes->length > 0) {
+            foreach ($nodes as $node) {
+                $id = $xmlReader->getAttribute('w:id', $node);
+                $type = $xmlReader->getAttribute('w:type', $node);
+
+                // Avoid w:type "separator" and "continuationSeparator"
+                // Only look for <footnote> or <endnote> without w:type attribute
+                if (is_null($type) && isset($collection[$id])) {
+                    $element = $collection[$id];
+                    $pNodes = $xmlReader->getElements('w:p/*', $node);
+                    foreach ($pNodes as $pNode) {
+                        $this->readRun($xmlReader, $pNode, $element, $this->collection);
+                    }
+                    $addMethod = "add{$this->element}";
+                    $phpWord->$addMethod($element);
+                }
+            }
+        }
+    }
+}

+ 123 - 0
includes/PhpWord/Reader/Word2007/Numbering.php

@@ -0,0 +1,123 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Numbering reader
+ *
+ * @since 0.10.0
+ */
+class Numbering extends AbstractPart
+{
+    /**
+     * Read numbering.xml.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $abstracts = array();
+        $numberings = array();
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+
+        // Abstract numbering definition
+        $nodes = $xmlReader->getElements('w:abstractNum');
+        if ($nodes->length > 0) {
+            foreach ($nodes as $node) {
+                $abstractId = $xmlReader->getAttribute('w:abstractNumId', $node);
+                $abstracts[$abstractId] = array('levels' => array());
+                $abstract = &$abstracts[$abstractId];
+                $subnodes = $xmlReader->getElements('*', $node);
+                foreach ($subnodes as $subnode) {
+                    switch ($subnode->nodeName) {
+                        case 'w:multiLevelType':
+                            $abstract['type'] = $xmlReader->getAttribute('w:val', $subnode);
+                            break;
+                        case 'w:lvl':
+                            $levelId = $xmlReader->getAttribute('w:ilvl', $subnode);
+                            $abstract['levels'][$levelId] = $this->readLevel($xmlReader, $subnode, $levelId);
+                            break;
+                    }
+                }
+            }
+        }
+
+        // Numbering instance definition
+        $nodes = $xmlReader->getElements('w:num');
+        if ($nodes->length > 0) {
+            foreach ($nodes as $node) {
+                $numId = $xmlReader->getAttribute('w:numId', $node);
+                $abstractId = $xmlReader->getAttribute('w:val', $node, 'w:abstractNumId');
+                $numberings[$numId] = $abstracts[$abstractId];
+                $numberings[$numId]['numId'] = $numId;
+                $subnodes = $xmlReader->getElements('w:lvlOverride/w:lvl', $node);
+                foreach ($subnodes as $subnode) {
+                    $levelId = $xmlReader->getAttribute('w:ilvl', $subnode);
+                    $overrides = $this->readLevel($xmlReader, $subnode, $levelId);
+                    foreach ($overrides as $key => $value) {
+                        $numberings[$numId]['levels'][$levelId][$key] = $value;
+                    }
+                }
+            }
+        }
+
+        // Push to Style collection
+        foreach ($numberings as $numId => $numbering) {
+            $phpWord->addNumberingStyle("PHPWordList{$numId}", $numbering);
+        }
+    }
+
+    /**
+     * Read numbering level definition from w:abstractNum and w:num
+     *
+     * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
+     * @param \DOMElement $subnode
+     * @param integer $levelId
+     * @return array
+     */
+    private function readLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId)
+    {
+        $level = array();
+
+        $level['level'] = $levelId;
+        $level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start');
+        $level['format'] = $xmlReader->getAttribute('w:val', $subnode, 'w:numFmt');
+        $level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart');
+        $level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff');
+        $level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText');
+        $level['align'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc');
+        $level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab');
+        $level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind');
+        $level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind');
+        $level['font'] = $xmlReader->getAttribute('w:ascii', $subnode, 'w:rPr/w:rFonts');
+        $level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts');
+
+        foreach ($level as $key => $value) {
+            if (is_null($value)) {
+                unset($level[$key]);
+            }
+        }
+
+        return $level;
+    }
+}

+ 86 - 0
includes/PhpWord/Reader/Word2007/Styles.php

@@ -0,0 +1,86 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Reader\Word2007;
+
+use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Shared\XMLReader;
+
+/**
+ * Styles reader
+ *
+ * @since 0.10.0
+ */
+class Styles extends AbstractPart
+{
+    /**
+     * Read styles.xml.
+     *
+     * @param \PhpOffice\PhpWord\PhpWord $phpWord
+     * @return void
+     */
+    public function read(PhpWord $phpWord)
+    {
+        $xmlReader = new XMLReader();
+        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
+
+        $nodes = $xmlReader->getElements('w:style');
+        if ($nodes->length > 0) {
+            foreach ($nodes as $node) {
+                $type = $xmlReader->getAttribute('w:type', $node);
+                $name = $xmlReader->getAttribute('w:styleId', $node);
+                if (is_null($name)) {
+                    $name = $xmlReader->getAttribute('w:val', $node, 'w:name');
+                }
+                preg_match('/Heading(\d)/', $name, $headingMatches);
+                // $default = ($xmlReader->getAttribute('w:default', $node) == 1);
+                switch ($type) {
+
+                    case 'paragraph':
+                        $paragraphStyle = $this->readParagraphStyle($xmlReader, $node);
+                        $fontStyle = $this->readFontStyle($xmlReader, $node);
+                        if (!empty($headingMatches)) {
+                            $phpWord->addTitleStyle($headingMatches[1], $fontStyle, $paragraphStyle);
+                        } else {
+                            if (empty($fontStyle)) {
+                                if (is_array($paragraphStyle)) {
+                                    $phpWord->addParagraphStyle($name, $paragraphStyle);
+                                }
+                            } else {
+                                $phpWord->addFontStyle($name, $fontStyle, $paragraphStyle);
+                            }
+                        }
+                        break;
+
+                    case 'character':
+                        $fontStyle = $this->readFontStyle($xmlReader, $node);
+                        if (!empty($fontStyle)) {
+                            $phpWord->addFontStyle($name, $fontStyle);
+                        }
+                        break;
+
+                    case 'table':
+                        $tStyle = $this->readTableStyle($xmlReader, $node);
+                        if (!empty($tStyle)) {
+                            $phpWord->addTableStyle($name, $tStyle);
+                        }
+                        break;
+                }
+            }
+        }
+    }
+}

+ 416 - 0
includes/PhpWord/Settings.php

@@ -0,0 +1,416 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord;
+
+/**
+ * PHPWord settings class
+ *
+ * @since 0.8.0
+ */
+class Settings
+{
+    /**
+     * Zip libraries
+     *
+     * @const string
+     */
+    const ZIPARCHIVE = 'ZipArchive';
+    const PCLZIP     = 'PclZip';
+    const OLD_LIB    = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; // @deprecated 0.11
+
+    /**
+     * PDF rendering libraries
+     *
+     * @const string
+     */
+    const PDF_RENDERER_DOMPDF = 'DomPDF';
+    const PDF_RENDERER_TCPDF  = 'TCPDF';
+    const PDF_RENDERER_MPDF   = 'MPDF';
+
+    /**
+     * Measurement units multiplication factor
+     *
+     * Applied to:
+     * - Section: margins, header/footer height, gutter, column spacing
+     * - Tab: position
+     * - Indentation: left, right, firstLine, hanging
+     * - Spacing: before, after
+     *
+     * @const string
+     */
+    const UNIT_TWIP  = 'twip'; // = 1/20 point
+    const UNIT_CM    = 'cm';
+    const UNIT_MM    = 'mm';
+    const UNIT_INCH  = 'inch';
+    const UNIT_POINT = 'point'; // = 1/72 inch
+    const UNIT_PICA  = 'pica'; // = 1/6 inch = 12 points
+
+    /**
+     * Default font settings
+     *
+     * OOXML defined font size values in halfpoints, i.e. twice of what PhpWord
+     * use, and the conversion will be conducted during XML writing.
+     */
+    const DEFAULT_FONT_NAME = 'Arial';
+    const DEFAULT_FONT_SIZE = 10;
+    const DEFAULT_FONT_COLOR = '000000';
+    const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs
+
+    /**
+     * Compatibility option for XMLWriter
+     *
+     * @var bool
+     */
+    private static $xmlWriterCompatibility = true;
+
+    /**
+     * Name of the class used for Zip file management
+     *
+     * @var string
+     */
+    private static $zipClass = self::ZIPARCHIVE;
+
+    /**
+     * Name of the external Library used for rendering PDF files
+     *
+     * @var string
+     */
+    private static $pdfRendererName = null;
+
+    /**
+     * Directory Path to the external Library used for rendering PDF files
+     *
+     * @var string
+     */
+    private static $pdfRendererPath = null;
+
+    /**
+     * Measurement unit
+     *
+     * @var int|float
+     */
+    private static $measurementUnit = self::UNIT_TWIP;
+
+    /**
+     * Default font name
+     *
+     * @var string
+     */
+    private static $defaultFontName = self::DEFAULT_FONT_NAME;
+
+    /**
+     * Default font size
+     * @var int
+     */
+    private static $defaultFontSize = self::DEFAULT_FONT_SIZE;
+
+    /**
+     * The user defined temporary directory.
+     *
+     * @var string
+     */
+    private static $tempDir = '';
+
+    /**
+     * Return the compatibility option used by the XMLWriter
+     *
+     * @return bool Compatibility
+     */
+    public static function hasCompatibility()
+    {
+        return self::$xmlWriterCompatibility;
+    }
+
+    /**
+     * Set the compatibility option used by the XMLWriter
+     *
+     * This sets the setIndent and setIndentString for better compatibility
+     *
+     * @param bool $compatibility
+     * @return bool
+     */
+    public static function setCompatibility($compatibility)
+    {
+        $compatibility = (bool)$compatibility;
+        self::$xmlWriterCompatibility = $compatibility;
+
+        return true;
+    }
+
+    /**
+     * Get zip handler class
+     *
+     * @return string
+     */
+    public static function getZipClass()
+    {
+        return self::$zipClass;
+    }
+
+    /**
+     * Set zip handler class
+     *
+     * @param  string $zipClass
+     * @return bool
+     */
+    public static function setZipClass($zipClass)
+    {
+        if (in_array($zipClass, array(self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB))) {
+            self::$zipClass = $zipClass;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Set details of the external library for rendering PDF files
+     *
+     * @param string $libraryName
+     * @param string $libraryBaseDir
+     * @return bool Success or failure
+     */
+    public static function setPdfRenderer($libraryName, $libraryBaseDir)
+    {
+        if (!self::setPdfRendererName($libraryName)) {
+            return false;
+        }
+
+        return self::setPdfRendererPath($libraryBaseDir);
+    }
+
+    /**
+     * Return the PDF Rendering Library.
+     *
+     * @return string
+     */
+    public static function getPdfRendererName()
+    {
+        return self::$pdfRendererName;
+    }
+
+    /**
+     * Identify the external library to use for rendering PDF files
+     *
+     * @param string $libraryName
+     * @return bool
+     */
+    public static function setPdfRendererName($libraryName)
+    {
+        $pdfRenderers = array(self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF);
+        if (!in_array($libraryName, $pdfRenderers)) {
+            return false;
+        }
+        self::$pdfRendererName = $libraryName;
+
+        return true;
+    }
+
+
+    /**
+     * Return the directory path to the PDF Rendering Library.
+     *
+     * @return string
+     */
+    public static function getPdfRendererPath()
+    {
+        return self::$pdfRendererPath;
+    }
+
+    /**
+     * Location of external library to use for rendering PDF files
+     *
+     * @param string $libraryBaseDir Directory path to the library's base folder
+     * @return bool Success or failure
+     */
+    public static function setPdfRendererPath($libraryBaseDir)
+    {
+        if (false === file_exists($libraryBaseDir) || false === is_readable($libraryBaseDir)) {
+            return false;
+        }
+        self::$pdfRendererPath = $libraryBaseDir;
+
+        return true;
+    }
+
+    /**
+     * Get measurement unit
+     *
+     * @return string
+     */
+    public static function getMeasurementUnit()
+    {
+        return self::$measurementUnit;
+    }
+
+    /**
+     * Set measurement unit
+     *
+     * @param string $value
+     * @return bool
+     */
+    public static function setMeasurementUnit($value)
+    {
+        $units = array(self::UNIT_TWIP, self::UNIT_CM, self::UNIT_MM, self::UNIT_INCH,
+            self::UNIT_POINT, self::UNIT_PICA);
+        if (!in_array($value, $units)) {
+            return false;
+        }
+        self::$measurementUnit = $value;
+
+        return true;
+    }
+
+    /**
+     * Sets the user defined path to temporary directory.
+     *
+     * @since 0.12.0
+     *
+     * @param string $tempDir The user defined path to temporary directory.
+     * @return void
+     */
+    public static function setTempDir($tempDir)
+    {
+        self::$tempDir = $tempDir;
+    }
+
+    /**
+     * Returns path to temporary directory.
+     *
+     * @since 0.12.0
+     *
+     * @return string
+     */
+    public static function getTempDir()
+    {
+        $tempDir = sys_get_temp_dir();
+
+        if (!empty(self::$tempDir)) {
+            $tempDir = self::$tempDir;
+        }
+
+        return $tempDir;
+    }
+
+    /**
+     * Get default font name
+     *
+     * @return string
+     */
+    public static function getDefaultFontName()
+    {
+        return self::$defaultFontName;
+    }
+
+    /**
+     * Set default font name
+     *
+     * @param string $value
+     * @return bool
+     */
+    public static function setDefaultFontName($value)
+    {
+        if (is_string($value) && trim($value) !== '') {
+            self::$defaultFontName = $value;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Get default font size
+     *
+     * @return integer
+     */
+    public static function getDefaultFontSize()
+    {
+        return self::$defaultFontSize;
+    }
+
+    /**
+     * Set default font size
+     *
+     * @param int $value
+     * @return bool
+     */
+    public static function setDefaultFontSize($value)
+    {
+        $value = intval($value);
+        if ($value > 0) {
+            self::$defaultFontSize = $value;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Load setting from phpword.yml or phpword.yml.dist
+     *
+     * @param string $filename
+     * @return array
+     */
+    public static function loadConfig($filename = null)
+    {
+        // Get config file
+        $configFile = null;
+        $configPath = __DIR__ . '/../../';
+        if ($filename !== null) {
+            $files = array($filename);
+        } else {
+            $files = array("{$configPath}phpword.ini", "{$configPath}phpword.ini.dist");
+        }
+        foreach ($files as $file) {
+            if (file_exists($file)) {
+                $configFile = realpath($file);
+                break;
+            }
+        }
+
+        // Parse config file
+        $config = array();
+        if ($configFile !== null) {
+            $config = @parse_ini_file($configFile);
+            if ($config === false) {
+                return $config;
+            }
+        }
+
+        // Set config value
+        foreach ($config as $key => $value) {
+            $method = "set{$key}";
+            if (method_exists(__CLASS__, $method)) {
+                self::$method($value);
+            }
+        }
+
+        return $config;
+    }
+
+    /**
+     * Return the compatibility option used by the XMLWriter
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public static function getCompatibility()
+    {
+        return self::hasCompatibility();
+    }
+}

+ 278 - 0
includes/PhpWord/Shared/Converter.php

@@ -0,0 +1,278 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+/**
+ * Common converter functions
+ */
+class Converter
+{
+    const INCH_TO_CM        = 2.54;
+    const INCH_TO_TWIP      = 1440;
+    const INCH_TO_PIXEL     = 96;
+    const INCH_TO_POINT     = 72;
+    const PIXEL_TO_EMU      = 9525;
+    const DEGREE_TO_ANGLE   = 60000;
+
+    /**
+     * Convert centimeter to twip
+     *
+     * @param int $centimeter
+     * @return float
+     */
+    public static function cmToTwip($centimeter = 1)
+    {
+        return $centimeter / self::INCH_TO_CM * self::INCH_TO_TWIP;
+    }
+
+    /**
+     * Convert centimeter to inch
+     *
+     * @param int $centimeter
+     * @return float
+     */
+    public static function cmToInch($centimeter = 1)
+    {
+        return $centimeter / self::INCH_TO_CM;
+    }
+
+    /**
+     * Convert centimeter to pixel
+     *
+     * @param int $centimeter
+     * @return float
+     */
+    public static function cmToPixel($centimeter = 1)
+    {
+        return $centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL;
+    }
+
+    /**
+     * Convert centimeter to point
+     *
+     * @param int $centimeter
+     * @return float
+     */
+    public static function cmToPoint($centimeter = 1)
+    {
+        return $centimeter / self::INCH_TO_CM * self::INCH_TO_POINT;
+    }
+
+    /**
+     * Convert centimeter to EMU
+     *
+     * @param int $centimeter
+     * @return int
+     */
+    public static function cmToEmu($centimeter = 1)
+    {
+        return round($centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
+    }
+
+    /**
+     * Convert inch to twip
+     *
+     * @param int $inch
+     * @return int
+     */
+    public static function inchToTwip($inch = 1)
+    {
+        return $inch * self::INCH_TO_TWIP;
+    }
+
+    /**
+     * Convert inch to centimeter
+     *
+     * @param int $inch
+     * @return float
+     */
+    public static function inchToCm($inch = 1)
+    {
+        return $inch * self::INCH_TO_CM;
+    }
+
+    /**
+     * Convert inch to pixel
+     *
+     * @param int $inch
+     * @return int
+     */
+    public static function inchToPixel($inch = 1)
+    {
+        return $inch * self::INCH_TO_PIXEL;
+    }
+
+    /**
+     * Convert inch to point
+     *
+     * @param int $inch
+     * @return int
+     */
+    public static function inchToPoint($inch = 1)
+    {
+        return $inch * self::INCH_TO_POINT;
+    }
+
+    /**
+     * Convert inch to EMU
+     *
+     * @param int $inch
+     * @return int
+     */
+    public static function inchToEmu($inch = 1)
+    {
+        return round($inch * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
+    }
+
+    /**
+     * Convert pixel to twip
+     *
+     * @param int $pixel
+     * @return int
+     */
+    public static function pixelToTwip($pixel = 1)
+    {
+        return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_TWIP;
+    }
+
+    /**
+     * Convert pixel to centimeter
+     *
+     * @param int $pixel
+     * @return float
+     */
+    public static function pixelToCm($pixel = 1)
+    {
+        return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_CM;
+    }
+
+    /**
+     * Convert pixel to point
+     *
+     * @param int $pixel
+     * @return float
+     */
+    public static function pixelToPoint($pixel = 1)
+    {
+        return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_POINT;
+    }
+
+    /**
+     * Convert pixel to EMU
+     *
+     * @param int $pixel
+     * @return int
+     */
+    public static function pixelToEmu($pixel = 1)
+    {
+        return round($pixel * self::PIXEL_TO_EMU);
+    }
+
+    /**
+     * Convert point to twip unit
+     *
+     * @param int $point
+     * @return int
+     */
+    public static function pointToTwip($point = 1)
+    {
+        return $point / self::INCH_TO_POINT * self::INCH_TO_TWIP;
+    }
+
+    /**
+     * Convert point to pixel
+     *
+     * @param int $point
+     * @return float
+     */
+    public static function pointToPixel($point = 1)
+    {
+        return $point / self::INCH_TO_POINT * self::INCH_TO_PIXEL;
+    }
+
+    /**
+     * Convert point to EMU
+     *
+     * @param int $point
+     * @return int
+     */
+    public static function pointToEmu($point = 1)
+    {
+        return round($point / self::INCH_TO_POINT * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
+    }
+
+    /**
+     * Convert EMU to pixel
+     *
+     * @param int $emu
+     * @return int
+     */
+    public static function emuToPixel($emu = 1)
+    {
+        return round($emu / self::PIXEL_TO_EMU);
+    }
+
+    /**
+     * Convert degree to angle
+     *
+     * @param int $degree
+     * @return int
+     */
+    public static function degreeToAngle($degree = 1)
+    {
+        return (int)round($degree * self::DEGREE_TO_ANGLE);
+    }
+
+    /**
+     * Convert angle to degrees
+     *
+     * @param int $angle
+     * @return int
+     */
+    public static function angleToDegree($angle = 1)
+    {
+        return round($angle / self::DEGREE_TO_ANGLE);
+    }
+
+    /**
+     * Convert HTML hexadecimal to RGB
+     *
+     * @param string $value HTML Color in hexadecimal
+     * @return array Value in RGB
+     */
+    public static function htmlToRgb($value)
+    {
+        if ($value[0] == '#') {
+            $value = substr($value, 1);
+        }
+
+        if (strlen($value) == 6) {
+            list($red, $green, $blue) = array($value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]);
+        } elseif (strlen($value) == 3) {
+            list($red, $green, $blue) = array($value[0] . $value[0], $value[1] . $value[1], $value[2] . $value[2]);
+        } else {
+            return false;
+        }
+
+        $red = hexdec($red);
+        $green = hexdec($green);
+        $blue = hexdec($blue);
+
+        return array($red, $green, $blue);
+    }
+}

+ 217 - 0
includes/PhpWord/Shared/Drawing.php

@@ -0,0 +1,217 @@
+<?php
+/**
+ * PHPWord
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2014 PHPWord
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+/**
+ * Common drawing functions
+ */
+class Drawing
+{
+    /**
+     * Convert pixels to EMU
+     *
+     * @param integer $pValue Value in pixels
+     * @return double Value in EMU
+     */
+    public static function pixelsToEMU($pValue = 0)
+    {
+        return round($pValue * 9525);
+    }
+
+    /**
+     * Convert EMU to pixels
+     *
+     * @param integer $pValue Value in EMU
+     * @return integer Value in pixels
+     */
+    public static function emuToPixels($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return round($pValue / 9525);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert pixels to points
+     *
+     * @param integer $pValue Value in pixels
+     * @return double Value in points
+     */
+    public static function pixelsToPoints($pValue = 0)
+    {
+        return $pValue * 0.67777777;
+    }
+
+    /**
+     * Convert points width to pixels
+     *
+     * @param integer $pValue Value in points
+     * @return integer Value in pixels
+     */
+    public static function pointsToPixels($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return $pValue * 1.333333333;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert degrees to angle
+     *
+     * @param integer $pValue Degrees
+     * @return integer Angle
+     */
+    public static function degreesToAngle($pValue = 0)
+    {
+        return (integer)round($pValue * 60000);
+    }
+
+    /**
+     * Convert angle to degrees
+     *
+     * @param integer $pValue Angle
+     * @return integer Degrees
+     */
+    public static function angleToDegrees($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return round($pValue / 60000);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert pixels to centimeters
+     *
+     * @param integer $pValue Value in pixels
+     * @return double Value in centimeters
+     */
+    public static function pixelsToCentimeters($pValue = 0)
+    {
+        return $pValue * 0.028;
+    }
+
+    /**
+     * Convert centimeters width to pixels
+     *
+     * @param integer $pValue Value in centimeters
+     * @return integer Value in pixels
+     */
+    public static function centimetersToPixels($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return $pValue / 0.028;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert centimeters width to twips
+     *
+     * @param integer $pValue
+     */
+    public static function centimetersToTwips($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return $pValue * 566.928;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert twips width to centimeters
+     *
+     * @param integer $pValue
+     */
+    public static function twipsToCentimeters($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return $pValue / 566.928;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert inches width to twips
+     *
+     * @param integer $pValue
+     */
+    public static function inchesToTwips($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return $pValue * 1440;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert twips width to inches
+     *
+     * @param integer $pValue
+     */
+    public static function twipsToInches($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return $pValue / 1440;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert twips width to pixels
+     *
+     * @param integer $pValue
+     */
+    public static function twipsToPixels($pValue = 0)
+    {
+        if ($pValue != 0) {
+            return round($pValue / 15.873984);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Convert HTML hexadecimal to RGB
+     *
+     * @param string $pValue HTML Color in hexadecimal
+     * @return array Value in RGB
+     */
+    public static function htmlToRGB($pValue)
+    {
+        if ($pValue[0] == '#') {
+            $pValue = substr($pValue, 1);
+        }
+
+        if (strlen($pValue) == 6) {
+            list($colorR, $colorG, $colorB) = array($pValue[0] . $pValue[1], $pValue[2] . $pValue[3], $pValue[4] . $pValue[5]);
+        } elseif (strlen($pValue) == 3) {
+            list($colorR, $colorG, $colorB) = array($pValue[0] . $pValue[0], $pValue[1] . $pValue[1], $pValue[2] . $pValue[2]);
+        } else {
+            return false;
+        }
+
+        $colorR = hexdec($colorR);
+        $colorG = hexdec($colorG);
+        $colorB = hexdec($colorB);
+
+        return array($colorR, $colorG, $colorB);
+    }
+}

+ 104 - 0
includes/PhpWord/Shared/Font.php

@@ -0,0 +1,104 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+/**
+ * DEPRECATED: Common font functions; Use 'Converter'
+ *
+ * @deprecated 0.12.0
+ * @codeCoverageIgnore
+ */
+class Font
+{
+    /**
+     * Calculate an (approximate) pixel size, based on a font points size
+     *
+     * @param int $fontSizeInPoints Font size (in points)
+     * @return int Font size (in pixels)
+     */
+    public static function fontSizeToPixels($fontSizeInPoints = 12)
+    {
+        return Converter::pointToPixel($fontSizeInPoints);
+    }
+
+    /**
+     * Calculate an (approximate) pixel size, based on inch size
+     *
+     * @param int $sizeInInch Font size (in inch)
+     * @return int Size (in pixels)
+     */
+    public static function inchSizeToPixels($sizeInInch = 1)
+    {
+        return Converter::inchToPixel($sizeInInch);
+    }
+
+    /**
+     * Calculate an (approximate) pixel size, based on centimeter size
+     *
+     * @param int $sizeInCm Font size (in centimeters)
+     * @return double Size (in pixels)
+     */
+    public static function centimeterSizeToPixels($sizeInCm = 1)
+    {
+        return Converter::cmToPixel($sizeInCm);
+    }
+
+    /**
+     * Convert centimeter to twip
+     *
+     * @param int $sizeInCm
+     * @return double
+     */
+    public static function centimeterSizeToTwips($sizeInCm = 1)
+    {
+        return Converter::cmToTwip($sizeInCm);
+    }
+
+    /**
+     * Convert inch to twip
+     *
+     * @param int $sizeInInch
+     * @return double
+     */
+    public static function inchSizeToTwips($sizeInInch = 1)
+    {
+        return Converter::inchToTwip($sizeInInch);
+    }
+
+    /**
+     * Convert pixel to twip
+     *
+     * @param int $sizeInPixel
+     * @return double
+     */
+    public static function pixelSizeToTwips($sizeInPixel = 1)
+    {
+        return Converter::pixelToTwip($sizeInPixel);
+    }
+
+    /**
+     * Calculate twip based on point size, used mainly for paragraph spacing
+     *
+     * @param integer $sizeInPoint Size in point
+     * @return integer Size (in twips)
+     */
+    public static function pointSizeToTwips($sizeInPoint = 1)
+    {
+        return Converter::pointToTwip($sizeInPoint);
+    }
+}

+ 377 - 0
includes/PhpWord/Shared/Html.php

@@ -0,0 +1,377 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+use PhpOffice\PhpWord\Element\AbstractContainer;
+
+/**
+ * Common Html functions
+ *
+ * @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
+ */
+class Html
+{
+    /**
+     * Add HTML parts.
+     *
+     * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter
+     *
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added
+     * @param string $html The code to parse
+     * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag
+     * @return void
+     */
+    public static function addHtml($element, $html, $fullHTML = false)
+    {
+        /*
+         * @todo parse $stylesheet for default styles.  Should result in an array based on id, class and element,
+         * which could be applied when such an element occurs in the parseNode function.
+         */
+
+        // Preprocess: remove all line ends, decode HTML entity,
+        // fix ampersand and angle brackets and add body tag for HTML fragments
+        $html = str_replace(array("\n", "\r"), '', $html);
+        $html = str_replace(array('&lt;', '&gt;', '&amp;'), array('_lt_', '_gt_', '_amp_'), $html);
+        $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');
+        $html = str_replace('&', '&amp;', $html);
+        $html = str_replace(array('_lt_', '_gt_', '_amp_'), array('&lt;', '&gt;', '&amp;'), $html);
+
+        if ($fullHTML === false) {
+            $html = '<body>' . $html . '</body>';
+        }
+
+        // Load DOM
+        $dom = new \DOMDocument();
+        $dom->preserveWhiteSpace = true;
+        $dom->loadXML($html);
+        $node = $dom->getElementsByTagName('body');
+
+        self::parseNode($node->item(0), $element);
+    }
+
+    /**
+     * parse Inline style of a node
+     *
+     * @param \DOMNode $node Node to check on attributes and to compile a style array
+     * @param array $styles is supplied, the inline style attributes are added to the already existing style
+     * @return array
+     */
+    protected static function parseInlineStyle($node, $styles = array())
+    {
+        if ($node->nodeType == XML_ELEMENT_NODE) {
+            $attributes = $node->attributes; // get all the attributes(eg: id, class)
+
+            foreach ($attributes as $attribute) {
+                switch ($attribute->name) {
+                    case 'style':
+                        $styles = self::parseStyle($attribute, $styles);
+                        break;
+                }
+            }
+        }
+
+        return $styles;
+    }
+
+    /**
+     * Parse a node and add a corresponding element to the parent element.
+     *
+     * @param \DOMNode $node node to parse
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element object to add an element corresponding with the node
+     * @param array $styles Array with all styles
+     * @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems
+     * @return void
+     */
+    protected static function parseNode($node, $element, $styles = array(), $data = array())
+    {
+        // Populate styles array
+        $styleTypes = array('font', 'paragraph', 'list');
+        foreach ($styleTypes as $styleType) {
+            if (!isset($styles[$styleType])) {
+                $styles[$styleType] = array();
+            }
+        }
+
+        // Node mapping table
+        $nodes = array(
+                              // $method        $node   $element    $styles     $data   $argument1      $argument2
+            'p'         => array('Paragraph',   $node,  $element,   $styles,    null,   null,           null),
+            'h1'        => array('Heading',     null,   $element,   $styles,    null,   'Heading1',     null),
+            'h2'        => array('Heading',     null,   $element,   $styles,    null,   'Heading2',     null),
+            'h3'        => array('Heading',     null,   $element,   $styles,    null,   'Heading3',     null),
+            'h4'        => array('Heading',     null,   $element,   $styles,    null,   'Heading4',     null),
+            'h5'        => array('Heading',     null,   $element,   $styles,    null,   'Heading5',     null),
+            'h6'        => array('Heading',     null,   $element,   $styles,    null,   'Heading6',     null),
+            '#text'     => array('Text',        $node,  $element,   $styles,    null,   null,           null),
+            'strong'    => array('Property',    null,   null,       $styles,    null,   'bold',         true),
+            'em'        => array('Property',    null,   null,       $styles,    null,   'italic',       true),
+            'sup'       => array('Property',    null,   null,       $styles,    null,   'superScript',  true),
+            'sub'       => array('Property',    null,   null,       $styles,    null,   'subScript',    true),
+            'table'     => array('Table',       $node,  $element,   $styles,    null,   'addTable',     true),
+            'tr'        => array('Table',       $node,  $element,   $styles,    null,   'addRow',       true),
+            'td'        => array('Table',       $node,  $element,   $styles,    null,   'addCell',      true),
+            'ul'        => array('List',        null,   null,       $styles,    $data,  3,              null),
+            'ol'        => array('List',        null,   null,       $styles,    $data,  7,              null),
+            'li'        => array('ListItem',    $node,  $element,   $styles,    $data,  null,           null),
+        );
+
+        $newElement = null;
+        $keys = array('node', 'element', 'styles', 'data', 'argument1', 'argument2');
+
+        if (isset($nodes[$node->nodeName])) {
+            // Execute method based on node mapping table and return $newElement or null
+            // Arguments are passed by reference
+            $arguments = array();
+            $args = array();
+            list($method, $args[0], $args[1], $args[2], $args[3], $args[4], $args[5]) = $nodes[$node->nodeName];
+            for ($i = 0; $i <= 5; $i++) {
+                if ($args[$i] !== null) {
+                    $arguments[$keys[$i]] = &$args[$i];
+                }
+            }
+            $method = "parse{$method}";
+            $newElement = call_user_func_array(array('PhpOffice\PhpWord\Shared\Html', $method), $arguments);
+
+            // Retrieve back variables from arguments
+            foreach ($keys as $key) {
+                if (array_key_exists($key, $arguments)) {
+                    $$key = $arguments[$key];
+                }
+            }
+        }
+
+        if ($newElement === null) {
+            $newElement = $element;
+        }
+
+        self::parseChildNodes($node, $newElement, $styles, $data);
+    }
+
+    /**
+     * Parse child nodes.
+     *
+     * @param \DOMNode $node
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+     * @param array $styles
+     * @param array $data
+     * @return void
+     */
+    private static function parseChildNodes($node, $element, $styles, $data)
+    {
+        if ($node->nodeName != 'li') {
+            $cNodes = $node->childNodes;
+            if (count($cNodes) > 0) {
+                foreach ($cNodes as $cNode) {
+                    if ($element instanceof AbstractContainer) {
+                        self::parseNode($cNode, $element, $styles, $data);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Parse paragraph node
+     *
+     * @param \DOMNode $node
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+     * @param array &$styles
+     * @return \PhpOffice\PhpWord\Element\TextRun
+     */
+    private static function parseParagraph($node, $element, &$styles)
+    {
+        $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']);
+        $newElement = $element->addTextRun($styles['paragraph']);
+
+        return $newElement;
+    }
+
+    /**
+     * Parse heading node
+     *
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+     * @param array &$styles
+     * @param string $argument1 Name of heading style
+     * @return \PhpOffice\PhpWord\Element\TextRun
+     *
+     * @todo Think of a clever way of defining header styles, now it is only based on the assumption, that
+     * Heading1 - Heading6 are already defined somewhere
+     */
+    private static function parseHeading($element, &$styles, $argument1)
+    {
+        $styles['paragraph'] = $argument1;
+        $newElement = $element->addTextRun($styles['paragraph']);
+
+        return $newElement;
+    }
+
+    /**
+     * Parse text node
+     *
+     * @param \DOMNode $node
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+     * @param array &$styles
+     * @return null
+     */
+    private static function parseText($node, $element, &$styles)
+    {
+        $styles['font'] = self::parseInlineStyle($node, $styles['font']);
+
+        // Commented as source of bug #257. `method_exists` doesn't seems to work properly in this case.
+        // @todo Find better error checking for this one
+        // if (method_exists($element, 'addText')) {
+            $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);
+        // }
+
+        return null;
+    }
+
+    /**
+     * Parse property node
+     *
+     * @param array &$styles
+     * @param string $argument1 Style name
+     * @param string $argument2 Style value
+     * @return null
+     */
+    private static function parseProperty(&$styles, $argument1, $argument2)
+    {
+        $styles['font'][$argument1] = $argument2;
+
+        return null;
+    }
+
+    /**
+     * Parse table node
+     *
+     * @param \DOMNode $node
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+     * @param array &$styles
+     * @param string $argument1 Method name
+     * @return \PhpOffice\PhpWord\Element\AbstractContainer $element
+     *
+     * @todo As soon as TableItem, RowItem and CellItem support relative width and height
+     */
+    private static function parseTable($node, $element, &$styles, $argument1)
+    {
+        $styles['paragraph'] = self::parseInlineStyle($node, $styles['paragraph']);
+
+        $newElement = $element->$argument1();
+
+        // $attributes = $node->attributes;
+        // if ($attributes->getNamedItem('width') !== null) {
+            // $newElement->setWidth($attributes->getNamedItem('width')->value);
+        // }
+
+        // if ($attributes->getNamedItem('height') !== null) {
+            // $newElement->setHeight($attributes->getNamedItem('height')->value);
+        // }
+        // if ($attributes->getNamedItem('width') !== null) {
+            // $newElement=$element->addCell($width=$attributes->getNamedItem('width')->value);
+        // }
+
+        return $newElement;
+    }
+
+    /**
+     * Parse list node
+     *
+     * @param array &$styles
+     * @param array &$data
+     * @param string $argument1 List type
+     * @return null
+     */
+    private static function parseList(&$styles, &$data, $argument1)
+    {
+        if (isset($data['listdepth'])) {
+            $data['listdepth']++;
+        } else {
+            $data['listdepth'] = 0;
+        }
+        $styles['list']['listType'] = $argument1;
+
+        return null;
+    }
+
+    /**
+     * Parse list item node
+     *
+     * @param \DOMNode $node
+     * @param \PhpOffice\PhpWord\Element\AbstractContainer $element
+     * @param array &$styles
+     * @param array $data
+     * @return null
+     *
+     * @todo This function is almost the same like `parseChildNodes`. Merged?
+     * @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes
+     */
+    private static function parseListItem($node, $element, &$styles, $data)
+    {
+        $cNodes = $node->childNodes;
+        if (count($cNodes) > 0) {
+            $text = '';
+            foreach ($cNodes as $cNode) {
+                if ($cNode->nodeName == '#text') {
+                    $text = $cNode->nodeValue;
+                }
+            }
+            $element->addListItem($text, $data['listdepth'], $styles['font'], $styles['list'], $styles['paragraph']);
+        }
+
+        return null;
+    }
+
+    /**
+     * Parse style
+     *
+     * @param \DOMAttr $attribute
+     * @param array $styles
+     * @return array
+     */
+    private static function parseStyle($attribute, $styles)
+    {
+        $properties = explode(';', trim($attribute->value, " \t\n\r\0\x0B;"));
+        foreach ($properties as $property) {
+            list($cKey, $cValue) = explode(':', $property, 2);
+            $cValue = trim($cValue);
+            switch (trim($cKey)) {
+                case 'text-decoration':
+                    switch ($cValue) {
+                        case 'underline':
+                            $styles['underline'] = 'single';
+                            break;
+                        case 'line-through':
+                            $styles['strikethrough'] = true;
+                            break;
+                    }
+                    break;
+                case 'text-align':
+                    $styles['align'] = $cValue;
+                    break;
+                case 'color':
+                    $styles['color'] = trim($cValue, "#");
+                    break;
+                case 'background-color':
+                    $styles['bgColor'] = trim($cValue, "#");
+                    break;
+            }
+        }
+
+        return $styles;
+    }
+}

+ 313 - 0
includes/PhpWord/Shared/OLERead.php

@@ -0,0 +1,313 @@
+<?php
+/**
+ * PHPWord
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2014 PHPWord
+ * @license     http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+
+use PhpOffice\PhpWord\Exception\Exception;
+
+defined('IDENTIFIER_OLE') ||
+define('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));
+
+class OLERead
+{
+    private $data = '';
+
+    // OLE identifier
+    const IDENTIFIER_OLE = IDENTIFIER_OLE;
+
+    // Size of a sector = 512 bytes
+    const BIG_BLOCK_SIZE                    = 0x200;
+
+    // Size of a short sector = 64 bytes
+    const SMALL_BLOCK_SIZE                  = 0x40;
+
+    // Size of a directory entry always = 128 bytes
+    const PROPERTY_STORAGE_BLOCK_SIZE       = 0x80;
+
+    // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
+    const SMALL_BLOCK_THRESHOLD             = 0x1000;
+
+    // header offsets
+    const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS    = 0x2c;
+    const ROOT_START_BLOCK_POS              = 0x30;
+    const SMALL_BLOCK_DEPOT_BLOCK_POS       = 0x3c;
+    const EXTENSION_BLOCK_POS               = 0x44;
+    const NUM_EXTENSION_BLOCK_POS           = 0x48;
+    const BIG_BLOCK_DEPOT_BLOCKS_POS        = 0x4c;
+
+    // property storage offsets (directory offsets)
+    const SIZE_OF_NAME_POS                  = 0x40;
+    const TYPE_POS                          = 0x42;
+    const START_BLOCK_POS                   = 0x74;
+    const SIZE_POS                          = 0x78;
+
+
+
+    public $wrkdocument                     = null;
+    public $wrk1Table                       = null;
+    public $wrkData                         = null;
+    public $wrkObjectPool                   = null;
+    public $summaryInformation              = null;
+    public $docSummaryInfos                 = null;
+
+
+    /**
+     * Read the file
+     *
+     * @param $sFileName string Filename
+     * @throws Exception
+     */
+    public function read($sFileName)
+    {
+        // Check if file exists and is readable
+        if (!is_readable($sFileName)) {
+            throw new Exception("Could not open " . $sFileName . " for reading! File does not exist, or it is not readable.");
+        }
+
+        // Get the file identifier
+        // Don't bother reading the whole file until we know it's a valid OLE file
+        $this->data = file_get_contents($sFileName, false, null, 0, 8);
+
+        // Check OLE identifier
+        if ($this->data != self::IDENTIFIER_OLE) {
+            throw new Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');
+        }
+
+        // Get the file data
+        $this->data = file_get_contents($sFileName);
+
+        // Total number of sectors used for the SAT
+        $this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);
+
+        // SecID of the first sector of the directory stream
+        $this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS);
+
+        // SecID of the first sector of the SSAT (or -2 if not extant)
+        $this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);
+
+        // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
+        $this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS);
+
+        // Total number of sectors used by MSAT
+        $this->numExtensionBlocks = self::getInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);
+
+        $bigBlockDepotBlocks = array();
+        $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;
+
+        $bbdBlocks = $this->numBigBlockDepotBlocks;
+
+        if ($this->numExtensionBlocks != 0) {
+            $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS)/4;
+        }
+
+        for ($i = 0; $i < $bbdBlocks; ++$i) {
+            $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
+            $pos += 4;
+        }
+
+        for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
+            $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
+            $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);
+
+            for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
+                $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
+                $pos += 4;
+            }
+
+            $bbdBlocks += $blocksToRead;
+            if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
+                $this->extensionBlock = self::getInt4d($this->data, $pos);
+            }
+        }
+
+        $pos = 0;
+        $this->bigBlockChain = '';
+        $bbs = self::BIG_BLOCK_SIZE / 4;
+        for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
+            $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;
+
+            $this->bigBlockChain .= substr($this->data, $pos, 4*$bbs);
+            $pos += 4*$bbs;
+        }
+
+        $pos = 0;
+        $sbdBlock = $this->sbdStartBlock;
+        $this->smallBlockChain = '';
+        while ($sbdBlock != -2) {
+            $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;
+
+            $this->smallBlockChain .= substr($this->data, $pos, 4*$bbs);
+            $pos += 4*$bbs;
+
+            $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock*4);
+        }
+
+        // read the directory stream
+        $block = $this->rootStartBlock;
+        $this->entry = $this->readData($block);
+
+        $this->readPropertySets();
+    }
+
+    /**
+     * Extract binary stream data
+     *
+     * @return string
+     */
+    public function getStream($stream)
+    {
+        if ($stream === null) {
+            return null;
+        }
+
+        $streamData = '';
+
+        if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
+            $rootdata = $this->readData($this->props[$this->rootentry]['startBlock']);
+
+            $block = $this->props[$stream]['startBlock'];
+
+            while ($block != -2) {
+                $pos = $block * self::SMALL_BLOCK_SIZE;
+                $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);
+
+                $block = self::getInt4d($this->smallBlockChain, $block*4);
+            }
+
+            return $streamData;
+        } else {
+            $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
+            if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
+                ++$numBlocks;
+            }
+
+            if ($numBlocks == 0) {
+                return '';
+            }
+
+            $block = $this->props[$stream]['startBlock'];
+
+            while ($block != -2) {
+                $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
+                $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
+                $block = self::getInt4d($this->bigBlockChain, $block*4);
+            }
+
+            return $streamData;
+        }
+    }
+
+    /**
+     * Read a standard stream (by joining sectors using information from SAT)
+     *
+     * @param int $blSectorId Sector ID where the stream starts
+     * @return string Data for standard stream
+     */
+    private function readData($blSectorId)
+    {
+        $block = $blSectorId;
+        $data = '';
+
+        while ($block != -2) {
+            $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
+            $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
+            $block = self::getInt4d($this->bigBlockChain, $block*4);
+        }
+        return $data;
+    }
+
+    /**
+     * Read entries in the directory stream.
+     */
+    private function readPropertySets()
+    {
+        $offset = 0;
+
+        // loop through entires, each entry is 128 bytes
+        $entryLen = strlen($this->entry);
+        while ($offset < $entryLen) {
+            // entry data (128 bytes)
+            $data = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);
+
+            // size in bytes of name
+            $nameSize = ord($data[self::SIZE_OF_NAME_POS]) | (ord($data[self::SIZE_OF_NAME_POS+1]) << 8);
+
+            // type of entry
+            $type = ord($data[self::TYPE_POS]);
+
+            // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
+            // sectorID of first sector of the short-stream container stream, if this entry is root entry
+            $startBlock = self::getInt4d($data, self::START_BLOCK_POS);
+
+            $size = self::getInt4d($data, self::SIZE_POS);
+
+            $name = str_replace("\x00", "", substr($data, 0, $nameSize));
+
+
+            $this->props[] = array (
+                'name' => $name,
+                'type' => $type,
+                'startBlock' => $startBlock,
+                'size' => $size);
+
+            // tmp helper to simplify checks
+            $upName = strtoupper($name);
+
+            // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
+            // print_r($upName.PHP_EOL);
+            if (($upName === 'WORDDOCUMENT')) {
+                $this->wrkdocument = count($this->props) - 1;
+            } elseif ($upName === '1TABLE') {
+                $this->wrk1Table = count($this->props) - 1;
+            } elseif ($upName === 'DATA') {
+                $this->wrkData = count($this->props) - 1;
+            } elseif ($upName === 'OBJECTPOOL') {
+                $this->wrkObjectPoolelseif = count($this->props) - 1;
+            } elseif ($upName === 'ROOT ENTRY' || $upName === 'R') {
+                $this->rootentry = count($this->props) - 1;
+            }
+
+            // Summary information
+            if ($name == chr(5) . 'SummaryInformation') {
+                $this->summaryInformation = count($this->props) - 1;
+            }
+
+            // Additional Document Summary information
+            if ($name == chr(5) . 'DocumentSummaryInformation') {
+                $this->docSummaryInfos = count($this->props) - 1;
+            }
+
+            $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
+        }
+
+    }
+
+    /**
+     * Read 4 bytes of data at specified position
+     *
+     * @param string $data
+     * @param int $pos
+     * @return int
+     */
+    private static function getInt4d($data, $pos)
+    {
+        // FIX: represent numbers correctly on 64-bit system
+        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
+        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
+        $or24 = ord($data[$pos + 3]);
+        if ($or24 >= 128) {
+            // negative number
+            $ord24 = -abs((256 - $or24) << 24);
+        } else {
+            $ord24 = ($or24 & 127) << 24;
+        }
+        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24;
+    }
+}

+ 5691 - 0
includes/PhpWord/Shared/PCLZip/pclzip.lib.php

@@ -0,0 +1,5691 @@
+<?php
+// --------------------------------------------------------------------------------
+// PhpConcept Library - Zip Module 2.8.2
+// --------------------------------------------------------------------------------
+// License GNU/LGPL - Vincent Blavet - August 2009
+// http://www.phpconcept.net
+// --------------------------------------------------------------------------------
+//
+// Presentation :
+//   PclZip is a PHP library that manage ZIP archives.
+//   So far tests show that archives generated by PclZip are readable by
+//   WinZip application and other tools.
+//
+// Description :
+//   See readme.txt and http://www.phpconcept.net
+//
+// Warning :
+//   This library and the associated files are non commercial, non professional
+//   work.
+//   It should not have unexpected results. However if any damage is caused by
+//   this software the author can not be responsible.
+//   The use of this software is at the risk of the user.
+//
+// --------------------------------------------------------------------------------
+// $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
+// --------------------------------------------------------------------------------
+
+  // ----- Constants
+  if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
+    define( 'PCLZIP_READ_BLOCK_SIZE', 2048 );
+  }
+
+  // ----- File list separator
+  // In version 1.x of PclZip, the separator for file list is a space
+  // (which is not a very smart choice, specifically for windows paths !).
+  // A better separator should be a comma (,). This constant gives you the
+  // abilty to change that.
+  // However notice that changing this value, may have impact on existing
+  // scripts, using space separated filenames.
+  // Recommanded values for compatibility with older versions :
+  //define( 'PCLZIP_SEPARATOR', ' ' );
+  // Recommanded values for smart separation of filenames.
+  if (!defined('PCLZIP_SEPARATOR')) {
+    define( 'PCLZIP_SEPARATOR', ',' );
+  }
+
+  // ----- Error configuration
+  // 0 : PclZip Class integrated error handling
+  // 1 : PclError external library error handling. By enabling this
+  //     you must ensure that you have included PclError library.
+  // [2,...] : reserved for futur use
+  if (!defined('PCLZIP_ERROR_EXTERNAL')) {
+    define( 'PCLZIP_ERROR_EXTERNAL', 0 );
+  }
+
+  // ----- Optional static temporary directory
+  //       By default temporary files are generated in the script current
+  //       path.
+  //       If defined :
+  //       - MUST BE terminated by a '/'.
+  //       - MUST be a valid, already created directory
+  //       Samples :
+  // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );
+  // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );
+  if (!defined('PCLZIP_TEMPORARY_DIR')) {
+    define( 'PCLZIP_TEMPORARY_DIR', '' );
+  }
+
+  // ----- Optional threshold ratio for use of temporary files
+  //       Pclzip sense the size of the file to add/extract and decide to
+  //       use or not temporary file. The algorythm is looking for
+  //       memory_limit of PHP and apply a ratio.
+  //       threshold = memory_limit * ratio.
+  //       Recommended values are under 0.5. Default 0.47.
+  //       Samples :
+  // define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );
+  if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
+    define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 );
+  }
+
+// --------------------------------------------------------------------------------
+// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
+// --------------------------------------------------------------------------------
+
+  // ----- Global variables
+  $g_pclzip_version = "2.8.2";
+
+  // ----- Error codes
+  //   -1 : Unable to open file in binary write mode
+  //   -2 : Unable to open file in binary read mode
+  //   -3 : Invalid parameters
+  //   -4 : File does not exist
+  //   -5 : Filename is too long (max. 255)
+  //   -6 : Not a valid zip file
+  //   -7 : Invalid extracted file size
+  //   -8 : Unable to create directory
+  //   -9 : Invalid archive extension
+  //  -10 : Invalid archive format
+  //  -11 : Unable to delete file (unlink)
+  //  -12 : Unable to rename file (rename)
+  //  -13 : Invalid header checksum
+  //  -14 : Invalid archive size
+  define( 'PCLZIP_ERR_USER_ABORTED', 2 );
+  define( 'PCLZIP_ERR_NO_ERROR', 0 );
+  define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 );
+  define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 );
+  define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 );
+  define( 'PCLZIP_ERR_MISSING_FILE', -4 );
+  define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 );
+  define( 'PCLZIP_ERR_INVALID_ZIP', -6 );
+  define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 );
+  define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 );
+  define( 'PCLZIP_ERR_BAD_EXTENSION', -9 );
+  define( 'PCLZIP_ERR_BAD_FORMAT', -10 );
+  define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 );
+  define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 );
+  define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 );
+  define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 );
+  define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 );
+  define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 );
+  define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 );
+  define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 );
+  define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 );
+  define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 );
+  define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 );
+
+  // ----- Options values
+  define( 'PCLZIP_OPT_PATH', 77001 );
+  define( 'PCLZIP_OPT_ADD_PATH', 77002 );
+  define( 'PCLZIP_OPT_REMOVE_PATH', 77003 );
+  define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 );
+  define( 'PCLZIP_OPT_SET_CHMOD', 77005 );
+  define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 );
+  define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 );
+  define( 'PCLZIP_OPT_BY_NAME', 77008 );
+  define( 'PCLZIP_OPT_BY_INDEX', 77009 );
+  define( 'PCLZIP_OPT_BY_EREG', 77010 );
+  define( 'PCLZIP_OPT_BY_PREG', 77011 );
+  define( 'PCLZIP_OPT_COMMENT', 77012 );
+  define( 'PCLZIP_OPT_ADD_COMMENT', 77013 );
+  define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 );
+  define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 );
+  define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 );
+  define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 );
+  // Having big trouble with crypt. Need to multiply 2 long int
+  // which is not correctly supported by PHP ...
+  //define( 'PCLZIP_OPT_CRYPT', 77018 );
+  define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 );
+  define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 );
+  define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias
+  define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 );
+  define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias
+  define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 );
+  define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias
+
+  // ----- File description attributes
+  define( 'PCLZIP_ATT_FILE_NAME', 79001 );
+  define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 );
+  define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 );
+  define( 'PCLZIP_ATT_FILE_MTIME', 79004 );
+  define( 'PCLZIP_ATT_FILE_CONTENT', 79005 );
+  define( 'PCLZIP_ATT_FILE_COMMENT', 79006 );
+
+  // ----- Call backs values
+  define( 'PCLZIP_CB_PRE_EXTRACT', 78001 );
+  define( 'PCLZIP_CB_POST_EXTRACT', 78002 );
+  define( 'PCLZIP_CB_PRE_ADD', 78003 );
+  define( 'PCLZIP_CB_POST_ADD', 78004 );
+  /* For futur use
+  define( 'PCLZIP_CB_PRE_LIST', 78005 );
+  define( 'PCLZIP_CB_POST_LIST', 78006 );
+  define( 'PCLZIP_CB_PRE_DELETE', 78007 );
+  define( 'PCLZIP_CB_POST_DELETE', 78008 );
+  */
+
+  // --------------------------------------------------------------------------------
+  // Class : PclZip
+  // Description :
+  //   PclZip is the class that represent a Zip archive.
+  //   The public methods allow the manipulation of the archive.
+  // Attributes :
+  //   Attributes must not be accessed directly.
+  // Methods :
+  //   PclZip() : Object creator
+  //   create() : Creates the Zip archive
+  //   listContent() : List the content of the Zip archive
+  //   extract() : Extract the content of the archive
+  //   properties() : List the properties of the archive
+  // --------------------------------------------------------------------------------
+  class PclZip
+  {
+    // ----- Filename of the zip file
+    var $zipname = '';
+
+    // ----- File descriptor of the zip file
+    var $zip_fd = 0;
+
+    // ----- Internal error handling
+    var $error_code = 1;
+    var $error_string = '';
+
+    // ----- Current status of the magic_quotes_runtime
+    // This value store the php configuration for magic_quotes
+    // The class can then disable the magic_quotes and reset it after
+    var $magic_quotes_status;
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZip()
+  // Description :
+  //   Creates a PclZip object and set the name of the associated Zip archive
+  //   filename.
+  //   Note that no real action is taken, if the archive does not exist it is not
+  //   created. Use create() for that.
+  // --------------------------------------------------------------------------------
+  function PclZip($p_zipname)
+  {
+
+    // ----- Tests the zlib
+    if (!function_exists('gzopen'))
+    {
+      die('Abort '.basename(__FILE__).' : Missing zlib extensions');
+    }
+
+    // ----- Set the attributes
+    $this->zipname = $p_zipname;
+    $this->zip_fd = 0;
+    $this->magic_quotes_status = -1;
+
+    // ----- Return
+    return;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function :
+  //   create($p_filelist, $p_add_dir="", $p_remove_dir="")
+  //   create($p_filelist, $p_option, $p_option_value, ...)
+  // Description :
+  //   This method supports two different synopsis. The first one is historical.
+  //   This method creates a Zip Archive. The Zip file is created in the
+  //   filesystem. The files and directories indicated in $p_filelist
+  //   are added in the archive. See the parameters description for the
+  //   supported format of $p_filelist.
+  //   When a directory is in the list, the directory and its content is added
+  //   in the archive.
+  //   In this synopsis, the function takes an optional variable list of
+  //   options. See bellow the supported options.
+  // Parameters :
+  //   $p_filelist : An array containing file or directory names, or
+  //                 a string containing one filename or one directory name, or
+  //                 a string containing a list of filenames and/or directory
+  //                 names separated by spaces.
+  //   $p_add_dir : A path to add before the real path of the archived file,
+  //                in order to have it memorized in the archive.
+  //   $p_remove_dir : A path to remove from the real path of the file to archive,
+  //                   in order to have a shorter path memorized in the archive.
+  //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+  //                   is removed first, before $p_add_dir is added.
+  // Options :
+  //   PCLZIP_OPT_ADD_PATH :
+  //   PCLZIP_OPT_REMOVE_PATH :
+  //   PCLZIP_OPT_REMOVE_ALL_PATH :
+  //   PCLZIP_OPT_COMMENT :
+  //   PCLZIP_CB_PRE_ADD :
+  //   PCLZIP_CB_POST_ADD :
+  // Return Values :
+  //   0 on failure,
+  //   The list of the added files, with a status of the add action.
+  //   (see PclZip::listContent() for list entry format)
+  // --------------------------------------------------------------------------------
+  function create($p_filelist)
+  {
+    $v_result=1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Set default values
+    $v_options = array();
+    $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
+
+    // ----- Look for variable options arguments
+    $v_size = func_num_args();
+
+    // ----- Look for arguments
+    if ($v_size > 1) {
+      // ----- Get the arguments
+      $v_arg_list = func_get_args();
+
+      // ----- Remove from the options list the first argument
+      array_shift($v_arg_list);
+      $v_size--;
+
+      // ----- Look for first arg
+      if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+        // ----- Parse the options
+        $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+                                            array (PCLZIP_OPT_REMOVE_PATH => 'optional',
+                                                   PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+                                                   PCLZIP_OPT_ADD_PATH => 'optional',
+                                                   PCLZIP_CB_PRE_ADD => 'optional',
+                                                   PCLZIP_CB_POST_ADD => 'optional',
+                                                   PCLZIP_OPT_NO_COMPRESSION => 'optional',
+                                                   PCLZIP_OPT_COMMENT => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+                                                   //, PCLZIP_OPT_CRYPT => 'optional'
+                                             ));
+        if ($v_result != 1) {
+          return 0;
+        }
+      }
+
+      // ----- Look for 2 args
+      // Here we need to support the first historic synopsis of the
+      // method.
+      else {
+
+        // ----- Get the first argument
+        $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
+
+        // ----- Look for the optional second argument
+        if ($v_size == 2) {
+          $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+        }
+        else if ($v_size > 2) {
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+                               "Invalid number / type of arguments");
+          return 0;
+        }
+      }
+    }
+
+    // ----- Look for default option values
+    $this->privOptionDefaultThreshold($v_options);
+
+    // ----- Init
+    $v_string_list = array();
+    $v_att_list = array();
+    $v_filedescr_list = array();
+    $p_result_list = array();
+
+    // ----- Look if the $p_filelist is really an array
+    if (is_array($p_filelist)) {
+
+      // ----- Look if the first element is also an array
+      //       This will mean that this is a file description entry
+      if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+        $v_att_list = $p_filelist;
+      }
+
+      // ----- The list is a list of string names
+      else {
+        $v_string_list = $p_filelist;
+      }
+    }
+
+    // ----- Look if the $p_filelist is a string
+    else if (is_string($p_filelist)) {
+      // ----- Create a list from the string
+      $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+    }
+
+    // ----- Invalid variable type for $p_filelist
+    else {
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
+      return 0;
+    }
+
+    // ----- Reformat the string list
+    if (sizeof($v_string_list) != 0) {
+      foreach ($v_string_list as $v_string) {
+        if ($v_string != '') {
+          $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+        }
+        else {
+        }
+      }
+    }
+
+    // ----- For each file in the list check the attributes
+    $v_supported_attributes
+    = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
+             ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
+             ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
+             ,PCLZIP_ATT_FILE_MTIME => 'optional'
+             ,PCLZIP_ATT_FILE_CONTENT => 'optional'
+             ,PCLZIP_ATT_FILE_COMMENT => 'optional'
+                        );
+    foreach ($v_att_list as $v_entry) {
+      $v_result = $this->privFileDescrParseAtt($v_entry,
+                                               $v_filedescr_list[],
+                                               $v_options,
+                                               $v_supported_attributes);
+      if ($v_result != 1) {
+        return 0;
+      }
+    }
+
+    // ----- Expand the filelist (expand directories)
+    $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+    if ($v_result != 1) {
+      return 0;
+    }
+
+    // ----- Call the create fct
+    $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
+    if ($v_result != 1) {
+      return 0;
+    }
+
+    // ----- Return
+    return $p_result_list;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function :
+  //   add($p_filelist, $p_add_dir="", $p_remove_dir="")
+  //   add($p_filelist, $p_option, $p_option_value, ...)
+  // Description :
+  //   This method supports two synopsis. The first one is historical.
+  //   This methods add the list of files in an existing archive.
+  //   If a file with the same name already exists, it is added at the end of the
+  //   archive, the first one is still present.
+  //   If the archive does not exist, it is created.
+  // Parameters :
+  //   $p_filelist : An array containing file or directory names, or
+  //                 a string containing one filename or one directory name, or
+  //                 a string containing a list of filenames and/or directory
+  //                 names separated by spaces.
+  //   $p_add_dir : A path to add before the real path of the archived file,
+  //                in order to have it memorized in the archive.
+  //   $p_remove_dir : A path to remove from the real path of the file to archive,
+  //                   in order to have a shorter path memorized in the archive.
+  //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+  //                   is removed first, before $p_add_dir is added.
+  // Options :
+  //   PCLZIP_OPT_ADD_PATH :
+  //   PCLZIP_OPT_REMOVE_PATH :
+  //   PCLZIP_OPT_REMOVE_ALL_PATH :
+  //   PCLZIP_OPT_COMMENT :
+  //   PCLZIP_OPT_ADD_COMMENT :
+  //   PCLZIP_OPT_PREPEND_COMMENT :
+  //   PCLZIP_CB_PRE_ADD :
+  //   PCLZIP_CB_POST_ADD :
+  // Return Values :
+  //   0 on failure,
+  //   The list of the added files, with a status of the add action.
+  //   (see PclZip::listContent() for list entry format)
+  // --------------------------------------------------------------------------------
+  function add($p_filelist)
+  {
+    $v_result=1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Set default values
+    $v_options = array();
+    $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
+
+    // ----- Look for variable options arguments
+    $v_size = func_num_args();
+
+    // ----- Look for arguments
+    if ($v_size > 1) {
+      // ----- Get the arguments
+      $v_arg_list = func_get_args();
+
+      // ----- Remove form the options list the first argument
+      array_shift($v_arg_list);
+      $v_size--;
+
+      // ----- Look for first arg
+      if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+        // ----- Parse the options
+        $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+                                            array (PCLZIP_OPT_REMOVE_PATH => 'optional',
+                                                   PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+                                                   PCLZIP_OPT_ADD_PATH => 'optional',
+                                                   PCLZIP_CB_PRE_ADD => 'optional',
+                                                   PCLZIP_CB_POST_ADD => 'optional',
+                                                   PCLZIP_OPT_NO_COMPRESSION => 'optional',
+                                                   PCLZIP_OPT_COMMENT => 'optional',
+                                                   PCLZIP_OPT_ADD_COMMENT => 'optional',
+                                                   PCLZIP_OPT_PREPEND_COMMENT => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+                                                   //, PCLZIP_OPT_CRYPT => 'optional'
+                                                   ));
+        if ($v_result != 1) {
+          return 0;
+        }
+      }
+
+      // ----- Look for 2 args
+      // Here we need to support the first historic synopsis of the
+      // method.
+      else {
+
+        // ----- Get the first argument
+        $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
+
+        // ----- Look for the optional second argument
+        if ($v_size == 2) {
+          $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+        }
+        else if ($v_size > 2) {
+          // ----- Error log
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+          // ----- Return
+          return 0;
+        }
+      }
+    }
+
+    // ----- Look for default option values
+    $this->privOptionDefaultThreshold($v_options);
+
+    // ----- Init
+    $v_string_list = array();
+    $v_att_list = array();
+    $v_filedescr_list = array();
+    $p_result_list = array();
+
+    // ----- Look if the $p_filelist is really an array
+    if (is_array($p_filelist)) {
+
+      // ----- Look if the first element is also an array
+      //       This will mean that this is a file description entry
+      if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+        $v_att_list = $p_filelist;
+      }
+
+      // ----- The list is a list of string names
+      else {
+        $v_string_list = $p_filelist;
+      }
+    }
+
+    // ----- Look if the $p_filelist is a string
+    else if (is_string($p_filelist)) {
+      // ----- Create a list from the string
+      $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+    }
+
+    // ----- Invalid variable type for $p_filelist
+    else {
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
+      return 0;
+    }
+
+    // ----- Reformat the string list
+    if (sizeof($v_string_list) != 0) {
+      foreach ($v_string_list as $v_string) {
+        $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+      }
+    }
+
+    // ----- For each file in the list check the attributes
+    $v_supported_attributes
+    = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
+             ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
+             ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
+             ,PCLZIP_ATT_FILE_MTIME => 'optional'
+             ,PCLZIP_ATT_FILE_CONTENT => 'optional'
+             ,PCLZIP_ATT_FILE_COMMENT => 'optional'
+                        );
+    foreach ($v_att_list as $v_entry) {
+      $v_result = $this->privFileDescrParseAtt($v_entry,
+                                               $v_filedescr_list[],
+                                               $v_options,
+                                               $v_supported_attributes);
+      if ($v_result != 1) {
+        return 0;
+      }
+    }
+
+    // ----- Expand the filelist (expand directories)
+    $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+    if ($v_result != 1) {
+      return 0;
+    }
+
+    // ----- Call the create fct
+    $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
+    if ($v_result != 1) {
+      return 0;
+    }
+
+    // ----- Return
+    return $p_result_list;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : listContent()
+  // Description :
+  //   This public method, gives the list of the files and directories, with their
+  //   properties.
+  //   The properties of each entries in the list are (used also in other functions) :
+  //     filename : Name of the file. For a create or add action it is the filename
+  //                given by the user. For an extract function it is the filename
+  //                of the extracted file.
+  //     stored_filename : Name of the file / directory stored in the archive.
+  //     size : Size of the stored file.
+  //     compressed_size : Size of the file's data compressed in the archive
+  //                       (without the headers overhead)
+  //     mtime : Last known modification date of the file (UNIX timestamp)
+  //     comment : Comment associated with the file
+  //     folder : true | false
+  //     index : index of the file in the archive
+  //     status : status of the action (depending of the action) :
+  //              Values are :
+  //                ok : OK !
+  //                filtered : the file / dir is not extracted (filtered by user)
+  //                already_a_directory : the file can not be extracted because a
+  //                                      directory with the same name already exists
+  //                write_protected : the file can not be extracted because a file
+  //                                  with the same name already exists and is
+  //                                  write protected
+  //                newer_exist : the file was not extracted because a newer file exists
+  //                path_creation_fail : the file is not extracted because the folder
+  //                                     does not exist and can not be created
+  //                write_error : the file was not extracted because there was a
+  //                              error while writing the file
+  //                read_error : the file was not extracted because there was a error
+  //                             while reading the file
+  //                invalid_header : the file was not extracted because of an archive
+  //                                 format error (bad file header)
+  //   Note that each time a method can continue operating when there
+  //   is an action error on a file, the error is only logged in the file status.
+  // Return Values :
+  //   0 on an unrecoverable failure,
+  //   The list of the files in the archive.
+  // --------------------------------------------------------------------------------
+  function listContent()
+  {
+    $v_result=1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Check archive
+    if (!$this->privCheckFormat()) {
+      return(0);
+    }
+
+    // ----- Call the extracting fct
+    $p_list = array();
+    if (($v_result = $this->privList($p_list)) != 1)
+    {
+      unset($p_list);
+      return(0);
+    }
+
+    // ----- Return
+    return $p_list;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function :
+  //   extract($p_path="./", $p_remove_path="")
+  //   extract([$p_option, $p_option_value, ...])
+  // Description :
+  //   This method supports two synopsis. The first one is historical.
+  //   This method extract all the files / directories from the archive to the
+  //   folder indicated in $p_path.
+  //   If you want to ignore the 'root' part of path of the memorized files
+  //   you can indicate this in the optional $p_remove_path parameter.
+  //   By default, if a newer file with the same name already exists, the
+  //   file is not extracted.
+  //
+  //   If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
+  //   are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
+  //   at the end of the path value of PCLZIP_OPT_PATH.
+  // Parameters :
+  //   $p_path : Path where the files and directories are to be extracted
+  //   $p_remove_path : First part ('root' part) of the memorized path
+  //                    (if any similar) to remove while extracting.
+  // Options :
+  //   PCLZIP_OPT_PATH :
+  //   PCLZIP_OPT_ADD_PATH :
+  //   PCLZIP_OPT_REMOVE_PATH :
+  //   PCLZIP_OPT_REMOVE_ALL_PATH :
+  //   PCLZIP_CB_PRE_EXTRACT :
+  //   PCLZIP_CB_POST_EXTRACT :
+  // Return Values :
+  //   0 or a negative value on failure,
+  //   The list of the extracted files, with a status of the action.
+  //   (see PclZip::listContent() for list entry format)
+  // --------------------------------------------------------------------------------
+  function extract()
+  {
+    $v_result=1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Check archive
+    if (!$this->privCheckFormat()) {
+      return(0);
+    }
+
+    // ----- Set default values
+    $v_options = array();
+//    $v_path = "./";
+    $v_path = '';
+    $v_remove_path = "";
+    $v_remove_all_path = false;
+
+    // ----- Look for variable options arguments
+    $v_size = func_num_args();
+
+    // ----- Default values for option
+    $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+
+    // ----- Look for arguments
+    if ($v_size > 0) {
+      // ----- Get the arguments
+      $v_arg_list = func_get_args();
+
+      // ----- Look for first arg
+      if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+        // ----- Parse the options
+        $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+                                            array (PCLZIP_OPT_PATH => 'optional',
+                                                   PCLZIP_OPT_REMOVE_PATH => 'optional',
+                                                   PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+                                                   PCLZIP_OPT_ADD_PATH => 'optional',
+                                                   PCLZIP_CB_PRE_EXTRACT => 'optional',
+                                                   PCLZIP_CB_POST_EXTRACT => 'optional',
+                                                   PCLZIP_OPT_SET_CHMOD => 'optional',
+                                                   PCLZIP_OPT_BY_NAME => 'optional',
+                                                   PCLZIP_OPT_BY_EREG => 'optional',
+                                                   PCLZIP_OPT_BY_PREG => 'optional',
+                                                   PCLZIP_OPT_BY_INDEX => 'optional',
+                                                   PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+                                                   PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
+                                                   PCLZIP_OPT_REPLACE_NEWER => 'optional'
+                                                   ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
+                                                   ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+                                                    ));
+        if ($v_result != 1) {
+          return 0;
+        }
+
+        // ----- Set the arguments
+        if (isset($v_options[PCLZIP_OPT_PATH])) {
+          $v_path = $v_options[PCLZIP_OPT_PATH];
+        }
+        if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+          $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+        }
+        if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+          $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+        }
+        if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+          // ----- Check for '/' in last path char
+          if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+            $v_path .= '/';
+          }
+          $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+        }
+      }
+
+      // ----- Look for 2 args
+      // Here we need to support the first historic synopsis of the
+      // method.
+      else {
+
+        // ----- Get the first argument
+        $v_path = $v_arg_list[0];
+
+        // ----- Look for the optional second argument
+        if ($v_size == 2) {
+          $v_remove_path = $v_arg_list[1];
+        }
+        else if ($v_size > 2) {
+          // ----- Error log
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+          // ----- Return
+          return 0;
+        }
+      }
+    }
+
+    // ----- Look for default option values
+    $this->privOptionDefaultThreshold($v_options);
+
+    // ----- Trace
+
+    // ----- Call the extracting fct
+    $p_list = array();
+    $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
+                                         $v_remove_all_path, $v_options);
+    if ($v_result < 1) {
+      unset($p_list);
+      return(0);
+    }
+
+    // ----- Return
+    return $p_list;
+  }
+  // --------------------------------------------------------------------------------
+
+
+  // --------------------------------------------------------------------------------
+  // Function :
+  //   extractByIndex($p_index, $p_path="./", $p_remove_path="")
+  //   extractByIndex($p_index, [$p_option, $p_option_value, ...])
+  // Description :
+  //   This method supports two synopsis. The first one is historical.
+  //   This method is doing a partial extract of the archive.
+  //   The extracted files or folders are identified by their index in the
+  //   archive (from 0 to n).
+  //   Note that if the index identify a folder, only the folder entry is
+  //   extracted, not all the files included in the archive.
+  // Parameters :
+  //   $p_index : A single index (integer) or a string of indexes of files to
+  //              extract. The form of the string is "0,4-6,8-12" with only numbers
+  //              and '-' for range or ',' to separate ranges. No spaces or ';'
+  //              are allowed.
+  //   $p_path : Path where the files and directories are to be extracted
+  //   $p_remove_path : First part ('root' part) of the memorized path
+  //                    (if any similar) to remove while extracting.
+  // Options :
+  //   PCLZIP_OPT_PATH :
+  //   PCLZIP_OPT_ADD_PATH :
+  //   PCLZIP_OPT_REMOVE_PATH :
+  //   PCLZIP_OPT_REMOVE_ALL_PATH :
+  //   PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
+  //     not as files.
+  //     The resulting content is in a new field 'content' in the file
+  //     structure.
+  //     This option must be used alone (any other options are ignored).
+  //   PCLZIP_CB_PRE_EXTRACT :
+  //   PCLZIP_CB_POST_EXTRACT :
+  // Return Values :
+  //   0 on failure,
+  //   The list of the extracted files, with a status of the action.
+  //   (see PclZip::listContent() for list entry format)
+  // --------------------------------------------------------------------------------
+  //function extractByIndex($p_index, options...)
+  function extractByIndex($p_index)
+  {
+    $v_result=1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Check archive
+    if (!$this->privCheckFormat()) {
+      return(0);
+    }
+
+    // ----- Set default values
+    $v_options = array();
+//    $v_path = "./";
+    $v_path = '';
+    $v_remove_path = "";
+    $v_remove_all_path = false;
+
+    // ----- Look for variable options arguments
+    $v_size = func_num_args();
+
+    // ----- Default values for option
+    $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+
+    // ----- Look for arguments
+    if ($v_size > 1) {
+      // ----- Get the arguments
+      $v_arg_list = func_get_args();
+
+      // ----- Remove form the options list the first argument
+      array_shift($v_arg_list);
+      $v_size--;
+
+      // ----- Look for first arg
+      if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+        // ----- Parse the options
+        $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+                                            array (PCLZIP_OPT_PATH => 'optional',
+                                                   PCLZIP_OPT_REMOVE_PATH => 'optional',
+                                                   PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+                                                   PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+                                                   PCLZIP_OPT_ADD_PATH => 'optional',
+                                                   PCLZIP_CB_PRE_EXTRACT => 'optional',
+                                                   PCLZIP_CB_POST_EXTRACT => 'optional',
+                                                   PCLZIP_OPT_SET_CHMOD => 'optional',
+                                                   PCLZIP_OPT_REPLACE_NEWER => 'optional'
+                                                   ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
+                                                   ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+                                                   PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+                                                   ));
+        if ($v_result != 1) {
+          return 0;
+        }
+
+        // ----- Set the arguments
+        if (isset($v_options[PCLZIP_OPT_PATH])) {
+          $v_path = $v_options[PCLZIP_OPT_PATH];
+        }
+        if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+          $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+        }
+        if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+          $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+        }
+        if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+          // ----- Check for '/' in last path char
+          if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+            $v_path .= '/';
+          }
+          $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+        }
+        if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
+          $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+        }
+        else {
+        }
+      }
+
+      // ----- Look for 2 args
+      // Here we need to support the first historic synopsis of the
+      // method.
+      else {
+
+        // ----- Get the first argument
+        $v_path = $v_arg_list[0];
+
+        // ----- Look for the optional second argument
+        if ($v_size == 2) {
+          $v_remove_path = $v_arg_list[1];
+        }
+        else if ($v_size > 2) {
+          // ----- Error log
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+          // ----- Return
+          return 0;
+        }
+      }
+    }
+
+    // ----- Trace
+
+    // ----- Trick
+    // Here I want to reuse extractByRule(), so I need to parse the $p_index
+    // with privParseOptions()
+    $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
+    $v_options_trick = array();
+    $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
+                                        array (PCLZIP_OPT_BY_INDEX => 'optional' ));
+    if ($v_result != 1) {
+        return 0;
+    }
+    $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
+
+    // ----- Look for default option values
+    $this->privOptionDefaultThreshold($v_options);
+
+    // ----- Call the extracting fct
+    if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
+        return(0);
+    }
+
+    // ----- Return
+    return $p_list;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function :
+  //   delete([$p_option, $p_option_value, ...])
+  // Description :
+  //   This method removes files from the archive.
+  //   If no parameters are given, then all the archive is emptied.
+  // Parameters :
+  //   None or optional arguments.
+  // Options :
+  //   PCLZIP_OPT_BY_INDEX :
+  //   PCLZIP_OPT_BY_NAME :
+  //   PCLZIP_OPT_BY_EREG :
+  //   PCLZIP_OPT_BY_PREG :
+  // Return Values :
+  //   0 on failure,
+  //   The list of the files which are still present in the archive.
+  //   (see PclZip::listContent() for list entry format)
+  // --------------------------------------------------------------------------------
+  function delete()
+  {
+    $v_result=1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Check archive
+    if (!$this->privCheckFormat()) {
+      return(0);
+    }
+
+    // ----- Set default values
+    $v_options = array();
+
+    // ----- Look for variable options arguments
+    $v_size = func_num_args();
+
+    // ----- Look for arguments
+    if ($v_size > 0) {
+      // ----- Get the arguments
+      $v_arg_list = func_get_args();
+
+      // ----- Parse the options
+      $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+                                        array (PCLZIP_OPT_BY_NAME => 'optional',
+                                               PCLZIP_OPT_BY_EREG => 'optional',
+                                               PCLZIP_OPT_BY_PREG => 'optional',
+                                               PCLZIP_OPT_BY_INDEX => 'optional' ));
+      if ($v_result != 1) {
+          return 0;
+      }
+    }
+
+    // ----- Magic quotes trick
+    $this->privDisableMagicQuotes();
+
+    // ----- Call the delete fct
+    $v_list = array();
+    if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
+      $this->privSwapBackMagicQuotes();
+      unset($v_list);
+      return(0);
+    }
+
+    // ----- Magic quotes trick
+    $this->privSwapBackMagicQuotes();
+
+    // ----- Return
+    return $v_list;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : deleteByIndex()
+  // Description :
+  //   ***** Deprecated *****
+  //   delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
+  // --------------------------------------------------------------------------------
+  function deleteByIndex($p_index)
+  {
+
+    $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
+
+    // ----- Return
+    return $p_list;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : properties()
+  // Description :
+  //   This method gives the properties of the archive.
+  //   The properties are :
+  //     nb : Number of files in the archive
+  //     comment : Comment associated with the archive file
+  //     status : not_exist, ok
+  // Parameters :
+  //   None
+  // Return Values :
+  //   0 on failure,
+  //   An array with the archive properties.
+  // --------------------------------------------------------------------------------
+  function properties()
+  {
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Magic quotes trick
+    $this->privDisableMagicQuotes();
+
+    // ----- Check archive
+    if (!$this->privCheckFormat()) {
+      $this->privSwapBackMagicQuotes();
+      return(0);
+    }
+
+    // ----- Default properties
+    $v_prop = array();
+    $v_prop['comment'] = '';
+    $v_prop['nb'] = 0;
+    $v_prop['status'] = 'not_exist';
+
+    // ----- Look if file exists
+    if (@is_file($this->zipname))
+    {
+      // ----- Open the zip file
+      if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
+      {
+        $this->privSwapBackMagicQuotes();
+
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
+
+        // ----- Return
+        return 0;
+      }
+
+      // ----- Read the central directory informations
+      $v_central_dir = array();
+      if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+      {
+        $this->privSwapBackMagicQuotes();
+        return 0;
+      }
+
+      // ----- Close the zip file
+      $this->privCloseFd();
+
+      // ----- Set the user attributes
+      $v_prop['comment'] = $v_central_dir['comment'];
+      $v_prop['nb'] = $v_central_dir['entries'];
+      $v_prop['status'] = 'ok';
+    }
+
+    // ----- Magic quotes trick
+    $this->privSwapBackMagicQuotes();
+
+    // ----- Return
+    return $v_prop;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : duplicate()
+  // Description :
+  //   This method creates an archive by copying the content of an other one. If
+  //   the archive already exist, it is replaced by the new one without any warning.
+  // Parameters :
+  //   $p_archive : The filename of a valid archive, or
+  //                a valid PclZip object.
+  // Return Values :
+  //   1 on success.
+  //   0 or a negative value on error (error code).
+  // --------------------------------------------------------------------------------
+  function duplicate($p_archive)
+  {
+    $v_result = 1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Look if the $p_archive is a PclZip object
+    if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
+    {
+
+      // ----- Duplicate the archive
+      $v_result = $this->privDuplicate($p_archive->zipname);
+    }
+
+    // ----- Look if the $p_archive is a string (so a filename)
+    else if (is_string($p_archive))
+    {
+
+      // ----- Check that $p_archive is a valid zip file
+      // TBC : Should also check the archive format
+      if (!is_file($p_archive)) {
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
+        $v_result = PCLZIP_ERR_MISSING_FILE;
+      }
+      else {
+        // ----- Duplicate the archive
+        $v_result = $this->privDuplicate($p_archive);
+      }
+    }
+
+    // ----- Invalid variable
+    else
+    {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+      $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : merge()
+  // Description :
+  //   This method merge the $p_archive_to_add archive at the end of the current
+  //   one ($this).
+  //   If the archive ($this) does not exist, the merge becomes a duplicate.
+  //   If the $p_archive_to_add archive does not exist, the merge is a success.
+  // Parameters :
+  //   $p_archive_to_add : It can be directly the filename of a valid zip archive,
+  //                       or a PclZip object archive.
+  // Return Values :
+  //   1 on success,
+  //   0 or negative values on error (see below).
+  // --------------------------------------------------------------------------------
+  function merge($p_archive_to_add)
+  {
+    $v_result = 1;
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Check archive
+    if (!$this->privCheckFormat()) {
+      return(0);
+    }
+
+    // ----- Look if the $p_archive_to_add is a PclZip object
+    if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
+    {
+
+      // ----- Merge the archive
+      $v_result = $this->privMerge($p_archive_to_add);
+    }
+
+    // ----- Look if the $p_archive_to_add is a string (so a filename)
+    else if (is_string($p_archive_to_add))
+    {
+
+      // ----- Create a temporary archive
+      $v_object_archive = new PclZip($p_archive_to_add);
+
+      // ----- Merge the archive
+      $v_result = $this->privMerge($v_object_archive);
+    }
+
+    // ----- Invalid variable
+    else
+    {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+      $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+
+
+  // --------------------------------------------------------------------------------
+  // Function : errorCode()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function errorCode()
+  {
+    if (PCLZIP_ERROR_EXTERNAL == 1) {
+      return(PclErrorCode());
+    }
+    else {
+      return($this->error_code);
+    }
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : errorName()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function errorName($p_with_code=false)
+  {
+    $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
+                      PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
+                      PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
+                      PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
+                      PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
+                      PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
+                      PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
+                      PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
+                      PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
+                      PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
+                      PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
+                      PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
+                      PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
+                      PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
+                      PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
+                      PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
+                      PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
+                      PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
+                      PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
+                      ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
+                      ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
+                    );
+
+    if (isset($v_name[$this->error_code])) {
+      $v_value = $v_name[$this->error_code];
+    }
+    else {
+      $v_value = 'NoName';
+    }
+
+    if ($p_with_code) {
+      return($v_value.' ('.$this->error_code.')');
+    }
+    else {
+      return($v_value);
+    }
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : errorInfo()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function errorInfo($p_full=false)
+  {
+    if (PCLZIP_ERROR_EXTERNAL == 1) {
+      return(PclErrorString());
+    }
+    else {
+      if ($p_full) {
+        return($this->errorName(true)." : ".$this->error_string);
+      }
+      else {
+        return($this->error_string." [code ".$this->error_code."]");
+      }
+    }
+  }
+  // --------------------------------------------------------------------------------
+
+
+// --------------------------------------------------------------------------------
+// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
+// *****                                                        *****
+// *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
+// --------------------------------------------------------------------------------
+
+
+
+  // --------------------------------------------------------------------------------
+  // Function : privCheckFormat()
+  // Description :
+  //   This method check that the archive exists and is a valid zip archive.
+  //   Several level of check exists. (futur)
+  // Parameters :
+  //   $p_level : Level of check. Default 0.
+  //              0 : Check the first bytes (magic codes) (default value))
+  //              1 : 0 + Check the central directory (futur)
+  //              2 : 1 + Check each file header (futur)
+  // Return Values :
+  //   true on success,
+  //   false on error, the error code is set.
+  // --------------------------------------------------------------------------------
+  function privCheckFormat($p_level=0)
+  {
+    $v_result = true;
+
+    // ----- Reset the file system cache
+    clearstatcache();
+
+    // ----- Reset the error handler
+    $this->privErrorReset();
+
+    // ----- Look if the file exits
+    if (!is_file($this->zipname)) {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
+      return(false);
+    }
+
+    // ----- Check that the file is readeable
+    if (!is_readable($this->zipname)) {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
+      return(false);
+    }
+
+    // ----- Check the magic code
+    // TBC
+
+    // ----- Check the central header
+    // TBC
+
+    // ----- Check each file header
+    // TBC
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privParseOptions()
+  // Description :
+  //   This internal methods reads the variable list of arguments ($p_options_list,
+  //   $p_size) and generate an array with the options and values ($v_result_list).
+  //   $v_requested_options contains the options that can be present and those that
+  //   must be present.
+  //   $v_requested_options is an array, with the option value as key, and 'optional',
+  //   or 'mandatory' as value.
+  // Parameters :
+  //   See above.
+  // Return Values :
+  //   1 on success.
+  //   0 on failure.
+  // --------------------------------------------------------------------------------
+  function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
+  {
+    $v_result=1;
+
+    // ----- Read the options
+    $i=0;
+    while ($i<$p_size) {
+
+      // ----- Check if the option is supported
+      if (!isset($v_requested_options[$p_options_list[$i]])) {
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+
+      // ----- Look for next option
+      switch ($p_options_list[$i]) {
+        // ----- Look for options that request a path value
+        case PCLZIP_OPT_PATH :
+        case PCLZIP_OPT_REMOVE_PATH :
+        case PCLZIP_OPT_ADD_PATH :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
+          $i++;
+        break;
+
+        case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+            return PclZip::errorCode();
+          }
+
+          // ----- Check for incompatible options
+          if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+            return PclZip::errorCode();
+          }
+
+          // ----- Check the value
+          $v_value = $p_options_list[$i+1];
+          if ((!is_integer($v_value)) || ($v_value<0)) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value (and convert it in bytes)
+          $v_result_list[$p_options_list[$i]] = $v_value*1048576;
+          $i++;
+        break;
+
+        case PCLZIP_OPT_TEMP_FILE_ON :
+          // ----- Check for incompatible options
+          if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+            return PclZip::errorCode();
+          }
+
+          $v_result_list[$p_options_list[$i]] = true;
+        break;
+
+        case PCLZIP_OPT_TEMP_FILE_OFF :
+          // ----- Check for incompatible options
+          if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
+            return PclZip::errorCode();
+          }
+          // ----- Check for incompatible options
+          if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
+            return PclZip::errorCode();
+          }
+
+          $v_result_list[$p_options_list[$i]] = true;
+        break;
+
+        case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          if (   is_string($p_options_list[$i+1])
+              && ($p_options_list[$i+1] != '')) {
+            $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
+            $i++;
+          }
+          else {
+          }
+        break;
+
+        // ----- Look for options that request an array of string for value
+        case PCLZIP_OPT_BY_NAME :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          if (is_string($p_options_list[$i+1])) {
+              $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
+          }
+          else if (is_array($p_options_list[$i+1])) {
+              $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+          }
+          else {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+          $i++;
+        break;
+
+        // ----- Look for options that request an EREG or PREG expression
+        case PCLZIP_OPT_BY_EREG :
+          // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
+          // to PCLZIP_OPT_BY_PREG
+          $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
+        case PCLZIP_OPT_BY_PREG :
+        //case PCLZIP_OPT_CRYPT :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          if (is_string($p_options_list[$i+1])) {
+              $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+          }
+          else {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+          $i++;
+        break;
+
+        // ----- Look for options that takes a string
+        case PCLZIP_OPT_COMMENT :
+        case PCLZIP_OPT_ADD_COMMENT :
+        case PCLZIP_OPT_PREPEND_COMMENT :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
+                                 "Missing parameter value for option '"
+                                 .PclZipUtilOptionText($p_options_list[$i])
+                                 ."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          if (is_string($p_options_list[$i+1])) {
+              $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+          }
+          else {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
+                                 "Wrong parameter value for option '"
+                                 .PclZipUtilOptionText($p_options_list[$i])
+                                 ."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+          $i++;
+        break;
+
+        // ----- Look for options that request an array of index
+        case PCLZIP_OPT_BY_INDEX :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          $v_work_list = array();
+          if (is_string($p_options_list[$i+1])) {
+
+              // ----- Remove spaces
+              $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
+
+              // ----- Parse items
+              $v_work_list = explode(",", $p_options_list[$i+1]);
+          }
+          else if (is_integer($p_options_list[$i+1])) {
+              $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
+          }
+          else if (is_array($p_options_list[$i+1])) {
+              $v_work_list = $p_options_list[$i+1];
+          }
+          else {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Reduce the index list
+          // each index item in the list must be a couple with a start and
+          // an end value : [0,3], [5-5], [8-10], ...
+          // ----- Check the format of each item
+          $v_sort_flag=false;
+          $v_sort_value=0;
+          for ($j=0; $j<sizeof($v_work_list); $j++) {
+              // ----- Explode the item
+              $v_item_list = explode("-", $v_work_list[$j]);
+              $v_size_item_list = sizeof($v_item_list);
+
+              // ----- TBC : Here we might check that each item is a
+              // real integer ...
+
+              // ----- Look for single value
+              if ($v_size_item_list == 1) {
+                  // ----- Set the option value
+                  $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
+                  $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
+              }
+              elseif ($v_size_item_list == 2) {
+                  // ----- Set the option value
+                  $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
+                  $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
+              }
+              else {
+                  // ----- Error log
+                  PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+                  // ----- Return
+                  return PclZip::errorCode();
+              }
+
+
+              // ----- Look for list sort
+              if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
+                  $v_sort_flag=true;
+
+                  // ----- TBC : An automatic sort should be writen ...
+                  // ----- Error log
+                  PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+                  // ----- Return
+                  return PclZip::errorCode();
+              }
+              $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
+          }
+
+          // ----- Sort the items
+          if ($v_sort_flag) {
+              // TBC : To Be Completed
+          }
+
+          // ----- Next option
+          $i++;
+        break;
+
+        // ----- Look for options that request no value
+        case PCLZIP_OPT_REMOVE_ALL_PATH :
+        case PCLZIP_OPT_EXTRACT_AS_STRING :
+        case PCLZIP_OPT_NO_COMPRESSION :
+        case PCLZIP_OPT_EXTRACT_IN_OUTPUT :
+        case PCLZIP_OPT_REPLACE_NEWER :
+        case PCLZIP_OPT_STOP_ON_ERROR :
+          $v_result_list[$p_options_list[$i]] = true;
+        break;
+
+        // ----- Look for options that request an octal value
+        case PCLZIP_OPT_SET_CHMOD :
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+          $i++;
+        break;
+
+        // ----- Look for options that request a call-back
+        case PCLZIP_CB_PRE_EXTRACT :
+        case PCLZIP_CB_POST_EXTRACT :
+        case PCLZIP_CB_PRE_ADD :
+        case PCLZIP_CB_POST_ADD :
+        /* for futur use
+        case PCLZIP_CB_PRE_DELETE :
+        case PCLZIP_CB_POST_DELETE :
+        case PCLZIP_CB_PRE_LIST :
+        case PCLZIP_CB_POST_LIST :
+        */
+          // ----- Check the number of parameters
+          if (($i+1) >= $p_size) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Get the value
+          $v_function_name = $p_options_list[$i+1];
+
+          // ----- Check that the value is a valid existing function
+          if (!function_exists($v_function_name)) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+
+          // ----- Set the attribute
+          $v_result_list[$p_options_list[$i]] = $v_function_name;
+          $i++;
+        break;
+
+        default :
+          // ----- Error log
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+                               "Unknown parameter '"
+                               .$p_options_list[$i]."'");
+
+          // ----- Return
+          return PclZip::errorCode();
+      }
+
+      // ----- Next options
+      $i++;
+    }
+
+    // ----- Look for mandatory options
+    if ($v_requested_options !== false) {
+      for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
+        // ----- Look for mandatory option
+        if ($v_requested_options[$key] == 'mandatory') {
+          // ----- Look if present
+          if (!isset($v_result_list[$key])) {
+            // ----- Error log
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
+
+            // ----- Return
+            return PclZip::errorCode();
+          }
+        }
+      }
+    }
+
+    // ----- Look for default values
+    if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privOptionDefaultThreshold()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privOptionDefaultThreshold(&$p_options)
+  {
+    $v_result=1;
+
+    if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+        || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
+      return $v_result;
+    }
+
+    // ----- Get 'memory_limit' configuration value
+    $v_memory_limit = ini_get('memory_limit');
+    $v_memory_limit = trim($v_memory_limit);
+    $last = strtolower(substr($v_memory_limit, -1));
+
+    if($last == 'g')
+        //$v_memory_limit = $v_memory_limit*1024*1024*1024;
+        $v_memory_limit = $v_memory_limit*1073741824;
+    if($last == 'm')
+        //$v_memory_limit = $v_memory_limit*1024*1024;
+        $v_memory_limit = $v_memory_limit*1048576;
+    if($last == 'k')
+        $v_memory_limit = $v_memory_limit*1024;
+
+    $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
+
+
+    // ----- Sanity check : No threshold if value lower than 1M
+    if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
+      unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privFileDescrParseAtt()
+  // Description :
+  // Parameters :
+  // Return Values :
+  //   1 on success.
+  //   0 on failure.
+  // --------------------------------------------------------------------------------
+  function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
+  {
+    $v_result=1;
+
+    // ----- For each file in the list check the attributes
+    foreach ($p_file_list as $v_key => $v_value) {
+
+      // ----- Check if the option is supported
+      if (!isset($v_requested_options[$v_key])) {
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+
+      // ----- Look for attribute
+      switch ($v_key) {
+        case PCLZIP_ATT_FILE_NAME :
+          if (!is_string($v_value)) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+
+          $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
+
+          if ($p_filedescr['filename'] == '') {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+
+        break;
+
+        case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
+          if (!is_string($v_value)) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+
+          $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
+
+          if ($p_filedescr['new_short_name'] == '') {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+        break;
+
+        case PCLZIP_ATT_FILE_NEW_FULL_NAME :
+          if (!is_string($v_value)) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+
+          $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
+
+          if ($p_filedescr['new_full_name'] == '') {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+        break;
+
+        // ----- Look for options that takes a string
+        case PCLZIP_ATT_FILE_COMMENT :
+          if (!is_string($v_value)) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+
+          $p_filedescr['comment'] = $v_value;
+        break;
+
+        case PCLZIP_ATT_FILE_MTIME :
+          if (!is_integer($v_value)) {
+            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
+            return PclZip::errorCode();
+          }
+
+          $p_filedescr['mtime'] = $v_value;
+        break;
+
+        case PCLZIP_ATT_FILE_CONTENT :
+          $p_filedescr['content'] = $v_value;
+        break;
+
+        default :
+          // ----- Error log
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+                                   "Unknown parameter '".$v_key."'");
+
+          // ----- Return
+          return PclZip::errorCode();
+      }
+
+      // ----- Look for mandatory options
+      if ($v_requested_options !== false) {
+        for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
+          // ----- Look for mandatory option
+          if ($v_requested_options[$key] == 'mandatory') {
+            // ----- Look if present
+            if (!isset($p_file_list[$key])) {
+              PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
+              return PclZip::errorCode();
+            }
+          }
+        }
+      }
+
+    // end foreach
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privFileDescrExpand()
+  // Description :
+  //   This method look for each item of the list to see if its a file, a folder
+  //   or a string to be added as file. For any other type of files (link, other)
+  //   just ignore the item.
+  //   Then prepare the information that will be stored for that file.
+  //   When its a folder, expand the folder with all the files that are in that
+  //   folder (recursively).
+  // Parameters :
+  // Return Values :
+  //   1 on success.
+  //   0 on failure.
+  // --------------------------------------------------------------------------------
+  function privFileDescrExpand(&$p_filedescr_list, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Create a result list
+    $v_result_list = array();
+
+    // ----- Look each entry
+    for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
+
+      // ----- Get filedescr
+      $v_descr = $p_filedescr_list[$i];
+
+      // ----- Reduce the filename
+      $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
+      $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
+
+      // ----- Look for real file or folder
+      if (file_exists($v_descr['filename'])) {
+        if (@is_file($v_descr['filename'])) {
+          $v_descr['type'] = 'file';
+        }
+        else if (@is_dir($v_descr['filename'])) {
+          $v_descr['type'] = 'folder';
+        }
+        else if (@is_link($v_descr['filename'])) {
+          // skip
+          continue;
+        }
+        else {
+          // skip
+          continue;
+        }
+      }
+
+      // ----- Look for string added as file
+      else if (isset($v_descr['content'])) {
+        $v_descr['type'] = 'virtual_file';
+      }
+
+      // ----- Missing file
+      else {
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+
+      // ----- Calculate the stored filename
+      $this->privCalculateStoredFilename($v_descr, $p_options);
+
+      // ----- Add the descriptor in result list
+      $v_result_list[sizeof($v_result_list)] = $v_descr;
+
+      // ----- Look for folder
+      if ($v_descr['type'] == 'folder') {
+        // ----- List of items in folder
+        $v_dirlist_descr = array();
+        $v_dirlist_nb = 0;
+        if ($v_folder_handler = @opendir($v_descr['filename'])) {
+          while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
+
+            // ----- Skip '.' and '..'
+            if (($v_item_handler == '.') || ($v_item_handler == '..')) {
+                continue;
+            }
+
+            // ----- Compose the full filename
+            $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
+
+            // ----- Look for different stored filename
+            // Because the name of the folder was changed, the name of the
+            // files/sub-folders also change
+            if (($v_descr['stored_filename'] != $v_descr['filename'])
+                 && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
+              if ($v_descr['stored_filename'] != '') {
+                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
+              }
+              else {
+                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
+              }
+            }
+
+            $v_dirlist_nb++;
+          }
+
+          @closedir($v_folder_handler);
+        }
+        else {
+          // TBC : unable to open folder in read mode
+        }
+
+        // ----- Expand each element of the list
+        if ($v_dirlist_nb != 0) {
+          // ----- Expand
+          if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
+            return $v_result;
+          }
+
+          // ----- Concat the resulting list
+          $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
+        }
+        else {
+        }
+
+        // ----- Free local array
+        unset($v_dirlist_descr);
+      }
+    }
+
+    // ----- Get the result list
+    $p_filedescr_list = $v_result_list;
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privCreate()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
+  {
+    $v_result=1;
+    $v_list_detail = array();
+
+    // ----- Magic quotes trick
+    $this->privDisableMagicQuotes();
+
+    // ----- Open the file in write mode
+    if (($v_result = $this->privOpenFd('wb')) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Add the list of files
+    $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
+
+    // ----- Close
+    $this->privCloseFd();
+
+    // ----- Magic quotes trick
+    $this->privSwapBackMagicQuotes();
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privAdd()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
+  {
+    $v_result=1;
+    $v_list_detail = array();
+
+    // ----- Look if the archive exists or is empty
+    if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
+    {
+
+      // ----- Do a create
+      $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
+
+      // ----- Return
+      return $v_result;
+    }
+    // ----- Magic quotes trick
+    $this->privDisableMagicQuotes();
+
+    // ----- Open the zip file
+    if (($v_result=$this->privOpenFd('rb')) != 1)
+    {
+      // ----- Magic quotes trick
+      $this->privSwapBackMagicQuotes();
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Read the central directory informations
+    $v_central_dir = array();
+    if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+    {
+      $this->privCloseFd();
+      $this->privSwapBackMagicQuotes();
+      return $v_result;
+    }
+
+    // ----- Go to beginning of File
+    @rewind($this->zip_fd);
+
+    // ----- Creates a temporay file
+    $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+    // ----- Open the temporary file in write mode
+    if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
+    {
+      $this->privCloseFd();
+      $this->privSwapBackMagicQuotes();
+
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Copy the files from the archive to the temporary file
+    // TBC : Here I should better append the file and go back to erase the central dir
+    $v_size = $v_central_dir['offset'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = fread($this->zip_fd, $v_read_size);
+      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Swap the file descriptor
+    // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+    // the following methods on the temporary fil and not the real archive
+    $v_swap = $this->zip_fd;
+    $this->zip_fd = $v_zip_temp_fd;
+    $v_zip_temp_fd = $v_swap;
+
+    // ----- Add the files
+    $v_header_list = array();
+    if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
+    {
+      fclose($v_zip_temp_fd);
+      $this->privCloseFd();
+      @unlink($v_zip_temp_name);
+      $this->privSwapBackMagicQuotes();
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Store the offset of the central dir
+    $v_offset = @ftell($this->zip_fd);
+
+    // ----- Copy the block of file headers from the old archive
+    $v_size = $v_central_dir['size'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
+      @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Create the Central Dir files header
+    for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++)
+    {
+      // ----- Create the file header
+      if ($v_header_list[$i]['status'] == 'ok') {
+        if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+          fclose($v_zip_temp_fd);
+          $this->privCloseFd();
+          @unlink($v_zip_temp_name);
+          $this->privSwapBackMagicQuotes();
+
+          // ----- Return
+          return $v_result;
+        }
+        $v_count++;
+      }
+
+      // ----- Transform the header to a 'usable' info
+      $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+    }
+
+    // ----- Zip file comment
+    $v_comment = $v_central_dir['comment'];
+    if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+      $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+    }
+    if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
+      $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
+    }
+    if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
+      $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
+    }
+
+    // ----- Calculate the size of the central header
+    $v_size = @ftell($this->zip_fd)-$v_offset;
+
+    // ----- Create the central dir footer
+    if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
+    {
+      // ----- Reset the file list
+      unset($v_header_list);
+      $this->privSwapBackMagicQuotes();
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Swap back the file descriptor
+    $v_swap = $this->zip_fd;
+    $this->zip_fd = $v_zip_temp_fd;
+    $v_zip_temp_fd = $v_swap;
+
+    // ----- Close
+    $this->privCloseFd();
+
+    // ----- Close the temporary file
+    @fclose($v_zip_temp_fd);
+
+    // ----- Magic quotes trick
+    $this->privSwapBackMagicQuotes();
+
+    // ----- Delete the zip file
+    // TBC : I should test the result ...
+    @unlink($this->zipname);
+
+    // ----- Rename the temporary file
+    // TBC : I should test the result ...
+    //@rename($v_zip_temp_name, $this->zipname);
+    PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privOpenFd()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function privOpenFd($p_mode)
+  {
+    $v_result=1;
+
+    // ----- Look if already open
+    if ($this->zip_fd != 0)
+    {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Open the zip file
+    if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
+    {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privCloseFd()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function privCloseFd()
+  {
+    $v_result=1;
+
+    if ($this->zip_fd != 0)
+      @fclose($this->zip_fd);
+    $this->zip_fd = 0;
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privAddList()
+  // Description :
+  //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
+  //   different from the real path of the file. This is usefull if you want to have PclTar
+  //   running in any directory, and memorize relative path from an other directory.
+  // Parameters :
+  //   $p_list : An array containing the file or directory names to add in the tar
+  //   $p_result_list : list of added files with their properties (specially the status field)
+  //   $p_add_dir : Path to add in the filename path archived
+  //   $p_remove_dir : Path to remove in the filename path archived
+  // Return Values :
+  // --------------------------------------------------------------------------------
+//  function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
+  function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Add the files
+    $v_header_list = array();
+    if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Store the offset of the central dir
+    $v_offset = @ftell($this->zip_fd);
+
+    // ----- Create the Central Dir files header
+    for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++)
+    {
+      // ----- Create the file header
+      if ($v_header_list[$i]['status'] == 'ok') {
+        if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+          // ----- Return
+          return $v_result;
+        }
+        $v_count++;
+      }
+
+      // ----- Transform the header to a 'usable' info
+      $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+    }
+
+    // ----- Zip file comment
+    $v_comment = '';
+    if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+      $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+    }
+
+    // ----- Calculate the size of the central header
+    $v_size = @ftell($this->zip_fd)-$v_offset;
+
+    // ----- Create the central dir footer
+    if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
+    {
+      // ----- Reset the file list
+      unset($v_header_list);
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privAddFileList()
+  // Description :
+  // Parameters :
+  //   $p_filedescr_list : An array containing the file description
+  //                      or directory names to add in the zip
+  //   $p_result_list : list of added files with their properties (specially the status field)
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
+  {
+    $v_result=1;
+    $v_header = array();
+
+    // ----- Recuperate the current number of elt in list
+    $v_nb = sizeof($p_result_list);
+
+    // ----- Loop on the files
+    for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
+      // ----- Format the filename
+      $p_filedescr_list[$j]['filename']
+      = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
+
+
+      // ----- Skip empty file names
+      // TBC : Can this be possible ? not checked in DescrParseAtt ?
+      if ($p_filedescr_list[$j]['filename'] == "") {
+        continue;
+      }
+
+      // ----- Check the filename
+      if (   ($p_filedescr_list[$j]['type'] != 'virtual_file')
+          && (!file_exists($p_filedescr_list[$j]['filename']))) {
+        PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
+        return PclZip::errorCode();
+      }
+
+      // ----- Look if it is a file or a dir with no all path remove option
+      // or a dir with all its path removed
+//      if (   (is_file($p_filedescr_list[$j]['filename']))
+//          || (   is_dir($p_filedescr_list[$j]['filename'])
+      if (   ($p_filedescr_list[$j]['type'] == 'file')
+          || ($p_filedescr_list[$j]['type'] == 'virtual_file')
+          || (   ($p_filedescr_list[$j]['type'] == 'folder')
+              && (   !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
+                  || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
+          ) {
+
+        // ----- Add the file
+        $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
+                                       $p_options);
+        if ($v_result != 1) {
+          return $v_result;
+        }
+
+        // ----- Store the file infos
+        $p_result_list[$v_nb++] = $v_header;
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privAddFile()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privAddFile($p_filedescr, &$p_header, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Working variable
+    $p_filename = $p_filedescr['filename'];
+
+    // TBC : Already done in the fileAtt check ... ?
+    if ($p_filename == "") {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Look for a stored different filename
+    /* TBC : Removed
+    if (isset($p_filedescr['stored_filename'])) {
+      $v_stored_filename = $p_filedescr['stored_filename'];
+    }
+    else {
+      $v_stored_filename = $p_filedescr['stored_filename'];
+    }
+    */
+
+    // ----- Set the file properties
+    clearstatcache();
+    $p_header['version'] = 20;
+    $p_header['version_extracted'] = 10;
+    $p_header['flag'] = 0;
+    $p_header['compression'] = 0;
+    $p_header['crc'] = 0;
+    $p_header['compressed_size'] = 0;
+    $p_header['filename_len'] = strlen($p_filename);
+    $p_header['extra_len'] = 0;
+    $p_header['disk'] = 0;
+    $p_header['internal'] = 0;
+    $p_header['offset'] = 0;
+    $p_header['filename'] = $p_filename;
+// TBC : Removed    $p_header['stored_filename'] = $v_stored_filename;
+    $p_header['stored_filename'] = $p_filedescr['stored_filename'];
+    $p_header['extra'] = '';
+    $p_header['status'] = 'ok';
+    $p_header['index'] = -1;
+
+    // ----- Look for regular file
+    if ($p_filedescr['type']=='file') {
+      $p_header['external'] = 0x00000000;
+      $p_header['size'] = filesize($p_filename);
+    }
+
+    // ----- Look for regular folder
+    else if ($p_filedescr['type']=='folder') {
+      $p_header['external'] = 0x00000010;
+      $p_header['mtime'] = filemtime($p_filename);
+      $p_header['size'] = filesize($p_filename);
+    }
+
+    // ----- Look for virtual file
+    else if ($p_filedescr['type'] == 'virtual_file') {
+      $p_header['external'] = 0x00000000;
+      $p_header['size'] = strlen($p_filedescr['content']);
+    }
+
+
+    // ----- Look for filetime
+    if (isset($p_filedescr['mtime'])) {
+      $p_header['mtime'] = $p_filedescr['mtime'];
+    }
+    else if ($p_filedescr['type'] == 'virtual_file') {
+      $p_header['mtime'] = time();
+    }
+    else {
+      $p_header['mtime'] = filemtime($p_filename);
+    }
+
+    // ------ Look for file comment
+    if (isset($p_filedescr['comment'])) {
+      $p_header['comment_len'] = strlen($p_filedescr['comment']);
+      $p_header['comment'] = $p_filedescr['comment'];
+    }
+    else {
+      $p_header['comment_len'] = 0;
+      $p_header['comment'] = '';
+    }
+
+    // ----- Look for pre-add callback
+    if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
+      if ($v_result == 0) {
+        // ----- Change the file status
+        $p_header['status'] = "skipped";
+        $v_result = 1;
+      }
+
+      // ----- Update the informations
+      // Only some fields can be modified
+      if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
+        $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
+      }
+    }
+
+    // ----- Look for empty stored filename
+    if ($p_header['stored_filename'] == "") {
+      $p_header['status'] = "filtered";
+    }
+
+    // ----- Check the path length
+    if (strlen($p_header['stored_filename']) > 0xFF) {
+      $p_header['status'] = 'filename_too_long';
+    }
+
+    // ----- Look if no error, or file not skipped
+    if ($p_header['status'] == 'ok') {
+
+      // ----- Look for a file
+      if ($p_filedescr['type'] == 'file') {
+        // ----- Look for using temporary file to zip
+        if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
+            && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
+                || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+                    && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
+          $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
+          if ($v_result < PCLZIP_ERR_NO_ERROR) {
+            return $v_result;
+          }
+        }
+
+        // ----- Use "in memory" zip algo
+        else {
+
+        // ----- Open the source file
+        if (($v_file = @fopen($p_filename, "rb")) == 0) {
+          PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+          return PclZip::errorCode();
+        }
+
+        // ----- Read the file content
+        $v_content = @fread($v_file, $p_header['size']);
+
+        // ----- Close the file
+        @fclose($v_file);
+
+        // ----- Calculate the CRC
+        $p_header['crc'] = @crc32($v_content);
+
+        // ----- Look for no compression
+        if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+          // ----- Set header parameters
+          $p_header['compressed_size'] = $p_header['size'];
+          $p_header['compression'] = 0;
+        }
+
+        // ----- Look for normal compression
+        else {
+          // ----- Compress the content
+          $v_content = @gzdeflate($v_content);
+
+          // ----- Set header parameters
+          $p_header['compressed_size'] = strlen($v_content);
+          $p_header['compression'] = 8;
+        }
+
+        // ----- Call the header generation
+        if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+          @fclose($v_file);
+          return $v_result;
+        }
+
+        // ----- Write the compressed (or not) content
+        @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+
+        }
+
+      }
+
+      // ----- Look for a virtual file (a file from string)
+      else if ($p_filedescr['type'] == 'virtual_file') {
+
+        $v_content = $p_filedescr['content'];
+
+        // ----- Calculate the CRC
+        $p_header['crc'] = @crc32($v_content);
+
+        // ----- Look for no compression
+        if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+          // ----- Set header parameters
+          $p_header['compressed_size'] = $p_header['size'];
+          $p_header['compression'] = 0;
+        }
+
+        // ----- Look for normal compression
+        else {
+          // ----- Compress the content
+          $v_content = @gzdeflate($v_content);
+
+          // ----- Set header parameters
+          $p_header['compressed_size'] = strlen($v_content);
+          $p_header['compression'] = 8;
+        }
+
+        // ----- Call the header generation
+        if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+          @fclose($v_file);
+          return $v_result;
+        }
+
+        // ----- Write the compressed (or not) content
+        @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+      }
+
+      // ----- Look for a directory
+      else if ($p_filedescr['type'] == 'folder') {
+        // ----- Look for directory last '/'
+        if (@substr($p_header['stored_filename'], -1) != '/') {
+          $p_header['stored_filename'] .= '/';
+        }
+
+        // ----- Set the file properties
+        $p_header['size'] = 0;
+        //$p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked
+        $p_header['external'] = 0x00000010;   // Value for a folder : to be checked
+
+        // ----- Call the header generation
+        if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
+        {
+          return $v_result;
+        }
+      }
+    }
+
+    // ----- Look for post-add callback
+    if (isset($p_options[PCLZIP_CB_POST_ADD])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
+      if ($v_result == 0) {
+        // ----- Ignored
+        $v_result = 1;
+      }
+
+      // ----- Update the informations
+      // Nothing can be modified
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privAddFileUsingTempFile()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
+  {
+    $v_result=PCLZIP_ERR_NO_ERROR;
+
+    // ----- Working variable
+    $p_filename = $p_filedescr['filename'];
+
+
+    // ----- Open the source file
+    if (($v_file = @fopen($p_filename, "rb")) == 0) {
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+      return PclZip::errorCode();
+    }
+
+    // ----- Creates a compressed temporary file
+    $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
+    if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
+      fclose($v_file);
+      PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
+      return PclZip::errorCode();
+    }
+
+    // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+    $v_size = filesize($p_filename);
+    while ($v_size != 0) {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @fread($v_file, $v_read_size);
+      //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+      @gzputs($v_file_compressed, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Close the file
+    @fclose($v_file);
+    @gzclose($v_file_compressed);
+
+    // ----- Check the minimum file size
+    if (filesize($v_gzip_temp_name) < 18) {
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
+      return PclZip::errorCode();
+    }
+
+    // ----- Extract the compressed attributes
+    if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+      return PclZip::errorCode();
+    }
+
+    // ----- Read the gzip file header
+    $v_binary_data = @fread($v_file_compressed, 10);
+    $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
+
+    // ----- Check some parameters
+    $v_data_header['os'] = bin2hex($v_data_header['os']);
+
+    // ----- Read the gzip file footer
+    @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
+    $v_binary_data = @fread($v_file_compressed, 8);
+    $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
+
+    // ----- Set the attributes
+    $p_header['compression'] = ord($v_data_header['cm']);
+    //$p_header['mtime'] = $v_data_header['mtime'];
+    $p_header['crc'] = $v_data_footer['crc'];
+    $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
+
+    // ----- Close the file
+    @fclose($v_file_compressed);
+
+    // ----- Call the header generation
+    if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+      return $v_result;
+    }
+
+    // ----- Add the compressed data
+    if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
+    {
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+      return PclZip::errorCode();
+    }
+
+    // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+    fseek($v_file_compressed, 10);
+    $v_size = $p_header['compressed_size'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @fread($v_file_compressed, $v_read_size);
+      //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+      @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Close the file
+    @fclose($v_file_compressed);
+
+    // ----- Unlink the temporary file
+    @unlink($v_gzip_temp_name);
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privCalculateStoredFilename()
+  // Description :
+  //   Based on file descriptor properties and global options, this method
+  //   calculate the filename that will be stored in the archive.
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privCalculateStoredFilename(&$p_filedescr, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Working variables
+    $p_filename = $p_filedescr['filename'];
+    if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
+      $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
+    }
+    else {
+      $p_add_dir = '';
+    }
+    if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
+      $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
+    }
+    else {
+      $p_remove_dir = '';
+    }
+    if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+      $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+    }
+    else {
+      $p_remove_all_dir = 0;
+    }
+
+
+    // ----- Look for full name change
+    if (isset($p_filedescr['new_full_name'])) {
+      // ----- Remove drive letter if any
+      $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
+    }
+
+    // ----- Look for path and/or short name change
+    else {
+
+      // ----- Look for short name change
+      // Its when we cahnge just the filename but not the path
+      if (isset($p_filedescr['new_short_name'])) {
+        $v_path_info = pathinfo($p_filename);
+        $v_dir = '';
+        if ($v_path_info['dirname'] != '') {
+          $v_dir = $v_path_info['dirname'].'/';
+        }
+        $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
+      }
+      else {
+        // ----- Calculate the stored filename
+        $v_stored_filename = $p_filename;
+      }
+
+      // ----- Look for all path to remove
+      if ($p_remove_all_dir) {
+        $v_stored_filename = basename($p_filename);
+      }
+      // ----- Look for partial path remove
+      else if ($p_remove_dir != "") {
+        if (substr($p_remove_dir, -1) != '/')
+          $p_remove_dir .= "/";
+
+        if (   (substr($p_filename, 0, 2) == "./")
+            || (substr($p_remove_dir, 0, 2) == "./")) {
+
+          if (   (substr($p_filename, 0, 2) == "./")
+              && (substr($p_remove_dir, 0, 2) != "./")) {
+            $p_remove_dir = "./".$p_remove_dir;
+          }
+          if (   (substr($p_filename, 0, 2) != "./")
+              && (substr($p_remove_dir, 0, 2) == "./")) {
+            $p_remove_dir = substr($p_remove_dir, 2);
+          }
+        }
+
+        $v_compare = PclZipUtilPathInclusion($p_remove_dir,
+                                             $v_stored_filename);
+        if ($v_compare > 0) {
+          if ($v_compare == 2) {
+            $v_stored_filename = "";
+          }
+          else {
+            $v_stored_filename = substr($v_stored_filename,
+                                        strlen($p_remove_dir));
+          }
+        }
+      }
+
+      // ----- Remove drive letter if any
+      $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
+
+      // ----- Look for path to add
+      if ($p_add_dir != "") {
+        if (substr($p_add_dir, -1) == "/")
+          $v_stored_filename = $p_add_dir.$v_stored_filename;
+        else
+          $v_stored_filename = $p_add_dir."/".$v_stored_filename;
+      }
+    }
+
+    // ----- Filename (reduce the path of stored name)
+    $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
+    $p_filedescr['stored_filename'] = $v_stored_filename;
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privWriteFileHeader()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privWriteFileHeader(&$p_header)
+  {
+    $v_result=1;
+
+    // ----- Store the offset position of the file
+    $p_header['offset'] = ftell($this->zip_fd);
+
+    // ----- Transform UNIX mtime to DOS format mdate/mtime
+    $v_date = getdate($p_header['mtime']);
+    $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
+    $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
+
+    // ----- Packed data
+    $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
+                          $p_header['version_extracted'], $p_header['flag'],
+                          $p_header['compression'], $v_mtime, $v_mdate,
+                          $p_header['crc'], $p_header['compressed_size'],
+                          $p_header['size'],
+                          strlen($p_header['stored_filename']),
+                          $p_header['extra_len']);
+
+    // ----- Write the first 148 bytes of the header in the archive
+    fputs($this->zip_fd, $v_binary_data, 30);
+
+    // ----- Write the variable fields
+    if (strlen($p_header['stored_filename']) != 0)
+    {
+      fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+    }
+    if ($p_header['extra_len'] != 0)
+    {
+      fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privWriteCentralFileHeader()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privWriteCentralFileHeader(&$p_header)
+  {
+    $v_result=1;
+
+    // TBC
+    //for(reset($p_header); $key = key($p_header); next($p_header)) {
+    //}
+
+    // ----- Transform UNIX mtime to DOS format mdate/mtime
+    $v_date = getdate($p_header['mtime']);
+    $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
+    $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
+
+
+    // ----- Packed data
+    $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
+                          $p_header['version'], $p_header['version_extracted'],
+                          $p_header['flag'], $p_header['compression'],
+                          $v_mtime, $v_mdate, $p_header['crc'],
+                          $p_header['compressed_size'], $p_header['size'],
+                          strlen($p_header['stored_filename']),
+                          $p_header['extra_len'], $p_header['comment_len'],
+                          $p_header['disk'], $p_header['internal'],
+                          $p_header['external'], $p_header['offset']);
+
+    // ----- Write the 42 bytes of the header in the zip file
+    fputs($this->zip_fd, $v_binary_data, 46);
+
+    // ----- Write the variable fields
+    if (strlen($p_header['stored_filename']) != 0)
+    {
+      fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+    }
+    if ($p_header['extra_len'] != 0)
+    {
+      fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+    }
+    if ($p_header['comment_len'] != 0)
+    {
+      fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privWriteCentralHeader()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
+  {
+    $v_result=1;
+
+    // ----- Packed data
+    $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
+                          $p_nb_entries, $p_size,
+                          $p_offset, strlen($p_comment));
+
+    // ----- Write the 22 bytes of the header in the zip file
+    fputs($this->zip_fd, $v_binary_data, 22);
+
+    // ----- Write the variable fields
+    if (strlen($p_comment) != 0)
+    {
+      fputs($this->zip_fd, $p_comment, strlen($p_comment));
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privList()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privList(&$p_list)
+  {
+    $v_result=1;
+
+    // ----- Magic quotes trick
+    $this->privDisableMagicQuotes();
+
+    // ----- Open the zip file
+    if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
+    {
+      // ----- Magic quotes trick
+      $this->privSwapBackMagicQuotes();
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Read the central directory informations
+    $v_central_dir = array();
+    if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+    {
+      $this->privSwapBackMagicQuotes();
+      return $v_result;
+    }
+
+    // ----- Go to beginning of Central Dir
+    @rewind($this->zip_fd);
+    if (@fseek($this->zip_fd, $v_central_dir['offset']))
+    {
+      $this->privSwapBackMagicQuotes();
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Read each entry
+    for ($i=0; $i<$v_central_dir['entries']; $i++)
+    {
+      // ----- Read the file header
+      if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
+      {
+        $this->privSwapBackMagicQuotes();
+        return $v_result;
+      }
+      $v_header['index'] = $i;
+
+      // ----- Get the only interesting attributes
+      $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
+      unset($v_header);
+    }
+
+    // ----- Close the zip file
+    $this->privCloseFd();
+
+    // ----- Magic quotes trick
+    $this->privSwapBackMagicQuotes();
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privConvertHeader2FileInfo()
+  // Description :
+  //   This function takes the file informations from the central directory
+  //   entries and extract the interesting parameters that will be given back.
+  //   The resulting file infos are set in the array $p_info
+  //     $p_info['filename'] : Filename with full path. Given by user (add),
+  //                           extracted in the filesystem (extract).
+  //     $p_info['stored_filename'] : Stored filename in the archive.
+  //     $p_info['size'] = Size of the file.
+  //     $p_info['compressed_size'] = Compressed size of the file.
+  //     $p_info['mtime'] = Last modification date of the file.
+  //     $p_info['comment'] = Comment associated with the file.
+  //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.
+  //     $p_info['status'] = status of the action on the file.
+  //     $p_info['crc'] = CRC of the file content.
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privConvertHeader2FileInfo($p_header, &$p_info)
+  {
+    $v_result=1;
+
+    // ----- Get the interesting attributes
+    $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
+    $p_info['filename'] = $v_temp_path;
+    $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
+    $p_info['stored_filename'] = $v_temp_path;
+    $p_info['size'] = $p_header['size'];
+    $p_info['compressed_size'] = $p_header['compressed_size'];
+    $p_info['mtime'] = $p_header['mtime'];
+    $p_info['comment'] = $p_header['comment'];
+    $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
+    $p_info['index'] = $p_header['index'];
+    $p_info['status'] = $p_header['status'];
+    $p_info['crc'] = $p_header['crc'];
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privExtractByRule()
+  // Description :
+  //   Extract a file or directory depending of rules (by index, by name, ...)
+  // Parameters :
+  //   $p_file_list : An array where will be placed the properties of each
+  //                  extracted file
+  //   $p_path : Path to add while writing the extracted files
+  //   $p_remove_path : Path to remove (from the file memorized path) while writing the
+  //                    extracted files. If the path does not match the file path,
+  //                    the file is extracted with its memorized path.
+  //                    $p_remove_path does not apply to 'list' mode.
+  //                    $p_path and $p_remove_path are commulative.
+  // Return Values :
+  //   1 on success,0 or less on error (see error code list)
+  // --------------------------------------------------------------------------------
+  function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Magic quotes trick
+    $this->privDisableMagicQuotes();
+
+    // ----- Check the path
+    if (   ($p_path == "")
+        || (   (substr($p_path, 0, 1) != "/")
+            && (substr($p_path, 0, 3) != "../")
+            && (substr($p_path,1,2)!=":/")))
+      $p_path = "./".$p_path;
+
+    // ----- Reduce the path last (and duplicated) '/'
+    if (($p_path != "./") && ($p_path != "/"))
+    {
+      // ----- Look for the path end '/'
+      while (substr($p_path, -1) == "/")
+      {
+        $p_path = substr($p_path, 0, strlen($p_path)-1);
+      }
+    }
+
+    // ----- Look for path to remove format (should end by /)
+    if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
+    {
+      $p_remove_path .= '/';
+    }
+    $p_remove_path_size = strlen($p_remove_path);
+
+    // ----- Open the zip file
+    if (($v_result = $this->privOpenFd('rb')) != 1)
+    {
+      $this->privSwapBackMagicQuotes();
+      return $v_result;
+    }
+
+    // ----- Read the central directory informations
+    $v_central_dir = array();
+    if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+    {
+      // ----- Close the zip file
+      $this->privCloseFd();
+      $this->privSwapBackMagicQuotes();
+
+      return $v_result;
+    }
+
+    // ----- Start at beginning of Central Dir
+    $v_pos_entry = $v_central_dir['offset'];
+
+    // ----- Read each entry
+    $j_start = 0;
+    for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
+    {
+
+      // ----- Read next Central dir entry
+      @rewind($this->zip_fd);
+      if (@fseek($this->zip_fd, $v_pos_entry))
+      {
+        // ----- Close the zip file
+        $this->privCloseFd();
+        $this->privSwapBackMagicQuotes();
+
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+
+      // ----- Read the file header
+      $v_header = array();
+      if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
+      {
+        // ----- Close the zip file
+        $this->privCloseFd();
+        $this->privSwapBackMagicQuotes();
+
+        return $v_result;
+      }
+
+      // ----- Store the index
+      $v_header['index'] = $i;
+
+      // ----- Store the file position
+      $v_pos_entry = ftell($this->zip_fd);
+
+      // ----- Look for the specific extract rules
+      $v_extract = false;
+
+      // ----- Look for extract by name rule
+      if (   (isset($p_options[PCLZIP_OPT_BY_NAME]))
+          && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+          // ----- Look if the filename is in the list
+          for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
+
+              // ----- Look for a directory
+              if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
+
+                  // ----- Look if the directory is in the filename path
+                  if (   (strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
+                      && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+                      $v_extract = true;
+                  }
+              }
+              // ----- Look for a filename
+              elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+                  $v_extract = true;
+              }
+          }
+      }
+
+      // ----- Look for extract by ereg rule
+      // ereg() is deprecated with PHP 5.3
+      /*
+      else if (   (isset($p_options[PCLZIP_OPT_BY_EREG]))
+               && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+          if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
+              $v_extract = true;
+          }
+      }
+      */
+
+      // ----- Look for extract by preg rule
+      else if (   (isset($p_options[PCLZIP_OPT_BY_PREG]))
+               && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+          if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
+              $v_extract = true;
+          }
+      }
+
+      // ----- Look for extract by index rule
+      else if (   (isset($p_options[PCLZIP_OPT_BY_INDEX]))
+               && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+          // ----- Look if the index is in the list
+          for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
+
+              if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+                  $v_extract = true;
+              }
+              if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+                  $j_start = $j+1;
+              }
+
+              if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
+                  break;
+              }
+          }
+      }
+
+      // ----- Look for no rule, which means extract all the archive
+      else {
+          $v_extract = true;
+      }
+
+      // ----- Check compression method
+      if (   ($v_extract)
+          && (   ($v_header['compression'] != 8)
+              && ($v_header['compression'] != 0))) {
+          $v_header['status'] = 'unsupported_compression';
+
+          // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+          if (   (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+              && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+              $this->privSwapBackMagicQuotes();
+
+              PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
+                                   "Filename '".$v_header['stored_filename']."' is "
+                                   ."compressed by an unsupported compression "
+                                   ."method (".$v_header['compression'].") ");
+
+              return PclZip::errorCode();
+          }
+      }
+
+      // ----- Check encrypted files
+      if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
+          $v_header['status'] = 'unsupported_encryption';
+
+          // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+          if (   (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+              && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+              $this->privSwapBackMagicQuotes();
+
+              PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
+                                   "Unsupported encryption for "
+                                   ." filename '".$v_header['stored_filename']
+                                   ."'");
+
+              return PclZip::errorCode();
+          }
+    }
+
+      // ----- Look for real extraction
+      if (($v_extract) && ($v_header['status'] != 'ok')) {
+          $v_result = $this->privConvertHeader2FileInfo($v_header,
+                                                $p_file_list[$v_nb_extracted++]);
+          if ($v_result != 1) {
+              $this->privCloseFd();
+              $this->privSwapBackMagicQuotes();
+              return $v_result;
+          }
+
+          $v_extract = false;
+      }
+
+      // ----- Look for real extraction
+      if ($v_extract)
+      {
+
+        // ----- Go to the file position
+        @rewind($this->zip_fd);
+        if (@fseek($this->zip_fd, $v_header['offset']))
+        {
+          // ----- Close the zip file
+          $this->privCloseFd();
+
+          $this->privSwapBackMagicQuotes();
+
+          // ----- Error log
+          PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+          // ----- Return
+          return PclZip::errorCode();
+        }
+
+        // ----- Look for extraction as string
+        if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
+
+          $v_string = '';
+
+          // ----- Extracting the file
+          $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
+          if ($v_result1 < 1) {
+            $this->privCloseFd();
+            $this->privSwapBackMagicQuotes();
+            return $v_result1;
+          }
+
+          // ----- Get the only interesting attributes
+          if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
+          {
+            // ----- Close the zip file
+            $this->privCloseFd();
+            $this->privSwapBackMagicQuotes();
+
+            return $v_result;
+          }
+
+          // ----- Set the file content
+          $p_file_list[$v_nb_extracted]['content'] = $v_string;
+
+          // ----- Next extracted file
+          $v_nb_extracted++;
+
+          // ----- Look for user callback abort
+          if ($v_result1 == 2) {
+            break;
+          }
+        }
+        // ----- Look for extraction in standard output
+        elseif (   (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
+                && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
+          // ----- Extracting the file in standard output
+          $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
+          if ($v_result1 < 1) {
+            $this->privCloseFd();
+            $this->privSwapBackMagicQuotes();
+            return $v_result1;
+          }
+
+          // ----- Get the only interesting attributes
+          if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
+            $this->privCloseFd();
+            $this->privSwapBackMagicQuotes();
+            return $v_result;
+          }
+
+          // ----- Look for user callback abort
+          if ($v_result1 == 2) {
+            break;
+          }
+        }
+        // ----- Look for normal extraction
+        else {
+          // ----- Extracting the file
+          $v_result1 = $this->privExtractFile($v_header,
+                                              $p_path, $p_remove_path,
+                                              $p_remove_all_path,
+                                              $p_options);
+          if ($v_result1 < 1) {
+            $this->privCloseFd();
+            $this->privSwapBackMagicQuotes();
+            return $v_result1;
+          }
+
+          // ----- Get the only interesting attributes
+          if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
+          {
+            // ----- Close the zip file
+            $this->privCloseFd();
+            $this->privSwapBackMagicQuotes();
+
+            return $v_result;
+          }
+
+          // ----- Look for user callback abort
+          if ($v_result1 == 2) {
+            break;
+          }
+        }
+      }
+    }
+
+    // ----- Close the zip file
+    $this->privCloseFd();
+    $this->privSwapBackMagicQuotes();
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privExtractFile()
+  // Description :
+  // Parameters :
+  // Return Values :
+  //
+  // 1 : ... ?
+  // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
+  // --------------------------------------------------------------------------------
+  function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Read the file header
+    if (($v_result = $this->privReadFileHeader($v_header)) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+
+    // ----- Check that the file header is coherent with $p_entry info
+    if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+        // TBC
+    }
+
+    // ----- Look for all path to remove
+    if ($p_remove_all_path == true) {
+        // ----- Look for folder entry that not need to be extracted
+        if (($p_entry['external']&0x00000010)==0x00000010) {
+
+            $p_entry['status'] = "filtered";
+
+            return $v_result;
+        }
+
+        // ----- Get the basename of the path
+        $p_entry['filename'] = basename($p_entry['filename']);
+    }
+
+    // ----- Look for path to remove
+    else if ($p_remove_path != "")
+    {
+      if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2)
+      {
+
+        // ----- Change the file status
+        $p_entry['status'] = "filtered";
+
+        // ----- Return
+        return $v_result;
+      }
+
+      $p_remove_path_size = strlen($p_remove_path);
+      if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
+      {
+
+        // ----- Remove the path
+        $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
+
+      }
+    }
+
+    // ----- Add the path
+    if ($p_path != '') {
+      $p_entry['filename'] = $p_path."/".$p_entry['filename'];
+    }
+
+    // ----- Check a base_dir_restriction
+    if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
+      $v_inclusion
+      = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
+                                $p_entry['filename']);
+      if ($v_inclusion == 0) {
+
+        PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
+                                 "Filename '".$p_entry['filename']."' is "
+                                 ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
+
+        return PclZip::errorCode();
+      }
+    }
+
+    // ----- Look for pre-extract callback
+    if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+      if ($v_result == 0) {
+        // ----- Change the file status
+        $p_entry['status'] = "skipped";
+        $v_result = 1;
+      }
+
+      // ----- Look for abort result
+      if ($v_result == 2) {
+        // ----- This status is internal and will be changed in 'skipped'
+        $p_entry['status'] = "aborted";
+        $v_result = PCLZIP_ERR_USER_ABORTED;
+      }
+
+      // ----- Update the informations
+      // Only some fields can be modified
+      $p_entry['filename'] = $v_local_header['filename'];
+    }
+
+
+    // ----- Look if extraction should be done
+    if ($p_entry['status'] == 'ok') {
+
+    // ----- Look for specific actions while the file exist
+    if (file_exists($p_entry['filename']))
+    {
+
+      // ----- Look if file is a directory
+      if (is_dir($p_entry['filename']))
+      {
+
+        // ----- Change the file status
+        $p_entry['status'] = "already_a_directory";
+
+        // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+        // For historical reason first PclZip implementation does not stop
+        // when this kind of error occurs.
+        if (   (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+            && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+            PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
+                                 "Filename '".$p_entry['filename']."' is "
+                                 ."already used by an existing directory");
+
+            return PclZip::errorCode();
+            }
+      }
+      // ----- Look if file is write protected
+      else if (!is_writeable($p_entry['filename']))
+      {
+
+        // ----- Change the file status
+        $p_entry['status'] = "write_protected";
+
+        // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+        // For historical reason first PclZip implementation does not stop
+        // when this kind of error occurs.
+        if (   (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+            && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
+                                 "Filename '".$p_entry['filename']."' exists "
+                                 ."and is write protected");
+
+            return PclZip::errorCode();
+            }
+      }
+
+      // ----- Look if the extracted file is older
+      else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
+      {
+        // ----- Change the file status
+        if (   (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
+            && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
+          }
+            else {
+            $p_entry['status'] = "newer_exist";
+
+            // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+            // For historical reason first PclZip implementation does not stop
+            // when this kind of error occurs.
+            if (   (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+                && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+                PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
+                         "Newer version of '".$p_entry['filename']."' exists "
+                        ."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
+
+                return PclZip::errorCode();
+              }
+            }
+      }
+      else {
+      }
+    }
+
+    // ----- Check the directory availability and create it if necessary
+    else {
+      if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
+        $v_dir_to_check = $p_entry['filename'];
+      else if (!strstr($p_entry['filename'], "/"))
+        $v_dir_to_check = "";
+      else
+        $v_dir_to_check = dirname($p_entry['filename']);
+
+        if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
+
+          // ----- Change the file status
+          $p_entry['status'] = "path_creation_fail";
+
+          // ----- Return
+          //return $v_result;
+          $v_result = 1;
+        }
+      }
+    }
+
+    // ----- Look if extraction should be done
+    if ($p_entry['status'] == 'ok') {
+
+      // ----- Do the extraction (if not a folder)
+      if (!(($p_entry['external']&0x00000010)==0x00000010))
+      {
+        // ----- Look for not compressed file
+        if ($p_entry['compression'] == 0) {
+
+              // ----- Opening destination file
+          if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
+          {
+
+            // ----- Change the file status
+            $p_entry['status'] = "write_error";
+
+            // ----- Return
+            return $v_result;
+          }
+
+
+          // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+          $v_size = $p_entry['compressed_size'];
+          while ($v_size != 0)
+          {
+            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+            $v_buffer = @fread($this->zip_fd, $v_read_size);
+            /* Try to speed up the code
+            $v_binary_data = pack('a'.$v_read_size, $v_buffer);
+            @fwrite($v_dest_file, $v_binary_data, $v_read_size);
+            */
+            @fwrite($v_dest_file, $v_buffer, $v_read_size);
+            $v_size -= $v_read_size;
+          }
+
+          // ----- Closing the destination file
+          fclose($v_dest_file);
+
+          // ----- Change the file mtime
+          touch($p_entry['filename'], $p_entry['mtime']);
+
+
+        }
+        else {
+          // ----- TBC
+          // Need to be finished
+          if (($p_entry['flag'] & 1) == 1) {
+            PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
+            return PclZip::errorCode();
+          }
+
+
+          // ----- Look for using temporary file to unzip
+          if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
+              && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
+                  || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+                      && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
+            $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
+            if ($v_result < PCLZIP_ERR_NO_ERROR) {
+              return $v_result;
+            }
+          }
+
+          // ----- Look for extract in memory
+          else {
+
+
+            // ----- Read the compressed file in a buffer (one shot)
+            $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+            // ----- Decompress the file
+            $v_file_content = @gzinflate($v_buffer);
+            unset($v_buffer);
+            if ($v_file_content === FALSE) {
+
+              // ----- Change the file status
+              // TBC
+              $p_entry['status'] = "error";
+
+              return $v_result;
+            }
+
+            // ----- Opening destination file
+            if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+
+              // ----- Change the file status
+              $p_entry['status'] = "write_error";
+
+              return $v_result;
+            }
+
+            // ----- Write the uncompressed data
+            @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
+            unset($v_file_content);
+
+            // ----- Closing the destination file
+            @fclose($v_dest_file);
+
+          }
+
+          // ----- Change the file mtime
+          @touch($p_entry['filename'], $p_entry['mtime']);
+        }
+
+        // ----- Look for chmod option
+        if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
+
+          // ----- Change the mode of the file
+          @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
+        }
+
+      }
+    }
+
+    // ----- Change abort status
+    if ($p_entry['status'] == "aborted") {
+        $p_entry['status'] = "skipped";
+    }
+
+    // ----- Look for post-extract callback
+    elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+      // ----- Look for abort result
+      if ($v_result == 2) {
+        $v_result = PCLZIP_ERR_USER_ABORTED;
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privExtractFileUsingTempFile()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privExtractFileUsingTempFile(&$p_entry, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Creates a temporary file
+    $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
+    if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
+      fclose($v_file);
+      PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
+      return PclZip::errorCode();
+    }
+
+
+    // ----- Write gz file format header
+    $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
+    @fwrite($v_dest_file, $v_binary_data, 10);
+
+    // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+    $v_size = $p_entry['compressed_size'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @fread($this->zip_fd, $v_read_size);
+      //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+      @fwrite($v_dest_file, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Write gz file format footer
+    $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
+    @fwrite($v_dest_file, $v_binary_data, 8);
+
+    // ----- Close the temporary file
+    @fclose($v_dest_file);
+
+    // ----- Opening destination file
+    if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+      $p_entry['status'] = "write_error";
+      return $v_result;
+    }
+
+    // ----- Open the temporary gz file
+    if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
+      @fclose($v_dest_file);
+      $p_entry['status'] = "read_error";
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+      return PclZip::errorCode();
+    }
+
+
+    // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+    $v_size = $p_entry['size'];
+    while ($v_size != 0) {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @gzread($v_src_file, $v_read_size);
+      //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+      @fwrite($v_dest_file, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+    @fclose($v_dest_file);
+    @gzclose($v_src_file);
+
+    // ----- Delete the temporary file
+    @unlink($v_gzip_temp_name);
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privExtractFileInOutput()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privExtractFileInOutput(&$p_entry, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Read the file header
+    if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
+      return $v_result;
+    }
+
+
+    // ----- Check that the file header is coherent with $p_entry info
+    if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+        // TBC
+    }
+
+    // ----- Look for pre-extract callback
+    if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+      if ($v_result == 0) {
+        // ----- Change the file status
+        $p_entry['status'] = "skipped";
+        $v_result = 1;
+      }
+
+      // ----- Look for abort result
+      if ($v_result == 2) {
+        // ----- This status is internal and will be changed in 'skipped'
+        $p_entry['status'] = "aborted";
+        $v_result = PCLZIP_ERR_USER_ABORTED;
+      }
+
+      // ----- Update the informations
+      // Only some fields can be modified
+      $p_entry['filename'] = $v_local_header['filename'];
+    }
+
+    // ----- Trace
+
+    // ----- Look if extraction should be done
+    if ($p_entry['status'] == 'ok') {
+
+      // ----- Do the extraction (if not a folder)
+      if (!(($p_entry['external']&0x00000010)==0x00000010)) {
+        // ----- Look for not compressed file
+        if ($p_entry['compressed_size'] == $p_entry['size']) {
+
+          // ----- Read the file in a buffer (one shot)
+          $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+          // ----- Send the file to the output
+          echo $v_buffer;
+          unset($v_buffer);
+        }
+        else {
+
+          // ----- Read the compressed file in a buffer (one shot)
+          $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+          // ----- Decompress the file
+          $v_file_content = gzinflate($v_buffer);
+          unset($v_buffer);
+
+          // ----- Send the file to the output
+          echo $v_file_content;
+          unset($v_file_content);
+        }
+      }
+    }
+
+    // ----- Change abort status
+    if ($p_entry['status'] == "aborted") {
+      $p_entry['status'] = "skipped";
+    }
+
+    // ----- Look for post-extract callback
+    elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+      // ----- Look for abort result
+      if ($v_result == 2) {
+        $v_result = PCLZIP_ERR_USER_ABORTED;
+      }
+    }
+
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privExtractFileAsString()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
+  {
+    $v_result=1;
+
+    // ----- Read the file header
+    $v_header = array();
+    if (($v_result = $this->privReadFileHeader($v_header)) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+
+    // ----- Check that the file header is coherent with $p_entry info
+    if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+        // TBC
+    }
+
+    // ----- Look for pre-extract callback
+    if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+      if ($v_result == 0) {
+        // ----- Change the file status
+        $p_entry['status'] = "skipped";
+        $v_result = 1;
+      }
+
+      // ----- Look for abort result
+      if ($v_result == 2) {
+        // ----- This status is internal and will be changed in 'skipped'
+        $p_entry['status'] = "aborted";
+        $v_result = PCLZIP_ERR_USER_ABORTED;
+      }
+
+      // ----- Update the informations
+      // Only some fields can be modified
+      $p_entry['filename'] = $v_local_header['filename'];
+    }
+
+
+    // ----- Look if extraction should be done
+    if ($p_entry['status'] == 'ok') {
+
+      // ----- Do the extraction (if not a folder)
+      if (!(($p_entry['external']&0x00000010)==0x00000010)) {
+        // ----- Look for not compressed file
+  //      if ($p_entry['compressed_size'] == $p_entry['size'])
+        if ($p_entry['compression'] == 0) {
+
+          // ----- Reading the file
+          $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
+        }
+        else {
+
+          // ----- Reading the file
+          $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+          // ----- Decompress the file
+          if (($p_string = @gzinflate($v_data)) === FALSE) {
+              // TBC
+          }
+        }
+
+        // ----- Trace
+      }
+      else {
+          // TBC : error : can not extract a folder in a string
+      }
+
+    }
+
+    // ----- Change abort status
+    if ($p_entry['status'] == "aborted") {
+        $p_entry['status'] = "skipped";
+    }
+
+    // ----- Look for post-extract callback
+    elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+      // ----- Generate a local information
+      $v_local_header = array();
+      $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+      // ----- Swap the content to header
+      $v_local_header['content'] = $p_string;
+      $p_string = '';
+
+      // ----- Call the callback
+      // Here I do not use call_user_func() because I need to send a reference to the
+      // header.
+//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
+      $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+      // ----- Swap back the content to header
+      $p_string = $v_local_header['content'];
+      unset($v_local_header['content']);
+
+      // ----- Look for abort result
+      if ($v_result == 2) {
+        $v_result = PCLZIP_ERR_USER_ABORTED;
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privReadFileHeader()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privReadFileHeader(&$p_header)
+  {
+    $v_result=1;
+
+    // ----- Read the 4 bytes signature
+    $v_binary_data = @fread($this->zip_fd, 4);
+    $v_data = unpack('Vid', $v_binary_data);
+
+    // ----- Check signature
+    if ($v_data['id'] != 0x04034b50)
+    {
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Read the first 42 bytes of the header
+    $v_binary_data = fread($this->zip_fd, 26);
+
+    // ----- Look for invalid block size
+    if (strlen($v_binary_data) != 26)
+    {
+      $p_header['filename'] = "";
+      $p_header['status'] = "invalid_header";
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Extract the values
+    $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
+
+    // ----- Get filename
+    $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
+
+    // ----- Get extra_fields
+    if ($v_data['extra_len'] != 0) {
+      $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
+    }
+    else {
+      $p_header['extra'] = '';
+    }
+
+    // ----- Extract properties
+    $p_header['version_extracted'] = $v_data['version'];
+    $p_header['compression'] = $v_data['compression'];
+    $p_header['size'] = $v_data['size'];
+    $p_header['compressed_size'] = $v_data['compressed_size'];
+    $p_header['crc'] = $v_data['crc'];
+    $p_header['flag'] = $v_data['flag'];
+    $p_header['filename_len'] = $v_data['filename_len'];
+
+    // ----- Recuperate date in UNIX format
+    $p_header['mdate'] = $v_data['mdate'];
+    $p_header['mtime'] = $v_data['mtime'];
+    if ($p_header['mdate'] && $p_header['mtime'])
+    {
+      // ----- Extract time
+      $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+      $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+      $v_seconde = ($p_header['mtime'] & 0x001F)*2;
+
+      // ----- Extract date
+      $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+      $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+      $v_day = $p_header['mdate'] & 0x001F;
+
+      // ----- Get UNIX date format
+      $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+    }
+    else
+    {
+      $p_header['mtime'] = time();
+    }
+
+    // TBC
+    //for(reset($v_data); $key = key($v_data); next($v_data)) {
+    //}
+
+    // ----- Set the stored filename
+    $p_header['stored_filename'] = $p_header['filename'];
+
+    // ----- Set the status field
+    $p_header['status'] = "ok";
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privReadCentralFileHeader()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privReadCentralFileHeader(&$p_header)
+  {
+    $v_result=1;
+
+    // ----- Read the 4 bytes signature
+    $v_binary_data = @fread($this->zip_fd, 4);
+    $v_data = unpack('Vid', $v_binary_data);
+
+    // ----- Check signature
+    if ($v_data['id'] != 0x02014b50)
+    {
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Read the first 42 bytes of the header
+    $v_binary_data = fread($this->zip_fd, 42);
+
+    // ----- Look for invalid block size
+    if (strlen($v_binary_data) != 42)
+    {
+      $p_header['filename'] = "";
+      $p_header['status'] = "invalid_header";
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Extract the values
+    $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
+
+    // ----- Get filename
+    if ($p_header['filename_len'] != 0)
+      $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
+    else
+      $p_header['filename'] = '';
+
+    // ----- Get extra
+    if ($p_header['extra_len'] != 0)
+      $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
+    else
+      $p_header['extra'] = '';
+
+    // ----- Get comment
+    if ($p_header['comment_len'] != 0)
+      $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
+    else
+      $p_header['comment'] = '';
+
+    // ----- Extract properties
+
+    // ----- Recuperate date in UNIX format
+    //if ($p_header['mdate'] && $p_header['mtime'])
+    // TBC : bug : this was ignoring time with 0/0/0
+    if (1)
+    {
+      // ----- Extract time
+      $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+      $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+      $v_seconde = ($p_header['mtime'] & 0x001F)*2;
+
+      // ----- Extract date
+      $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+      $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+      $v_day = $p_header['mdate'] & 0x001F;
+
+      // ----- Get UNIX date format
+      $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+    }
+    else
+    {
+      $p_header['mtime'] = time();
+    }
+
+    // ----- Set the stored filename
+    $p_header['stored_filename'] = $p_header['filename'];
+
+    // ----- Set default status to ok
+    $p_header['status'] = 'ok';
+
+    // ----- Look if it is a directory
+    if (substr($p_header['filename'], -1) == '/') {
+      //$p_header['external'] = 0x41FF0010;
+      $p_header['external'] = 0x00000010;
+    }
+
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privCheckFileHeaders()
+  // Description :
+  // Parameters :
+  // Return Values :
+  //   1 on success,
+  //   0 on error;
+  // --------------------------------------------------------------------------------
+  function privCheckFileHeaders(&$p_local_header, &$p_central_header)
+  {
+    $v_result=1;
+
+    // ----- Check the static values
+    // TBC
+    if ($p_local_header['filename'] != $p_central_header['filename']) {
+    }
+    if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
+    }
+    if ($p_local_header['flag'] != $p_central_header['flag']) {
+    }
+    if ($p_local_header['compression'] != $p_central_header['compression']) {
+    }
+    if ($p_local_header['mtime'] != $p_central_header['mtime']) {
+    }
+    if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
+    }
+
+    // ----- Look for flag bit 3
+    if (($p_local_header['flag'] & 8) == 8) {
+          $p_local_header['size'] = $p_central_header['size'];
+          $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
+          $p_local_header['crc'] = $p_central_header['crc'];
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privReadEndCentralDir()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privReadEndCentralDir(&$p_central_dir)
+  {
+    $v_result=1;
+
+    // ----- Go to the end of the zip file
+    $v_size = filesize($this->zipname);
+    @fseek($this->zip_fd, $v_size);
+    if (@ftell($this->zip_fd) != $v_size)
+    {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- First try : look if this is an archive with no commentaries (most of the time)
+    // in this case the end of central dir is at 22 bytes of the file end
+    $v_found = 0;
+    if ($v_size > 26) {
+      @fseek($this->zip_fd, $v_size-22);
+      if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22))
+      {
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+
+      // ----- Read for bytes
+      $v_binary_data = @fread($this->zip_fd, 4);
+      $v_data = @unpack('Vid', $v_binary_data);
+
+      // ----- Check signature
+      if ($v_data['id'] == 0x06054b50) {
+        $v_found = 1;
+      }
+
+      $v_pos = ftell($this->zip_fd);
+    }
+
+    // ----- Go back to the maximum possible size of the Central Dir End Record
+    if (!$v_found) {
+      $v_maximum_size = 65557; // 0xFFFF + 22;
+      if ($v_maximum_size > $v_size)
+        $v_maximum_size = $v_size;
+      @fseek($this->zip_fd, $v_size-$v_maximum_size);
+      if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size))
+      {
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+
+      // ----- Read byte per byte in order to find the signature
+      $v_pos = ftell($this->zip_fd);
+      $v_bytes = 0x00000000;
+      while ($v_pos < $v_size)
+      {
+        // ----- Read a byte
+        $v_byte = @fread($this->zip_fd, 1);
+
+        // -----  Add the byte
+        //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
+        // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
+        // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
+        $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
+
+        // ----- Compare the bytes
+        if ($v_bytes == 0x504b0506)
+        {
+          $v_pos++;
+          break;
+        }
+
+        $v_pos++;
+      }
+
+      // ----- Look if not found end of central dir
+      if ($v_pos == $v_size)
+      {
+
+        // ----- Error log
+        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
+
+        // ----- Return
+        return PclZip::errorCode();
+      }
+    }
+
+    // ----- Read the first 18 bytes of the header
+    $v_binary_data = fread($this->zip_fd, 18);
+
+    // ----- Look for invalid block size
+    if (strlen($v_binary_data) != 18)
+    {
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Extract the values
+    $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
+
+    // ----- Check the global size
+    if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
+
+      // ----- Removed in release 2.2 see readme file
+      // The check of the file size is a little too strict.
+      // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
+      // While decrypted, zip has training 0 bytes
+      if (0) {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
+                           'The central dir is not at the end of the archive.'
+                           .' Some trailing bytes exists after the archive.');
+
+      // ----- Return
+      return PclZip::errorCode();
+      }
+    }
+
+    // ----- Get comment
+    if ($v_data['comment_size'] != 0) {
+      $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
+    }
+    else
+      $p_central_dir['comment'] = '';
+
+    $p_central_dir['entries'] = $v_data['entries'];
+    $p_central_dir['disk_entries'] = $v_data['disk_entries'];
+    $p_central_dir['offset'] = $v_data['offset'];
+    $p_central_dir['size'] = $v_data['size'];
+    $p_central_dir['disk'] = $v_data['disk'];
+    $p_central_dir['disk_start'] = $v_data['disk_start'];
+
+    // TBC
+    //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
+    //}
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privDeleteByRule()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privDeleteByRule(&$p_result_list, &$p_options)
+  {
+    $v_result=1;
+    $v_list_detail = array();
+
+    // ----- Open the zip file
+    if (($v_result=$this->privOpenFd('rb')) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Read the central directory informations
+    $v_central_dir = array();
+    if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+    {
+      $this->privCloseFd();
+      return $v_result;
+    }
+
+    // ----- Go to beginning of File
+    @rewind($this->zip_fd);
+
+    // ----- Scan all the files
+    // ----- Start at beginning of Central Dir
+    $v_pos_entry = $v_central_dir['offset'];
+    @rewind($this->zip_fd);
+    if (@fseek($this->zip_fd, $v_pos_entry))
+    {
+      // ----- Close the zip file
+      $this->privCloseFd();
+
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Read each entry
+    $v_header_list = array();
+    $j_start = 0;
+    for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
+    {
+
+      // ----- Read the file header
+      $v_header_list[$v_nb_extracted] = array();
+      if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1)
+      {
+        // ----- Close the zip file
+        $this->privCloseFd();
+
+        return $v_result;
+      }
+
+
+      // ----- Store the index
+      $v_header_list[$v_nb_extracted]['index'] = $i;
+
+      // ----- Look for the specific extract rules
+      $v_found = false;
+
+      // ----- Look for extract by name rule
+      if (   (isset($p_options[PCLZIP_OPT_BY_NAME]))
+          && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+          // ----- Look if the filename is in the list
+          for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
+
+              // ----- Look for a directory
+              if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
+
+                  // ----- Look if the directory is in the filename path
+                  if (   (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
+                      && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+                      $v_found = true;
+                  }
+                  elseif (   (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */
+                          && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+                      $v_found = true;
+                  }
+              }
+              // ----- Look for a filename
+              elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+                  $v_found = true;
+              }
+          }
+      }
+
+      // ----- Look for extract by ereg rule
+      // ereg() is deprecated with PHP 5.3
+      /*
+      else if (   (isset($p_options[PCLZIP_OPT_BY_EREG]))
+               && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+          if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+              $v_found = true;
+          }
+      }
+      */
+
+      // ----- Look for extract by preg rule
+      else if (   (isset($p_options[PCLZIP_OPT_BY_PREG]))
+               && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+          if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+              $v_found = true;
+          }
+      }
+
+      // ----- Look for extract by index rule
+      else if (   (isset($p_options[PCLZIP_OPT_BY_INDEX]))
+               && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+          // ----- Look if the index is in the list
+          for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
+
+              if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+                  $v_found = true;
+              }
+              if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+                  $j_start = $j+1;
+              }
+
+              if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
+                  break;
+              }
+          }
+      }
+      else {
+        $v_found = true;
+      }
+
+      // ----- Look for deletion
+      if ($v_found)
+      {
+        unset($v_header_list[$v_nb_extracted]);
+      }
+      else
+      {
+        $v_nb_extracted++;
+      }
+    }
+
+    // ----- Look if something need to be deleted
+    if ($v_nb_extracted > 0) {
+
+        // ----- Creates a temporay file
+        $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+        // ----- Creates a temporary zip archive
+        $v_temp_zip = new PclZip($v_zip_temp_name);
+
+        // ----- Open the temporary zip file in write mode
+        if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
+            $this->privCloseFd();
+
+            // ----- Return
+            return $v_result;
+        }
+
+        // ----- Look which file need to be kept
+        for ($i=0; $i<sizeof($v_header_list); $i++) {
+
+            // ----- Calculate the position of the header
+            @rewind($this->zip_fd);
+            if (@fseek($this->zip_fd,  $v_header_list[$i]['offset'])) {
+                // ----- Close the zip file
+                $this->privCloseFd();
+                $v_temp_zip->privCloseFd();
+                @unlink($v_zip_temp_name);
+
+                // ----- Error log
+                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+                // ----- Return
+                return PclZip::errorCode();
+            }
+
+            // ----- Read the file header
+            $v_local_header = array();
+            if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
+                // ----- Close the zip file
+                $this->privCloseFd();
+                $v_temp_zip->privCloseFd();
+                @unlink($v_zip_temp_name);
+
+                // ----- Return
+                return $v_result;
+            }
+
+            // ----- Check that local file header is same as central file header
+            if ($this->privCheckFileHeaders($v_local_header,
+                                            $v_header_list[$i]) != 1) {
+                // TBC
+            }
+            unset($v_local_header);
+
+            // ----- Write the file header
+            if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
+                // ----- Close the zip file
+                $this->privCloseFd();
+                $v_temp_zip->privCloseFd();
+                @unlink($v_zip_temp_name);
+
+                // ----- Return
+                return $v_result;
+            }
+
+            // ----- Read/write the data block
+            if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
+                // ----- Close the zip file
+                $this->privCloseFd();
+                $v_temp_zip->privCloseFd();
+                @unlink($v_zip_temp_name);
+
+                // ----- Return
+                return $v_result;
+            }
+        }
+
+        // ----- Store the offset of the central dir
+        $v_offset = @ftell($v_temp_zip->zip_fd);
+
+        // ----- Re-Create the Central Dir files header
+        for ($i=0; $i<sizeof($v_header_list); $i++) {
+            // ----- Create the file header
+            if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+                $v_temp_zip->privCloseFd();
+                $this->privCloseFd();
+                @unlink($v_zip_temp_name);
+
+                // ----- Return
+                return $v_result;
+            }
+
+            // ----- Transform the header to a 'usable' info
+            $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+        }
+
+
+        // ----- Zip file comment
+        $v_comment = '';
+        if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+          $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+        }
+
+        // ----- Calculate the size of the central header
+        $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
+
+        // ----- Create the central dir footer
+        if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
+            // ----- Reset the file list
+            unset($v_header_list);
+            $v_temp_zip->privCloseFd();
+            $this->privCloseFd();
+            @unlink($v_zip_temp_name);
+
+            // ----- Return
+            return $v_result;
+        }
+
+        // ----- Close
+        $v_temp_zip->privCloseFd();
+        $this->privCloseFd();
+
+        // ----- Delete the zip file
+        // TBC : I should test the result ...
+        @unlink($this->zipname);
+
+        // ----- Rename the temporary file
+        // TBC : I should test the result ...
+        //@rename($v_zip_temp_name, $this->zipname);
+        PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+        // ----- Destroy the temporary archive
+        unset($v_temp_zip);
+    }
+
+    // ----- Remove every files : reset the file
+    else if ($v_central_dir['entries'] != 0) {
+        $this->privCloseFd();
+
+        if (($v_result = $this->privOpenFd('wb')) != 1) {
+          return $v_result;
+        }
+
+        if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
+          return $v_result;
+        }
+
+        $this->privCloseFd();
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privDirCheck()
+  // Description :
+  //   Check if a directory exists, if not it creates it and all the parents directory
+  //   which may be useful.
+  // Parameters :
+  //   $p_dir : Directory path to check.
+  // Return Values :
+  //    1 : OK
+  //   -1 : Unable to create directory
+  // --------------------------------------------------------------------------------
+  function privDirCheck($p_dir, $p_is_dir=false)
+  {
+    $v_result = 1;
+
+
+    // ----- Remove the final '/'
+    if (($p_is_dir) && (substr($p_dir, -1)=='/'))
+    {
+      $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
+    }
+
+    // ----- Check the directory availability
+    if ((is_dir($p_dir)) || ($p_dir == ""))
+    {
+      return 1;
+    }
+
+    // ----- Extract parent directory
+    $p_parent_dir = dirname($p_dir);
+
+    // ----- Just a check
+    if ($p_parent_dir != $p_dir)
+    {
+      // ----- Look for parent directory
+      if ($p_parent_dir != "")
+      {
+        if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
+        {
+          return $v_result;
+        }
+      }
+    }
+
+    // ----- Create the directory
+    if (!@mkdir($p_dir, 0777))
+    {
+      // ----- Error log
+      PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privMerge()
+  // Description :
+  //   If $p_archive_to_add does not exist, the function exit with a success result.
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privMerge(&$p_archive_to_add)
+  {
+    $v_result=1;
+
+    // ----- Look if the archive_to_add exists
+    if (!is_file($p_archive_to_add->zipname))
+    {
+
+      // ----- Nothing to merge, so merge is a success
+      $v_result = 1;
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Look if the archive exists
+    if (!is_file($this->zipname))
+    {
+
+      // ----- Do a duplicate
+      $v_result = $this->privDuplicate($p_archive_to_add->zipname);
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Open the zip file
+    if (($v_result=$this->privOpenFd('rb')) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Read the central directory informations
+    $v_central_dir = array();
+    if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+    {
+      $this->privCloseFd();
+      return $v_result;
+    }
+
+    // ----- Go to beginning of File
+    @rewind($this->zip_fd);
+
+    // ----- Open the archive_to_add file
+    if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
+    {
+      $this->privCloseFd();
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Read the central directory informations
+    $v_central_dir_to_add = array();
+    if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
+    {
+      $this->privCloseFd();
+      $p_archive_to_add->privCloseFd();
+
+      return $v_result;
+    }
+
+    // ----- Go to beginning of File
+    @rewind($p_archive_to_add->zip_fd);
+
+    // ----- Creates a temporay file
+    $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+    // ----- Open the temporary file in write mode
+    if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
+    {
+      $this->privCloseFd();
+      $p_archive_to_add->privCloseFd();
+
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Copy the files from the archive to the temporary file
+    // TBC : Here I should better append the file and go back to erase the central dir
+    $v_size = $v_central_dir['offset'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = fread($this->zip_fd, $v_read_size);
+      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Copy the files from the archive_to_add into the temporary file
+    $v_size = $v_central_dir_to_add['offset'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
+      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Store the offset of the central dir
+    $v_offset = @ftell($v_zip_temp_fd);
+
+    // ----- Copy the block of file headers from the old archive
+    $v_size = $v_central_dir['size'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @fread($this->zip_fd, $v_read_size);
+      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Copy the block of file headers from the archive_to_add
+    $v_size = $v_central_dir_to_add['size'];
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
+      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Merge the file comments
+    $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
+
+    // ----- Calculate the size of the (new) central header
+    $v_size = @ftell($v_zip_temp_fd)-$v_offset;
+
+    // ----- Swap the file descriptor
+    // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+    // the following methods on the temporary fil and not the real archive fd
+    $v_swap = $this->zip_fd;
+    $this->zip_fd = $v_zip_temp_fd;
+    $v_zip_temp_fd = $v_swap;
+
+    // ----- Create the central dir footer
+    if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
+    {
+      $this->privCloseFd();
+      $p_archive_to_add->privCloseFd();
+      @fclose($v_zip_temp_fd);
+      $this->zip_fd = null;
+
+      // ----- Reset the file list
+      unset($v_header_list);
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Swap back the file descriptor
+    $v_swap = $this->zip_fd;
+    $this->zip_fd = $v_zip_temp_fd;
+    $v_zip_temp_fd = $v_swap;
+
+    // ----- Close
+    $this->privCloseFd();
+    $p_archive_to_add->privCloseFd();
+
+    // ----- Close the temporary file
+    @fclose($v_zip_temp_fd);
+
+    // ----- Delete the zip file
+    // TBC : I should test the result ...
+    @unlink($this->zipname);
+
+    // ----- Rename the temporary file
+    // TBC : I should test the result ...
+    //@rename($v_zip_temp_name, $this->zipname);
+    PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privDuplicate()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privDuplicate($p_archive_filename)
+  {
+    $v_result=1;
+
+    // ----- Look if the $p_archive_filename exists
+    if (!is_file($p_archive_filename))
+    {
+
+      // ----- Nothing to duplicate, so duplicate is a success.
+      $v_result = 1;
+
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Open the zip file
+    if (($v_result=$this->privOpenFd('wb')) != 1)
+    {
+      // ----- Return
+      return $v_result;
+    }
+
+    // ----- Open the temporary file in write mode
+    if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
+    {
+      $this->privCloseFd();
+
+      PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
+
+      // ----- Return
+      return PclZip::errorCode();
+    }
+
+    // ----- Copy the files from the archive to the temporary file
+    // TBC : Here I should better append the file and go back to erase the central dir
+    $v_size = filesize($p_archive_filename);
+    while ($v_size != 0)
+    {
+      $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+      $v_buffer = fread($v_zip_temp_fd, $v_read_size);
+      @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+      $v_size -= $v_read_size;
+    }
+
+    // ----- Close
+    $this->privCloseFd();
+
+    // ----- Close the temporary file
+    @fclose($v_zip_temp_fd);
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privErrorLog()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function privErrorLog($p_error_code=0, $p_error_string='')
+  {
+    if (PCLZIP_ERROR_EXTERNAL == 1) {
+      PclError($p_error_code, $p_error_string);
+    }
+    else {
+      $this->error_code = $p_error_code;
+      $this->error_string = $p_error_string;
+    }
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privErrorReset()
+  // Description :
+  // Parameters :
+  // --------------------------------------------------------------------------------
+  function privErrorReset()
+  {
+    if (PCLZIP_ERROR_EXTERNAL == 1) {
+      PclErrorReset();
+    }
+    else {
+      $this->error_code = 0;
+      $this->error_string = '';
+    }
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privDisableMagicQuotes()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privDisableMagicQuotes()
+  {
+    $v_result=1;
+
+    // ----- Look if function exists
+    if (   (!function_exists("get_magic_quotes_runtime"))
+        || (!function_exists("set_magic_quotes_runtime"))) {
+      return $v_result;
+    }
+
+    // ----- Look if already done
+    if ($this->magic_quotes_status != -1) {
+      return $v_result;
+    }
+
+    // ----- Get and memorize the magic_quote value
+    $this->magic_quotes_status = @get_magic_quotes_runtime();
+
+    // ----- Disable magic_quotes
+    if ($this->magic_quotes_status == 1) {
+      @set_magic_quotes_runtime(0);
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : privSwapBackMagicQuotes()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function privSwapBackMagicQuotes()
+  {
+    $v_result=1;
+
+    // ----- Look if function exists
+    if (   (!function_exists("get_magic_quotes_runtime"))
+        || (!function_exists("set_magic_quotes_runtime"))) {
+      return $v_result;
+    }
+
+    // ----- Look if something to do
+    if ($this->magic_quotes_status != -1) {
+      return $v_result;
+    }
+
+    // ----- Swap back magic_quotes
+    if ($this->magic_quotes_status == 1) {
+      @set_magic_quotes_runtime($this->magic_quotes_status);
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  }
+  // End of class
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZipUtilPathReduction()
+  // Description :
+  // Parameters :
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function PclZipUtilPathReduction($p_dir)
+  {
+    $v_result = "";
+
+    // ----- Look for not empty path
+    if ($p_dir != "") {
+      // ----- Explode path by directory names
+      $v_list = explode("/", $p_dir);
+
+      // ----- Study directories from last to first
+      $v_skip = 0;
+      for ($i=sizeof($v_list)-1; $i>=0; $i--) {
+        // ----- Look for current path
+        if ($v_list[$i] == ".") {
+          // ----- Ignore this directory
+          // Should be the first $i=0, but no check is done
+        }
+        else if ($v_list[$i] == "..") {
+          $v_skip++;
+        }
+        else if ($v_list[$i] == "") {
+          // ----- First '/' i.e. root slash
+          if ($i == 0) {
+            $v_result = "/".$v_result;
+            if ($v_skip > 0) {
+                // ----- It is an invalid path, so the path is not modified
+                // TBC
+                $v_result = $p_dir;
+                $v_skip = 0;
+            }
+          }
+          // ----- Last '/' i.e. indicates a directory
+          else if ($i == (sizeof($v_list)-1)) {
+            $v_result = $v_list[$i];
+          }
+          // ----- Double '/' inside the path
+          else {
+            // ----- Ignore only the double '//' in path,
+            // but not the first and last '/'
+          }
+        }
+        else {
+          // ----- Look for item to skip
+          if ($v_skip > 0) {
+            $v_skip--;
+          }
+          else {
+            $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
+          }
+        }
+      }
+
+      // ----- Look for skip
+      if ($v_skip > 0) {
+        while ($v_skip > 0) {
+            $v_result = '../'.$v_result;
+            $v_skip--;
+        }
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZipUtilPathInclusion()
+  // Description :
+  //   This function indicates if the path $p_path is under the $p_dir tree. Or,
+  //   said in an other way, if the file or sub-dir $p_path is inside the dir
+  //   $p_dir.
+  //   The function indicates also if the path is exactly the same as the dir.
+  //   This function supports path with duplicated '/' like '//', but does not
+  //   support '.' or '..' statements.
+  // Parameters :
+  // Return Values :
+  //   0 if $p_path is not inside directory $p_dir
+  //   1 if $p_path is inside directory $p_dir
+  //   2 if $p_path is exactly the same as $p_dir
+  // --------------------------------------------------------------------------------
+  function PclZipUtilPathInclusion($p_dir, $p_path)
+  {
+    $v_result = 1;
+
+    // ----- Look for path beginning by ./
+    if (   ($p_dir == '.')
+        || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
+      $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
+    }
+    if (   ($p_path == '.')
+        || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
+      $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
+    }
+
+    // ----- Explode dir and path by directory separator
+    $v_list_dir = explode("/", $p_dir);
+    $v_list_dir_size = sizeof($v_list_dir);
+    $v_list_path = explode("/", $p_path);
+    $v_list_path_size = sizeof($v_list_path);
+
+    // ----- Study directories paths
+    $i = 0;
+    $j = 0;
+    while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
+
+      // ----- Look for empty dir (path reduction)
+      if ($v_list_dir[$i] == '') {
+        $i++;
+        continue;
+      }
+      if ($v_list_path[$j] == '') {
+        $j++;
+        continue;
+      }
+
+      // ----- Compare the items
+      if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != ''))  {
+        $v_result = 0;
+      }
+
+      // ----- Next items
+      $i++;
+      $j++;
+    }
+
+    // ----- Look if everything seems to be the same
+    if ($v_result) {
+      // ----- Skip all the empty items
+      while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
+      while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
+
+      if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
+        // ----- There are exactly the same
+        $v_result = 2;
+      }
+      else if ($i < $v_list_dir_size) {
+        // ----- The path is shorter than the dir
+        $v_result = 0;
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZipUtilCopyBlock()
+  // Description :
+  // Parameters :
+  //   $p_mode : read/write compression mode
+  //             0 : src & dest normal
+  //             1 : src gzip, dest normal
+  //             2 : src normal, dest gzip
+  //             3 : src & dest gzip
+  // Return Values :
+  // --------------------------------------------------------------------------------
+  function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0)
+  {
+    $v_result = 1;
+
+    if ($p_mode==0)
+    {
+      while ($p_size != 0)
+      {
+        $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+        $v_buffer = @fread($p_src, $v_read_size);
+        @fwrite($p_dest, $v_buffer, $v_read_size);
+        $p_size -= $v_read_size;
+      }
+    }
+    else if ($p_mode==1)
+    {
+      while ($p_size != 0)
+      {
+        $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+        $v_buffer = @gzread($p_src, $v_read_size);
+        @fwrite($p_dest, $v_buffer, $v_read_size);
+        $p_size -= $v_read_size;
+      }
+    }
+    else if ($p_mode==2)
+    {
+      while ($p_size != 0)
+      {
+        $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+        $v_buffer = @fread($p_src, $v_read_size);
+        @gzwrite($p_dest, $v_buffer, $v_read_size);
+        $p_size -= $v_read_size;
+      }
+    }
+    else if ($p_mode==3)
+    {
+      while ($p_size != 0)
+      {
+        $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+        $v_buffer = @gzread($p_src, $v_read_size);
+        @gzwrite($p_dest, $v_buffer, $v_read_size);
+        $p_size -= $v_read_size;
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZipUtilRename()
+  // Description :
+  //   This function tries to do a simple rename() function. If it fails, it
+  //   tries to copy the $p_src file in a new $p_dest file and then unlink the
+  //   first one.
+  // Parameters :
+  //   $p_src : Old filename
+  //   $p_dest : New filename
+  // Return Values :
+  //   1 on success, 0 on failure.
+  // --------------------------------------------------------------------------------
+  function PclZipUtilRename($p_src, $p_dest)
+  {
+    $v_result = 1;
+
+    // ----- Try to rename the files
+    if (!@rename($p_src, $p_dest)) {
+
+      // ----- Try to copy & unlink the src
+      if (!@copy($p_src, $p_dest)) {
+        $v_result = 0;
+      }
+      else if (!@unlink($p_src)) {
+        $v_result = 0;
+      }
+    }
+
+    // ----- Return
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZipUtilOptionText()
+  // Description :
+  //   Translate option value in text. Mainly for debug purpose.
+  // Parameters :
+  //   $p_option : the option value.
+  // Return Values :
+  //   The option text value.
+  // --------------------------------------------------------------------------------
+  function PclZipUtilOptionText($p_option)
+  {
+
+    $v_list = get_defined_constants();
+    for (reset($v_list); $v_key = key($v_list); next($v_list)) {
+        $v_prefix = substr($v_key, 0, 10);
+        if ((   ($v_prefix == 'PCLZIP_OPT')
+           || ($v_prefix == 'PCLZIP_CB_')
+           || ($v_prefix == 'PCLZIP_ATT'))
+            && ($v_list[$v_key] == $p_option)) {
+        return $v_key;
+        }
+    }
+
+    $v_result = 'Unknown';
+
+    return $v_result;
+  }
+  // --------------------------------------------------------------------------------
+
+  // --------------------------------------------------------------------------------
+  // Function : PclZipUtilTranslateWinPath()
+  // Description :
+  //   Translate windows path by replacing '\' by '/' and optionally removing
+  //   drive letter.
+  // Parameters :
+  //   $p_path : path to translate.
+  //   $p_remove_disk_letter : true | false
+  // Return Values :
+  //   The path translated.
+  // --------------------------------------------------------------------------------
+  function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true)
+  {
+    if (stristr(php_uname(), 'windows')) {
+      // ----- Look for potential disk letter
+      if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
+          $p_path = substr($p_path, $v_position+1);
+      }
+      // ----- Change potential windows directory separator
+      if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
+          $p_path = strtr($p_path, '\\', '/');
+      }
+    }
+    return $p_path;
+  }
+  // --------------------------------------------------------------------------------

+ 195 - 0
includes/PhpWord/Shared/String.php

@@ -0,0 +1,195 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+/**
+ * Common string functions
+ */
+class String
+{
+    /**
+     * Control characters array
+     *
+     * @var string[]
+     */
+    private static $controlCharacters = array();
+
+    /**
+     * Convert from OpenXML escaped control character to PHP control character
+     *
+     * @param string $value Value to unescape
+     * @return string
+     */
+    public static function controlCharacterOOXML2PHP($value = '')
+    {
+        if (empty(self::$controlCharacters)) {
+            self::buildControlCharacters();
+        }
+
+        return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);
+    }
+
+    /**
+     * Convert from PHP control character to OpenXML escaped control character
+     *
+     * @param string $value Value to escape
+     * @return string
+     */
+    public static function controlCharacterPHP2OOXML($value = '')
+    {
+        if (empty(self::$controlCharacters)) {
+            self::buildControlCharacters();
+        }
+
+        return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);
+    }
+
+    /**
+     * Check if a string contains UTF-8 data
+     *
+     * @param string $value
+     * @return boolean
+     */
+    public static function isUTF8($value = '')
+    {
+        return $value === '' || preg_match('/^./su', $value) === 1;
+    }
+
+    /**
+     * Return UTF8 encoded value
+     *
+     * @param string $value
+     * @return string
+     */
+    public static function toUTF8($value = '')
+    {
+        if (!is_null($value) && !self::isUTF8($value)) {
+            $value = utf8_encode($value);
+        }
+
+        return $value;
+    }
+
+    /**
+     * Returns unicode from UTF8 text
+     *
+     * The function is splitted to reduce cyclomatic complexity
+     *
+     * @param string $text UTF8 text
+     * @return string Unicode text
+     * @since 0.11.0
+     */
+    public static function toUnicode($text)
+    {
+        return self::unicodeToEntities(self::utf8ToUnicode($text));
+    }
+
+    /**
+     * Returns unicode array from UTF8 text
+     *
+     * @param string $text UTF8 text
+     * @return array
+     * @since 0.11.0
+     * @link http://www.randomchaos.com/documents/?source=php_and_unicode
+     */
+    private static function utf8ToUnicode($text)
+    {
+        $unicode = array();
+        $values = array();
+        $lookingFor = 1;
+
+        // Gets unicode for each character
+        for ($i = 0; $i < strlen($text); $i++) {
+            $thisValue = ord($text[$i]);
+            if ($thisValue < 128) {
+                $unicode[] = $thisValue;
+            } else {
+                if (count($values) == 0) {
+                    $lookingFor = $thisValue < 224 ? 2 : 3;
+                }
+                $values[] = $thisValue;
+                if (count($values) == $lookingFor) {
+                    if ($lookingFor == 3) {
+                        $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64);
+                    } else {
+                        $number = (($values[0] % 32) * 64) + ($values[1] % 64);
+                    }
+                    $unicode[] = $number;
+                    $values = array();
+                    $lookingFor = 1;
+                }
+            }
+        }
+
+        return $unicode;
+    }
+
+    /**
+     * Returns entites from unicode array
+     *
+     * @param array $unicode
+     * @return string
+     * @since 0.11.0
+     * @link http://www.randomchaos.com/documents/?source=php_and_unicode
+     */
+    private static function unicodeToEntities($unicode)
+    {
+        $entities = '';
+
+        foreach ($unicode as $value) {
+            if ($value != 65279) {
+                $entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value);
+            }
+        }
+
+        return $entities;
+    }
+
+    /**
+     * Return name without underscore for < 0.10.0 variable name compatibility
+     *
+     * @param string $value
+     * @return string
+     */
+    public static function removeUnderscorePrefix($value)
+    {
+        if (!is_null($value)) {
+            if (substr($value, 0, 1) == '_') {
+                $value = substr($value, 1);
+            }
+        }
+
+        return $value;
+    }
+
+    /**
+     * Build control characters array.
+     *
+     * @return void
+     */
+    private static function buildControlCharacters()
+    {
+        for ($i = 0; $i <= 19; ++$i) {
+            if ($i != 9 && $i != 10 && $i != 13) {
+                $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';
+                $replace = chr($i);
+                self::$controlCharacters[$find] = $replace;
+            }
+        }
+    }
+}

+ 192 - 0
includes/PhpWord/Shared/XMLReader.php

@@ -0,0 +1,192 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+use PhpOffice\PhpWord\Exception\Exception;
+
+/**
+ * XML Reader wrapper
+ *
+ * @since   0.10.0
+ */
+class XMLReader
+{
+    /**
+     * DOMDocument object
+     *
+     * @var \DOMDocument
+     */
+    private $dom = null;
+
+    /**
+     * DOMXpath object
+     *
+     * @var \DOMXpath
+     */
+    private $xpath = null;
+
+    /**
+     * Get DOMDocument from ZipArchive
+     *
+     * @param string $zipFile
+     * @param string $xmlFile
+     * @return \DOMDocument|false
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     */
+    public function getDomFromZip($zipFile, $xmlFile)
+    {
+        if (file_exists($zipFile) === false) {
+            throw new Exception('Cannot find archive file.');
+        }
+
+        $zip = new ZipArchive();
+        $zip->open($zipFile);
+        $content = $zip->getFromName($xmlFile);
+        $zip->close();
+
+        if ($content === false) {
+            return false;
+        } else {
+            return $this->getDomFromString($content);
+        }
+    }
+
+    /**
+     * Get DOMDocument from content string
+     *
+     * @param string $content
+     * @return \DOMDocument
+     */
+    public function getDomFromString($content)
+    {
+        $this->dom = new \DOMDocument();
+        $this->dom->loadXML($content);
+
+        return $this->dom;
+    }
+
+    /**
+     * Get elements
+     *
+     * @param string $path
+     * @param \DOMElement $contextNode
+     * @return \DOMNodeList
+     */
+    public function getElements($path, \DOMElement $contextNode = null)
+    {
+        if ($this->dom === null) {
+            return array();
+        }
+        if ($this->xpath === null) {
+            $this->xpath = new \DOMXpath($this->dom);
+        }
+
+        if (is_null($contextNode)) {
+            return $this->xpath->query($path);
+        } else {
+            return $this->xpath->query($path, $contextNode);
+        }
+    }
+
+    /**
+     * Get element
+     *
+     * @param string $path
+     * @param \DOMElement $contextNode
+     * @return \DOMElement|null
+     */
+    public function getElement($path, \DOMElement $contextNode = null)
+    {
+        $elements = $this->getElements($path, $contextNode);
+        if ($elements->length > 0) {
+            return $elements->item(0);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get element attribute
+     *
+     * @param string $attribute
+     * @param \DOMElement $contextNode
+     * @param string $path
+     * @return string|null
+     */
+    public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null)
+    {
+        $return = null;
+        if ($path !== null) {
+            $elements = $this->getElements($path, $contextNode);
+            if ($elements->length > 0) {
+                /** @var \DOMElement $node Type hint */
+                $node = $elements->item(0);
+                $return = $node->getAttribute($attribute);
+            }
+        } else {
+            if ($contextNode !== null) {
+                $return = $contextNode->getAttribute($attribute);
+            }
+        }
+
+        return ($return == '') ? null : $return;
+    }
+
+    /**
+     * Get element value
+     *
+     * @param string $path
+     * @param \DOMElement $contextNode
+     * @return string|null
+     */
+    public function getValue($path, \DOMElement $contextNode = null)
+    {
+        $elements = $this->getElements($path, $contextNode);
+        if ($elements->length > 0) {
+            return $elements->item(0)->nodeValue;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Count elements
+     *
+     * @param string $path
+     * @param \DOMElement $contextNode
+     * @return integer
+     */
+    public function countElements($path, \DOMElement $contextNode = null)
+    {
+        $elements = $this->getElements($path, $contextNode);
+
+        return $elements->length;
+    }
+
+    /**
+     * Element exists
+     *
+     * @param string $path
+     * @param \DOMElement $contextNode
+     * @return boolean
+     */
+    public function elementExists($path, \DOMElement $contextNode = null)
+    {
+        return $this->getElements($path, $contextNode)->length > 0;
+    }
+}

+ 202 - 0
includes/PhpWord/Shared/XMLWriter.php

@@ -0,0 +1,202 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+use PhpOffice\PhpWord\Settings;
+
+/**
+ * XMLWriter wrapper
+ *
+ * @method bool endElement()
+ * @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null)
+ * @method bool startElement(string $name)
+ * @method bool text(string $content)
+ * @method bool writeAttribute(string $name, mixed $value)
+ * @method bool writeElement(string $name, string $content = null)
+ * @method bool writeRaw(string $content)
+ */
+class XMLWriter
+{
+    /** Temporary storage location */
+    const STORAGE_MEMORY = 1;
+    const STORAGE_DISK = 2;
+
+    /**
+     * Internal XMLWriter
+     *
+     * @var \XMLWriter
+     */
+    private $xmlWriter;
+
+    /**
+     * Temporary filename
+     *
+     * @var string
+     */
+    private $tempFile = '';
+
+    /**
+     * Create new XMLWriter
+     *
+     * @param int $tempLocation Temporary storage location
+     * @param string $tempFolder Temporary storage folder
+     */
+    public function __construct($tempLocation = self::STORAGE_MEMORY, $tempFolder = './')
+    {
+        // Create internal XMLWriter
+        $this->xmlWriter = new \XMLWriter();
+
+        // Open temporary storage
+        if ($tempLocation == self::STORAGE_MEMORY) {
+            $this->xmlWriter->openMemory();
+        } else {
+            // Create temporary filename
+            $this->tempFile = tempnam($tempFolder, 'xml');
+
+            // Fallback to memory when temporary file cannot be used
+            // @codeCoverageIgnoreStart
+            // Can't find any test case. Uncomment when found.
+            if (false === $this->tempFile || false === $this->xmlWriter->openUri($this->tempFile)) {
+                $this->xmlWriter->openMemory();
+            }
+            // @codeCoverageIgnoreEnd
+        }
+
+        // Set xml Compatibility
+        $compatibility = Settings::hasCompatibility();
+        if ($compatibility) {
+            $this->xmlWriter->setIndent(false);
+            $this->xmlWriter->setIndentString('');
+        } else {
+            $this->xmlWriter->setIndent(true);
+            $this->xmlWriter->setIndentString('  ');
+        }
+    }
+
+    /**
+     * Destructor
+     */
+    public function __destruct()
+    {
+        // Destruct XMLWriter
+        unset($this->xmlWriter);
+
+        // Unlink temporary files
+        if ($this->tempFile != '') {
+            @unlink($this->tempFile);
+        }
+    }
+
+    /**
+     * Catch function calls (and pass them to internal XMLWriter)
+     *
+     * @param mixed $function
+     * @param mixed $args
+     * @throws \BadMethodCallException
+     */
+    public function __call($function, $args)
+    {
+        // Catch exception
+        if (method_exists($this->xmlWriter, $function) === false) {
+            throw new \BadMethodCallException("Method '{$function}' does not exists.");
+        }
+
+        // Run method
+        try {
+            @call_user_func_array(array($this->xmlWriter, $function), $args);
+        } catch (\Exception $ex) {
+            // Do nothing!
+        }
+    }
+
+    /**
+     * Get written data
+     *
+     * @return string XML data
+     */
+    public function getData()
+    {
+        if ($this->tempFile == '') {
+            return $this->xmlWriter->outputMemory(true);
+        } else {
+            $this->xmlWriter->flush();
+            return file_get_contents($this->tempFile);
+        }
+    }
+
+    /**
+     * Write simple element and attribute(s) block
+     *
+     * There are two options:
+     * 1. If the `$attributes` is an array, then it's an associative array of attributes
+     * 2. If not, then it's a simple attribute-value pair
+     *
+     * @param string $element
+     * @param string|array $attributes
+     * @param string $value
+     * @return void
+     */
+    public function writeElementBlock($element, $attributes, $value = null)
+    {
+        $this->xmlWriter->startElement($element);
+        if (!is_array($attributes)) {
+            $attributes = array($attributes => $value);
+        }
+        foreach ($attributes as $attribute => $value) {
+            $this->xmlWriter->writeAttribute($attribute, $value);
+        }
+        $this->xmlWriter->endElement();
+    }
+
+    /**
+     * Write element if ...
+     *
+     * @param bool $condition
+     * @param string $element
+     * @param string $attribute
+     * @param mixed $value
+     * @return void
+     */
+    public function writeElementIf($condition, $element, $attribute = null, $value = null)
+    {
+        if ($condition == true) {
+            if (is_null($attribute)) {
+                $this->xmlWriter->writeElement($element, $value);
+            } else {
+                $this->xmlWriter->startElement($element);
+                $this->xmlWriter->writeAttribute($attribute, $value);
+                $this->xmlWriter->endElement();
+            }
+        }
+    }
+
+    /**
+     * Write attribute if ...
+     *
+     * @param bool $condition
+     * @param string $attribute
+     * @param mixed $value
+     * @return void
+     */
+    public function writeAttributeIf($condition, $attribute, $value)
+    {
+        if ($condition == true) {
+            $this->xmlWriter->writeAttribute($attribute, $value);
+        }
+    }
+}

+ 389 - 0
includes/PhpWord/Shared/ZipArchive.php

@@ -0,0 +1,389 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Shared;
+
+use PhpOffice\PhpWord\Exception\Exception;
+use PhpOffice\PhpWord\Settings;
+
+/**
+ * ZipArchive wrapper
+ *
+ * Wraps zip archive functionality of PHP ZipArchive and PCLZip. PHP ZipArchive
+ * properties and methods are bypassed and used as the model for the PCLZip
+ * emulation. Only needed PHP ZipArchive features are implemented.
+ *
+ * @method  bool addFile(string $filename, string $localname = null)
+ * @method  bool addFromString(string $localname, string $contents)
+ * @method  string getNameIndex(int $index)
+ * @method  int locateName(string $name)
+ *
+ * @since   0.10.0
+ */
+class ZipArchive
+{
+    /** @const int Flags for open method */
+    const CREATE    = 1; // Emulate \ZipArchive::CREATE
+    const OVERWRITE = 8; // Emulate \ZipArchive::OVERWRITE
+
+    /**
+     * Number of files (emulate ZipArchive::$numFiles)
+     *
+     * @var int
+     */
+    public $numFiles = 0;
+
+    /**
+     * Archive filename (emulate ZipArchive::$filename)
+     *
+     * @var string
+     */
+    public $filename;
+
+    /**
+     * Temporary storage directory
+     *
+     * @var string
+     */
+    private $tempDir;
+
+    /**
+     * Internal zip archive object
+     *
+     * @var \ZipArchive|\PclZip
+     */
+    private $zip;
+
+    /**
+     * Use PCLZip (default behaviour)
+     *
+     * @var bool
+     */
+    private $usePclzip = true;
+
+    /**
+     * Create new instance
+     */
+    public function __construct()
+    {
+        $this->usePclzip = (Settings::getZipClass() != 'ZipArchive');
+        if ($this->usePclzip) {
+            if (!defined('PCLZIP_TEMPORARY_DIR')) {
+                define('PCLZIP_TEMPORARY_DIR', Settings::getTempDir() . '/');
+            }
+            require_once 'PCLZip/pclzip.lib.php';
+        }
+    }
+
+    /**
+     * Catch function calls: pass to ZipArchive or PCLZip
+     *
+     * `call_user_func_array` can only used for public function, hence the `public` in all `pcl...` methods
+     *
+     * @param mixed $function
+     * @param mixed $args
+     * @return mixed
+     */
+    public function __call($function, $args)
+    {
+        // Set object and function
+        $zipFunction = $function;
+        if (!$this->usePclzip) {
+            $zipObject = $this->zip;
+        } else {
+            $zipObject = $this;
+            $zipFunction = "pclzip{$zipFunction}";
+        }
+
+        // Run function
+        $result = false;
+        if (method_exists($zipObject, $zipFunction)) {
+            $result = @call_user_func_array(array($zipObject, $zipFunction), $args);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Open a new zip archive
+     *
+     * @param string $filename The file name of the ZIP archive to open
+     * @param int $flags The mode to use to open the archive
+     * @return bool
+     */
+    public function open($filename, $flags = null)
+    {
+        $result = true;
+        $this->filename = $filename;
+
+        if (!$this->usePclzip) {
+            $zip = new \ZipArchive();
+            $result = $zip->open($this->filename, $flags);
+
+            // Scrutizer will report the property numFiles does not exist
+            // See https://github.com/scrutinizer-ci/php-analyzer/issues/190
+            $this->numFiles = $zip->numFiles;
+        } else {
+            $zip = new \PclZip($this->filename);
+            $this->tempDir = Settings::getTempDir();
+            $this->numFiles = count($zip->listContent());
+        }
+        $this->zip = $zip;
+
+        return $result;
+    }
+
+    /**
+     * Close the active archive
+     *
+     * @return bool
+     * @throws \PhpOffice\PhpWord\Exception\Exception
+     * @codeCoverageIgnore Can't find any test case. Uncomment when found.
+     */
+    public function close()
+    {
+        if (!$this->usePclzip) {
+            if ($this->zip->close() === false) {
+                throw new Exception("Could not close zip file {$this->filename}.");
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Extract the archive contents (emulate \ZipArchive)
+     *
+     * @param string $destination
+     * @param string|array $entries
+     * @return bool
+     * @since 0.10.0
+     */
+    public function extractTo($destination, $entries = null)
+    {
+        if (!is_dir($destination)) {
+            return false;
+        }
+
+        if (!$this->usePclzip) {
+            return $this->zip->extractTo($destination, $entries);
+        } else {
+            return $this->pclzipExtractTo($destination, $entries);
+        }
+    }
+
+    /**
+     * Extract file from archive by given file name (emulate \ZipArchive)
+     *
+     * @param  string $filename Filename for the file in zip archive
+     * @return string $contents File string contents
+     */
+    public function getFromName($filename)
+    {
+        if (!$this->usePclzip) {
+            $contents = $this->zip->getFromName($filename);
+            if ($contents === false) {
+                $filename = substr($filename, 1);
+                $contents = $this->zip->getFromName($filename);
+            }
+        } else {
+            $contents = $this->pclzipGetFromName($filename);
+        }
+
+        return $contents;
+    }
+
+    /**
+     * Add a new file to the zip archive (emulate \ZipArchive)
+     *
+     * @param string $filename Directory/Name of the file to add to the zip archive
+     * @param string $localname Directory/Name of the file added to the zip
+     * @return bool
+     */
+    public function pclzipAddFile($filename, $localname = null)
+    {
+        /** @var \PclZip $zip Type hint */
+        $zip = $this->zip;
+
+        // Bugfix GH-261 https://github.com/PHPOffice/PHPWord/pull/261
+        $realpathFilename = realpath($filename);
+        if ($realpathFilename !== false) {
+            $filename = $realpathFilename;
+        }
+
+        $filenameParts = pathinfo($filename);
+        $localnameParts = pathinfo($localname);
+
+        // To Rename the file while adding it to the zip we
+        //   need to create a temp file with the correct name
+        $tempFile = false;
+        if ($filenameParts['basename'] != $localnameParts['basename']) {
+            $tempFile = true; // temp file created
+            $temppath = $this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename'];
+            copy($filename, $temppath);
+            $filename = $temppath;
+            $filenameParts = pathinfo($temppath);
+        }
+
+        $pathRemoved = $filenameParts['dirname'];
+        $pathAdded = $localnameParts['dirname'];
+
+        $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded);
+
+        if ($tempFile) {
+            // Remove temp file, if created
+            unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnameParts['basename']);
+        }
+
+        return ($res == 0) ? false : true;
+    }
+
+    /**
+     * Add a new file to the zip archive from a string of raw data (emulate \ZipArchive)
+     *
+     * @param string $localname Directory/Name of the file to add to the zip archive
+     * @param string $contents String of data to add to the zip archive
+     * @return bool
+     */
+    public function pclzipAddFromString($localname, $contents)
+    {
+        /** @var \PclZip $zip Type hint */
+        $zip = $this->zip;
+        $filenameParts = pathinfo($localname);
+
+        // Write $contents to a temp file
+        $handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'], 'wb');
+        fwrite($handle, $contents);
+        fclose($handle);
+
+        // Add temp file to zip
+        $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'];
+        $pathRemoved = $this->tempDir;
+        $pathAdded = $filenameParts['dirname'];
+
+        $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded);
+
+        // Remove temp file
+        @unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']);
+
+        return ($res == 0) ? false : true;
+    }
+
+    /**
+     * Extract the archive contents (emulate \ZipArchive)
+     *
+     * @param string $destination
+     * @param string|array $entries
+     * @return bool
+     * @since 0.10.0
+     */
+    public function pclzipExtractTo($destination, $entries = null)
+    {
+        /** @var \PclZip $zip Type hint */
+        $zip = $this->zip;
+
+        // Extract all files
+        if (is_null($entries)) {
+            $result = $zip->extract(PCLZIP_OPT_PATH, $destination);
+            return ($result > 0) ? true : false;
+        }
+
+        // Extract by entries
+        if (!is_array($entries)) {
+            $entries = array($entries);
+        }
+        foreach ($entries as $entry) {
+            $entryIndex = $this->locateName($entry);
+            $result = $zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination);
+            if ($result <= 0) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Extract file from archive by given file name (emulate \ZipArchive)
+     *
+     * @param  string $filename Filename for the file in zip archive
+     * @return string $contents File string contents
+     */
+    public function pclzipGetFromName($filename)
+    {
+        /** @var \PclZip $zip Type hint */
+        $zip = $this->zip;
+        $listIndex = $this->pclzipLocateName($filename);
+        $contents = false;
+
+        if ($listIndex !== false) {
+            $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING);
+        } else {
+            $filename = substr($filename, 1);
+            $listIndex = $this->pclzipLocateName($filename);
+            $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING);
+        }
+        if ((is_array($extracted)) && ($extracted != 0)) {
+            $contents = $extracted[0]['content'];
+        }
+
+        return $contents;
+    }
+
+    /**
+     * Returns the name of an entry using its index (emulate \ZipArchive)
+     *
+     * @param int $index
+     * @return string
+     * @since 0.10.0
+     */
+    public function pclzipGetNameIndex($index)
+    {
+        /** @var \PclZip $zip Type hint */
+        $zip = $this->zip;
+        $list = $zip->listContent();
+        if (isset($list[$index])) {
+            return $list[$index]['filename'];
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the index of the entry in the archive (emulate \ZipArchive)
+     *
+     * @param string $filename Filename for the file in zip archive
+     * @return int
+     */
+    public function pclzipLocateName($filename)
+    {
+        /** @var \PclZip $zip Type hint */
+        $zip = $this->zip;
+        $list = $zip->listContent();
+        $listCount = count($list);
+        $listIndex = -1;
+        for ($i = 0; $i < $listCount; ++$i) {
+            if (strtolower($list[$i]['filename']) == strtolower($filename) ||
+                strtolower($list[$i]['stored_filename']) == strtolower($filename)) {
+                $listIndex = $i;
+                break;
+            }
+        }
+
+        return ($listIndex > -1) ? $listIndex : false;
+    }
+}

+ 202 - 0
includes/PhpWord/Style.php

@@ -0,0 +1,202 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord;
+
+use PhpOffice\PhpWord\Style\AbstractStyle;
+use PhpOffice\PhpWord\Style\Font;
+use PhpOffice\PhpWord\Style\Numbering;
+use PhpOffice\PhpWord\Style\Paragraph;
+use PhpOffice\PhpWord\Style\Table;
+
+/**
+ * Style collection
+ */
+class Style
+{
+    /**
+     * Style register
+     *
+     * @var array
+     */
+    private static $styles = array();
+
+    /**
+     * Add paragraph style
+     *
+     * @param string $styleName
+     * @param array $styles
+     * @return \PhpOffice\PhpWord\Style\Paragraph
+     */
+    public static function addParagraphStyle($styleName, $styles)
+    {
+        return self::setStyleValues($styleName, new Paragraph(), $styles);
+    }
+
+    /**
+     * Add font style
+     *
+     * @param string $styleName
+     * @param array $fontStyle
+     * @param array $paragraphStyle
+     * @return \PhpOffice\PhpWord\Style\Font
+     */
+    public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null)
+    {
+        return self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle);
+    }
+
+    /**
+     * Add link style
+     *
+     * @param string $styleName
+     * @param array $styles
+     * @return \PhpOffice\PhpWord\Style\Font
+     */
+    public static function addLinkStyle($styleName, $styles)
+    {
+        return self::setStyleValues($styleName, new Font('link'), $styles);
+    }
+
+    /**
+     * Add numbering style
+     *
+     * @param string $styleName
+     * @param array $styleValues
+     * @return \PhpOffice\PhpWord\Style\Numbering
+     * @since 0.10.0
+     */
+    public static function addNumberingStyle($styleName, $styleValues)
+    {
+        return self::setStyleValues($styleName, new Numbering(), $styleValues);
+    }
+
+    /**
+     * Add title style
+     *
+     * @param int $depth
+     * @param array $fontStyle
+     * @param array $paragraphStyle
+     * @return \PhpOffice\PhpWord\Style\Font
+     */
+    public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null)
+    {
+        return self::setStyleValues("Heading_{$depth}", new Font('title', $paragraphStyle), $fontStyle);
+    }
+
+    /**
+     * Add table style
+     *
+     * @param string $styleName
+     * @param array $styleTable
+     * @param array|null $styleFirstRow
+     * @return \PhpOffice\PhpWord\Style\Table
+     */
+    public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null)
+    {
+        return self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null);
+    }
+
+    /**
+     * Count styles
+     *
+     * @return int
+     * @since 0.10.0
+     */
+    public static function countStyles()
+    {
+        return count(self::$styles);
+    }
+
+    /**
+     * Reset styles.
+     *
+     * @since 0.10.0
+     *
+     * @return void
+     */
+    public static function resetStyles()
+    {
+        self::$styles = array();
+    }
+
+    /**
+     * Set default paragraph style
+     *
+     * @param array $styles Paragraph style definition
+     * @return \PhpOffice\PhpWord\Style\Paragraph
+     */
+    public static function setDefaultParagraphStyle($styles)
+    {
+        return self::addParagraphStyle('Normal', $styles);
+    }
+
+    /**
+     * Get all styles
+     *
+     * @return \PhpOffice\PhpWord\Style\AbstractStyle[]
+     */
+    public static function getStyles()
+    {
+        return self::$styles;
+    }
+
+    /**
+     * Get style by name
+     *
+     * @param string $styleName
+     * @return \PhpOffice\PhpWord\Style\AbstractStyle Paragraph|Font|Table|Numbering
+     */
+    public static function getStyle($styleName)
+    {
+        if (isset(self::$styles[$styleName])) {
+            return self::$styles[$styleName];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set style values and put it to static style collection
+     *
+     * The $styleValues could be an array or object
+     *
+     * @param string $name
+     * @param \PhpOffice\PhpWord\Style\AbstractStyle $style
+     * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $value
+     * @return \PhpOffice\PhpWord\Style\AbstractStyle
+     */
+    private static function setStyleValues($name, $style, $value = null)
+    {
+        if (!isset(self::$styles[$name])) {
+            if ($value !== null) {
+                if (is_array($value)) {
+                    $style->setStyleByArray($value);
+                } elseif ($value instanceof AbstractStyle) {
+                    if (get_class($style) == get_class($value)) {
+                        $style = $value;
+                    }
+                }
+            }
+            $style->setStyleName($name);
+            $style->setIndex(self::countStyles() + 1); // One based index
+            self::$styles[$name] = $style;
+        }
+
+        return self::getStyle($name);
+    }
+}

+ 349 - 0
includes/PhpWord/Style/AbstractStyle.php

@@ -0,0 +1,349 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+use PhpOffice\PhpWord\Shared\String;
+
+/**
+ * Abstract style class
+ *
+ * @since 0.10.0
+ */
+abstract class AbstractStyle
+{
+    /**
+     * Style name
+     *
+     * @var string
+     */
+    protected $styleName;
+
+    /**
+     * Index number in Style collection for named style
+     *
+     * This number starts from one and defined in Style::setStyleValues()
+     *
+     * @var int|null
+     */
+    protected $index;
+
+    /**
+     * Aliases
+     *
+     * @var array
+     */
+    protected $aliases = array();
+
+    /**
+     * Is this an automatic style? (Used primarily in OpenDocument driver)
+     *
+     * @var bool
+     * @since 0.11.0
+     */
+    private $isAuto = false;
+
+    /**
+     * Get style name
+     *
+     * @return string
+     */
+    public function getStyleName()
+    {
+        return $this->styleName;
+    }
+
+    /**
+     * Set style name
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setStyleName($value)
+    {
+        $this->styleName = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get index number
+     *
+     * @return int|null
+     */
+    public function getIndex()
+    {
+        return $this->index;
+    }
+
+    /**
+     * Set index number
+     *
+     * @param int|null $value
+     * @return self
+     */
+    public function setIndex($value = null)
+    {
+        $this->index = $this->setIntVal($value, $this->index);
+
+        return $this;
+    }
+
+    /**
+     * Get is automatic style flag
+     *
+     * @return bool
+     */
+    public function isAuto()
+    {
+        return $this->isAuto;
+    }
+
+    /**
+     * Set is automatic style flag
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setAuto($value = true)
+    {
+        $this->isAuto = $this->setBoolVal($value, $this->isAuto);
+
+        return $this;
+    }
+
+    /**
+     * Return style value of child style object, e.g. `left` from `Indentation` child style of `Paragraph`
+     *
+     * @param \PhpOffice\PhpWord\Style\AbstractStyle $substyleObject
+     * @param string $substyleProperty
+     * @return mixed
+     * @since 0.12.0
+     */
+    public function getChildStyleValue($substyleObject, $substyleProperty)
+    {
+        if ($substyleObject !== null) {
+            $method = "get{$substyleProperty}";
+            return $substyleObject->$method();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set style value template method
+     *
+     * Some child classes have their own specific overrides.
+     * Backward compability check for versions < 0.10.0 which use underscore
+     * prefix for their private properties.
+     * Check if the set method is exists. Throws an exception?
+     *
+     * @param string $key
+     * @param string $value
+     * @return self
+     */
+    public function setStyleValue($key, $value)
+    {
+        if (isset($this->aliases[$key])) {
+            $key = $this->aliases[$key];
+        }
+        $method = 'set' . String::removeUnderscorePrefix($key);
+        if (method_exists($this, $method)) {
+            $this->$method($value);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set style by using associative array
+     *
+     * @param array $values
+     * @return self
+     */
+    public function setStyleByArray($values = array())
+    {
+        foreach ($values as $key => $value) {
+            $this->setStyleValue($key, $value);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set default for null and empty value
+     *
+     * @param string $value (was: mixed)
+     * @param string $default (was: mixed)
+     * @return string (was: mixed)
+     */
+    protected function setNonEmptyVal($value, $default)
+    {
+        if ($value === null || $value == '') {
+            $value = $default;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Set bool value
+     *
+     * @param bool $value
+     * @param bool $default
+     * @return bool
+     */
+    protected function setBoolVal($value, $default)
+    {
+        if (!is_bool($value)) {
+            $value = $default;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Set numeric value
+     *
+     * @param mixed $value
+     * @param int|float|null $default
+     * @return int|float|null
+     */
+    protected function setNumericVal($value, $default = null)
+    {
+        if (!is_numeric($value)) {
+            $value = $default;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Set integer value: Convert string that contains only numeric into integer
+     *
+     * @param int|null $value
+     * @param int|null $default
+     * @return int|null
+     */
+    protected function setIntVal($value, $default = null)
+    {
+        if (is_string($value) && (preg_match('/[^\d]/', $value) == 0)) {
+            $value = intval($value);
+        }
+        if (!is_numeric($value)) {
+            $value = $default;
+        } else {
+            $value = intval($value);
+        }
+
+        return $value;
+    }
+
+    /**
+     * Set float value: Convert string that contains only numeric into float
+     *
+     * @param mixed $value
+     * @param float|null $default
+     * @return float|null
+     */
+    protected function setFloatVal($value, $default = null)
+    {
+        if (is_string($value) && (preg_match('/[^\d\.\,]/', $value) == 0)) {
+            $value = floatval($value);
+        }
+        if (!is_numeric($value)) {
+            $value = $default;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Set enum value
+     *
+     * @param mixed $value
+     * @param array $enum
+     * @param mixed $default
+     * @return mixed
+     * @throws \InvalidArgumentException
+     */
+    protected function setEnumVal($value = null, $enum = array(), $default = null)
+    {
+        if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {
+            throw new \InvalidArgumentException("Invalid style value: {$value} Options:".join(',', $enum));
+        } elseif ($value === null || trim($value) == '') {
+            $value = $default;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Set object value
+     *
+     * @param mixed $value
+     * @param string $styleName
+     * @param mixed &$style
+     * @return mixed
+     */
+    protected function setObjectVal($value, $styleName, &$style)
+    {
+        $styleClass = substr(get_class($this), 0, strrpos(get_class($this), '\\')) . '\\' . $styleName;
+        if (is_array($value)) {
+            /** @var \PhpOffice\PhpWord\Style\AbstractStyle $style Type hint */
+            if (!$style instanceof $styleClass) {
+                $style = new $styleClass();
+            }
+            $style->setStyleByArray($value);
+        } else {
+            $style = $value;
+        }
+
+        return $style;
+    }
+
+    /**
+     * Set $property value and set $pairProperty = false when $value = true
+     *
+     * @param bool &$property
+     * @param bool &$pairProperty
+     * @param bool $value
+     * @return self
+     */
+    protected function setPairedVal(&$property, &$pairProperty, $value)
+    {
+        $property = $this->setBoolVal($value, $property);
+        if ($value == true) {
+            $pairProperty = false;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Set style using associative array
+     *
+     * @param array $style
+     * @return self
+     * @deprecated 0.11.0
+     * @codeCoverageIgnore
+     */
+    public function setArrayStyle(array $style = array())
+    {
+        return $this->setStyleByArray($style);
+    }
+}

+ 78 - 0
includes/PhpWord/Style/Alignment.php

@@ -0,0 +1,78 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Alignment style
+ *
+ * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Jc.html
+ * @since 0.11.0
+ */
+class Alignment extends AbstractStyle
+{
+    /**
+     * @const string Alignment http://www.schemacentral.com/sc/ooxml/t-w_ST_Jc.html
+     */
+    const ALIGN_LEFT = 'left'; // Align left
+    const ALIGN_RIGHT = 'right'; // Align right
+    const ALIGN_CENTER = 'center'; // Align center
+    const ALIGN_BOTH = 'both'; // Align both
+    const ALIGN_JUSTIFY = 'justify'; // Alias for align both
+
+    /**
+     * @var string Alignment
+     */
+    private $value = null;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get alignment
+     *
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Set alignment
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setValue($value = null)
+    {
+        if (strtolower($value) == self::ALIGN_JUSTIFY) {
+            $value = self::ALIGN_BOTH;
+        }
+        $enum = array(self::ALIGN_LEFT, self::ALIGN_RIGHT, self::ALIGN_CENTER, self::ALIGN_BOTH, self::ALIGN_JUSTIFY);
+        $this->value = $this->setEnumVal($value, $enum, $this->value);
+
+        return $this;
+    }
+}

+ 338 - 0
includes/PhpWord/Style/Border.php

@@ -0,0 +1,338 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Border style
+ */
+class Border extends AbstractStyle
+{
+    /**
+     * Border Top Size
+     *
+     * @var int|float
+     */
+    protected $borderTopSize;
+
+    /**
+     * Border Top Color
+     *
+     * @var string
+     */
+    protected $borderTopColor;
+
+    /**
+     * Border Left Size
+     *
+     * @var int|float
+     */
+    protected $borderLeftSize;
+
+    /**
+     * Border Left Color
+     *
+     * @var string
+     */
+    protected $borderLeftColor;
+
+    /**
+     * Border Right Size
+     *
+     * @var int|float
+     */
+    protected $borderRightSize;
+
+    /**
+     * Border Right Color
+     *
+     * @var string
+     */
+    protected $borderRightColor;
+
+    /**
+     * Border Bottom Size
+     *
+     * @var int|float
+     */
+    protected $borderBottomSize;
+
+    /**
+     * Border Bottom Color
+     *
+     * @var string
+     */
+    protected $borderBottomColor;
+
+    /**
+     * Get border size
+     *
+     * @return integer[]
+     */
+    public function getBorderSize()
+    {
+        return array(
+            $this->getBorderTopSize(),
+            $this->getBorderLeftSize(),
+            $this->getBorderRightSize(),
+            $this->getBorderBottomSize(),
+        );
+    }
+
+    /**
+     * Set border size
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setBorderSize($value = null)
+    {
+        $this->setBorderTopSize($value);
+        $this->setBorderLeftSize($value);
+        $this->setBorderRightSize($value);
+        $this->setBorderBottomSize($value);
+
+        return $this;
+    }
+
+    /**
+     * Get border color
+     *
+     * @return string[]
+     */
+    public function getBorderColor()
+    {
+        return array(
+            $this->getBorderTopColor(),
+            $this->getBorderLeftColor(),
+            $this->getBorderRightColor(),
+            $this->getBorderBottomColor(),
+        );
+    }
+
+    /**
+     * Set border color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBorderColor($value = null)
+    {
+        $this->setBorderTopColor($value);
+        $this->setBorderLeftColor($value);
+        $this->setBorderRightColor($value);
+        $this->setBorderBottomColor($value);
+
+        return $this;
+    }
+
+    /**
+     * Get border top size
+     *
+     * @return int|float
+     */
+    public function getBorderTopSize()
+    {
+        return $this->borderTopSize;
+    }
+
+    /**
+     * Set border top size
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setBorderTopSize($value = null)
+    {
+        $this->borderTopSize = $this->setNumericVal($value, $this->borderTopSize);
+
+        return $this;
+    }
+
+    /**
+     * Get border top color
+     *
+     * @return string
+     */
+    public function getBorderTopColor()
+    {
+        return $this->borderTopColor;
+    }
+
+    /**
+     * Set border top color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBorderTopColor($value = null)
+    {
+        $this->borderTopColor = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get border left size
+     *
+     * @return int|float
+     */
+    public function getBorderLeftSize()
+    {
+        return $this->borderLeftSize;
+    }
+
+    /**
+     * Set border left size
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setBorderLeftSize($value = null)
+    {
+        $this->borderLeftSize = $this->setNumericVal($value, $this->borderLeftSize);
+
+        return $this;
+    }
+
+    /**
+     * Get border left color
+     *
+     * @return string
+     */
+    public function getBorderLeftColor()
+    {
+        return $this->borderLeftColor;
+    }
+
+    /**
+     * Set border left color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBorderLeftColor($value = null)
+    {
+        $this->borderLeftColor = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get border right size
+     *
+     * @return int|float
+     */
+    public function getBorderRightSize()
+    {
+        return $this->borderRightSize;
+    }
+
+    /**
+     * Set border right size
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setBorderRightSize($value = null)
+    {
+        $this->borderRightSize = $this->setNumericVal($value, $this->borderRightSize);
+
+        return $this;
+    }
+
+    /**
+     * Get border right color
+     *
+     * @return string
+     */
+    public function getBorderRightColor()
+    {
+        return $this->borderRightColor;
+    }
+
+    /**
+     * Set border right color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBorderRightColor($value = null)
+    {
+        $this->borderRightColor = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get border bottom size
+     *
+     * @return int|float
+     */
+    public function getBorderBottomSize()
+    {
+        return $this->borderBottomSize;
+    }
+
+    /**
+     * Set border bottom size
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setBorderBottomSize($value = null)
+    {
+        $this->borderBottomSize = $this->setNumericVal($value, $this->borderBottomSize);
+
+        return $this;
+    }
+
+    /**
+     * Get border bottom color
+     *
+     * @return string
+     */
+    public function getBorderBottomColor()
+    {
+        return $this->borderBottomColor;
+    }
+
+    /**
+     * Set border bottom color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBorderBottomColor($value = null)
+    {
+        $this->borderBottomColor = $value;
+
+        return $this;
+    }
+
+    /**
+     * Check if any of the border is not null
+     *
+     * @return bool
+     */
+    public function hasBorder()
+    {
+        $borders = $this->getBorderSize();
+
+        return $borders !== array_filter($borders, 'is_null');
+    }
+}

+ 249 - 0
includes/PhpWord/Style/Cell.php

@@ -0,0 +1,249 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Table cell style
+ */
+class Cell extends Border
+{
+    /**
+     * Vertical alignment constants
+     *
+     * @const string
+     */
+    const VALIGN_TOP = 'top';
+    const VALIGN_CENTER = 'center';
+    const VALIGN_BOTTOM = 'bottom';
+    const VALIGN_BOTH = 'both';
+
+    /**
+     * Text direction constants
+     *
+     * @const string
+     */
+    const TEXT_DIR_BTLR = 'btLr';
+    const TEXT_DIR_TBRL = 'tbRl';
+
+    /**
+     * Vertical merge (rowspan) constants
+     *
+     * @const string
+     */
+    const VMERGE_RESTART = 'restart';
+    const VMERGE_CONTINUE = 'continue';
+
+    /**
+     * Default border color
+     *
+     * @const string
+     */
+    const DEFAULT_BORDER_COLOR = '000000';
+
+    /**
+     * Vertical align (top, center, both, bottom)
+     *
+     * @var string
+     */
+    private $vAlign;
+
+    /**
+     * Text Direction
+     *
+     * @var string
+     */
+    private $textDirection;
+
+    /**
+     * colspan
+     *
+     * @var integer
+     */
+    private $gridSpan;
+
+    /**
+     * rowspan (restart, continue)
+     *
+     * - restart: Start/restart merged region
+     * - continue: Continue merged region
+     *
+     * @var string
+     */
+    private $vMerge;
+
+    /**
+     * Shading
+     *
+     * @var \PhpOffice\PhpWord\Style\Shading
+     */
+    private $shading;
+
+    /**
+     * Get vertical align.
+     *
+     * @return string
+     */
+    public function getVAlign()
+    {
+        return $this->vAlign;
+    }
+
+    /**
+     * Set vertical align
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setVAlign($value = null)
+    {
+        $enum = array(self::VALIGN_TOP, self::VALIGN_CENTER, self::VALIGN_BOTTOM, self::VALIGN_BOTH);
+        $this->vAlign = $this->setEnumVal($value, $enum, $this->vAlign);
+
+        return $this;
+    }
+
+    /**
+     * Get text direction.
+     *
+     * @return string
+     */
+    public function getTextDirection()
+    {
+        return $this->textDirection;
+    }
+
+    /**
+     * Set text direction
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setTextDirection($value = null)
+    {
+        $enum = array(self::TEXT_DIR_BTLR, self::TEXT_DIR_TBRL);
+        $this->textDirection = $this->setEnumVal($value, $enum, $this->textDirection);
+
+        return $this;
+    }
+
+    /**
+     * Get background
+     *
+     * @return string
+     */
+    public function getBgColor()
+    {
+        if ($this->shading !== null) {
+            return $this->shading->getFill();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set background
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBgColor($value = null)
+    {
+        return $this->setShading(array('fill' => $value));
+    }
+
+    /**
+     * Get grid span (colspan).
+     *
+     * @return integer
+     */
+    public function getGridSpan()
+    {
+        return $this->gridSpan;
+    }
+
+    /**
+     * Set grid span (colspan)
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setGridSpan($value = null)
+    {
+        $this->gridSpan = $this->setIntVal($value, $this->gridSpan);
+
+        return $this;
+    }
+
+    /**
+     * Get vertical merge (rowspan).
+     *
+     * @return string
+     */
+    public function getVMerge()
+    {
+        return $this->vMerge;
+    }
+
+    /**
+     * Set vertical merge (rowspan)
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setVMerge($value = null)
+    {
+        $enum = array(self::VMERGE_RESTART, self::VMERGE_CONTINUE);
+        $this->vMerge = $this->setEnumVal($value, $enum, $this->vMerge);
+
+        return $this;
+    }
+
+    /**
+     * Get shading
+     *
+     * @return \PhpOffice\PhpWord\Style\Shading
+     */
+    public function getShading()
+    {
+        return $this->shading;
+    }
+
+    /**
+     * Set shading
+     *
+     * @param mixed $value
+     * @return self
+     */
+    public function setShading($value = null)
+    {
+        $this->setObjectVal($value, 'Shading', $this->shading);
+
+        return $this;
+    }
+
+    /**
+     * Get default border color
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getDefaultBorderColor()
+    {
+        return self::DEFAULT_BORDER_COLOR;
+    }
+}

+ 127 - 0
includes/PhpWord/Style/Chart.php

@@ -0,0 +1,127 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Chart style
+ *
+ * @since 0.12.0
+ */
+class Chart extends AbstractStyle
+{
+
+    /**
+     * Width (in EMU)
+     *
+     * @var int
+     */
+    private $width = 1000000;
+
+    /**
+     * Height (in EMU)
+     *
+     * @var int
+     */
+    private $height = 1000000;
+
+    /**
+     * Is 3D; applies to pie, bar, line, area
+     *
+     * @var bool
+     */
+    private $is3d = false;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get width
+     *
+     * @return int
+     */
+    public function getWidth()
+    {
+        return $this->width;
+    }
+
+    /**
+     * Set width
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setWidth($value = null)
+    {
+        $this->width = $this->setIntVal($value, $this->width);
+
+        return $this;
+    }
+
+    /**
+     * Get height
+     *
+     * @return int
+     */
+    public function getHeight()
+    {
+        return $this->height;
+    }
+
+    /**
+     * Set height
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setHeight($value = null)
+    {
+        $this->height = $this->setIntVal($value, $this->height);
+
+        return $this;
+    }
+
+    /**
+     * Is 3D
+     *
+     * @return bool
+     */
+    public function is3d()
+    {
+        return $this->is3d;
+    }
+
+    /**
+     * Set 3D
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function set3d($value = true)
+    {
+        $this->is3d = $this->setBoolVal($value, $this->is3d);
+
+        return $this;
+    }
+}

+ 106 - 0
includes/PhpWord/Style/Extrusion.php

@@ -0,0 +1,106 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * 3D extrusion style
+ *
+ * @link http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html
+ * @since 0.12.0
+ */
+class Extrusion extends AbstractStyle
+{
+    /**
+     * Type constants
+     *
+     * @const string
+     */
+    const EXTRUSION_PARALLEL = 'parallel';
+    const EXTRUSION_PERSPECTIVE = 'perspective';
+
+    /**
+     * Type: parallel|perspective
+     *
+     * @var string
+     */
+    private $type;
+
+    /**
+     * Color
+     *
+     * @var string
+     */
+    private $color;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get type
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Set pattern
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setType($value = null)
+    {
+        $enum = array(self::EXTRUSION_PARALLEL, self::EXTRUSION_PERSPECTIVE);
+        $this->type = $this->setEnumVal($value, $enum, null);
+
+        return $this;
+    }
+
+    /**
+     * Get color
+     *
+     * @return string
+     */
+    public function getColor()
+    {
+        return $this->color;
+    }
+
+    /**
+     * Set color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setColor($value = null)
+    {
+        $this->color = $value;
+
+        return $this;
+    }
+}

+ 69 - 0
includes/PhpWord/Style/Fill.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Fill style
+ *
+ * There are still lot of interesting things for this style that can be added, including gradient. See @link.
+ *
+ * @link http://www.schemacentral.com/sc/ooxml/t-v_CT_Fill.html
+ * @since 0.12.0
+ */
+class Fill extends AbstractStyle
+{
+    /**
+     * Color
+     *
+     * @var string
+     */
+    private $color;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get color
+     *
+     * @return string
+     */
+    public function getColor()
+    {
+        return $this->color;
+    }
+
+    /**
+     * Set color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setColor($value = null)
+    {
+        $this->color = $value;
+
+        return $this;
+    }
+}

+ 851 - 0
includes/PhpWord/Style/Font.php

@@ -0,0 +1,851 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Font style
+ */
+class Font extends AbstractStyle
+{
+    /**
+     * Underline types
+     *
+     * @const string
+     */
+    const UNDERLINE_NONE = 'none';
+    const UNDERLINE_DASH = 'dash';
+    const UNDERLINE_DASHHEAVY = 'dashHeavy';
+    const UNDERLINE_DASHLONG = 'dashLong';
+    const UNDERLINE_DASHLONGHEAVY = 'dashLongHeavy';
+    const UNDERLINE_DOUBLE = 'dbl';
+    const UNDERLINE_DOTHASH = 'dotDash';
+    const UNDERLINE_DOTHASHHEAVY = 'dotDashHeavy';
+    const UNDERLINE_DOTDOTDASH = 'dotDotDash';
+    const UNDERLINE_DOTDOTDASHHEAVY = 'dotDotDashHeavy';
+    const UNDERLINE_DOTTED = 'dotted';
+    const UNDERLINE_DOTTEDHEAVY = 'dottedHeavy';
+    const UNDERLINE_HEAVY = 'heavy';
+    const UNDERLINE_SINGLE = 'single';
+    const UNDERLINE_WAVY = 'wavy';
+    const UNDERLINE_WAVYDOUBLE = 'wavyDbl';
+    const UNDERLINE_WAVYHEAVY = 'wavyHeavy';
+    const UNDERLINE_WORDS = 'words';
+
+    /**
+     * Foreground colors
+     *
+     * @const string
+     */
+    const FGCOLOR_YELLOW = 'yellow';
+    const FGCOLOR_LIGHTGREEN = 'green';
+    const FGCOLOR_CYAN = 'cyan';
+    const FGCOLOR_MAGENTA = 'magenta';
+    const FGCOLOR_BLUE = 'blue';
+    const FGCOLOR_RED = 'red';
+    const FGCOLOR_DARKBLUE = 'darkBlue';
+    const FGCOLOR_DARKCYAN = 'darkCyan';
+    const FGCOLOR_DARKGREEN = 'darkGreen';
+    const FGCOLOR_DARKMAGENTA = 'darkMagenta';
+    const FGCOLOR_DARKRED = 'darkRed';
+    const FGCOLOR_DARKYELLOW = 'darkYellow';
+    const FGCOLOR_DARKGRAY = 'darkGray';
+    const FGCOLOR_LIGHTGRAY = 'lightGray';
+    const FGCOLOR_BLACK = 'black';
+
+    /**
+     * Aliases
+     *
+     * @var array
+     */
+    protected $aliases = array('line-height' => 'lineHeight');
+
+    /**
+     * Font style type
+     *
+     * @var string
+     */
+    private $type;
+
+    /**
+     * Font name
+     *
+     * @var string
+     */
+    private $name;
+
+    /**
+     * Font Content Type
+     *
+     * @var string
+     */
+    private $hint;
+
+    /**
+     * Font size
+     *
+     * @var int|float
+     */
+    private $size;
+
+    /**
+     * Font color
+     *
+     * @var string
+     */
+    private $color;
+
+    /**
+     * Bold
+     *
+     * @var bool
+     */
+    private $bold = false;
+
+    /**
+     * Italic
+     *
+     * @var bool
+     */
+    private $italic = false;
+
+    /**
+     * Undeline
+     *
+     * @var string
+     */
+    private $underline = self::UNDERLINE_NONE;
+
+    /**
+     * Superscript
+     *
+     * @var bool
+     */
+    private $superScript = false;
+
+    /**
+     * Subscript
+     *
+     * @var bool
+     */
+    private $subScript = false;
+
+    /**
+     * Strikethrough
+     *
+     * @var bool
+     */
+    private $strikethrough = false;
+
+    /**
+     * Double strikethrough
+     *
+     * @var bool
+     */
+    private $doubleStrikethrough = false;
+
+    /**
+     * Small caps
+     *
+     * @var bool
+     * @link http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html
+     */
+    private $smallCaps = false;
+
+    /**
+     * All caps
+     *
+     * @var bool
+     * @link http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html
+     */
+    private $allCaps = false;
+
+    /**
+     * Foreground/highlight
+     *
+     * @var string
+     */
+    private $fgColor;
+
+    /**
+     * Expanded/compressed text: 0-600 (percent)
+     *
+     * @var int
+     * @since 0.12.0
+     * @link http://www.schemacentral.com/sc/ooxml/e-w_w-1.html
+     */
+    private $scale;
+
+    /**
+     * Character spacing adjustment: twip
+     *
+     * @var int|float
+     * @since 0.12.0
+     * @link http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html
+     */
+    private $spacing;
+
+    /**
+     * Font kerning: halfpoint
+     *
+     * @var int|float
+     * @since 0.12.0
+     * @link http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html
+     */
+    private $kerning;
+
+    /**
+     * Paragraph style
+     *
+     * @var \PhpOffice\PhpWord\Style\Paragraph
+     */
+    private $paragraph;
+
+    /**
+     * Shading
+     *
+     * @var \PhpOffice\PhpWord\Style\Shading
+     */
+    private $shading;
+
+    /**
+     * Right to left languages 
+     * @var boolean
+     */
+    private $rtl = false;
+
+    /**
+     * Create new font style
+     *
+     * @param string $type Type of font
+     * @param array $paragraph Paragraph styles definition
+     */
+    public function __construct($type = 'text', $paragraph = null)
+    {
+        $this->type = $type;
+        $this->setParagraph($paragraph);
+    }
+
+    /**
+     * Get style values
+     *
+     * @return array
+     * @since 0.12.0
+     */
+    public function getStyleValues()
+    {
+        $styles = array(
+            'name'          => $this->getStyleName(),
+            'basic'         => array(
+                'name'      => $this->getName(),
+                'size'      => $this->getSize(),
+                'color'     => $this->getColor(),
+                'hint'      => $this->getHint(),
+            ),
+            'style'         => array(
+                'bold'      => $this->isBold(),
+                'italic'    => $this->isItalic(),
+                'underline' => $this->getUnderline(),
+                'strike'    => $this->isStrikethrough(),
+                'dStrike'   => $this->isDoubleStrikethrough(),
+                'super'     => $this->isSuperScript(),
+                'sub'       => $this->isSubScript(),
+                'smallCaps' => $this->isSmallCaps(),
+                'allCaps'   => $this->isAllCaps(),
+                'fgColor'   => $this->getFgColor(),
+            ),
+            'spacing'       => array(
+                'scale'     => $this->getScale(),
+                'spacing'   => $this->getSpacing(),
+                'kerning'   => $this->getKerning(),
+            ),
+            'paragraph'     => $this->getParagraph(),
+            'rtl'           => $this->isRTL(),
+            'shading'       => $this->getShading(),
+        );
+
+        return $styles;
+    }
+
+    /**
+     * Get style type
+     *
+     * @return string
+     */
+    public function getStyleType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Get font name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Set font name
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setName($value = null)
+    {
+        $this->name = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get Font Content Type
+     *
+     * @return string
+     */
+    public function getHint()
+    {
+        return $this->hint;
+    }
+
+    /**
+     * Set Font Content Type
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setHint($value = null)
+    {
+        $this->hint = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get font size
+     *
+     * @return int|float
+     */
+    public function getSize()
+    {
+        return $this->size;
+    }
+
+    /**
+     * Set font size
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setSize($value = null)
+    {
+        $this->size = $this->setNumericVal($value, $this->size);
+
+        return $this;
+    }
+
+    /**
+     * Get font color
+     *
+     * @return string
+     */
+    public function getColor()
+    {
+        return $this->color;
+    }
+
+    /**
+     * Set font color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setColor($value = null)
+    {
+        $this->color = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get bold
+     *
+     * @return bool
+     */
+    public function isBold()
+    {
+        return $this->bold;
+    }
+
+    /**
+     * Set bold
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setBold($value = true)
+    {
+        $this->bold = $this->setBoolVal($value, $this->bold);
+
+        return $this;
+    }
+
+    /**
+     * Get italic
+     *
+     * @return bool
+     */
+    public function isItalic()
+    {
+        return $this->italic;
+    }
+
+    /**
+     * Set italic
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setItalic($value = true)
+    {
+        $this->italic = $this->setBoolVal($value, $this->italic);
+
+        return $this;
+    }
+
+    /**
+     * Get underline
+     *
+     * @return string
+     */
+    public function getUnderline()
+    {
+        return $this->underline;
+    }
+
+    /**
+     * Set underline
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setUnderline($value = self::UNDERLINE_NONE)
+    {
+        $this->underline = $this->setNonEmptyVal($value, self::UNDERLINE_NONE);
+
+        return $this;
+    }
+
+    /**
+     * Get superscript
+     *
+     * @return bool
+     */
+    public function isSuperScript()
+    {
+        return $this->superScript;
+    }
+
+    /**
+     * Set superscript
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setSuperScript($value = true)
+    {
+        return $this->setPairedVal($this->superScript, $this->subScript, $value);
+    }
+
+    /**
+     * Get subscript
+     *
+     * @return bool
+     */
+    public function isSubScript()
+    {
+        return $this->subScript;
+    }
+
+    /**
+     * Set subscript
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setSubScript($value = true)
+    {
+        return $this->setPairedVal($this->subScript, $this->superScript, $value);
+    }
+
+    /**
+     * Get strikethrough
+     *
+     * @return bool
+     */
+    public function isStrikethrough()
+    {
+        return $this->strikethrough;
+    }
+
+    /**
+     * Set strikethrough
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setStrikethrough($value = true)
+    {
+        return $this->setPairedVal($this->strikethrough, $this->doubleStrikethrough, $value);
+    }
+
+    /**
+     * Get double strikethrough
+     *
+     * @return bool
+     */
+    public function isDoubleStrikethrough()
+    {
+        return $this->doubleStrikethrough;
+    }
+
+    /**
+     * Set double strikethrough
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setDoubleStrikethrough($value = true)
+    {
+        return $this->setPairedVal($this->doubleStrikethrough, $this->strikethrough, $value);
+    }
+
+    /**
+     * Get small caps
+     *
+     * @return bool
+     */
+    public function isSmallCaps()
+    {
+        return $this->smallCaps;
+    }
+
+    /**
+     * Set small caps
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setSmallCaps($value = true)
+    {
+        return $this->setPairedVal($this->smallCaps, $this->allCaps, $value);
+    }
+
+    /**
+     * Get all caps
+     *
+     * @return bool
+     */
+    public function isAllCaps()
+    {
+        return $this->allCaps;
+    }
+
+    /**
+     * Set all caps
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setAllCaps($value = true)
+    {
+        return $this->setPairedVal($this->allCaps, $this->smallCaps, $value);
+    }
+
+    /**
+     * Get foreground/highlight color
+     *
+     * @return string
+     */
+    public function getFgColor()
+    {
+        return $this->fgColor;
+    }
+
+    /**
+     * Set foreground/highlight color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setFgColor($value = null)
+    {
+        $this->fgColor = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get background
+     *
+     * @return string
+     */
+    public function getBgColor()
+    {
+        return $this->getChildStyleValue($this->shading, 'fill');
+    }
+
+    /**
+     * Set background
+     *
+     * @param string $value
+     * @return \PhpOffice\PhpWord\Style\Table
+     */
+    public function setBgColor($value = null)
+    {
+        $this->setShading(array('fill' => $value));
+    }
+
+    /**
+     * Get scale
+     *
+     * @return int
+     */
+    public function getScale()
+    {
+        return $this->scale;
+    }
+
+    /**
+     * Set scale
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setScale($value = null)
+    {
+        $this->scale = $this->setIntVal($value, null);
+
+        return $this;
+    }
+
+    /**
+     * Get font spacing
+     *
+     * @return int|float
+     */
+    public function getSpacing()
+    {
+        return $this->spacing;
+    }
+
+    /**
+     * Set font spacing
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setSpacing($value = null)
+    {
+        $this->spacing = $this->setNumericVal($value, null);
+
+        return $this;
+    }
+
+    /**
+     * Get font kerning
+     *
+     * @return int|float
+     */
+    public function getKerning()
+    {
+        return $this->kerning;
+    }
+
+    /**
+     * Set font kerning
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setKerning($value = null)
+    {
+        $this->kerning = $this->setNumericVal($value, null);
+
+        return $this;
+    }
+
+    /**
+     * Get line height
+     *
+     * @return int|float
+     */
+    public function getLineHeight()
+    {
+        return $this->getParagraph()->getLineHeight();
+    }
+
+    /**
+     * Set lineheight
+     *
+     * @param int|float|string $value
+     * @return self
+     */
+    public function setLineHeight($value)
+    {
+        $this->setParagraph(array('lineHeight' => $value));
+
+        return $this;
+    }
+
+    /**
+     * Get paragraph style
+     *
+     * @return \PhpOffice\PhpWord\Style\Paragraph
+     */
+    public function getParagraph()
+    {
+        return $this->paragraph;
+    }
+
+    /**
+     * Set shading
+     *
+     * @param mixed $value
+     * @return self
+     */
+    public function setParagraph($value = null)
+    {
+        $this->setObjectVal($value, 'Paragraph', $this->paragraph);
+
+        return $this;
+    }
+
+    /**
+     * Get rtl
+     *
+     * @return bool
+     */
+    public function isRTL()
+    {
+        return $this->rtl;
+    }
+
+    /**
+     * Set rtl
+     *
+     * @param bool $value
+     * @return self
+     */
+    public function setRTL($value = true)
+    {
+        $this->rtl = $this->setBoolVal($value, $this->rtl);
+
+        return $this;
+    }
+
+    /**
+     * Get shading
+     *
+     * @return \PhpOffice\PhpWord\Style\Shading
+     */
+    public function getShading()
+    {
+        return $this->shading;
+    }
+
+    /**
+     * Set shading
+     *
+     * @param mixed $value
+     * @return self
+     */
+    public function setShading($value = null)
+    {
+        $this->setObjectVal($value, 'Shading', $this->shading);
+
+        return $this;
+    }
+
+    /**
+     * Get bold
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getBold()
+    {
+        return $this->isBold();
+    }
+
+    /**
+     * Get italic
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getItalic()
+    {
+        return $this->isItalic();
+    }
+
+    /**
+     * Get superscript
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getSuperScript()
+    {
+        return $this->isSuperScript();
+    }
+
+    /**
+     * Get subscript
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getSubScript()
+    {
+        return $this->isSubScript();
+    }
+
+    /**
+     * Get strikethrough
+     *
+     * @deprecated 0.10.0
+     * @codeCoverageIgnore
+     */
+    public function getStrikethrough()
+    {
+        return $this->isStrikethrough();
+    }
+
+    /**
+     * Get paragraph style
+     *
+     * @deprecated 0.11.0
+     * @codeCoverageIgnore
+     */
+    public function getParagraphStyle()
+    {
+        return $this->getParagraph();
+    }
+}

+ 513 - 0
includes/PhpWord/Style/Frame.php

@@ -0,0 +1,513 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Frame defines the size and position of an object
+ *
+ * Width, height, left/hpos, top/vpos, hrel, vrel, wrap, zindex
+ *
+ * @since 0.12.0
+ * @todo Make existing style (image, textbox, etc) use this style
+ */
+class Frame extends AbstractStyle
+{
+    /**
+     * Length unit
+     *
+     * @const string
+     */
+    const UNIT_PT = 'pt'; // Mostly for shapes
+    const UNIT_PX = 'px'; // Mostly for images
+
+    /**
+     * General positioning options.
+     *
+     * @const string
+     */
+    const POS_ABSOLUTE = 'absolute';
+    const POS_RELATIVE = 'relative';
+
+    /**
+     * Horizontal/vertical value
+     *
+     * @const string
+     */
+    const POS_CENTER = 'center';
+    const POS_LEFT = 'left';
+    const POS_RIGHT = 'right';
+    const POS_TOP = 'top';
+    const POS_BOTTOM = 'bottom';
+    const POS_INSIDE = 'inside';
+    const POS_OUTSIDE = 'outside';
+
+    /**
+     * Position relative to
+     *
+     * @const string
+     */
+    const POS_RELTO_MARGIN = 'margin';
+    const POS_RELTO_PAGE = 'page';
+    const POS_RELTO_COLUMN = 'column'; // horizontal only
+    const POS_RELTO_CHAR = 'char'; // horizontal only
+    const POS_RELTO_TEXT = 'text'; // vertical only
+    const POS_RELTO_LINE = 'line'; // vertical only
+    const POS_RELTO_LMARGIN = 'left-margin-area'; // horizontal only
+    const POS_RELTO_RMARGIN = 'right-margin-area'; // horizontal only
+    const POS_RELTO_TMARGIN = 'top-margin-area'; // vertical only
+    const POS_RELTO_BMARGIN = 'bottom-margin-area'; // vertical only
+    const POS_RELTO_IMARGIN = 'inner-margin-area';
+    const POS_RELTO_OMARGIN = 'outer-margin-area';
+
+    /**
+     * Wrap type
+     *
+     * @const string
+     */
+    const WRAP_INLINE = 'inline';
+    const WRAP_SQUARE = 'square';
+    const WRAP_TIGHT = 'tight';
+    const WRAP_THROUGH = 'through';
+    const WRAP_TOPBOTTOM = 'topAndBottom';
+    const WRAP_BEHIND = 'behind';
+    const WRAP_INFRONT = 'infront';
+
+    /**
+     * Alignment
+     *
+     * @var \PhpOffice\PhpWord\Style\Alignment
+     */
+    private $alignment;
+
+    /**
+     * Unit
+     *
+     * @var string
+     */
+    private $unit = 'pt';
+
+    /**
+     * Width
+     *
+     * @var int|float
+     */
+    private $width;
+
+    /**
+     * Height
+     *
+     * @var int|float
+     */
+    private $height;
+
+    /**
+     * Leftmost (horizontal) position
+     *
+     * @var int|float
+     */
+    private $left = 0;
+
+    /**
+     * Topmost (vertical) position
+     *
+     * @var int|float
+     */
+    private $top = 0;
+
+    /**
+     * Position type: absolute|relative
+     *
+     * @var string
+     */
+    private $pos;
+
+    /**
+     * Horizontal position
+     *
+     * @var string
+     */
+    private $hPos;
+
+    /**
+     * Horizontal position relative to
+     *
+     * @var string
+     */
+    private $hPosRelTo;
+
+    /**
+     * Vertical position
+     *
+     * @var string
+     */
+    private $vPos;
+
+    /**
+     * Vertical position relative to
+     *
+     * @var string
+     */
+    private $vPosRelTo;
+
+    /**
+     * Wrap type
+     *
+     * @var string
+     */
+    private $wrap;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->alignment = new Alignment();
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get alignment
+     *
+     * @return string
+     */
+    public function getAlign()
+    {
+        return $this->alignment->getValue();
+    }
+
+    /**
+     * Set alignment
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setAlign($value = null)
+    {
+        $this->alignment->setValue($value);
+
+        return $this;
+    }
+
+    /**
+     * Get unit
+     *
+     * @return string
+     */
+    public function getUnit()
+    {
+        return $this->unit;
+    }
+
+    /**
+     * Set unit
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setUnit($value)
+    {
+        $this->unit = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get width
+     *
+     * @return int|float
+     */
+    public function getWidth()
+    {
+        return $this->width;
+    }
+
+    /**
+     * Set width
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setWidth($value = null)
+    {
+        $this->width = $this->setNumericVal($value, null);
+
+        return $this;
+    }
+
+    /**
+     * Get height
+     *
+     * @return int|float
+     */
+    public function getHeight()
+    {
+        return $this->height;
+    }
+
+    /**
+     * Set height
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setHeight($value = null)
+    {
+        $this->height = $this->setNumericVal($value, null);
+
+        return $this;
+    }
+
+    /**
+     * Get left
+     *
+     * @return int|float
+     */
+    public function getLeft()
+    {
+        return $this->left;
+    }
+
+    /**
+     * Set left
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setLeft($value = 0)
+    {
+        $this->left = $this->setNumericVal($value, 0);
+
+        return $this;
+    }
+
+    /**
+     * Get topmost position
+     *
+     * @return int|float
+     */
+    public function getTop()
+    {
+        return $this->top;
+    }
+
+    /**
+     * Set topmost position
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setTop($value = 0)
+    {
+        $this->top = $this->setNumericVal($value, 0);
+
+        return $this;
+    }
+
+    /**
+     * Get position type
+     *
+     * @return string
+     */
+    public function getPos()
+    {
+        return $this->pos;
+    }
+
+    /**
+     * Set position type
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setPos($value)
+    {
+        $enum = array(
+            self::POS_ABSOLUTE,
+            self::POS_RELATIVE,
+        );
+        $this->pos = $this->setEnumVal($value, $enum, $this->pos);
+
+        return $this;
+    }
+
+    /**
+     * Get horizontal position
+     *
+     * @return string
+     */
+    public function getHPos()
+    {
+        return $this->hPos;
+    }
+
+    /**
+     * Set horizontal position
+     *
+     * @since 0.12.0 "absolute" option is available.
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setHPos($value)
+    {
+        $enum = array(
+            self::POS_ABSOLUTE,
+            self::POS_LEFT,
+            self::POS_CENTER,
+            self::POS_RIGHT,
+            self::POS_INSIDE,
+            self::POS_OUTSIDE,
+        );
+        $this->hPos = $this->setEnumVal($value, $enum, $this->hPos);
+
+        return $this;
+    }
+
+    /**
+     * Get vertical position
+     *
+     * @return string
+     */
+    public function getVPos()
+    {
+        return $this->vPos;
+    }
+
+    /**
+     * Set vertical position
+     *
+     * @since 0.12.0 "absolute" option is available.
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setVPos($value)
+    {
+        $enum = array(
+            self::POS_ABSOLUTE,
+            self::POS_TOP,
+            self::POS_CENTER,
+            self::POS_BOTTOM,
+            self::POS_INSIDE,
+            self::POS_OUTSIDE,
+        );
+        $this->vPos = $this->setEnumVal($value, $enum, $this->vPos);
+
+        return $this;
+    }
+
+    /**
+     * Get horizontal position relative to
+     *
+     * @return string
+     */
+    public function getHPosRelTo()
+    {
+        return $this->hPosRelTo;
+    }
+
+    /**
+     * Set horizontal position relative to
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setHPosRelTo($value)
+    {
+        $enum = array(
+            self::POS_RELTO_MARGIN,
+            self::POS_RELTO_PAGE,
+            self::POS_RELTO_COLUMN,
+            self::POS_RELTO_CHAR,
+            self::POS_RELTO_LMARGIN,
+            self::POS_RELTO_RMARGIN,
+            self::POS_RELTO_IMARGIN,
+            self::POS_RELTO_OMARGIN,
+        );
+        $this->hPosRelTo = $this->setEnumVal($value, $enum, $this->hPosRelTo);
+
+        return $this;
+    }
+
+    /**
+     * Get vertical position relative to
+     *
+     * @return string
+     */
+    public function getVPosRelTo()
+    {
+        return $this->vPosRelTo;
+    }
+
+    /**
+     * Set vertical position relative to
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setVPosRelTo($value)
+    {
+        $enum = array(
+            self::POS_RELTO_MARGIN,
+            self::POS_RELTO_PAGE,
+            self::POS_RELTO_TEXT,
+            self::POS_RELTO_LINE,
+            self::POS_RELTO_TMARGIN,
+            self::POS_RELTO_BMARGIN,
+            self::POS_RELTO_IMARGIN,
+            self::POS_RELTO_OMARGIN,
+        );
+        $this->vPosRelTo = $this->setEnumVal($value, $enum, $this->vPosRelTo);
+
+        return $this;
+    }
+
+    /**
+     * Get wrap type
+     *
+     * @return string
+     */
+    public function getWrap()
+    {
+        return $this->wrap;
+    }
+
+    /**
+     * Set wrap type
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setWrap($value)
+    {
+        $enum = array(
+            self::WRAP_INLINE,
+            self::WRAP_SQUARE,
+            self::WRAP_TIGHT,
+            self::WRAP_THROUGH,
+            self::WRAP_TOPBOTTOM,
+            self::WRAP_BEHIND,
+            self::WRAP_INFRONT,
+        );
+        $this->wrap = $this->setEnumVal($value, $enum, $this->wrap);
+
+        return $this;
+    }
+}

+ 265 - 0
includes/PhpWord/Style/Image.php

@@ -0,0 +1,265 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Image and memory image style
+ */
+class Image extends Frame
+{
+    /**
+     * Backward compatibility constants
+     *
+     * @const string
+     */
+    const WRAPPING_STYLE_INLINE = self::WRAP_INLINE;
+    const WRAPPING_STYLE_SQUARE = self::WRAP_SQUARE;
+    const WRAPPING_STYLE_TIGHT = self::WRAP_TIGHT;
+    const WRAPPING_STYLE_BEHIND = self::WRAP_BEHIND;
+    const WRAPPING_STYLE_INFRONT = self::WRAP_INFRONT;
+    const POSITION_HORIZONTAL_LEFT = self::POS_LEFT;
+    const POSITION_HORIZONTAL_CENTER = self::POS_CENTER;
+    const POSITION_HORIZONTAL_RIGHT = self::POS_RIGHT;
+    const POSITION_VERTICAL_TOP = self::POS_TOP;
+    const POSITION_VERTICAL_CENTER = self::POS_CENTER;
+    const POSITION_VERTICAL_BOTTOM = self::POS_BOTTOM;
+    const POSITION_VERTICAL_INSIDE = self::POS_INSIDE;
+    const POSITION_VERTICAL_OUTSIDE = self::POS_OUTSIDE;
+    const POSITION_RELATIVE_TO_MARGIN = self::POS_RELTO_MARGIN;
+    const POSITION_RELATIVE_TO_PAGE = self::POS_RELTO_PAGE;
+    const POSITION_RELATIVE_TO_COLUMN = self::POS_RELTO_COLUMN;
+    const POSITION_RELATIVE_TO_CHAR = self::POS_RELTO_CHAR;
+    const POSITION_RELATIVE_TO_TEXT = self::POS_RELTO_TEXT;
+    const POSITION_RELATIVE_TO_LINE = self::POS_RELTO_LINE;
+    const POSITION_RELATIVE_TO_LMARGIN = self::POS_RELTO_LMARGIN;
+    const POSITION_RELATIVE_TO_RMARGIN = self::POS_RELTO_RMARGIN;
+    const POSITION_RELATIVE_TO_TMARGIN = self::POS_RELTO_TMARGIN;
+    const POSITION_RELATIVE_TO_BMARGIN = self::POS_RELTO_BMARGIN;
+    const POSITION_RELATIVE_TO_IMARGIN = self::POS_RELTO_IMARGIN;
+    const POSITION_RELATIVE_TO_OMARGIN = self::POS_RELTO_OMARGIN;
+    const POSITION_ABSOLUTE = self::POS_ABSOLUTE;
+    const POSITION_RELATIVE = self::POS_RELATIVE;
+
+    /**
+     * Create new instance
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->setUnit('px');
+
+        // Backward compatilibity setting
+        // @todo Remove on 1.0.0
+        $this->setWrap(self::WRAPPING_STYLE_INLINE);
+        $this->setHPos(self::POSITION_HORIZONTAL_LEFT);
+        $this->setHPosRelTo(self::POSITION_RELATIVE_TO_CHAR);
+        $this->setVPos(self::POSITION_VERTICAL_TOP);
+        $this->setVPosRelTo(self::POSITION_RELATIVE_TO_LINE);
+    }
+
+    /**
+     * Get margin top
+     *
+     * @return int|float
+     */
+    public function getMarginTop()
+    {
+        return $this->getTop();
+    }
+
+    /**
+     * Set margin top
+     *
+     * @ignoreScrutinizerPatch
+     * @param int|float $value
+     * @return self
+     */
+    public function setMarginTop($value = 0)
+    {
+        $this->setTop($value);
+
+        return $this;
+    }
+
+    /**
+     * Get margin left
+     *
+     * @return int|float
+     */
+    public function getMarginLeft()
+    {
+        return $this->getLeft();
+    }
+
+    /**
+     * Set margin left
+     *
+     * @ignoreScrutinizerPatch
+     * @param int|float $value
+     * @return self
+     */
+    public function setMarginLeft($value = 0)
+    {
+        $this->setLeft($value);
+
+        return $this;
+    }
+
+    /**
+     * Get wrapping style
+     *
+     * @return string
+     */
+    public function getWrappingStyle()
+    {
+        return $this->getWrap();
+    }
+
+    /**
+     * Set wrapping style
+     *
+     * @param string $wrappingStyle
+     * @throws \InvalidArgumentException
+     * @return self
+     */
+    public function setWrappingStyle($wrappingStyle)
+    {
+        $this->setWrap($wrappingStyle);
+
+        return $this;
+    }
+
+    /**
+     * Get positioning type
+     *
+     * @return string
+     */
+    public function getPositioning()
+    {
+        return $this->getPos();
+    }
+
+    /**
+     * Set positioning type
+     *
+     * @param string $positioning
+     * @throws \InvalidArgumentException
+     * @return self
+     */
+    public function setPositioning($positioning)
+    {
+        $this->setPos($positioning);
+
+        return $this;
+    }
+
+    /**
+     * Get horizontal alignment
+     *
+     * @return string
+     */
+    public function getPosHorizontal()
+    {
+        return $this->getHPos();
+    }
+
+    /**
+     * Set horizontal alignment
+     *
+     * @param string $alignment
+     * @throws \InvalidArgumentException
+     * @return self
+     */
+    public function setPosHorizontal($alignment)
+    {
+        $this->setHPos($alignment);
+
+        return $this;
+    }
+
+    /**
+     * Get vertical alignment
+     *
+     * @return string
+     */
+    public function getPosVertical()
+    {
+        return $this->getVPos();
+    }
+
+    /**
+     * Set vertical alignment
+     *
+     * @param string $alignment
+     * @throws \InvalidArgumentException
+     * @return self
+     */
+    public function setPosVertical($alignment)
+    {
+        $this->setVPos($alignment);
+
+        return $this;
+    }
+
+    /**
+     * Get horizontal relation
+     *
+     * @return string
+     */
+    public function getPosHorizontalRel()
+    {
+        return $this->getHPosRelTo();
+    }
+
+    /**
+     * Set horizontal relation
+     *
+     * @param string $relto
+     * @throws \InvalidArgumentException
+     * @return self
+     */
+    public function setPosHorizontalRel($relto)
+    {
+        $this->setHPosRelTo($relto);
+
+        return $this;
+    }
+
+    /**
+     * Get vertical relation
+     *
+     * @return string
+     */
+    public function getPosVerticalRel()
+    {
+        return $this->getVPosRelTo();
+    }
+
+    /**
+     * Set vertical relation
+     *
+     * @param string $relto
+     * @throws \InvalidArgumentException
+     * @return self
+     */
+    public function setPosVerticalRel($relto)
+    {
+        $this->setVPosRelTo($relto);
+
+        return $this;
+    }
+}

+ 157 - 0
includes/PhpWord/Style/Indentation.php

@@ -0,0 +1,157 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Paragraph indentation style
+ *
+ * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html
+ * @since 0.10.0
+ */
+class Indentation extends AbstractStyle
+{
+    /**
+     * Left indentation (twip)
+     *
+     * @var int|float
+     */
+    private $left = 0;
+
+    /**
+     * Right indentation (twip)
+     *
+     * @var int|float
+     */
+    private $right = 0;
+
+    /**
+     * Additional first line indentation (twip)
+     *
+     * @var int|float
+     */
+    private $firstLine;
+
+    /**
+     * Indentation removed from first line (twip)
+     *
+     * @var int|float
+     */
+    private $hanging;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get left
+     *
+     * @return int|float
+     */
+    public function getLeft()
+    {
+        return $this->left;
+    }
+
+    /**
+     * Set left
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setLeft($value = null)
+    {
+        $this->left = $this->setNumericVal($value, $this->left);
+
+        return $this;
+    }
+
+    /**
+     * Get right
+     *
+     * @return int|float
+     */
+    public function getRight()
+    {
+        return $this->right;
+    }
+
+    /**
+     * Set right
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setRight($value = null)
+    {
+        $this->right = $this->setNumericVal($value, $this->right);
+
+        return $this;
+    }
+
+    /**
+     * Get first line
+     *
+     * @return int|float
+     */
+    public function getFirstLine()
+    {
+        return $this->firstLine;
+    }
+
+    /**
+     * Set first line
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setFirstLine($value = null)
+    {
+        $this->firstLine = $this->setNumericVal($value, $this->firstLine);
+
+        return $this;
+    }
+
+    /**
+     * Get hanging
+     *
+     * @return int|float
+     */
+    public function getHanging()
+    {
+        return $this->hanging;
+    }
+
+    /**
+     * Set hanging
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setHanging($value = null)
+    {
+        $this->hanging = $this->setNumericVal($value, $this->hanging);
+
+        return $this;
+    }
+}

+ 280 - 0
includes/PhpWord/Style/Line.php

@@ -0,0 +1,280 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Line style
+ */
+class Line extends Image
+{
+    /**
+     * Connector types
+     *
+     * @const string
+     */
+    const CONNECTOR_TYPE_STRAIGHT = 'straight';
+
+    /**
+     * Arrow styles
+     *
+     * @const string
+     */
+    const ARROW_STYLE_BLOCK = 'block';
+    const ARROW_STYLE_OPEN = 'open';
+    const ARROW_STYLE_CLASSIC = 'classic';
+    const ARROW_STYLE_DIAMOND = 'diamond';
+    const ARROW_STYLE_OVAL = 'oval';
+
+    /**
+     * Dash styles
+     *
+     * @const string
+     */
+    const DASH_STYLE_DASH = 'dash';
+    const DASH_STYLE_ROUND_DOT = 'rounddot';
+    const DASH_STYLE_SQUARE_DOT = 'squaredot';
+    const DASH_STYLE_DASH_DOT = 'dashdot';
+    const DASH_STYLE_LONG_DASH = 'longdash';
+    const DASH_STYLE_LONG_DASH_DOT = 'longdashdot';
+    const DASH_STYLE_LONG_DASH_DOT_DOT = 'longdashdotdot';
+
+    /**
+     * flip Line
+     *
+     * @var boolean
+     */
+    private $flip = false;
+
+    /**
+     * connectorType
+     *
+     * @var string
+     */
+    private $connectorType = self::CONNECTOR_TYPE_STRAIGHT;
+
+    /**
+     * Line Weight
+     *
+     * @var int
+     */
+    private $weight;
+
+    /**
+     * Line color
+     *
+     * @var string
+     */
+    private $color;
+
+    /**
+     * Dash style
+     *
+     * @var string
+     */
+    private $dash;
+
+    /**
+     * Begin arrow
+     *
+     * @var string
+     */
+    private $beginArrow;
+
+    /**
+     * End arrow
+     *
+     * @var string
+     */
+    private $endArrow;
+
+    /**
+     * Get flip
+     *
+     * @return boolean
+     */
+    public function isFlip()
+    {
+        return $this->flip;
+    }
+
+    /**
+     * Set flip
+     *
+     * @param boolean $value
+     * @return self
+     */
+    public function setFlip($value = false)
+    {
+        $this->flip = $this->setBoolVal($value, $this->flip);
+
+        return $this;
+    }
+
+    /**
+     * Get connectorType
+     *
+     * @return string
+     */
+    public function getConnectorType()
+    {
+        return $this->connectorType;
+    }
+
+    /**
+     * Set connectorType
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setConnectorType($value = null)
+    {
+        $enum = array(
+            self::CONNECTOR_TYPE_STRAIGHT
+        );
+        $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType);
+
+        return $this;
+    }
+
+    /**
+     * Get weight
+     *
+     * @return int
+     */
+    public function getWeight()
+    {
+        return $this->weight;
+    }
+
+    /**
+     * Set weight
+     *
+     * @param int $value Weight in points
+     * @return self
+     */
+    public function setWeight($value = null)
+    {
+        $this->weight = $this->setNumericVal($value, $this->weight);
+
+        return $this;
+    }
+
+    /**
+     * Get color
+     *
+     * @return string
+     */
+    public function getColor()
+    {
+        return $this->color;
+    }
+
+    /**
+     * Set color
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setColor($value = null)
+    {
+        $this->color = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get beginArrow
+     *
+     * @return string
+     */
+    public function getBeginArrow()
+    {
+        return $this->beginArrow;
+    }
+
+    /**
+     * Set beginArrow
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setBeginArrow($value = null)
+    {
+        $enum = array(
+            self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND,
+            self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL
+        );
+        $this->beginArrow = $this->setEnumVal($value, $enum, $this->beginArrow);
+
+        return $this;
+    }
+
+    /**
+     * Get endArrow
+     *
+     * @return string
+     */
+    public function getEndArrow()
+    {
+        return $this->endArrow;
+    }
+
+    /**
+     * Set endArrow
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setEndArrow($value = null)
+    {
+        $enum = array(
+            self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND,
+            self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL
+        );
+        $this->endArrow = $this->setEnumVal($value, $enum, $this->endArrow);
+
+        return $this;
+    }
+
+    /**
+     * Get Dash
+     *
+     * @return string
+     */
+    public function getDash()
+    {
+        return $this->dash;
+    }
+
+    /**
+     * Set Dash
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setDash($value = null)
+    {
+        $enum = array(
+            self::DASH_STYLE_DASH, self::DASH_STYLE_DASH_DOT, self::DASH_STYLE_LONG_DASH,
+            self::DASH_STYLE_LONG_DASH_DOT, self::DASH_STYLE_LONG_DASH_DOT_DOT, self::DASH_STYLE_ROUND_DOT,
+            self::DASH_STYLE_SQUARE_DOT
+        );
+        $this->dash = $this->setEnumVal($value, $enum, $this->dash);
+
+        return $this;
+    }
+}

+ 164 - 0
includes/PhpWord/Style/LineNumbering.php

@@ -0,0 +1,164 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+/**
+ * Line numbering style
+ *
+ * @link http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html
+ * @since 0.10.0
+ */
+class LineNumbering extends AbstractStyle
+{
+    /** @const string Line numbering restart setting http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */
+    const LINE_NUMBERING_CONTINUOUS  = 'continuous';
+    const LINE_NUMBERING_NEW_PAGE    = 'newPage';
+    const LINE_NUMBERING_NEW_SECTION = 'newSection';
+
+    /**
+     * Line numbering starting value
+     *
+     * @var int
+     */
+    private $start = 1;
+
+    /**
+     * Line number increments
+     *
+     * @var int
+     */
+    private $increment = 1;
+
+    /**
+     * Distance between text and line numbering in twip
+     *
+     * @var int|float
+     */
+    private $distance;
+
+    /**
+     * Line numbering restart setting continuous|newPage|newSection
+     *
+     * @var string
+     * @link http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html
+     */
+    private $restart;
+
+    /**
+     * Create a new instance
+     *
+     * @param array $style
+     */
+    public function __construct($style = array())
+    {
+        $this->setStyleByArray($style);
+    }
+
+    /**
+     * Get start
+     *
+     * @return int
+     */
+    public function getStart()
+    {
+        return $this->start;
+    }
+
+    /**
+     * Set start
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setStart($value = null)
+    {
+        $this->start = $this->setIntVal($value, $this->start);
+
+        return $this;
+    }
+
+    /**
+     * Get increment
+     *
+     * @return int
+     */
+    public function getIncrement()
+    {
+        return $this->increment;
+    }
+
+    /**
+     * Set increment
+     *
+     * @param int $value
+     * @return self
+     */
+    public function setIncrement($value = null)
+    {
+        $this->increment = $this->setIntVal($value, $this->increment);
+
+        return $this;
+    }
+
+    /**
+     * Get distance
+     *
+     * @return int|float
+     */
+    public function getDistance()
+    {
+        return $this->distance;
+    }
+
+    /**
+     * Set distance
+     *
+     * @param int|float $value
+     * @return self
+     */
+    public function setDistance($value = null)
+    {
+        $this->distance = $this->setNumericVal($value, $this->distance);
+
+        return $this;
+    }
+
+    /**
+     * Get restart
+     *
+     * @return string
+     */
+    public function getRestart()
+    {
+        return $this->restart;
+    }
+
+    /**
+     * Set distance
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setRestart($value = null)
+    {
+        $enum = array(self::LINE_NUMBERING_CONTINUOUS, self::LINE_NUMBERING_NEW_PAGE, self::LINE_NUMBERING_NEW_SECTION);
+        $this->restart = $this->setEnumVal($value, $enum, $this->restart);
+
+        return $this;
+    }
+}

+ 263 - 0
includes/PhpWord/Style/ListItem.php

@@ -0,0 +1,263 @@
+<?php
+/**
+ * This file is part of PHPWord - A pure PHP library for reading and writing
+ * word processing documents.
+ *
+ * PHPWord is free software distributed under the terms of the GNU Lesser
+ * General Public License version 3 as published by the Free Software Foundation.
+ *
+ * For the full copyright and license information, please read the LICENSE
+ * file that was distributed with this source code. For the full list of
+ * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
+ *
+ * @link        https://github.com/PHPOffice/PHPWord
+ * @copyright   2010-2014 PHPWord contributors
+ * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
+ */
+
+namespace PhpOffice\PhpWord\Style;
+
+use PhpOffice\PhpWord\Style;
+
+/**
+ * List item style
+ *
+ * Before version 0.10.0, numbering style is defined statically with $listType.
+ * After version 0.10.0, numbering style is defined by using Numbering and
+ * recorded by $numStyle. $listStyle is maintained for backward compatility
+ */
+class ListItem extends AbstractStyle
+{
+    const TYPE_SQUARE_FILLED = 1;
+    const TYPE_BULLET_FILLED = 3; // default
+    const TYPE_BULLET_EMPTY = 5;
+    const TYPE_NUMBER = 7;
+    const TYPE_NUMBER_NESTED = 8;
+    const TYPE_ALPHANUM = 9;
+
+    /**
+     * Legacy list type
+     *
+     * @var integer
+     */
+    private $listType;
+
+    /**
+     * Numbering style name
+     *
+     * @var string
+     * @since 0.10.0
+     */
+    private $numStyle;
+
+    /**
+     * Numbering definition instance ID
+     *
+     * @var integer
+     * @since 0.10.0
+     */
+    private $numId;
+
+    /**
+     * Create new instance
+     *
+     * @param string $numStyle
+     */
+    public function __construct($numStyle = null)
+    {
+        if ($numStyle !== null) {
+            $this->setNumStyle($numStyle);
+        } else {
+            $this->setListType();
+        }
+    }
+
+    /**
+     * Get List Type
+     *
+     * @return integer
+     */
+    public function getListType()
+    {
+        return $this->listType;
+    }
+
+    /**
+     * Set legacy list type for version < 0.10.0
+     *
+     * @param integer $value
+     * @return self
+     */
+    public function setListType($value = self::TYPE_BULLET_FILLED)
+    {
+        $enum = array(
+            self::TYPE_SQUARE_FILLED, self::TYPE_BULLET_FILLED,
+            self::TYPE_BULLET_EMPTY, self::TYPE_NUMBER,
+            self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM
+        );
+        $this->listType = $this->setEnumVal($value, $enum, $this->listType);
+        $this->getListTypeStyle();
+
+        return $this;
+    }
+
+    /**
+     * Get numbering style name
+     *
+     * @return string
+     */
+    public function getNumStyle()
+    {
+        return $this->numStyle;
+    }
+
+    /**
+     * Set numbering style name
+     *
+     * @param string $value
+     * @return self
+     */
+    public function setNumStyle($value)
+    {
+        $this->numStyle = $value;
+        $numStyleObject = Style::getStyle($this->numStyle);
+        if ($numStyleObject instanceof Numbering) {
+            $this->numId = $numStyleObject->getIndex();
+            $numStyleObject->setNumId($this->numId);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get numbering Id
+     *
+     * @return integer
+     */
+    public function getNumId()
+    {
+        return $this->numId;
+    }
+
+    /**
+     * Get legacy numbering definition
+     *
+     * @return array
+     * @since 0.10.0
+     */
+    private function getListTypeStyle()
+    {
+        // Check if legacy style already registered in global Style collection
+        $numStyle = "PHPWordList{$this->listType}";
+        if (Style::getStyle($numStyle) !== null) {
+            $this->setNumStyle($numStyle);
+            return;
+        }
+
+        // Property mapping for numbering level information
+        $properties = array('start', 'format', 'text', 'align', 'tabPos', 'left', 'hanging', 'font', 'hint');
+
+        // Legacy level information
+        $listTypeStyles = array(
+            self::TYPE_SQUARE_FILLED => array(
+                'type' => 'hybridMultilevel',
+                'levels' => array(
+                    0 => '1, bullet, , left, 720, 720, 360, Wingdings, default',
+                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',
+                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',
+                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',
+                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',
+                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',
+                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',
+                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',
+                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',
+                ),
+            ),
+            self::TYPE_BULLET_FILLED => array(
+                'type' => 'hybridMultilevel',
+                'levels' => array(
+                    0 => '1, bullet, , left, 720, 720, 360, Symbol, default',
+                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',
+                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',
+                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',
+                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',
+                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',
+                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',
+                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',
+                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',
+                ),
+            ),
+            self::TYPE_BULLET_EMPTY => array(
+                'type' => 'hybridMultilevel',
+                'levels' => array(
+                    0 => '1, bullet, o, left, 720, 720, 360, Courier New, default',
+                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',
+                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',
+                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',
+                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',
+                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',
+                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',
+                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',
+                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',
+                ),
+            ),
+            self::TYPE_NUMBER => array(
+                'type' => 'hybridMultilevel',
+                'levels' => array(
+                    0 => '1, decimal, %1., left, 720, 720, 360, , default',
+                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',
+                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',
+                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',
+                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',
+                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',
+                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',
+                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',
+                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',
+                ),
+            ),
+            self::TYPE_NUMBER_NESTED => array(
+                'type' => 'multilevel',
+                'levels' => array(
+                    0 => '1, decimal, %1., left, 360, 360, 360, , ',
+                    1 => '1, decimal, %1.%2., left, 792, 792, 432, , ',
+                    2 => '1, decimal, %1.%2.%3., left, 1224, 1224, 504, , ',
+                    3 => '1, decimal, %1.%2.%3.%4., left, 1800, 1728, 648, , ',
+                    4 => '1, decimal, %1.%2.%3.%4.%5., left, 2520, 2232, 792, , ',
+                    5 => '1, decimal, %1.%2.%3.%4.%5.%6., left, 2880, 2736, 936, , ',
+                    6 => '1, decimal, %1.%2.%3.%4.%5.%6.%7., left, 3600, 3240, 1080, , ',
+                    7 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8., left, 3960, 3744, 1224, , ',
+                    8 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8.%9., left, 4680, 4320, 1440, , ',
+                ),
+            ),
+            self::TYPE_ALPHANUM => array(
+                'type' => 'multilevel',
+                'levels' => array(
+                    0 => '1, decimal, %1., left, 720, 720, 360, , ',
+                    1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ',
+                    2 => '1, lowerRoman, %3., right, 2160, 2160, 180, , ',
+                    3 => '1, decimal, %4., left, 2880, 2880, 360, , ',
+                    4 => '1, lowerLetter, %5., left, 3600, 3600, 360, , ',
+                    5 => '1, lowerRoman, %6., right, 4320, 4320, 180, , ',
+                    6 => '1, decimal, %7., left, 5040, 5040, 360, , ',
+                    7 => '1, lowerLetter, %8., left, 5760, 5760, 360, , ',
+                    8 => '1, lowerRoman, %9., right, 6480, 6480, 180, , ',
+                ),
+            ),
+        );
+
+        // Populate style and register to global Style register
+        $style = $listTypeStyles[$this->listType];
+        foreach ($style['levels'] as $key => $value) {
+            $level = array();
+            $levelProperties = explode(', ', $value);
+            $level['level'] = $key;
+            for ($i = 0; $i < count($properties); $i++) {
+                $property = $properties[$i];
+                $level[$property] = $levelProperties[$i];
+            }
+            $style['levels'][$key] = $level;
+        }
+        Style::addNumberingStyle($numStyle, $style);
+        $this->setNumStyle($numStyle);
+    }
+}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff