diff --git a/upstream-3.x/LICENSE b/upstream-3.x/LICENSE
deleted file mode 100644
index 38ce746..0000000
--- a/upstream-3.x/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2022 openspout
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/upstream-3.x/LICENSE-for-cc42c1d b/upstream-3.x/LICENSE-for-cc42c1d
deleted file mode 100644
index 167ec4d..0000000
--- a/upstream-3.x/LICENSE-for-cc42c1d
+++ /dev/null
@@ -1,166 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
diff --git a/upstream-3.x/README.md b/upstream-3.x/README.md
deleted file mode 100644
index 0ceb637..0000000
--- a/upstream-3.x/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# OpenSpout
-
-[](https://packagist.org/packages/openspout/openspout)
-[](https://github.com/openspout/openspout/actions/workflows/ci.yml)
-[](https://codecov.io/gh/openspout/openspout?branch=main)
-[](https://packagist.org/packages/openspout/openspout)
-
-OpenSpout is a community driven fork of `box/spout`, a PHP library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way.
-Unlike other file readers or writers, it is capable of processing very large files, while keeping the memory usage really low (less than 3MB).
-
-## Documentation
-
-Documentation can be found at [https://openspout.readthedocs.io/en/latest/](https://openspout.readthedocs.io/en/latest/).
-
-## Requirements
-
-* PHP version 7.3 or higher
-* PHP extension `php_zip` enabled
-* PHP extension `php_xmlreader` enabled
-
-## Upgrade from `box/spout`
-
-1. Replace `box/spout` with `openspout/openspout` in your `composer.json`
-2. Replace `Box\Spout` with `OpenSpout` in your code
-
-## Upgrade guide
-
-Version 3 introduced new functionality but also some breaking changes. If you want to upgrade your Spout codebase from version 2 please consult the [Upgrade guide](UPGRADE-3.0.md).
-
-## Running tests
-
-The `main` branch includes unit, functional and performance tests.
-If you just want to check that everything is working as expected, executing the unit and functional tests is enough.
-
-* `phpunit` - runs unit and functional tests
-* `phpunit --group perf-tests` - only runs the performance tests
-
-For information, the performance tests take about 10 minutes to run (processing 1 million rows files is not a quick thing).
-
-> Performance tests status: [](https://travis-ci.org/box/spout)
-
-## Copyright and License
-
-This is a fork of Box's Spout library: https://github.com/box/spout
-
-Code until and directly descending from commit [`cc42c1d`](https://github.com/openspout/openspout/commit/cc42c1d29fc5d29f07caeace99bd29dbb6d7c2f8)
-is copyright of _Box, Inc._ and licensed under the Apache License, Version 2.0:
-
-https://github.com/openspout/openspout/blob/cc42c1d29fc5d29f07caeace99bd29dbb6d7c2f8/LICENSE
-
-Code created, edited and released after the commit mentioned above
-is copyright of _openspout_ Github organization and licensed under MIT License.
-
-https://github.com/openspout/openspout/blob/main/LICENSE
diff --git a/upstream-3.x/UPGRADE-3.0.md b/upstream-3.x/UPGRADE-3.0.md
deleted file mode 100644
index 8f6ae91..0000000
--- a/upstream-3.x/UPGRADE-3.0.md
+++ /dev/null
@@ -1,89 +0,0 @@
-Upgrading from 2.x to 3.0
-=========================
-
-Spout 3.0 introduced several backwards-incompatible changes. The upgrade from Spout 2.x to 3.0 must therefore be done with caution.
-This guide is meant to ease this process.
-
-Most notable changes
---------------------
-In 2.x, styles were applied per row; it was therefore impossible to apply different styles to cells in the same row.
-With the 3.0 version, this is now possible: each cell can have its own style.
-
-Spout 3.0 tries to enforce better typing. For instance, instead of using/returning generic arrays, Spout now makes use of specific `Row` and `Cell` objects that can encapsulate more data such as type, style, value.
-
-Finally, **_Spout 3.2 only supports PHP 7.2 and above_**, as other PHP versions are no longer supported by the community.
-
-Reader changes
---------------
-Creating a reader should now be done through the Reader `ReaderEntityFactory`, instead of using the `ReaderFactory`.
-Also, the `ReaderFactory::create($type)` method was removed and replaced by methods for each reader:
-```php
-use OpenSpout\Reader\Common\Creator\ReaderEntityFactory; // namespace is no longer "OpenSpout\Reader"
-...
-$reader = ReaderEntityFactory::createXLSXReader(); // replaces ReaderFactory::create(Type::XLSX)
-$reader = ReaderEntityFactory::createCSVReader(); // replaces ReaderFactory::create(Type::CSV)
-$reader = ReaderEntityFactory::createODSReader(); // replaces ReaderFactory::create(Type::ODS)
-```
-
-When iterating over the spreadsheet rows, Spout now returns `Row` objects, instead of an array containing row values. Accessing the row values should now be done this way:
-```php
-...
-foreach ($reader->getSheetIterator() as $sheet) {
- foreach ($sheet->getRowIterator() as $row) { // $row is a "Row" object, not an array
- $rowAsArray = $row->toArray(); // this is the 2.x equivalent
- // OR
- $cellsArray = $row->getCells(); // this can be used to get access to cells' details
- ...
- }
-}
-```
-
-Writer changes
---------------
-Writer creation follows the same change as the reader. It should now be done through the Writer `WriterEntityFactory`, instead of using the `WriterFactory`.
-Also, the `WriterFactory::create($type)` method was removed and replaced by methods for each writer:
-
-```php
-use OpenSpout\Writer\Common\Creator\WriterEntityFactory; // namespace is no longer "OpenSpout\Writer"
-...
-$writer = WriterEntityFactory::createXLSXWriter(); // replaces WriterFactory::create(Type::XLSX)
-$writer = WriterEntityFactory::createCSVWriter(); // replaces WriterFactory::create(Type::CSV)
-$writer = WriterEntityFactory::createODSWriter(); // replaces WriterFactory::create(Type::ODS)
-```
-
-Adding rows is also done differently: instead of passing an array, the writer now takes in a `Row` object (or an array of `Row`). Creating such objects can easily be done this way:
-```php
-// Adding a row from an array of values (2.x equivalent)
-$cellValues = ['foo', 12345];
-$row1 = WriterEntityFactory::createRowFromArray($cellValues, $rowStyle);
-
-// Adding a row from an array of Cell
-$cell1 = WriterEntityFactory::createCell('foo', $cellStyle1); // this cell has its own style
-$cell2 = WriterEntityFactory::createCell(12345, $cellStyle2); // this cell has its own style
-$row2 = WriterEntityFactory::createRow([$cell1, $cell2]);
-
-$writer->addRows([$row1, $row2]);
-```
-
-Namespace changes for styles
------------------
-The namespaces for styles have changed. Styles are still created by using a `builder` class.
-
-For the builder, please update your import statements to use the following namespaces:
-
- OpenSpout\Writer\Common\Creator\Style\StyleBuilder
- OpenSpout\Writer\Common\Creator\Style\BorderBuilder
-
-The `Style` base class and style definitions like `Border`, `BorderPart` and `Color` also have a new namespace.
-
-If your are using these classes directly via an import statement in your code, please use the following namespaces:
-
- OpenSpout\Common\Entity\Style\Border
- OpenSpout\Common\Entity\Style\BorderPart
- OpenSpout\Common\Entity\Style\Color
- OpenSpout\Common\Entity\Style\Style
-
-Handling of empty rows
-----------------------
-In 2.x, empty rows were not added to the spreadsheet.
-In 3.0, `addRow` now always writes a row to the spreadsheet: when the row does not contain any cells, an empty row is created in the sheet.
diff --git a/upstream-3.x/composer.json b/upstream-3.x/composer.json
deleted file mode 100644
index 1a2a8ef..0000000
--- a/upstream-3.x/composer.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "name": "openspout/openspout",
- "description": "PHP Library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way",
- "license": "MIT",
- "type": "library",
- "keywords": [
- "php",
- "read",
- "write",
- "csv",
- "xlsx",
- "ods",
- "odf",
- "open",
- "office",
- "excel",
- "spreadsheet",
- "scale",
- "memory",
- "stream",
- "ooxml"
- ],
- "authors": [
- {
- "name": "Adrien Loison",
- "email": "adrien@box.com"
- }
- ],
- "homepage": "https://github.com/openspout/openspout",
- "require": {
- "php": "~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0",
- "ext-dom": "*",
- "ext-filter": "*",
- "ext-libxml": "*",
- "ext-xmlreader": "*",
- "ext-zip": "*"
- },
- "require-dev": {
- "ext-zlib": "*",
- "friendsofphp/php-cs-fixer": "^3.4",
- "phpstan/phpstan": "^1.4",
- "phpstan/phpstan-phpunit": "^1.0",
- "phpunit/phpunit": "^9.5"
- },
- "suggest": {
- "ext-iconv": "To handle non UTF-8 CSV files (if \"php-intl\" is not already installed or is too limited)",
- "ext-intl": "To handle non UTF-8 CSV files (if \"iconv\" is not already installed)"
- },
- "autoload": {
- "psr-4": {
- "OpenSpout\\": "src/"
- }
- },
- "autoload-dev": {
- "classmap": [
- "tests/"
- ]
- },
- "config": {
- "platform": {
- "php": "7.3"
- }
- },
- "extra": {
- "branch-alias": {
- "dev-master": "3.3.x-dev"
- }
- }
-}
diff --git a/upstream-3.x/src/Autoloader/Psr4Autoloader.php b/upstream-3.x/src/Autoloader/Psr4Autoloader.php
deleted file mode 100644
index 59eac31..0000000
--- a/upstream-3.x/src/Autoloader/Psr4Autoloader.php
+++ /dev/null
@@ -1,147 +0,0 @@
-prefixes[$prefix])) {
- $this->prefixes[$prefix] = [];
- }
-
- // retain the base directory for the namespace prefix
- if ($prepend) {
- array_unshift($this->prefixes[$prefix], $baseDir);
- } else {
- $this->prefixes[$prefix][] = $baseDir;
- }
- }
-
- /**
- * Loads the class file for a given class name.
- *
- * @param string $class the fully-qualified class name
- *
- * @return mixed the mapped file name on success, or boolean false on
- * failure
- */
- public function loadClass($class)
- {
- // the current namespace prefix
- $prefix = $class;
-
- // work backwards through the namespace names of the fully-qualified
- // class name to find a mapped file name
- while (($pos = strrpos($prefix, '\\')) !== false) {
- // retain the trailing namespace separator in the prefix
- $prefix = substr($class, 0, $pos + 1);
-
- // the rest is the relative class name
- $relativeClass = substr($class, $pos + 1);
-
- // try to load a mapped file for the prefix and relative class
- $mappedFile = $this->loadMappedFile($prefix, $relativeClass);
- if (false !== $mappedFile) {
- return $mappedFile;
- }
-
- // remove the trailing namespace separator for the next iteration
- // of strrpos()
- $prefix = rtrim($prefix, '\\');
- }
-
- // never found a mapped file
- return false;
- }
-
- /**
- * Load the mapped file for a namespace prefix and relative class.
- *
- * @param string $prefix the namespace prefix
- * @param string $relativeClass the relative class name
- *
- * @return mixed boolean false if no mapped file can be loaded, or the
- * name of the mapped file that was loaded
- */
- protected function loadMappedFile($prefix, $relativeClass)
- {
- // are there any base directories for this namespace prefix?
- if (false === isset($this->prefixes[$prefix])) {
- return false;
- }
-
- // look through base directories for this namespace prefix
- foreach ($this->prefixes[$prefix] as $baseDir) {
- // replace the namespace prefix with the base directory,
- // replace namespace separators with directory separators
- // in the relative class name, append with .php
- $file = $baseDir
- .str_replace('\\', '/', $relativeClass)
- .'.php';
-
- // if the mapped file exists, require it
- if ($this->requireFile($file)) {
- // yes, we're done
- return $file;
- }
- }
-
- // never found it
- return false;
- }
-
- /**
- * If a file exists, require it from the file system.
- *
- * @param string $file the file to require
- *
- * @return bool true if the file exists, false if not
- */
- protected function requireFile($file)
- {
- if (file_exists($file)) {
- require $file;
-
- return true;
- }
-
- return false;
- }
-}
diff --git a/upstream-3.x/src/Autoloader/autoload.php b/upstream-3.x/src/Autoloader/autoload.php
deleted file mode 100644
index a6768d4..0000000
--- a/upstream-3.x/src/Autoloader/autoload.php
+++ /dev/null
@@ -1,15 +0,0 @@
-register();
-$loader->addNamespace('OpenSpout', $srcBaseDirectory);
diff --git a/upstream-3.x/src/Common/Creator/HelperFactory.php b/upstream-3.x/src/Common/Creator/HelperFactory.php
deleted file mode 100644
index 55f1f57..0000000
--- a/upstream-3.x/src/Common/Creator/HelperFactory.php
+++ /dev/null
@@ -1,48 +0,0 @@
-setValue($value);
- $this->setStyle($style);
- }
-
- /**
- * @return string
- */
- public function __toString()
- {
- return (string) $this->getValue();
- }
-
- /**
- * @param null|mixed $value
- */
- public function setValue($value)
- {
- $this->value = $value;
- $this->type = $this->detectType($value);
- }
-
- /**
- * @return null|mixed
- */
- public function getValue()
- {
- return !$this->isError() ? $this->value : null;
- }
-
- /**
- * @return mixed
- */
- public function getValueEvenIfError()
- {
- return $this->value;
- }
-
- /**
- * @param null|Style $style
- */
- public function setStyle($style)
- {
- $this->style = $style ?: new Style();
- }
-
- /**
- * @return Style
- */
- public function getStyle()
- {
- return $this->style;
- }
-
- /**
- * @return null|int
- */
- public function getType()
- {
- return $this->type;
- }
-
- /**
- * @param int $type
- */
- public function setType($type)
- {
- $this->type = $type;
- }
-
- /**
- * @return bool
- */
- public function isBoolean()
- {
- return self::TYPE_BOOLEAN === $this->type;
- }
-
- /**
- * @return bool
- */
- public function isEmpty()
- {
- return self::TYPE_EMPTY === $this->type;
- }
-
- /**
- * @return bool
- */
- public function isNumeric()
- {
- return self::TYPE_NUMERIC === $this->type;
- }
-
- /**
- * @return bool
- */
- public function isString()
- {
- return self::TYPE_STRING === $this->type;
- }
-
- /**
- * @return bool
- */
- public function isDate()
- {
- return self::TYPE_DATE === $this->type;
- }
-
- /**
- * @return bool
- */
- public function isFormula()
- {
- return self::TYPE_FORMULA === $this->type;
- }
-
- /**
- * @return bool
- */
- public function isError()
- {
- return self::TYPE_ERROR === $this->type;
- }
-
- /**
- * Get the current value type.
- *
- * @param null|mixed $value
- *
- * @return int
- */
- protected function detectType($value)
- {
- if (CellTypeHelper::isBoolean($value)) {
- return self::TYPE_BOOLEAN;
- }
- if (CellTypeHelper::isEmpty($value)) {
- return self::TYPE_EMPTY;
- }
- if (CellTypeHelper::isNumeric($value)) {
- return self::TYPE_NUMERIC;
- }
- if (CellTypeHelper::isDateTimeOrDateInterval($value)) {
- return self::TYPE_DATE;
- }
- if (CellTypeHelper::isFormula($value)) {
- return self::TYPE_FORMULA;
- }
- if (CellTypeHelper::isNonEmptyString($value)) {
- return self::TYPE_STRING;
- }
-
- return self::TYPE_ERROR;
- }
-}
diff --git a/upstream-3.x/src/Common/Entity/Row.php b/upstream-3.x/src/Common/Entity/Row.php
deleted file mode 100644
index db6481f..0000000
--- a/upstream-3.x/src/Common/Entity/Row.php
+++ /dev/null
@@ -1,166 +0,0 @@
-setCells($cells)
- ->setStyle($style)
- ;
- }
-
- /**
- * @return Cell[] $cells
- */
- public function getCells()
- {
- return $this->cells;
- }
-
- /**
- * @param Cell[] $cells
- *
- * @return Row
- */
- public function setCells(array $cells)
- {
- $this->cells = [];
- foreach ($cells as $cell) {
- $this->addCell($cell);
- }
-
- return $this;
- }
-
- /**
- * @param int $cellIndex
- *
- * @return Row
- */
- public function setCellAtIndex(Cell $cell, $cellIndex)
- {
- $this->cells[$cellIndex] = $cell;
-
- return $this;
- }
-
- /**
- * @param int $cellIndex
- *
- * @return null|Cell
- */
- public function getCellAtIndex($cellIndex)
- {
- return $this->cells[$cellIndex] ?? null;
- }
-
- /**
- * @return Row
- */
- public function addCell(Cell $cell)
- {
- $this->cells[] = $cell;
-
- return $this;
- }
-
- /**
- * @return int
- */
- public function getNumCells()
- {
- // When using "setCellAtIndex", it's possible to
- // have "$this->cells" contain holes.
- if (empty($this->cells)) {
- return 0;
- }
-
- return max(array_keys($this->cells)) + 1;
- }
-
- /**
- * @return Style
- */
- public function getStyle()
- {
- return $this->style;
- }
-
- /**
- * @param null|Style $style
- *
- * @return Row
- */
- public function setStyle($style)
- {
- $this->style = $style ?: new Style();
-
- return $this;
- }
-
- /**
- * @return array The row values, as array
- */
- public function toArray()
- {
- return array_map(function (Cell $cell) {
- return $cell->getValue();
- }, $this->cells);
- }
-
- /**
- * Set row height.
- *
- * @param string $height
- *
- * @return Row
- */
- public function setHeight($height)
- {
- $this->height = $height;
-
- return $this;
- }
-
- /**
- * Returns row height.
- *
- * @return string
- */
- public function getHeight()
- {
- return $this->height;
- }
-}
diff --git a/upstream-3.x/src/Common/Entity/Style/Border.php b/upstream-3.x/src/Common/Entity/Style/Border.php
deleted file mode 100644
index 53b59da..0000000
--- a/upstream-3.x/src/Common/Entity/Style/Border.php
+++ /dev/null
@@ -1,80 +0,0 @@
-setParts($borderParts);
- }
-
- /**
- * @param string $name The name of the border part
- *
- * @return null|BorderPart
- */
- public function getPart($name)
- {
- return $this->hasPart($name) ? $this->parts[$name] : null;
- }
-
- /**
- * @param string $name The name of the border part
- *
- * @return bool
- */
- public function hasPart($name)
- {
- return isset($this->parts[$name]);
- }
-
- /**
- * @return array
- */
- public function getParts()
- {
- return $this->parts;
- }
-
- /**
- * Set BorderParts.
- *
- * @param array $parts
- */
- public function setParts($parts)
- {
- $this->parts = [];
- foreach ($parts as $part) {
- $this->addPart($part);
- }
- }
-
- /**
- * @return Border
- */
- public function addPart(BorderPart $borderPart)
- {
- $this->parts[$borderPart->getName()] = $borderPart;
-
- return $this;
- }
-}
diff --git a/upstream-3.x/src/Common/Entity/Style/BorderPart.php b/upstream-3.x/src/Common/Entity/Style/BorderPart.php
deleted file mode 100644
index afee776..0000000
--- a/upstream-3.x/src/Common/Entity/Style/BorderPart.php
+++ /dev/null
@@ -1,181 +0,0 @@
-setName($name);
- $this->setColor($color);
- $this->setWidth($width);
- $this->setStyle($style);
- }
-
- /**
- * @return string
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * @param string $name The name of the border part @see BorderPart::$allowedNames
- *
- * @throws InvalidNameException
- */
- public function setName($name)
- {
- if (!\in_array($name, self::$allowedNames, true)) {
- throw new InvalidNameException($name);
- }
- $this->name = $name;
- }
-
- /**
- * @return string
- */
- public function getStyle()
- {
- return $this->style;
- }
-
- /**
- * @param string $style The style of the border part @see BorderPart::$allowedStyles
- *
- * @throws InvalidStyleException
- */
- public function setStyle($style)
- {
- if (!\in_array($style, self::$allowedStyles, true)) {
- throw new InvalidStyleException($style);
- }
- $this->style = $style;
- }
-
- /**
- * @return string
- */
- public function getColor()
- {
- return $this->color;
- }
-
- /**
- * @param string $color The color of the border part @see Color::rgb()
- */
- public function setColor($color)
- {
- $this->color = $color;
- }
-
- /**
- * @return string
- */
- public function getWidth()
- {
- return $this->width;
- }
-
- /**
- * @param string $width The width of the border part @see BorderPart::$allowedWidths
- *
- * @throws InvalidWidthException
- */
- public function setWidth($width)
- {
- if (!\in_array($width, self::$allowedWidths, true)) {
- throw new InvalidWidthException($width);
- }
- $this->width = $width;
- }
-
- /**
- * @return array
- */
- public static function getAllowedStyles()
- {
- return self::$allowedStyles;
- }
-
- /**
- * @return array
- */
- public static function getAllowedNames()
- {
- return self::$allowedNames;
- }
-
- /**
- * @return array
- */
- public static function getAllowedWidths()
- {
- return self::$allowedWidths;
- }
-}
diff --git a/upstream-3.x/src/Common/Entity/Style/CellAlignment.php b/upstream-3.x/src/Common/Entity/Style/CellAlignment.php
deleted file mode 100644
index ecfa6d7..0000000
--- a/upstream-3.x/src/Common/Entity/Style/CellAlignment.php
+++ /dev/null
@@ -1,31 +0,0 @@
- 1,
- self::RIGHT => 1,
- self::CENTER => 1,
- self::JUSTIFY => 1,
- ];
-
- /**
- * @param string $cellAlignment
- *
- * @return bool Whether the given cell alignment is valid
- */
- public static function isValid($cellAlignment)
- {
- return isset(self::$VALID_ALIGNMENTS[$cellAlignment]);
- }
-}
diff --git a/upstream-3.x/src/Common/Entity/Style/Color.php b/upstream-3.x/src/Common/Entity/Style/Color.php
deleted file mode 100644
index cd9bdfd..0000000
--- a/upstream-3.x/src/Common/Entity/Style/Color.php
+++ /dev/null
@@ -1,86 +0,0 @@
- 255) {
- throw new InvalidColorException("The RGB components must be between 0 and 255. Received: {$colorComponent}");
- }
- }
-
- /**
- * Converts the color component to its corresponding hexadecimal value.
- *
- * @param int $colorComponent Color component, 0 - 255
- *
- * @return string Corresponding hexadecimal value, with a leading 0 if needed. E.g "0f", "2d"
- */
- protected static function convertColorComponentToHex($colorComponent)
- {
- return str_pad(dechex($colorComponent), 2, '0', STR_PAD_LEFT);
- }
-}
diff --git a/upstream-3.x/src/Common/Entity/Style/Style.php b/upstream-3.x/src/Common/Entity/Style/Style.php
deleted file mode 100644
index 28f1597..0000000
--- a/upstream-3.x/src/Common/Entity/Style/Style.php
+++ /dev/null
@@ -1,549 +0,0 @@
-id;
- }
-
- /**
- * @param int $id
- *
- * @return Style
- */
- public function setId($id)
- {
- $this->id = $id;
-
- return $this;
- }
-
- /**
- * @return null|Border
- */
- public function getBorder()
- {
- return $this->border;
- }
-
- /**
- * @return Style
- */
- public function setBorder(Border $border)
- {
- $this->shouldApplyBorder = true;
- $this->border = $border;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function shouldApplyBorder()
- {
- return $this->shouldApplyBorder;
- }
-
- /**
- * @return bool
- */
- public function isFontBold()
- {
- return $this->fontBold;
- }
-
- /**
- * @return Style
- */
- public function setFontBold()
- {
- $this->fontBold = true;
- $this->hasSetFontBold = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontBold()
- {
- return $this->hasSetFontBold;
- }
-
- /**
- * @return bool
- */
- public function isFontItalic()
- {
- return $this->fontItalic;
- }
-
- /**
- * @return Style
- */
- public function setFontItalic()
- {
- $this->fontItalic = true;
- $this->hasSetFontItalic = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontItalic()
- {
- return $this->hasSetFontItalic;
- }
-
- /**
- * @return bool
- */
- public function isFontUnderline()
- {
- return $this->fontUnderline;
- }
-
- /**
- * @return Style
- */
- public function setFontUnderline()
- {
- $this->fontUnderline = true;
- $this->hasSetFontUnderline = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontUnderline()
- {
- return $this->hasSetFontUnderline;
- }
-
- /**
- * @return bool
- */
- public function isFontStrikethrough()
- {
- return $this->fontStrikethrough;
- }
-
- /**
- * @return Style
- */
- public function setFontStrikethrough()
- {
- $this->fontStrikethrough = true;
- $this->hasSetFontStrikethrough = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontStrikethrough()
- {
- return $this->hasSetFontStrikethrough;
- }
-
- /**
- * @return int
- */
- public function getFontSize()
- {
- return $this->fontSize;
- }
-
- /**
- * @param int $fontSize Font size, in pixels
- *
- * @return Style
- */
- public function setFontSize($fontSize)
- {
- $this->fontSize = $fontSize;
- $this->hasSetFontSize = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontSize()
- {
- return $this->hasSetFontSize;
- }
-
- /**
- * @return string
- */
- public function getFontColor()
- {
- return $this->fontColor;
- }
-
- /**
- * Sets the font color.
- *
- * @param string $fontColor ARGB color (@see Color)
- *
- * @return Style
- */
- public function setFontColor($fontColor)
- {
- $this->fontColor = $fontColor;
- $this->hasSetFontColor = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontColor()
- {
- return $this->hasSetFontColor;
- }
-
- /**
- * @return string
- */
- public function getFontName()
- {
- return $this->fontName;
- }
-
- /**
- * @param string $fontName Name of the font to use
- *
- * @return Style
- */
- public function setFontName($fontName)
- {
- $this->fontName = $fontName;
- $this->hasSetFontName = true;
- $this->shouldApplyFont = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetFontName()
- {
- return $this->hasSetFontName;
- }
-
- /**
- * @return string
- */
- public function getCellAlignment()
- {
- return $this->cellAlignment;
- }
-
- /**
- * @param string $cellAlignment The cell alignment
- *
- * @return Style
- */
- public function setCellAlignment($cellAlignment)
- {
- $this->cellAlignment = $cellAlignment;
- $this->hasSetCellAlignment = true;
- $this->shouldApplyCellAlignment = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetCellAlignment()
- {
- return $this->hasSetCellAlignment;
- }
-
- /**
- * @return bool Whether specific cell alignment should be applied
- */
- public function shouldApplyCellAlignment()
- {
- return $this->shouldApplyCellAlignment;
- }
-
- /**
- * @return bool
- */
- public function shouldWrapText()
- {
- return $this->shouldWrapText;
- }
-
- /**
- * @param bool $shouldWrap Should the text be wrapped
- *
- * @return Style
- */
- public function setShouldWrapText($shouldWrap = true)
- {
- $this->shouldWrapText = $shouldWrap;
- $this->hasSetWrapText = true;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return bool
- */
- public function hasSetWrapText()
- {
- return $this->hasSetWrapText;
- }
-
- /**
- * @return bool Whether specific font properties should be applied
- */
- public function shouldApplyFont()
- {
- return $this->shouldApplyFont;
- }
-
- /**
- * Sets the background color.
- *
- * @param string $color ARGB color (@see Color)
- *
- * @return Style
- */
- public function setBackgroundColor($color)
- {
- $this->hasSetBackgroundColor = true;
- $this->backgroundColor = $color;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return null|string
- */
- public function getBackgroundColor()
- {
- return $this->backgroundColor;
- }
-
- /**
- * @return bool Whether the background color should be applied
- */
- public function shouldApplyBackgroundColor()
- {
- return $this->hasSetBackgroundColor;
- }
-
- /**
- * Sets format.
- *
- * @param string $format
- *
- * @return Style
- */
- public function setFormat($format)
- {
- $this->hasSetFormat = true;
- $this->format = $format;
- $this->isEmpty = false;
-
- return $this;
- }
-
- /**
- * @return null|string
- */
- public function getFormat()
- {
- return $this->format;
- }
-
- /**
- * @return bool Whether format should be applied
- */
- public function shouldApplyFormat()
- {
- return $this->hasSetFormat;
- }
-
- public function isRegistered(): bool
- {
- return $this->isRegistered;
- }
-
- public function markAsRegistered(?int $id): void
- {
- $this->setId($id);
- $this->isRegistered = true;
- }
-
- public function unmarkAsRegistered(): void
- {
- $this->setId(0);
- $this->isRegistered = false;
- }
-
- public function isEmpty(): bool
- {
- return $this->isEmpty;
- }
-
- /**
- * Sets should shrink to fit.
- *
- * @param bool $shrinkToFit
- *
- * @return Style
- */
- public function setShouldShrinkToFit($shrinkToFit = true)
- {
- $this->hasSetShrinkToFit = true;
- $this->shouldShrinkToFit = $shrinkToFit;
-
- return $this;
- }
-
- /**
- * @return bool Whether format should be applied
- */
- public function shouldShrinkToFit()
- {
- return $this->shouldShrinkToFit;
- }
-
- /**
- * @return bool
- */
- public function hasSetShrinkToFit()
- {
- return $this->hasSetShrinkToFit;
- }
-}
diff --git a/upstream-3.x/src/Common/Exception/EncodingConversionException.php b/upstream-3.x/src/Common/Exception/EncodingConversionException.php
deleted file mode 100644
index ef0cdc6..0000000
--- a/upstream-3.x/src/Common/Exception/EncodingConversionException.php
+++ /dev/null
@@ -1,7 +0,0 @@
-globalFunctionsHelper = $globalFunctionsHelper;
-
- $this->supportedEncodingsWithBom = [
- self::ENCODING_UTF8 => self::BOM_UTF8,
- self::ENCODING_UTF16_LE => self::BOM_UTF16_LE,
- self::ENCODING_UTF16_BE => self::BOM_UTF16_BE,
- self::ENCODING_UTF32_LE => self::BOM_UTF32_LE,
- self::ENCODING_UTF32_BE => self::BOM_UTF32_BE,
- ];
- }
-
- /**
- * Returns the number of bytes to use as offset in order to skip the BOM.
- *
- * @param resource $filePointer Pointer to the file to check
- * @param string $encoding Encoding of the file to check
- *
- * @return int Bytes offset to apply to skip the BOM (0 means no BOM)
- */
- public function getBytesOffsetToSkipBOM($filePointer, $encoding)
- {
- $byteOffsetToSkipBom = 0;
-
- if ($this->hasBOM($filePointer, $encoding)) {
- $bomUsed = $this->supportedEncodingsWithBom[$encoding];
-
- // we skip the N first bytes
- $byteOffsetToSkipBom = \strlen($bomUsed);
- }
-
- return $byteOffsetToSkipBom;
- }
-
- /**
- * Attempts to convert a non UTF-8 string into UTF-8.
- *
- * @param string $string Non UTF-8 string to be converted
- * @param string $sourceEncoding The encoding used to encode the source string
- *
- * @throws \OpenSpout\Common\Exception\EncodingConversionException If conversion is not supported or if the conversion failed
- *
- * @return string The converted, UTF-8 string
- */
- public function attemptConversionToUTF8($string, $sourceEncoding)
- {
- return $this->attemptConversion($string, $sourceEncoding, self::ENCODING_UTF8);
- }
-
- /**
- * Attempts to convert a UTF-8 string into the given encoding.
- *
- * @param string $string UTF-8 string to be converted
- * @param string $targetEncoding The encoding the string should be re-encoded into
- *
- * @throws \OpenSpout\Common\Exception\EncodingConversionException If conversion is not supported or if the conversion failed
- *
- * @return string The converted string, encoded with the given encoding
- */
- public function attemptConversionFromUTF8($string, $targetEncoding)
- {
- return $this->attemptConversion($string, self::ENCODING_UTF8, $targetEncoding);
- }
-
- /**
- * Returns whether the file identified by the given pointer has a BOM.
- *
- * @param resource $filePointer Pointer to the file to check
- * @param string $encoding Encoding of the file to check
- *
- * @return bool TRUE if the file has a BOM, FALSE otherwise
- */
- protected function hasBOM($filePointer, $encoding)
- {
- $hasBOM = false;
-
- $this->globalFunctionsHelper->rewind($filePointer);
-
- if (\array_key_exists($encoding, $this->supportedEncodingsWithBom)) {
- $potentialBom = $this->supportedEncodingsWithBom[$encoding];
- $numBytesInBom = \strlen($potentialBom);
-
- $hasBOM = ($this->globalFunctionsHelper->fgets($filePointer, $numBytesInBom + 1) === $potentialBom);
- }
-
- return $hasBOM;
- }
-
- /**
- * Attempts to convert the given string to the given encoding.
- * Depending on what is installed on the server, we will try to iconv or mbstring.
- *
- * @param string $string string to be converted
- * @param string $sourceEncoding The encoding used to encode the source string
- * @param string $targetEncoding The encoding the string should be re-encoded into
- *
- * @throws \OpenSpout\Common\Exception\EncodingConversionException If conversion is not supported or if the conversion failed
- *
- * @return string The converted string, encoded with the given encoding
- */
- protected function attemptConversion($string, $sourceEncoding, $targetEncoding)
- {
- // if source and target encodings are the same, it's a no-op
- if ($sourceEncoding === $targetEncoding) {
- return $string;
- }
-
- $convertedString = null;
-
- if ($this->canUseIconv()) {
- $convertedString = $this->globalFunctionsHelper->iconv($string, $sourceEncoding, $targetEncoding);
- } elseif ($this->canUseMbString()) {
- $convertedString = $this->globalFunctionsHelper->mb_convert_encoding($string, $sourceEncoding, $targetEncoding);
- } else {
- throw new EncodingConversionException("The conversion from {$sourceEncoding} to {$targetEncoding} is not supported. Please install \"iconv\" or \"PHP Intl\".");
- }
-
- if (false === $convertedString) {
- throw new EncodingConversionException("The conversion from {$sourceEncoding} to {$targetEncoding} failed.");
- }
-
- return $convertedString;
- }
-
- /**
- * Returns whether "iconv" can be used.
- *
- * @return bool TRUE if "iconv" is available and can be used, FALSE otherwise
- */
- protected function canUseIconv()
- {
- return $this->globalFunctionsHelper->function_exists('iconv');
- }
-
- /**
- * Returns whether "mb_string" functions can be used.
- * These functions come with the PHP Intl package.
- *
- * @return bool TRUE if "mb_string" functions are available and can be used, FALSE otherwise
- */
- protected function canUseMbString()
- {
- return $this->globalFunctionsHelper->function_exists('mb_convert_encoding');
- }
-}
diff --git a/upstream-3.x/src/Common/Helper/Escaper/CSV.php b/upstream-3.x/src/Common/Helper/Escaper/CSV.php
deleted file mode 100644
index d68199a..0000000
--- a/upstream-3.x/src/Common/Helper/Escaper/CSV.php
+++ /dev/null
@@ -1,37 +0,0 @@
-', '&') as well as
- // single/double quotes (for XML attributes) need to be encoded.
- if (\defined('ENT_DISALLOWED')) {
- /**
- * 'ENT_DISALLOWED' ensures that invalid characters in the given document type are replaced.
- * Otherwise control characters like a vertical tab "\v" will make the XML document unreadable by the XML processor.
- *
- * @see https://github.com/box/spout/issues/329
- */
- $replacedString = htmlspecialchars($string, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8');
- } else {
- // We are on hhvm or any other engine that does not support ENT_DISALLOWED.
- $escapedString = htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
-
- // control characters values are from 0 to 1F (hex values) in the ASCII table
- // some characters should not be escaped though: "\t", "\r" and "\n".
- $regexPattern = '[\x00-\x08'.
- // skipping "\t" (0x9) and "\n" (0xA)
- '\x0B-\x0C'.
- // skipping "\r" (0xD)
- '\x0E-\x1F]';
- $replacedString = preg_replace("/{$regexPattern}/", '�', $escapedString);
- }
-
- return $replacedString;
- }
-
- /**
- * Unescapes the given string to make it compatible with XLSX.
- *
- * @param string $string The string to unescape
- *
- * @return string The unescaped string
- */
- public function unescape($string)
- {
- // ==============
- // = WARNING =
- // ==============
- // It is assumed that the given string has already had its XML entities decoded.
- // This is true if the string is coming from a DOMNode (as DOMNode already decode XML entities on creation).
- // Therefore there is no need to call "htmlspecialchars_decode()".
- return $string;
- }
-}
diff --git a/upstream-3.x/src/Common/Helper/Escaper/XLSX.php b/upstream-3.x/src/Common/Helper/Escaper/XLSX.php
deleted file mode 100644
index 16bb162..0000000
--- a/upstream-3.x/src/Common/Helper/Escaper/XLSX.php
+++ /dev/null
@@ -1,194 +0,0 @@
-initIfNeeded();
-
- $escapedString = $this->escapeControlCharacters($string);
- // @NOTE: Using ENT_QUOTES as XML entities ('<', '>', '&') as well as
- // single/double quotes (for XML attributes) need to be encoded.
- return htmlspecialchars($escapedString, ENT_QUOTES, 'UTF-8');
- }
-
- /**
- * Unescapes the given string to make it compatible with XLSX.
- *
- * @param string $string The string to unescape
- *
- * @return string The unescaped string
- */
- public function unescape($string)
- {
- $this->initIfNeeded();
-
- // ==============
- // = WARNING =
- // ==============
- // It is assumed that the given string has already had its XML entities decoded.
- // This is true if the string is coming from a DOMNode (as DOMNode already decode XML entities on creation).
- // Therefore there is no need to call "htmlspecialchars_decode()".
- return $this->unescapeControlCharacters($string);
- }
-
- /**
- * Initializes the control characters if not already done.
- */
- protected function initIfNeeded()
- {
- if (!$this->isAlreadyInitialized) {
- $this->escapableControlCharactersPattern = $this->getEscapableControlCharactersPattern();
- $this->controlCharactersEscapingMap = $this->getControlCharactersEscapingMap();
- $this->controlCharactersEscapingReverseMap = array_flip($this->controlCharactersEscapingMap);
-
- $this->isAlreadyInitialized = true;
- }
- }
-
- /**
- * @return string Regex pattern containing all escapable control characters
- */
- protected function getEscapableControlCharactersPattern()
- {
- // control characters values are from 0 to 1F (hex values) in the ASCII table
- // some characters should not be escaped though: "\t", "\r" and "\n".
- return '[\x00-\x08'.
- // skipping "\t" (0x9) and "\n" (0xA)
- '\x0B-\x0C'.
- // skipping "\r" (0xD)
- '\x0E-\x1F]';
- }
-
- /**
- * Builds the map containing control characters to be escaped
- * mapped to their escaped values.
- * "\t", "\r" and "\n" don't need to be escaped.
- *
- * NOTE: the logic has been adapted from the XlsxWriter library (BSD License)
- *
- * @see https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89
- *
- * @return string[]
- */
- protected function getControlCharactersEscapingMap()
- {
- $controlCharactersEscapingMap = [];
-
- // control characters values are from 0 to 1F (hex values) in the ASCII table
- for ($charValue = 0x00; $charValue <= 0x1F; ++$charValue) {
- $character = \chr($charValue);
- if (preg_match("/{$this->escapableControlCharactersPattern}/", $character)) {
- $charHexValue = dechex($charValue);
- $escapedChar = '_x'.sprintf('%04s', strtoupper($charHexValue)).'_';
- $controlCharactersEscapingMap[$escapedChar] = $character;
- }
- }
-
- return $controlCharactersEscapingMap;
- }
-
- /**
- * Converts PHP control characters from the given string to OpenXML escaped control characters.
- *
- * Excel escapes control characters with _xHHHH_ and also escapes any
- * literal strings of that type by encoding the leading underscore.
- * So "\0" -> _x0000_ and "_x0000_" -> _x005F_x0000_.
- *
- * NOTE: the logic has been adapted from the XlsxWriter library (BSD License)
- *
- * @see https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89
- *
- * @param string $string String to escape
- *
- * @return string
- */
- protected function escapeControlCharacters($string)
- {
- $escapedString = $this->escapeEscapeCharacter($string);
-
- // if no control characters
- if (!preg_match("/{$this->escapableControlCharactersPattern}/", $escapedString)) {
- return $escapedString;
- }
-
- return preg_replace_callback("/({$this->escapableControlCharactersPattern})/", function ($matches) {
- return $this->controlCharactersEscapingReverseMap[$matches[0]];
- }, $escapedString);
- }
-
- /**
- * Escapes the escape character: "_x0000_" -> "_x005F_x0000_".
- *
- * @param string $string String to escape
- *
- * @return string The escaped string
- */
- protected function escapeEscapeCharacter($string)
- {
- return preg_replace('/_(x[\dA-F]{4})_/', '_x005F_$1_', $string);
- }
-
- /**
- * Converts OpenXML escaped control characters from the given string to PHP control characters.
- *
- * Excel escapes control characters with _xHHHH_ and also escapes any
- * literal strings of that type by encoding the leading underscore.
- * So "_x0000_" -> "\0" and "_x005F_x0000_" -> "_x0000_"
- *
- * NOTE: the logic has been adapted from the XlsxWriter library (BSD License)
- *
- * @see https://github.com/jmcnamara/XlsxWriter/blob/f1e610f29/xlsxwriter/sharedstrings.py#L89
- *
- * @param string $string String to unescape
- *
- * @return string
- */
- protected function unescapeControlCharacters($string)
- {
- $unescapedString = $string;
-
- foreach ($this->controlCharactersEscapingMap as $escapedCharValue => $charValue) {
- // only unescape characters that don't contain the escaped escape character for now
- $unescapedString = preg_replace("/(?unescapeEscapeCharacter($unescapedString);
- }
-
- /**
- * Unecapes the escape character: "_x005F_x0000_" => "_x0000_".
- *
- * @param string $string String to unescape
- *
- * @return string The unescaped string
- */
- protected function unescapeEscapeCharacter($string)
- {
- return preg_replace('/_x005F(_x[\dA-F]{4}_)/', '$1', $string);
- }
-}
diff --git a/upstream-3.x/src/Common/Helper/FileSystemHelper.php b/upstream-3.x/src/Common/Helper/FileSystemHelper.php
deleted file mode 100644
index 130f1f8..0000000
--- a/upstream-3.x/src/Common/Helper/FileSystemHelper.php
+++ /dev/null
@@ -1,138 +0,0 @@
-baseFolderRealPath = realpath($baseFolderPath);
- }
-
- /**
- * Creates an empty folder with the given name under the given parent folder.
- *
- * @param string $parentFolderPath The parent folder path under which the folder is going to be created
- * @param string $folderName The name of the folder to create
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder or if the folder path is not inside of the base folder
- *
- * @return string Path of the created folder
- */
- public function createFolder($parentFolderPath, $folderName)
- {
- $this->throwIfOperationNotInBaseFolder($parentFolderPath);
-
- $folderPath = $parentFolderPath.'/'.$folderName;
-
- $wasCreationSuccessful = mkdir($folderPath, 0777, true);
- if (!$wasCreationSuccessful) {
- throw new IOException("Unable to create folder: {$folderPath}");
- }
-
- return $folderPath;
- }
-
- /**
- * Creates a file with the given name and content in the given folder.
- * The parent folder must exist.
- *
- * @param string $parentFolderPath The parent folder path where the file is going to be created
- * @param string $fileName The name of the file to create
- * @param string $fileContents The contents of the file to create
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file or if the file path is not inside of the base folder
- *
- * @return string Path of the created file
- */
- public function createFileWithContents($parentFolderPath, $fileName, $fileContents)
- {
- $this->throwIfOperationNotInBaseFolder($parentFolderPath);
-
- $filePath = $parentFolderPath.'/'.$fileName;
-
- $wasCreationSuccessful = file_put_contents($filePath, $fileContents);
- if (false === $wasCreationSuccessful) {
- throw new IOException("Unable to create file: {$filePath}");
- }
-
- return $filePath;
- }
-
- /**
- * Delete the file at the given path.
- *
- * @param string $filePath Path of the file to delete
- *
- * @throws \OpenSpout\Common\Exception\IOException If the file path is not inside of the base folder
- */
- public function deleteFile($filePath)
- {
- $this->throwIfOperationNotInBaseFolder($filePath);
-
- if (file_exists($filePath) && is_file($filePath)) {
- unlink($filePath);
- }
- }
-
- /**
- * Delete the folder at the given path as well as all its contents.
- *
- * @param string $folderPath Path of the folder to delete
- *
- * @throws \OpenSpout\Common\Exception\IOException If the folder path is not inside of the base folder
- */
- public function deleteFolderRecursively($folderPath)
- {
- $this->throwIfOperationNotInBaseFolder($folderPath);
-
- $itemIterator = new \RecursiveIteratorIterator(
- new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS),
- \RecursiveIteratorIterator::CHILD_FIRST
- );
-
- foreach ($itemIterator as $item) {
- if ($item->isDir()) {
- rmdir($item->getPathname());
- } else {
- unlink($item->getPathname());
- }
- }
-
- rmdir($folderPath);
- }
-
- /**
- * All I/O operations must occur inside the base folder, for security reasons.
- * This function will throw an exception if the folder where the I/O operation
- * should occur is not inside the base folder.
- *
- * @param string $operationFolderPath The path of the folder where the I/O operation should occur
- *
- * @throws \OpenSpout\Common\Exception\IOException If the folder where the I/O operation should occur
- * is not inside the base folder or the base folder does not exist
- */
- protected function throwIfOperationNotInBaseFolder(string $operationFolderPath)
- {
- $operationFolderRealPath = realpath($operationFolderPath);
- if (!$this->baseFolderRealPath) {
- throw new IOException("The base folder path is invalid: {$this->baseFolderRealPath}");
- }
- $isInBaseFolder = (0 === strpos($operationFolderRealPath, $this->baseFolderRealPath));
- if (!$isInBaseFolder) {
- throw new IOException("Cannot perform I/O operation outside of the base folder: {$this->baseFolderRealPath}");
- }
- }
-}
diff --git a/upstream-3.x/src/Common/Helper/FileSystemHelperInterface.php b/upstream-3.x/src/Common/Helper/FileSystemHelperInterface.php
deleted file mode 100644
index 90082d2..0000000
--- a/upstream-3.x/src/Common/Helper/FileSystemHelperInterface.php
+++ /dev/null
@@ -1,54 +0,0 @@
-= 70400 ? '' : "\0";
-
- return fgetcsv($handle, $length, $delimiter, $enclosure, $escapeCharacter);
- }
-
- /**
- * Wrapper around global function fputcsv().
- *
- * @see fputcsv()
- *
- * @param resource $handle
- * @param null|string $delimiter
- * @param null|string $enclosure
- *
- * @return false|int
- */
- public function fputcsv($handle, array $fields, $delimiter = null, $enclosure = null)
- {
- /**
- * PHP uses '\' as the default escape character. This is not RFC-4180 compliant...
- * To fix that, simply disable the escape character.
- *
- * @see https://bugs.php.net/bug.php?id=43225
- * @see http://tools.ietf.org/html/rfc4180
- */
- $escapeCharacter = \PHP_VERSION_ID >= 70400 ? '' : "\0";
-
- return fputcsv($handle, $fields, $delimiter, $enclosure, $escapeCharacter);
- }
-
- /**
- * Wrapper around global function fwrite().
- *
- * @see fwrite()
- *
- * @param resource $handle
- * @param string $string
- *
- * @return int
- */
- public function fwrite($handle, $string)
- {
- return fwrite($handle, $string);
- }
-
- /**
- * Wrapper around global function fclose().
- *
- * @see fclose()
- *
- * @param resource $handle
- *
- * @return bool
- */
- public function fclose($handle)
- {
- return fclose($handle);
- }
-
- /**
- * Wrapper around global function rewind().
- *
- * @see rewind()
- *
- * @param resource $handle
- *
- * @return bool
- */
- public function rewind($handle)
- {
- return rewind($handle);
- }
-
- /**
- * Wrapper around global function file_exists().
- *
- * @see file_exists()
- *
- * @param string $fileName
- *
- * @return bool
- */
- public function file_exists($fileName)
- {
- return file_exists($fileName);
- }
-
- /**
- * Wrapper around global function file_get_contents().
- *
- * @see file_get_contents()
- *
- * @param string $filePath
- *
- * @return string
- */
- public function file_get_contents($filePath)
- {
- $realFilePath = $this->convertToUseRealPath($filePath);
-
- return file_get_contents($realFilePath);
- }
-
- /**
- * Wrapper around global function feof().
- *
- * @see feof()
- *
- * @param resource $handle
- *
- * @return bool
- */
- public function feof($handle)
- {
- return feof($handle);
- }
-
- /**
- * Wrapper around global function is_readable().
- *
- * @see is_readable()
- *
- * @param string $fileName
- *
- * @return bool
- */
- public function is_readable($fileName)
- {
- return is_readable($fileName);
- }
-
- /**
- * Wrapper around global function basename().
- *
- * @see basename()
- *
- * @param string $path
- * @param string $suffix
- *
- * @return string
- */
- public function basename($path, $suffix = '')
- {
- return basename($path, $suffix);
- }
-
- /**
- * Wrapper around global function header().
- *
- * @see header()
- *
- * @param string $string
- */
- public function header($string)
- {
- header($string);
- }
-
- /**
- * Wrapper around global function ob_end_clean().
- *
- * @see ob_end_clean()
- */
- public function ob_end_clean()
- {
- if (ob_get_length() > 0) {
- ob_end_clean();
- }
- }
-
- /**
- * Wrapper around global function iconv().
- *
- * @see iconv()
- *
- * @param string $string The string to be converted
- * @param string $sourceEncoding The encoding of the source string
- * @param string $targetEncoding The encoding the source string should be converted to
- *
- * @return bool|string the converted string or FALSE on failure
- */
- public function iconv($string, $sourceEncoding, $targetEncoding)
- {
- return iconv($sourceEncoding, $targetEncoding, $string);
- }
-
- /**
- * Wrapper around global function mb_convert_encoding().
- *
- * @see mb_convert_encoding()
- *
- * @param string $string The string to be converted
- * @param string $sourceEncoding The encoding of the source string
- * @param string $targetEncoding The encoding the source string should be converted to
- *
- * @return bool|string the converted string or FALSE on failure
- */
- public function mb_convert_encoding($string, $sourceEncoding, $targetEncoding)
- {
- return mb_convert_encoding($string, $targetEncoding, $sourceEncoding);
- }
-
- /**
- * Wrapper around global function stream_get_wrappers().
- *
- * @see stream_get_wrappers()
- *
- * @return array
- */
- public function stream_get_wrappers()
- {
- return stream_get_wrappers();
- }
-
- /**
- * Wrapper around global function function_exists().
- *
- * @see function_exists()
- *
- * @param string $functionName
- *
- * @return bool
- */
- public function function_exists($functionName)
- {
- return \function_exists($functionName);
- }
-
- /**
- * Updates the given file path to use a real path.
- * This is to avoid issues on some Windows setup.
- *
- * @param string $filePath File path
- *
- * @return string The file path using a real path
- */
- protected function convertToUseRealPath($filePath)
- {
- $realFilePath = $filePath;
-
- if ($this->isZipStream($filePath)) {
- if (preg_match('/zip:\/\/(.*)#(.*)/', $filePath, $matches)) {
- $documentPath = $matches[1];
- $documentInsideZipPath = $matches[2];
- $realFilePath = 'zip://'.realpath($documentPath).'#'.$documentInsideZipPath;
- }
- } else {
- $realFilePath = realpath($filePath);
- }
-
- return $realFilePath;
- }
-
- /**
- * Returns whether the given path is a zip stream.
- *
- * @param string $path Path pointing to a document
- *
- * @return bool TRUE if path is a zip stream, FALSE otherwise
- */
- protected function isZipStream($path)
- {
- return 0 === strpos($path, 'zip://');
- }
-}
diff --git a/upstream-3.x/src/Common/Helper/StringHelper.php b/upstream-3.x/src/Common/Helper/StringHelper.php
deleted file mode 100644
index 96e7f2c..0000000
--- a/upstream-3.x/src/Common/Helper/StringHelper.php
+++ /dev/null
@@ -1,108 +0,0 @@
-hasMbstringSupport = \extension_loaded('mbstring');
- $this->isRunningPhp7OrOlder = version_compare(PHP_VERSION, '8.0.0') < 0;
- $this->localeInfo = localeconv();
- }
-
- /**
- * Returns the length of the given string.
- * It uses the multi-bytes function is available.
- *
- * @see strlen
- * @see mb_strlen
- *
- * @param string $string
- *
- * @return int
- */
- public function getStringLength($string)
- {
- return $this->hasMbstringSupport ? mb_strlen($string) : \strlen($string);
- }
-
- /**
- * Returns the position of the first occurrence of the given character/substring within the given string.
- * It uses the multi-bytes function is available.
- *
- * @see strpos
- * @see mb_strpos
- *
- * @param string $char Needle
- * @param string $string Haystack
- *
- * @return int Char/substring's first occurrence position within the string if found (starts at 0) or -1 if not found
- */
- public function getCharFirstOccurrencePosition($char, $string)
- {
- $position = $this->hasMbstringSupport ? mb_strpos($string, $char) : strpos($string, $char);
-
- return (false !== $position) ? $position : -1;
- }
-
- /**
- * Returns the position of the last occurrence of the given character/substring within the given string.
- * It uses the multi-bytes function is available.
- *
- * @see strrpos
- * @see mb_strrpos
- *
- * @param string $char Needle
- * @param string $string Haystack
- *
- * @return int Char/substring's last occurrence position within the string if found (starts at 0) or -1 if not found
- */
- public function getCharLastOccurrencePosition($char, $string)
- {
- $position = $this->hasMbstringSupport ? mb_strrpos($string, $char) : strrpos($string, $char);
-
- return (false !== $position) ? $position : -1;
- }
-
- /**
- * Formats a numeric value (int or float) in a way that's compatible with the expected spreadsheet format.
- *
- * Formatting of float values is locale dependent in PHP < 8.
- * Thousands separators and decimal points vary from locale to locale (en_US: 12.34 vs pl_PL: 12,34).
- * However, float values must be formatted with no thousands separator and a "." as decimal point
- * to work properly. This method can be used to convert the value to the correct format before storing it.
- *
- * @see https://wiki.php.net/rfc/locale_independent_float_to_string for the changed behavior in PHP8.
- *
- * @param float|int $numericValue
- *
- * @return float|int|string
- */
- public function formatNumericValue($numericValue)
- {
- if ($this->isRunningPhp7OrOlder && \is_float($numericValue)) {
- return str_replace(
- [$this->localeInfo['thousands_sep'], $this->localeInfo['decimal_point']],
- ['', '.'],
- (string) $numericValue
- );
- }
-
- return $numericValue;
- }
-}
diff --git a/upstream-3.x/src/Common/Manager/OptionsManagerAbstract.php b/upstream-3.x/src/Common/Manager/OptionsManagerAbstract.php
deleted file mode 100644
index 3bfce39..0000000
--- a/upstream-3.x/src/Common/Manager/OptionsManagerAbstract.php
+++ /dev/null
@@ -1,82 +0,0 @@
- OPTION_VALUE] */
- private $options = [];
-
- /**
- * OptionsManagerAbstract constructor.
- */
- public function __construct()
- {
- $this->supportedOptions = $this->getSupportedOptions();
- $this->setDefaultOptions();
- }
-
- /**
- * Sets the given option, if this option is supported.
- *
- * @param string $optionName
- * @param mixed $optionValue
- */
- public function setOption($optionName, $optionValue)
- {
- if (\in_array($optionName, $this->supportedOptions, true)) {
- $this->options[$optionName] = $optionValue;
- }
- }
-
- /**
- * Add an option to the internal list of options
- * Used only for mergeCells() for now.
- *
- * @param mixed $optionName
- * @param mixed $optionValue
- */
- public function addOption($optionName, $optionValue)
- {
- if (\in_array($optionName, $this->supportedOptions, true)) {
- if (!isset($this->options[$optionName])) {
- $this->options[$optionName] = [];
- } elseif (!\is_array($this->options[$optionName])) {
- $this->options[$optionName] = [$this->options[$optionName]];
- }
- $this->options[$optionName][] = $optionValue;
- }
- }
-
- /**
- * @param string $optionName
- *
- * @return null|mixed The set option or NULL if no option with given name found
- */
- public function getOption($optionName)
- {
- $optionValue = null;
-
- if (isset($this->options[$optionName])) {
- $optionValue = $this->options[$optionName];
- }
-
- return $optionValue;
- }
-
- /**
- * @return array List of supported options
- */
- abstract protected function getSupportedOptions();
-
- /**
- * Sets the default options.
- * To be overriden by child classes.
- */
- abstract protected function setDefaultOptions();
-}
diff --git a/upstream-3.x/src/Common/Manager/OptionsManagerInterface.php b/upstream-3.x/src/Common/Manager/OptionsManagerInterface.php
deleted file mode 100644
index 7913017..0000000
--- a/upstream-3.x/src/Common/Manager/OptionsManagerInterface.php
+++ /dev/null
@@ -1,31 +0,0 @@
-helperFactory = $helperFactory;
- }
-
- /**
- * @param resource $filePointer Pointer to the CSV file to read
- * @param OptionsManagerInterface $optionsManager
- * @param GlobalFunctionsHelper $globalFunctionsHelper
- *
- * @return SheetIterator
- */
- public function createSheetIterator($filePointer, $optionsManager, $globalFunctionsHelper)
- {
- $rowIterator = $this->createRowIterator($filePointer, $optionsManager, $globalFunctionsHelper);
- $sheet = $this->createSheet($rowIterator);
-
- return new SheetIterator($sheet);
- }
-
- /**
- * @param Cell[] $cells
- *
- * @return Row
- */
- public function createRow(array $cells = [])
- {
- return new Row($cells, null);
- }
-
- /**
- * @param mixed $cellValue
- *
- * @return Cell
- */
- public function createCell($cellValue)
- {
- return new Cell($cellValue);
- }
-
- /**
- * @return Row
- */
- public function createRowFromArray(array $cellValues = [])
- {
- $cells = array_map(function ($cellValue) {
- return $this->createCell($cellValue);
- }, $cellValues);
-
- return $this->createRow($cells);
- }
-
- /**
- * @param RowIterator $rowIterator
- *
- * @return Sheet
- */
- private function createSheet($rowIterator)
- {
- return new Sheet($rowIterator);
- }
-
- /**
- * @param resource $filePointer Pointer to the CSV file to read
- * @param OptionsManagerInterface $optionsManager
- * @param GlobalFunctionsHelper $globalFunctionsHelper
- *
- * @return RowIterator
- */
- private function createRowIterator($filePointer, $optionsManager, $globalFunctionsHelper)
- {
- $encodingHelper = $this->helperFactory->createEncodingHelper($globalFunctionsHelper);
-
- return new RowIterator($filePointer, $optionsManager, $encodingHelper, $this, $globalFunctionsHelper);
- }
-}
diff --git a/upstream-3.x/src/Reader/CSV/Manager/OptionsManager.php b/upstream-3.x/src/Reader/CSV/Manager/OptionsManager.php
deleted file mode 100644
index 9772a43..0000000
--- a/upstream-3.x/src/Reader/CSV/Manager/OptionsManager.php
+++ /dev/null
@@ -1,39 +0,0 @@
-setOption(Options::SHOULD_FORMAT_DATES, false);
- $this->setOption(Options::SHOULD_PRESERVE_EMPTY_ROWS, false);
- $this->setOption(Options::FIELD_DELIMITER, ',');
- $this->setOption(Options::FIELD_ENCLOSURE, '"');
- $this->setOption(Options::ENCODING, EncodingHelper::ENCODING_UTF8);
- }
-}
diff --git a/upstream-3.x/src/Reader/CSV/Reader.php b/upstream-3.x/src/Reader/CSV/Reader.php
deleted file mode 100644
index d62b933..0000000
--- a/upstream-3.x/src/Reader/CSV/Reader.php
+++ /dev/null
@@ -1,149 +0,0 @@
-= 8.1 */
- private $isRunningAtLeastPhp81;
-
- public function __construct(
- OptionsManagerInterface $optionsManager,
- GlobalFunctionsHelper $globalFunctionsHelper,
- InternalEntityFactoryInterface $entityFactory
- ) {
- parent::__construct($optionsManager, $globalFunctionsHelper, $entityFactory);
- $this->isRunningAtLeastPhp81 = version_compare(PHP_VERSION, '8.1.0') >= 0;
- }
-
- /**
- * Sets the field delimiter for the CSV.
- * Needs to be called before opening the reader.
- *
- * @param string $fieldDelimiter Character that delimits fields
- *
- * @return Reader
- */
- public function setFieldDelimiter($fieldDelimiter)
- {
- $this->optionsManager->setOption(Options::FIELD_DELIMITER, $fieldDelimiter);
-
- return $this;
- }
-
- /**
- * Sets the field enclosure for the CSV.
- * Needs to be called before opening the reader.
- *
- * @param string $fieldEnclosure Character that enclose fields
- *
- * @return Reader
- */
- public function setFieldEnclosure($fieldEnclosure)
- {
- $this->optionsManager->setOption(Options::FIELD_ENCLOSURE, $fieldEnclosure);
-
- return $this;
- }
-
- /**
- * Sets the encoding of the CSV file to be read.
- * Needs to be called before opening the reader.
- *
- * @param string $encoding Encoding of the CSV file to be read
- *
- * @return Reader
- */
- public function setEncoding($encoding)
- {
- $this->optionsManager->setOption(Options::ENCODING, $encoding);
-
- return $this;
- }
-
- /**
- * Returns whether stream wrappers are supported.
- *
- * @return bool
- */
- protected function doesSupportStreamWrapper()
- {
- return true;
- }
-
- /**
- * Opens the file at the given path to make it ready to be read.
- * If setEncoding() was not called, it assumes that the file is encoded in UTF-8.
- *
- * @param string $filePath Path of the CSV file to be read
- *
- * @throws \OpenSpout\Common\Exception\IOException
- */
- protected function openReader($filePath)
- {
- // "auto_detect_line_endings" is deprecated in PHP 8.1
- if (!$this->isRunningAtLeastPhp81) {
- $this->originalAutoDetectLineEndings = ini_get('auto_detect_line_endings');
- ini_set('auto_detect_line_endings', '1');
- }
-
- $this->filePointer = $this->globalFunctionsHelper->fopen($filePath, 'r');
- if (!$this->filePointer) {
- throw new IOException("Could not open file {$filePath} for reading.");
- }
-
- /** @var InternalEntityFactory $entityFactory */
- $entityFactory = $this->entityFactory;
-
- $this->sheetIterator = $entityFactory->createSheetIterator(
- $this->filePointer,
- $this->optionsManager,
- $this->globalFunctionsHelper
- );
- }
-
- /**
- * Returns an iterator to iterate over sheets.
- *
- * @return SheetIterator To iterate over sheets
- */
- protected function getConcreteSheetIterator()
- {
- return $this->sheetIterator;
- }
-
- /**
- * Closes the reader. To be used after reading the file.
- */
- protected function closeReader()
- {
- if (\is_resource($this->filePointer)) {
- $this->globalFunctionsHelper->fclose($this->filePointer);
- }
-
- // "auto_detect_line_endings" is deprecated in PHP 8.1
- if (!$this->isRunningAtLeastPhp81) {
- ini_set('auto_detect_line_endings', $this->originalAutoDetectLineEndings);
- }
- }
-}
diff --git a/upstream-3.x/src/Reader/CSV/RowIterator.php b/upstream-3.x/src/Reader/CSV/RowIterator.php
deleted file mode 100644
index 497d266..0000000
--- a/upstream-3.x/src/Reader/CSV/RowIterator.php
+++ /dev/null
@@ -1,249 +0,0 @@
-filePointer = $filePointer;
- $this->fieldDelimiter = $optionsManager->getOption(Options::FIELD_DELIMITER);
- $this->fieldEnclosure = $optionsManager->getOption(Options::FIELD_ENCLOSURE);
- $this->encoding = $optionsManager->getOption(Options::ENCODING);
- $this->shouldPreserveEmptyRows = $optionsManager->getOption(Options::SHOULD_PRESERVE_EMPTY_ROWS);
- $this->encodingHelper = $encodingHelper;
- $this->entityFactory = $entityFactory;
- $this->globalFunctionsHelper = $globalFunctionsHelper;
- }
-
- /**
- * Rewind the Iterator to the first element.
- *
- * @see http://php.net/manual/en/iterator.rewind.php
- */
- #[\ReturnTypeWillChange]
- public function rewind(): void
- {
- $this->rewindAndSkipBom();
-
- $this->numReadRows = 0;
- $this->rowBuffer = null;
-
- $this->next();
- }
-
- /**
- * Checks if current position is valid.
- *
- * @see http://php.net/manual/en/iterator.valid.php
- */
- #[\ReturnTypeWillChange]
- public function valid(): bool
- {
- return $this->filePointer && !$this->hasReachedEndOfFile;
- }
-
- /**
- * Move forward to next element. Reads data for the next unprocessed row.
- *
- * @see http://php.net/manual/en/iterator.next.php
- *
- * @throws \OpenSpout\Common\Exception\EncodingConversionException If unable to convert data to UTF-8
- */
- #[\ReturnTypeWillChange]
- public function next(): void
- {
- $this->hasReachedEndOfFile = $this->globalFunctionsHelper->feof($this->filePointer);
-
- if (!$this->hasReachedEndOfFile) {
- $this->readDataForNextRow();
- }
- }
-
- /**
- * Return the current element from the buffer.
- *
- * @see http://php.net/manual/en/iterator.current.php
- */
- #[\ReturnTypeWillChange]
- public function current(): ?Row
- {
- return $this->rowBuffer;
- }
-
- /**
- * Return the key of the current element.
- *
- * @see http://php.net/manual/en/iterator.key.php
- */
- #[\ReturnTypeWillChange]
- public function key(): int
- {
- return $this->numReadRows;
- }
-
- /**
- * Cleans up what was created to iterate over the object.
- */
- #[\ReturnTypeWillChange]
- public function end(): void
- {
- // do nothing
- }
-
- /**
- * This rewinds and skips the BOM if inserted at the beginning of the file
- * by moving the file pointer after it, so that it is not read.
- */
- protected function rewindAndSkipBom()
- {
- $byteOffsetToSkipBom = $this->encodingHelper->getBytesOffsetToSkipBOM($this->filePointer, $this->encoding);
-
- // sets the cursor after the BOM (0 means no BOM, so rewind it)
- $this->globalFunctionsHelper->fseek($this->filePointer, $byteOffsetToSkipBom);
- }
-
- /**
- * @throws \OpenSpout\Common\Exception\EncodingConversionException If unable to convert data to UTF-8
- */
- protected function readDataForNextRow()
- {
- do {
- $rowData = $this->getNextUTF8EncodedRow();
- } while ($this->shouldReadNextRow($rowData));
-
- if (false !== $rowData) {
- // array_map will replace NULL values by empty strings
- $rowDataBufferAsArray = array_map(function ($value) { return (string) $value; }, $rowData);
- $this->rowBuffer = $this->entityFactory->createRowFromArray($rowDataBufferAsArray);
- ++$this->numReadRows;
- } else {
- // If we reach this point, it means end of file was reached.
- // This happens when the last lines are empty lines.
- $this->hasReachedEndOfFile = true;
- }
- }
-
- /**
- * @param array|bool $currentRowData
- *
- * @return bool Whether the data for the current row can be returned or if we need to keep reading
- */
- protected function shouldReadNextRow($currentRowData)
- {
- $hasSuccessfullyFetchedRowData = (false !== $currentRowData);
- $hasNowReachedEndOfFile = $this->globalFunctionsHelper->feof($this->filePointer);
- $isEmptyLine = $this->isEmptyLine($currentRowData);
-
- return
- (!$hasSuccessfullyFetchedRowData && !$hasNowReachedEndOfFile)
- || (!$this->shouldPreserveEmptyRows && $isEmptyLine)
- ;
- }
-
- /**
- * Returns the next row, converted if necessary to UTF-8.
- * As fgetcsv() does not manage correctly encoding for non UTF-8 data,
- * we remove manually whitespace with ltrim or rtrim (depending on the order of the bytes).
- *
- * @throws \OpenSpout\Common\Exception\EncodingConversionException If unable to convert data to UTF-8
- *
- * @return array|false The row for the current file pointer, encoded in UTF-8 or FALSE if nothing to read
- */
- protected function getNextUTF8EncodedRow()
- {
- $encodedRowData = $this->globalFunctionsHelper->fgetcsv($this->filePointer, self::MAX_READ_BYTES_PER_LINE, $this->fieldDelimiter, $this->fieldEnclosure);
- if (false === $encodedRowData) {
- return false;
- }
-
- foreach ($encodedRowData as $cellIndex => $cellValue) {
- switch ($this->encoding) {
- case EncodingHelper::ENCODING_UTF16_LE:
- case EncodingHelper::ENCODING_UTF32_LE:
- // remove whitespace from the beginning of a string as fgetcsv() add extra whitespace when it try to explode non UTF-8 data
- $cellValue = ltrim($cellValue);
-
- break;
-
- case EncodingHelper::ENCODING_UTF16_BE:
- case EncodingHelper::ENCODING_UTF32_BE:
- // remove whitespace from the end of a string as fgetcsv() add extra whitespace when it try to explode non UTF-8 data
- $cellValue = rtrim($cellValue);
-
- break;
- }
-
- $encodedRowData[$cellIndex] = $this->encodingHelper->attemptConversionToUTF8($cellValue, $this->encoding);
- }
-
- return $encodedRowData;
- }
-
- /**
- * @param array|bool $lineData Array containing the cells value for the line
- *
- * @return bool Whether the given line is empty
- */
- protected function isEmptyLine($lineData)
- {
- return \is_array($lineData) && 1 === \count($lineData) && null === $lineData[0];
- }
-}
diff --git a/upstream-3.x/src/Reader/CSV/Sheet.php b/upstream-3.x/src/Reader/CSV/Sheet.php
deleted file mode 100644
index f64b2ee..0000000
--- a/upstream-3.x/src/Reader/CSV/Sheet.php
+++ /dev/null
@@ -1,59 +0,0 @@
-rowIterator = $rowIterator;
- }
-
- /**
- * @return \OpenSpout\Reader\CSV\RowIterator
- */
- public function getRowIterator()
- {
- return $this->rowIterator;
- }
-
- /**
- * @return int Index of the sheet
- */
- public function getIndex()
- {
- return 0;
- }
-
- /**
- * @return string Name of the sheet - empty string since CSV does not support that
- */
- public function getName()
- {
- return '';
- }
-
- /**
- * @return bool Always TRUE as there is only one sheet
- */
- public function isActive()
- {
- return true;
- }
-
- /**
- * @return bool Always TRUE as the only sheet is always visible
- */
- public function isVisible()
- {
- return true;
- }
-}
diff --git a/upstream-3.x/src/Reader/CSV/SheetIterator.php b/upstream-3.x/src/Reader/CSV/SheetIterator.php
deleted file mode 100644
index cbcf7c1..0000000
--- a/upstream-3.x/src/Reader/CSV/SheetIterator.php
+++ /dev/null
@@ -1,89 +0,0 @@
-sheet = $sheet;
- }
-
- /**
- * Rewind the Iterator to the first element.
- *
- * @see http://php.net/manual/en/iterator.rewind.php
- */
- #[\ReturnTypeWillChange]
- public function rewind(): void
- {
- $this->hasReadUniqueSheet = false;
- }
-
- /**
- * Checks if current position is valid.
- *
- * @see http://php.net/manual/en/iterator.valid.php
- */
- #[\ReturnTypeWillChange]
- public function valid(): bool
- {
- return !$this->hasReadUniqueSheet;
- }
-
- /**
- * Move forward to next element.
- *
- * @see http://php.net/manual/en/iterator.next.php
- */
- #[\ReturnTypeWillChange]
- public function next(): void
- {
- $this->hasReadUniqueSheet = true;
- }
-
- /**
- * Return the current element.
- *
- * @see http://php.net/manual/en/iterator.current.php
- */
- #[\ReturnTypeWillChange]
- public function current(): Sheet
- {
- return $this->sheet;
- }
-
- /**
- * Return the key of the current element.
- *
- * @see http://php.net/manual/en/iterator.key.php
- */
- #[\ReturnTypeWillChange]
- public function key(): int
- {
- return 1;
- }
-
- /**
- * Cleans up what was created to iterate over the object.
- */
- #[\ReturnTypeWillChange]
- public function end(): void
- {
- // do nothing
- }
-}
diff --git a/upstream-3.x/src/Reader/Common/Creator/InternalEntityFactoryInterface.php b/upstream-3.x/src/Reader/Common/Creator/InternalEntityFactoryInterface.php
deleted file mode 100644
index e9cee4f..0000000
--- a/upstream-3.x/src/Reader/Common/Creator/InternalEntityFactoryInterface.php
+++ /dev/null
@@ -1,26 +0,0 @@
-createGlobalFunctionsHelper();
-
- return new CSVReader($optionsManager, $globalFunctionsHelper, $entityFactory);
- }
-
- /**
- * @return XLSXReader
- */
- private static function createXLSXReader()
- {
- $optionsManager = new XLSXOptionsManager();
- $helperFactory = new XLSXHelperFactory();
- $managerFactory = new XLSXManagerFactory($helperFactory, new CachingStrategyFactory());
- $entityFactory = new XLSXInternalEntityFactory($managerFactory, $helperFactory);
- $globalFunctionsHelper = $helperFactory->createGlobalFunctionsHelper();
-
- return new XLSXReader($optionsManager, $globalFunctionsHelper, $entityFactory, $managerFactory);
- }
-
- /**
- * @return ODSReader
- */
- private static function createODSReader()
- {
- $optionsManager = new ODSOptionsManager();
- $helperFactory = new ODSHelperFactory();
- $managerFactory = new ODSManagerFactory();
- $entityFactory = new ODSInternalEntityFactory($helperFactory, $managerFactory);
- $globalFunctionsHelper = $helperFactory->createGlobalFunctionsHelper();
-
- return new ODSReader($optionsManager, $globalFunctionsHelper, $entityFactory);
- }
-}
diff --git a/upstream-3.x/src/Reader/Common/Entity/Options.php b/upstream-3.x/src/Reader/Common/Entity/Options.php
deleted file mode 100644
index 48e15a1..0000000
--- a/upstream-3.x/src/Reader/Common/Entity/Options.php
+++ /dev/null
@@ -1,22 +0,0 @@
-entityFactory = $entityFactory;
- }
-
- /**
- * Detect whether a row is considered empty.
- * An empty row has all of its cells empty.
- *
- * @return bool
- */
- public function isEmpty(Row $row)
- {
- foreach ($row->getCells() as $cell) {
- if (!$cell->isEmpty()) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Fills the missing indexes of a row with empty cells.
- *
- * @return Row
- */
- public function fillMissingIndexesWithEmptyCells(Row $row)
- {
- $numCells = $row->getNumCells();
-
- if (0 === $numCells) {
- return $row;
- }
-
- $rowCells = $row->getCells();
- $maxCellIndex = $numCells;
-
- /**
- * If the row has empty cells, calling "setCellAtIndex" will add the cell
- * but in the wrong place (the new cell is added at the end of the array).
- * Therefore, we need to sort the array using keys to have proper order.
- *
- * @see https://github.com/box/spout/issues/740
- */
- $needsSorting = false;
-
- for ($cellIndex = 0; $cellIndex < $maxCellIndex; ++$cellIndex) {
- if (!isset($rowCells[$cellIndex])) {
- $row->setCellAtIndex($this->entityFactory->createCell(''), $cellIndex);
- $needsSorting = true;
- }
- }
-
- if ($needsSorting) {
- $rowCells = $row->getCells();
- ksort($rowCells);
- $row->setCells($rowCells);
- }
-
- return $row;
- }
-}
diff --git a/upstream-3.x/src/Reader/Common/XMLProcessor.php b/upstream-3.x/src/Reader/Common/XMLProcessor.php
deleted file mode 100644
index 967c0ff..0000000
--- a/upstream-3.x/src/Reader/Common/XMLProcessor.php
+++ /dev/null
@@ -1,151 +0,0 @@
-xmlReader = $xmlReader;
- }
-
- /**
- * @param string $nodeName A callback may be triggered when a node with this name is read
- * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END]
- * @param callable $callback Callback to execute when the read node has the given name and type
- *
- * @return XMLProcessor
- */
- public function registerCallback($nodeName, $nodeType, $callback)
- {
- $callbackKey = $this->getCallbackKey($nodeName, $nodeType);
- $this->callbacks[$callbackKey] = $this->getInvokableCallbackData($callback);
-
- return $this;
- }
-
- /**
- * Resumes the reading of the XML file where it was left off.
- * Stops whenever a callback indicates that reading should stop or at the end of the file.
- *
- * @throws \OpenSpout\Reader\Exception\XMLProcessingException
- */
- public function readUntilStopped()
- {
- while ($this->xmlReader->read()) {
- $nodeType = $this->xmlReader->nodeType;
- $nodeNamePossiblyWithPrefix = $this->xmlReader->name;
- $nodeNameWithoutPrefix = $this->xmlReader->localName;
-
- $callbackData = $this->getRegisteredCallbackData($nodeNamePossiblyWithPrefix, $nodeNameWithoutPrefix, $nodeType);
-
- if (null !== $callbackData) {
- $callbackResponse = $this->invokeCallback($callbackData, [$this->xmlReader]);
-
- if (self::PROCESSING_STOP === $callbackResponse) {
- // stop reading
- break;
- }
- }
- }
- }
-
- /**
- * @param string $nodeName Name of the node
- * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END]
- *
- * @return string Key used to store the associated callback
- */
- private function getCallbackKey($nodeName, $nodeType)
- {
- return "{$nodeName}{$nodeType}";
- }
-
- /**
- * Because the callback can be a "protected" function, we don't want to use call_user_func() directly
- * but instead invoke the callback using Reflection. This allows the invocation of "protected" functions.
- * Since some functions can be called a lot, we pre-process the callback to only return the elements that
- * will be needed to invoke the callback later.
- *
- * @param callable $callback Array reference to a callback: [OBJECT, METHOD_NAME]
- *
- * @return array Associative array containing the elements needed to invoke the callback using Reflection
- */
- private function getInvokableCallbackData($callback)
- {
- $callbackObject = $callback[0];
- $callbackMethodName = $callback[1];
- $reflectionMethod = new \ReflectionMethod(\get_class($callbackObject), $callbackMethodName);
- $reflectionMethod->setAccessible(true);
-
- return [
- self::CALLBACK_REFLECTION_METHOD => $reflectionMethod,
- self::CALLBACK_REFLECTION_OBJECT => $callbackObject,
- ];
- }
-
- /**
- * @param string $nodeNamePossiblyWithPrefix Name of the node, possibly prefixed
- * @param string $nodeNameWithoutPrefix Name of the same node, un-prefixed
- * @param int $nodeType Type of the node [NODE_TYPE_START || NODE_TYPE_END]
- *
- * @return null|array Callback data to be used for execution when a node of the given name/type is read or NULL if none found
- */
- private function getRegisteredCallbackData($nodeNamePossiblyWithPrefix, $nodeNameWithoutPrefix, $nodeType)
- {
- // With prefixed nodes, we should match if (by order of preference):
- // 1. the callback was registered with the prefixed node name (e.g. "x:worksheet")
- // 2. the callback was registered with the un-prefixed node name (e.g. "worksheet")
- $callbackKeyForPossiblyPrefixedName = $this->getCallbackKey($nodeNamePossiblyWithPrefix, $nodeType);
- $callbackKeyForUnPrefixedName = $this->getCallbackKey($nodeNameWithoutPrefix, $nodeType);
- $hasPrefix = ($nodeNamePossiblyWithPrefix !== $nodeNameWithoutPrefix);
-
- $callbackKeyToUse = $callbackKeyForUnPrefixedName;
- if ($hasPrefix && isset($this->callbacks[$callbackKeyForPossiblyPrefixedName])) {
- $callbackKeyToUse = $callbackKeyForPossiblyPrefixedName;
- }
-
- // Using isset here because it is way faster than array_key_exists...
- return $this->callbacks[$callbackKeyToUse] ?? null;
- }
-
- /**
- * @param array $callbackData Associative array containing data to invoke the callback using Reflection
- * @param array $args Arguments to pass to the callback
- *
- * @return int Callback response
- */
- private function invokeCallback($callbackData, $args)
- {
- $reflectionMethod = $callbackData[self::CALLBACK_REFLECTION_METHOD];
- $callbackObject = $callbackData[self::CALLBACK_REFLECTION_OBJECT];
-
- return $reflectionMethod->invokeArgs($callbackObject, $args);
- }
-}
diff --git a/upstream-3.x/src/Reader/Exception/InvalidValueException.php b/upstream-3.x/src/Reader/Exception/InvalidValueException.php
deleted file mode 100644
index 9bbcebd..0000000
--- a/upstream-3.x/src/Reader/Exception/InvalidValueException.php
+++ /dev/null
@@ -1,30 +0,0 @@
-invalidValue = $invalidValue;
- parent::__construct($message, $code, $previous);
- }
-
- /**
- * @return mixed
- */
- public function getInvalidValue()
- {
- return $this->invalidValue;
- }
-}
diff --git a/upstream-3.x/src/Reader/Exception/IteratorNotRewindableException.php b/upstream-3.x/src/Reader/Exception/IteratorNotRewindableException.php
deleted file mode 100644
index 06aac22..0000000
--- a/upstream-3.x/src/Reader/Exception/IteratorNotRewindableException.php
+++ /dev/null
@@ -1,7 +0,0 @@
-createStringsEscaper();
-
- return new CellValueFormatter($shouldFormatDates, $escaper);
- }
-
- /**
- * @param InternalEntityFactory $entityFactory
- *
- * @return SettingsHelper
- */
- public function createSettingsHelper($entityFactory)
- {
- return new SettingsHelper($entityFactory);
- }
-
- /**
- * @return \OpenSpout\Common\Helper\Escaper\ODS
- */
- public function createStringsEscaper()
- {
- // @noinspection PhpUnnecessaryFullyQualifiedNameInspection
- return new \OpenSpout\Common\Helper\Escaper\ODS();
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/Creator/InternalEntityFactory.php b/upstream-3.x/src/Reader/ODS/Creator/InternalEntityFactory.php
deleted file mode 100644
index 960fec9..0000000
--- a/upstream-3.x/src/Reader/ODS/Creator/InternalEntityFactory.php
+++ /dev/null
@@ -1,124 +0,0 @@
-helperFactory = $helperFactory;
- $this->managerFactory = $managerFactory;
- }
-
- /**
- * @param string $filePath Path of the file to be read
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- *
- * @return SheetIterator
- */
- public function createSheetIterator($filePath, $optionsManager)
- {
- $escaper = $this->helperFactory->createStringsEscaper();
- $settingsHelper = $this->helperFactory->createSettingsHelper($this);
-
- return new SheetIterator($filePath, $optionsManager, $escaper, $settingsHelper, $this);
- }
-
- /**
- * @param XMLReader $xmlReader XML Reader
- * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based)
- * @param string $sheetName Name of the sheet
- * @param bool $isSheetActive Whether the sheet was defined as active
- * @param bool $isSheetVisible Whether the sheet is visible
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- *
- * @return Sheet
- */
- public function createSheet($xmlReader, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible, $optionsManager)
- {
- $rowIterator = $this->createRowIterator($xmlReader, $optionsManager);
-
- return new Sheet($rowIterator, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible);
- }
-
- /**
- * @param Cell[] $cells
- *
- * @return Row
- */
- public function createRow(array $cells = [])
- {
- return new Row($cells, null);
- }
-
- /**
- * @param mixed $cellValue
- *
- * @return Cell
- */
- public function createCell($cellValue)
- {
- return new Cell($cellValue);
- }
-
- /**
- * @return XMLReader
- */
- public function createXMLReader()
- {
- return new XMLReader();
- }
-
- /**
- * @return \ZipArchive
- */
- public function createZipArchive()
- {
- return new \ZipArchive();
- }
-
- /**
- * @param XMLReader $xmlReader XML Reader
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- *
- * @return RowIterator
- */
- private function createRowIterator($xmlReader, $optionsManager)
- {
- $shouldFormatDates = $optionsManager->getOption(Options::SHOULD_FORMAT_DATES);
- $cellValueFormatter = $this->helperFactory->createCellValueFormatter($shouldFormatDates);
- $xmlProcessor = $this->createXMLProcessor($xmlReader);
- $rowManager = $this->managerFactory->createRowManager($this);
-
- return new RowIterator($xmlReader, $optionsManager, $cellValueFormatter, $xmlProcessor, $rowManager, $this);
- }
-
- /**
- * @param XMLReader $xmlReader
- *
- * @return XMLProcessor
- */
- private function createXMLProcessor($xmlReader)
- {
- return new XMLProcessor($xmlReader);
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/Creator/ManagerFactory.php b/upstream-3.x/src/Reader/ODS/Creator/ManagerFactory.php
deleted file mode 100644
index 546069e..0000000
--- a/upstream-3.x/src/Reader/ODS/Creator/ManagerFactory.php
+++ /dev/null
@@ -1,21 +0,0 @@
- ' ',
- self::XML_NODE_TEXT_TAB => "\t",
- self::XML_NODE_TEXT_LINE_BREAK => "\n",
- ];
-
- /**
- * @param bool $shouldFormatDates Whether date/time values should be returned as PHP objects or be formatted as strings
- * @param \OpenSpout\Common\Helper\Escaper\ODS $escaper Used to unescape XML data
- */
- public function __construct($shouldFormatDates, $escaper)
- {
- $this->shouldFormatDates = $shouldFormatDates;
- $this->escaper = $escaper;
- }
-
- /**
- * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node.
- *
- * @see http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#refTable13
- *
- * @param \DOMElement $node
- *
- * @throws InvalidValueException If the node value is not valid
- *
- * @return bool|\DateInterval|\DateTime|float|int|string The value associated with the cell, empty string if cell's type is void/undefined
- */
- public function extractAndFormatNodeValue($node)
- {
- $cellType = $node->getAttribute(self::XML_ATTRIBUTE_TYPE);
-
- switch ($cellType) {
- case self::CELL_TYPE_STRING:
- return $this->formatStringCellValue($node);
-
- case self::CELL_TYPE_FLOAT:
- return $this->formatFloatCellValue($node);
-
- case self::CELL_TYPE_BOOLEAN:
- return $this->formatBooleanCellValue($node);
-
- case self::CELL_TYPE_DATE:
- return $this->formatDateCellValue($node);
-
- case self::CELL_TYPE_TIME:
- return $this->formatTimeCellValue($node);
-
- case self::CELL_TYPE_CURRENCY:
- return $this->formatCurrencyCellValue($node);
-
- case self::CELL_TYPE_PERCENTAGE:
- return $this->formatPercentageCellValue($node);
-
- case self::CELL_TYPE_VOID:
- default:
- return '';
- }
- }
-
- /**
- * Returns the cell String value.
- *
- * @param \DOMElement $node
- *
- * @return string The value associated with the cell
- */
- protected function formatStringCellValue($node)
- {
- $pNodeValues = [];
- $pNodes = $node->getElementsByTagName(self::XML_NODE_P);
-
- foreach ($pNodes as $pNode) {
- $pNodeValues[] = $this->extractTextValueFromNode($pNode);
- }
-
- $escapedCellValue = implode("\n", $pNodeValues);
-
- return $this->escaper->unescape($escapedCellValue);
- }
-
- /**
- * Returns the cell Numeric value from the given node.
- *
- * @param \DOMElement $node
- *
- * @return float|int The value associated with the cell
- */
- protected function formatFloatCellValue($node)
- {
- $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_VALUE);
-
- $nodeIntValue = (int) $nodeValue;
- $nodeFloatValue = (float) $nodeValue;
-
- return ((float) $nodeIntValue === $nodeFloatValue) ? $nodeIntValue : $nodeFloatValue;
- }
-
- /**
- * Returns the cell Boolean value from the given node.
- *
- * @param \DOMElement $node
- *
- * @return bool The value associated with the cell
- */
- protected function formatBooleanCellValue($node)
- {
- $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_BOOLEAN_VALUE);
-
- return (bool) $nodeValue;
- }
-
- /**
- * Returns the cell Date value from the given node.
- *
- * @param \DOMElement $node
- *
- * @throws InvalidValueException If the value is not a valid date
- *
- * @return \DateTime|string The value associated with the cell
- */
- protected function formatDateCellValue($node)
- {
- // The XML node looks like this:
- //
- // 05/19/16 04:39 PM
- //
-
- if ($this->shouldFormatDates) {
- // The date is already formatted in the "p" tag
- $nodeWithValueAlreadyFormatted = $node->getElementsByTagName(self::XML_NODE_P)->item(0);
- $cellValue = $nodeWithValueAlreadyFormatted->nodeValue;
- } else {
- // otherwise, get it from the "date-value" attribute
- $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_DATE_VALUE);
-
- try {
- $cellValue = new \DateTime($nodeValue);
- } catch (\Exception $e) {
- throw new InvalidValueException($nodeValue);
- }
- }
-
- return $cellValue;
- }
-
- /**
- * Returns the cell Time value from the given node.
- *
- * @param \DOMElement $node
- *
- * @throws InvalidValueException If the value is not a valid time
- *
- * @return \DateInterval|string The value associated with the cell
- */
- protected function formatTimeCellValue($node)
- {
- // The XML node looks like this:
- //
- // 01:24:00 PM
- //
-
- if ($this->shouldFormatDates) {
- // The date is already formatted in the "p" tag
- $nodeWithValueAlreadyFormatted = $node->getElementsByTagName(self::XML_NODE_P)->item(0);
- $cellValue = $nodeWithValueAlreadyFormatted->nodeValue;
- } else {
- // otherwise, get it from the "time-value" attribute
- $nodeValue = $node->getAttribute(self::XML_ATTRIBUTE_TIME_VALUE);
-
- try {
- $cellValue = new \DateInterval($nodeValue);
- } catch (\Exception $e) {
- throw new InvalidValueException($nodeValue);
- }
- }
-
- return $cellValue;
- }
-
- /**
- * Returns the cell Currency value from the given node.
- *
- * @param \DOMElement $node
- *
- * @return string The value associated with the cell (e.g. "100 USD" or "9.99 EUR")
- */
- protected function formatCurrencyCellValue($node)
- {
- $value = $node->getAttribute(self::XML_ATTRIBUTE_VALUE);
- $currency = $node->getAttribute(self::XML_ATTRIBUTE_CURRENCY);
-
- return "{$value} {$currency}";
- }
-
- /**
- * Returns the cell Percentage value from the given node.
- *
- * @param \DOMElement $node
- *
- * @return float|int The value associated with the cell
- */
- protected function formatPercentageCellValue($node)
- {
- // percentages are formatted like floats
- return $this->formatFloatCellValue($node);
- }
-
- /**
- * @param \DOMNode $pNode
- *
- * @return string
- */
- private function extractTextValueFromNode($pNode)
- {
- $textValue = '';
-
- foreach ($pNode->childNodes as $childNode) {
- if ($childNode instanceof \DOMText) {
- $textValue .= $childNode->nodeValue;
- } elseif ($this->isWhitespaceNode($childNode->nodeName)) {
- $textValue .= $this->transformWhitespaceNode($childNode);
- } elseif (self::XML_NODE_TEXT_A === $childNode->nodeName || self::XML_NODE_TEXT_SPAN === $childNode->nodeName) {
- $textValue .= $this->extractTextValueFromNode($childNode);
- }
- }
-
- return $textValue;
- }
-
- /**
- * Returns whether the given node is a whitespace node. It must be one of these:
- * -
- * -
- * - .
- *
- * @param string $nodeName
- *
- * @return bool
- */
- private function isWhitespaceNode($nodeName)
- {
- return isset(self::$WHITESPACE_XML_NODES[$nodeName]);
- }
-
- /**
- * The "" node can contain the string value directly
- * or contain child elements. In this case, whitespaces contain in
- * the child elements should be replaced by their XML equivalent:
- * - space =>
- * - tab =>
- * - line break => .
- *
- * @see https://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1415200_253892949
- *
- * @param \DOMElement $node The XML node representing a whitespace
- *
- * @return string The corresponding whitespace value
- */
- private function transformWhitespaceNode($node)
- {
- $countAttribute = $node->getAttribute(self::XML_ATTRIBUTE_C); // only defined for ""
- $numWhitespaces = (!empty($countAttribute)) ? (int) $countAttribute : 1;
-
- return str_repeat(self::$WHITESPACE_XML_NODES[$node->nodeName], $numWhitespaces);
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/Helper/SettingsHelper.php b/upstream-3.x/src/Reader/ODS/Helper/SettingsHelper.php
deleted file mode 100644
index 4463eeb..0000000
--- a/upstream-3.x/src/Reader/ODS/Helper/SettingsHelper.php
+++ /dev/null
@@ -1,61 +0,0 @@
-entityFactory = $entityFactory;
- }
-
- /**
- * @param string $filePath Path of the file to be read
- *
- * @return null|string Name of the sheet that was defined as active or NULL if none found
- */
- public function getActiveSheetName($filePath)
- {
- $xmlReader = $this->entityFactory->createXMLReader();
- if (false === $xmlReader->openFileInZip($filePath, self::SETTINGS_XML_FILE_PATH)) {
- return null;
- }
-
- $activeSheetName = null;
-
- try {
- while ($xmlReader->readUntilNodeFound(self::XML_NODE_CONFIG_ITEM)) {
- if (self::XML_ATTRIBUTE_VALUE_ACTIVE_TABLE === $xmlReader->getAttribute(self::XML_ATTRIBUTE_CONFIG_NAME)) {
- $activeSheetName = $xmlReader->readString();
-
- break;
- }
- }
- } catch (XMLProcessingException $exception) {
- // do nothing
- }
-
- $xmlReader->close();
-
- return $activeSheetName;
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/Manager/OptionsManager.php b/upstream-3.x/src/Reader/ODS/Manager/OptionsManager.php
deleted file mode 100644
index e13c544..0000000
--- a/upstream-3.x/src/Reader/ODS/Manager/OptionsManager.php
+++ /dev/null
@@ -1,32 +0,0 @@
-setOption(Options::SHOULD_FORMAT_DATES, false);
- $this->setOption(Options::SHOULD_PRESERVE_EMPTY_ROWS, false);
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/Reader.php b/upstream-3.x/src/Reader/ODS/Reader.php
deleted file mode 100644
index 8f3970a..0000000
--- a/upstream-3.x/src/Reader/ODS/Reader.php
+++ /dev/null
@@ -1,73 +0,0 @@
-entityFactory;
-
- $this->zip = $entityFactory->createZipArchive();
-
- if (true === $this->zip->open($filePath)) {
- /** @var InternalEntityFactory $entityFactory */
- $entityFactory = $this->entityFactory;
- $this->sheetIterator = $entityFactory->createSheetIterator($filePath, $this->optionsManager);
- } else {
- throw new IOException("Could not open {$filePath} for reading.");
- }
- }
-
- /**
- * Returns an iterator to iterate over sheets.
- *
- * @return SheetIterator To iterate over sheets
- */
- protected function getConcreteSheetIterator()
- {
- return $this->sheetIterator;
- }
-
- /**
- * Closes the reader. To be used after reading the file.
- */
- protected function closeReader()
- {
- if (null !== $this->zip) {
- $this->zip->close();
- }
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/RowIterator.php b/upstream-3.x/src/Reader/ODS/RowIterator.php
deleted file mode 100644
index a3ab7aa..0000000
--- a/upstream-3.x/src/Reader/ODS/RowIterator.php
+++ /dev/null
@@ -1,388 +0,0 @@
-" element
- * @param OptionsManagerInterface $optionsManager Reader's options manager
- * @param CellValueFormatter $cellValueFormatter Helper to format cell values
- * @param XMLProcessor $xmlProcessor Helper to process XML files
- * @param RowManager $rowManager Manages rows
- * @param InternalEntityFactory $entityFactory Factory to create entities
- */
- public function __construct(
- XMLReader $xmlReader,
- OptionsManagerInterface $optionsManager,
- CellValueFormatter $cellValueFormatter,
- XMLProcessor $xmlProcessor,
- RowManager $rowManager,
- InternalEntityFactory $entityFactory
- ) {
- $this->xmlReader = $xmlReader;
- $this->shouldPreserveEmptyRows = $optionsManager->getOption(Options::SHOULD_PRESERVE_EMPTY_ROWS);
- $this->cellValueFormatter = $cellValueFormatter;
- $this->entityFactory = $entityFactory;
- $this->rowManager = $rowManager;
-
- // Register all callbacks to process different nodes when reading the XML file
- $this->xmlProcessor = $xmlProcessor;
- $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_START, [$this, 'processRowStartingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_CELL, XMLProcessor::NODE_TYPE_START, [$this, 'processCellStartingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_END, [$this, 'processRowEndingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_TABLE, XMLProcessor::NODE_TYPE_END, [$this, 'processTableEndingNode']);
- }
-
- /**
- * Rewind the Iterator to the first element.
- * NOTE: It can only be done once, as it is not possible to read an XML file backwards.
- *
- * @see http://php.net/manual/en/iterator.rewind.php
- *
- * @throws \OpenSpout\Reader\Exception\IteratorNotRewindableException If the iterator is rewound more than once
- */
- #[\ReturnTypeWillChange]
- public function rewind(): void
- {
- // Because sheet and row data is located in the file, we can't rewind both the
- // sheet iterator and the row iterator, as XML file cannot be read backwards.
- // Therefore, rewinding the row iterator has been disabled.
- if ($this->hasAlreadyBeenRewound) {
- throw new IteratorNotRewindableException();
- }
-
- $this->hasAlreadyBeenRewound = true;
- $this->lastRowIndexProcessed = 0;
- $this->nextRowIndexToBeProcessed = 1;
- $this->rowBuffer = null;
- $this->hasReachedEndOfFile = false;
-
- $this->next();
- }
-
- /**
- * Checks if current position is valid.
- *
- * @see http://php.net/manual/en/iterator.valid.php
- */
- #[\ReturnTypeWillChange]
- public function valid(): bool
- {
- return !$this->hasReachedEndOfFile;
- }
-
- /**
- * Move forward to next element. Empty rows will be skipped.
- *
- * @see http://php.net/manual/en/iterator.next.php
- *
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If a shared string was not found
- * @throws \OpenSpout\Common\Exception\IOException If unable to read the sheet data XML
- */
- #[\ReturnTypeWillChange]
- public function next(): void
- {
- if ($this->doesNeedDataForNextRowToBeProcessed()) {
- $this->readDataForNextRow();
- }
-
- ++$this->lastRowIndexProcessed;
- }
-
- /**
- * Return the current element, from the buffer.
- *
- * @see http://php.net/manual/en/iterator.current.php
- */
- #[\ReturnTypeWillChange]
- public function current(): Row
- {
- return $this->rowBuffer;
- }
-
- /**
- * Return the key of the current element.
- *
- * @see http://php.net/manual/en/iterator.key.php
- */
- #[\ReturnTypeWillChange]
- public function key(): int
- {
- return $this->lastRowIndexProcessed;
- }
-
- /**
- * Cleans up what was created to iterate over the object.
- */
- #[\ReturnTypeWillChange]
- public function end(): void
- {
- $this->xmlReader->close();
- }
-
- /**
- * Returns whether we need data for the next row to be processed.
- * We DO need to read data if:
- * - we have not read any rows yet
- * OR
- * - the next row to be processed immediately follows the last read row.
- *
- * @return bool whether we need data for the next row to be processed
- */
- protected function doesNeedDataForNextRowToBeProcessed()
- {
- $hasReadAtLeastOneRow = (0 !== $this->lastRowIndexProcessed);
-
- return
- !$hasReadAtLeastOneRow
- || $this->lastRowIndexProcessed === $this->nextRowIndexToBeProcessed - 1
- ;
- }
-
- /**
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If a shared string was not found
- * @throws \OpenSpout\Common\Exception\IOException If unable to read the sheet data XML
- */
- protected function readDataForNextRow()
- {
- $this->currentlyProcessedRow = $this->entityFactory->createRow();
-
- try {
- $this->xmlProcessor->readUntilStopped();
- } catch (XMLProcessingException $exception) {
- throw new IOException("The sheet's data cannot be read. [{$exception->getMessage()}]");
- }
-
- $this->rowBuffer = $this->currentlyProcessedRow;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processRowStartingNode($xmlReader)
- {
- // Reset data from current row
- $this->hasAlreadyReadOneCellInCurrentRow = false;
- $this->lastProcessedCell = null;
- $this->numColumnsRepeated = 1;
- $this->numRowsRepeated = $this->getNumRowsRepeatedForCurrentNode($xmlReader);
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processCellStartingNode($xmlReader)
- {
- $currentNumColumnsRepeated = $this->getNumColumnsRepeatedForCurrentNode($xmlReader);
-
- // NOTE: expand() will automatically decode all XML entities of the child nodes
- /** @var \DOMElement $node */
- $node = $xmlReader->expand();
- $currentCell = $this->getCell($node);
-
- // process cell N only after having read cell N+1 (see below why)
- if ($this->hasAlreadyReadOneCellInCurrentRow) {
- for ($i = 0; $i < $this->numColumnsRepeated; ++$i) {
- $this->currentlyProcessedRow->addCell($this->lastProcessedCell);
- }
- }
-
- $this->hasAlreadyReadOneCellInCurrentRow = true;
- $this->lastProcessedCell = $currentCell;
- $this->numColumnsRepeated = $currentNumColumnsRepeated;
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processRowEndingNode()
- {
- $isEmptyRow = $this->isEmptyRow($this->currentlyProcessedRow, $this->lastProcessedCell);
-
- // if the fetched row is empty and we don't want to preserve it...
- if (!$this->shouldPreserveEmptyRows && $isEmptyRow) {
- // ... skip it
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- // if the row is empty, we don't want to return more than one cell
- $actualNumColumnsRepeated = (!$isEmptyRow) ? $this->numColumnsRepeated : 1;
- $numCellsInCurrentlyProcessedRow = $this->currentlyProcessedRow->getNumCells();
-
- // Only add the value if the last read cell is not a trailing empty cell repeater in Excel.
- // The current count of read columns is determined by counting the values in "$this->currentlyProcessedRowData".
- // This is to avoid creating a lot of empty cells, as Excel adds a last empty ""
- // with a number-columns-repeated value equals to the number of (supported columns - used columns).
- // In Excel, the number of supported columns is 16384, but we don't want to returns rows with
- // always 16384 cells.
- if (($numCellsInCurrentlyProcessedRow + $actualNumColumnsRepeated) !== self::MAX_COLUMNS_EXCEL) {
- for ($i = 0; $i < $actualNumColumnsRepeated; ++$i) {
- $this->currentlyProcessedRow->addCell($this->lastProcessedCell);
- }
- }
-
- // If we are processing row N and the row is repeated M times,
- // then the next row to be processed will be row (N+M).
- $this->nextRowIndexToBeProcessed += $this->numRowsRepeated;
-
- // at this point, we have all the data we need for the row
- // so that we can populate the buffer
- return XMLProcessor::PROCESSING_STOP;
- }
-
- /**
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processTableEndingNode()
- {
- // The closing "" marks the end of the file
- $this->hasReachedEndOfFile = true;
-
- return XMLProcessor::PROCESSING_STOP;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int The value of "table:number-rows-repeated" attribute of the current node, or 1 if attribute missing
- */
- protected function getNumRowsRepeatedForCurrentNode($xmlReader)
- {
- $numRowsRepeated = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_ROWS_REPEATED);
-
- return (null !== $numRowsRepeated) ? (int) $numRowsRepeated : 1;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int The value of "table:number-columns-repeated" attribute of the current node, or 1 if attribute missing
- */
- protected function getNumColumnsRepeatedForCurrentNode($xmlReader)
- {
- $numColumnsRepeated = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_COLUMNS_REPEATED);
-
- return (null !== $numColumnsRepeated) ? (int) $numColumnsRepeated : 1;
- }
-
- /**
- * Returns the cell with (unescaped) correctly marshalled, cell value associated to the given XML node.
- *
- * @param \DOMElement $node
- *
- * @return Cell The cell set with the associated with the cell
- */
- protected function getCell($node)
- {
- try {
- $cellValue = $this->cellValueFormatter->extractAndFormatNodeValue($node);
- $cell = $this->entityFactory->createCell($cellValue);
- } catch (InvalidValueException $exception) {
- $cell = $this->entityFactory->createCell($exception->getInvalidValue());
- $cell->setType(Cell::TYPE_ERROR);
- }
-
- return $cell;
- }
-
- /**
- * After finishing processing each cell, a row is considered empty if it contains
- * no cells or if the last read cell is empty.
- * After finishing processing each cell, the last read cell is not part of the
- * row data yet (as we still need to apply the "num-columns-repeated" attribute).
- *
- * @param Row $currentRow
- * @param null|Cell $lastReadCell The last read cell
- *
- * @return bool Whether the row is empty
- */
- protected function isEmptyRow($currentRow, $lastReadCell)
- {
- return
- $this->rowManager->isEmpty($currentRow)
- && (!isset($lastReadCell) || $lastReadCell->isEmpty())
- ;
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/Sheet.php b/upstream-3.x/src/Reader/ODS/Sheet.php
deleted file mode 100644
index 306f268..0000000
--- a/upstream-3.x/src/Reader/ODS/Sheet.php
+++ /dev/null
@@ -1,85 +0,0 @@
-rowIterator = $rowIterator;
- $this->index = $sheetIndex;
- $this->name = $sheetName;
- $this->isActive = $isSheetActive;
- $this->isVisible = $isSheetVisible;
- }
-
- /**
- * @return \OpenSpout\Reader\ODS\RowIterator
- */
- public function getRowIterator()
- {
- return $this->rowIterator;
- }
-
- /**
- * @return int Index of the sheet, based on order in the workbook (zero-based)
- */
- public function getIndex()
- {
- return $this->index;
- }
-
- /**
- * @return string Name of the sheet
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * @return bool Whether the sheet was defined as active
- */
- public function isActive()
- {
- return $this->isActive;
- }
-
- /**
- * @return bool Whether the sheet is visible
- */
- public function isVisible()
- {
- return $this->isVisible;
- }
-}
diff --git a/upstream-3.x/src/Reader/ODS/SheetIterator.php b/upstream-3.x/src/Reader/ODS/SheetIterator.php
deleted file mode 100644
index 5240e38..0000000
--- a/upstream-3.x/src/Reader/ODS/SheetIterator.php
+++ /dev/null
@@ -1,239 +0,0 @@
- [IS_SHEET_VISIBLE] */
- protected $sheetsVisibility;
-
- /**
- * @param string $filePath Path of the file to be read
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager
- * @param \OpenSpout\Common\Helper\Escaper\ODS $escaper Used to unescape XML data
- * @param SettingsHelper $settingsHelper Helper to get data from "settings.xml"
- * @param InternalEntityFactory $entityFactory Factory to create entities
- */
- public function __construct($filePath, $optionsManager, $escaper, $settingsHelper, $entityFactory)
- {
- $this->filePath = $filePath;
- $this->optionsManager = $optionsManager;
- $this->entityFactory = $entityFactory;
- $this->xmlReader = $entityFactory->createXMLReader();
- $this->escaper = $escaper;
- $this->activeSheetName = $settingsHelper->getActiveSheetName($filePath);
- }
-
- /**
- * Rewind the Iterator to the first element.
- *
- * @see http://php.net/manual/en/iterator.rewind.php
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to open the XML file containing sheets' data
- */
- #[\ReturnTypeWillChange]
- public function rewind()
- {
- $this->xmlReader->close();
-
- if (false === $this->xmlReader->openFileInZip($this->filePath, self::CONTENT_XML_FILE_PATH)) {
- $contentXmlFilePath = $this->filePath.'#'.self::CONTENT_XML_FILE_PATH;
-
- throw new IOException("Could not open \"{$contentXmlFilePath}\".");
- }
-
- try {
- $this->sheetsVisibility = $this->readSheetsVisibility();
- $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE);
- } catch (XMLProcessingException $exception) {
- throw new IOException("The content.xml file is invalid and cannot be read. [{$exception->getMessage()}]");
- }
-
- $this->currentSheetIndex = 0;
- }
-
- /**
- * Checks if current position is valid.
- *
- * @see http://php.net/manual/en/iterator.valid.php
- *
- * @return bool
- */
- #[\ReturnTypeWillChange]
- public function valid()
- {
- return $this->hasFoundSheet;
- }
-
- /**
- * Move forward to next element.
- *
- * @see http://php.net/manual/en/iterator.next.php
- */
- #[\ReturnTypeWillChange]
- public function next()
- {
- $this->hasFoundSheet = $this->xmlReader->readUntilNodeFound(self::XML_NODE_TABLE);
-
- if ($this->hasFoundSheet) {
- ++$this->currentSheetIndex;
- }
- }
-
- /**
- * Return the current element.
- *
- * @see http://php.net/manual/en/iterator.current.php
- *
- * @return \OpenSpout\Reader\ODS\Sheet
- */
- #[\ReturnTypeWillChange]
- public function current()
- {
- $escapedSheetName = $this->xmlReader->getAttribute(self::XML_ATTRIBUTE_TABLE_NAME);
- $sheetName = $this->escaper->unescape($escapedSheetName);
-
- $isSheetActive = $this->isSheetActive($sheetName, $this->currentSheetIndex, $this->activeSheetName);
-
- $sheetStyleName = $this->xmlReader->getAttribute(self::XML_ATTRIBUTE_TABLE_STYLE_NAME);
- $isSheetVisible = $this->isSheetVisible($sheetStyleName);
-
- return $this->entityFactory->createSheet(
- $this->xmlReader,
- $this->currentSheetIndex,
- $sheetName,
- $isSheetActive,
- $isSheetVisible,
- $this->optionsManager
- );
- }
-
- /**
- * Return the key of the current element.
- *
- * @see http://php.net/manual/en/iterator.key.php
- *
- * @return int
- */
- #[\ReturnTypeWillChange]
- public function key()
- {
- return $this->currentSheetIndex + 1;
- }
-
- /**
- * Cleans up what was created to iterate over the object.
- */
- #[\ReturnTypeWillChange]
- public function end()
- {
- $this->xmlReader->close();
- }
-
- /**
- * Extracts the visibility of the sheets.
- *
- * @return array Associative array [STYLE_NAME] => [IS_SHEET_VISIBLE]
- */
- private function readSheetsVisibility()
- {
- $sheetsVisibility = [];
-
- $this->xmlReader->readUntilNodeFound(self::XML_NODE_AUTOMATIC_STYLES);
- /** @var \DOMElement $automaticStylesNode */
- $automaticStylesNode = $this->xmlReader->expand();
-
- $tableStyleNodes = $automaticStylesNode->getElementsByTagNameNS(self::XML_STYLE_NAMESPACE, self::XML_NODE_STYLE_TABLE_PROPERTIES);
-
- /** @var \DOMElement $tableStyleNode */
- foreach ($tableStyleNodes as $tableStyleNode) {
- $isSheetVisible = ('false' !== $tableStyleNode->getAttribute(self::XML_ATTRIBUTE_TABLE_DISPLAY));
-
- $parentStyleNode = $tableStyleNode->parentNode;
- $styleName = $parentStyleNode->getAttribute(self::XML_ATTRIBUTE_STYLE_NAME);
-
- $sheetsVisibility[$styleName] = $isSheetVisible;
- }
-
- return $sheetsVisibility;
- }
-
- /**
- * Returns whether the current sheet was defined as the active one.
- *
- * @param string $sheetName Name of the current sheet
- * @param int $sheetIndex Index of the current sheet
- * @param null|string $activeSheetName Name of the sheet that was defined as active or NULL if none defined
- *
- * @return bool Whether the current sheet was defined as the active one
- */
- private function isSheetActive($sheetName, $sheetIndex, $activeSheetName)
- {
- // The given sheet is active if its name matches the defined active sheet's name
- // or if no information about the active sheet was found, it defaults to the first sheet.
- return
- (null === $activeSheetName && 0 === $sheetIndex)
- || ($activeSheetName === $sheetName)
- ;
- }
-
- /**
- * Returns whether the current sheet is visible.
- *
- * @param string $sheetStyleName Name of the sheet style
- *
- * @return bool Whether the current sheet is visible
- */
- private function isSheetVisible($sheetStyleName)
- {
- return $this->sheetsVisibility[$sheetStyleName] ??
- true;
- }
-}
diff --git a/upstream-3.x/src/Reader/ReaderAbstract.php b/upstream-3.x/src/Reader/ReaderAbstract.php
deleted file mode 100644
index 2b7c8b4..0000000
--- a/upstream-3.x/src/Reader/ReaderAbstract.php
+++ /dev/null
@@ -1,236 +0,0 @@
-optionsManager = $optionsManager;
- $this->globalFunctionsHelper = $globalFunctionsHelper;
- $this->entityFactory = $entityFactory;
- }
-
- /**
- * Sets whether date/time values should be returned as PHP objects or be formatted as strings.
- *
- * @param bool $shouldFormatDates
- *
- * @return ReaderAbstract
- */
- public function setShouldFormatDates($shouldFormatDates)
- {
- $this->optionsManager->setOption(Options::SHOULD_FORMAT_DATES, $shouldFormatDates);
-
- return $this;
- }
-
- /**
- * Sets whether empty rows should be returned or skipped.
- *
- * @param bool $shouldPreserveEmptyRows
- *
- * @return ReaderAbstract
- */
- public function setShouldPreserveEmptyRows($shouldPreserveEmptyRows)
- {
- $this->optionsManager->setOption(Options::SHOULD_PRESERVE_EMPTY_ROWS, $shouldPreserveEmptyRows);
-
- return $this;
- }
-
- /**
- * Prepares the reader to read the given file. It also makes sure
- * that the file exists and is readable.
- *
- * @param string $filePath Path of the file to be read
- *
- * @throws \OpenSpout\Common\Exception\IOException If the file at the given path does not exist, is not readable or is corrupted
- */
- public function open($filePath)
- {
- if ($this->isStreamWrapper($filePath) && (!$this->doesSupportStreamWrapper() || !$this->isSupportedStreamWrapper($filePath))) {
- throw new IOException("Could not open {$filePath} for reading! Stream wrapper used is not supported for this type of file.");
- }
-
- if (!$this->isPhpStream($filePath)) {
- // we skip the checks if the provided file path points to a PHP stream
- if (!$this->globalFunctionsHelper->file_exists($filePath)) {
- throw new IOException("Could not open {$filePath} for reading! File does not exist.");
- }
- if (!$this->globalFunctionsHelper->is_readable($filePath)) {
- throw new IOException("Could not open {$filePath} for reading! File is not readable.");
- }
- }
-
- try {
- $fileRealPath = $this->getFileRealPath($filePath);
- $this->openReader($fileRealPath);
- $this->isStreamOpened = true;
- } catch (\Exception $exception) {
- throw new IOException("Could not open {$filePath} for reading! ({$exception->getMessage()})");
- }
- }
-
- /**
- * Returns an iterator to iterate over sheets.
- *
- * @throws \OpenSpout\Reader\Exception\ReaderNotOpenedException If called before opening the reader
- *
- * @return SheetIteratorInterface To iterate over sheets
- */
- public function getSheetIterator()
- {
- if (!$this->isStreamOpened) {
- throw new ReaderNotOpenedException('Reader should be opened first.');
- }
-
- return $this->getConcreteSheetIterator();
- }
-
- /**
- * Closes the reader, preventing any additional reading.
- */
- public function close()
- {
- if ($this->isStreamOpened) {
- $this->closeReader();
-
- $sheetIterator = $this->getConcreteSheetIterator();
- if (null !== $sheetIterator) {
- $sheetIterator->end();
- }
-
- $this->isStreamOpened = false;
- }
- }
-
- /**
- * Returns whether stream wrappers are supported.
- *
- * @return bool
- */
- abstract protected function doesSupportStreamWrapper();
-
- /**
- * Opens the file at the given file path to make it ready to be read.
- *
- * @param string $filePath Path of the file to be read
- */
- abstract protected function openReader($filePath);
-
- /**
- * Returns an iterator to iterate over sheets.
- *
- * @return SheetIteratorInterface To iterate over sheets
- */
- abstract protected function getConcreteSheetIterator();
-
- /**
- * Closes the reader. To be used after reading the file.
- */
- abstract protected function closeReader();
-
- /**
- * Returns the real path of the given path.
- * If the given path is a valid stream wrapper, returns the path unchanged.
- *
- * @param string $filePath
- *
- * @return string
- */
- protected function getFileRealPath($filePath)
- {
- if ($this->isSupportedStreamWrapper($filePath)) {
- return $filePath;
- }
-
- // Need to use realpath to fix "Can't open file" on some Windows setup
- return realpath($filePath);
- }
-
- /**
- * Returns the scheme of the custom stream wrapper, if the path indicates a stream wrapper is used.
- * For example, php://temp => php, s3://path/to/file => s3...
- *
- * @param string $filePath Path of the file to be read
- *
- * @return null|string The stream wrapper scheme or NULL if not a stream wrapper
- */
- protected function getStreamWrapperScheme($filePath)
- {
- $streamScheme = null;
- if (preg_match('/^(\w+):\/\//', $filePath, $matches)) {
- $streamScheme = $matches[1];
- }
-
- return $streamScheme;
- }
-
- /**
- * Checks if the given path is an unsupported stream wrapper
- * (like local path, php://temp, mystream://foo/bar...).
- *
- * @param string $filePath Path of the file to be read
- *
- * @return bool Whether the given path is an unsupported stream wrapper
- */
- protected function isStreamWrapper($filePath)
- {
- return null !== $this->getStreamWrapperScheme($filePath);
- }
-
- /**
- * Checks if the given path is an supported stream wrapper
- * (like php://temp, mystream://foo/bar...).
- * If the given path is a local path, returns true.
- *
- * @param string $filePath Path of the file to be read
- *
- * @return bool Whether the given path is an supported stream wrapper
- */
- protected function isSupportedStreamWrapper($filePath)
- {
- $streamScheme = $this->getStreamWrapperScheme($filePath);
-
- return (null !== $streamScheme) ?
- \in_array($streamScheme, $this->globalFunctionsHelper->stream_get_wrappers(), true) :
- true;
- }
-
- /**
- * Checks if a path is a PHP stream (like php://output, php://memory, ...).
- *
- * @param string $filePath Path of the file to be read
- *
- * @return bool Whether the given path maps to a PHP stream
- */
- protected function isPhpStream($filePath)
- {
- $streamScheme = $this->getStreamWrapperScheme($filePath);
-
- return 'php' === $streamScheme;
- }
-}
diff --git a/upstream-3.x/src/Reader/ReaderInterface.php b/upstream-3.x/src/Reader/ReaderInterface.php
deleted file mode 100644
index a1d9f74..0000000
--- a/upstream-3.x/src/Reader/ReaderInterface.php
+++ /dev/null
@@ -1,33 +0,0 @@
-initialUseInternalErrorsValue = libxml_use_internal_errors(true);
- }
-
- /**
- * Throws an XMLProcessingException if an error occured.
- * It also always resets the "libxml_use_internal_errors" setting back to its initial value.
- *
- * @throws \OpenSpout\Reader\Exception\XMLProcessingException
- */
- protected function resetXMLInternalErrorsSettingAndThrowIfXMLErrorOccured()
- {
- if ($this->hasXMLErrorOccured()) {
- $this->resetXMLInternalErrorsSetting();
-
- throw new XMLProcessingException($this->getLastXMLErrorMessage());
- }
-
- $this->resetXMLInternalErrorsSetting();
- }
-
- protected function resetXMLInternalErrorsSetting()
- {
- libxml_use_internal_errors($this->initialUseInternalErrorsValue);
- }
-
- /**
- * Returns whether the a XML error has occured since the last time errors were cleared.
- *
- * @return bool TRUE if an error occured, FALSE otherwise
- */
- private function hasXMLErrorOccured()
- {
- return false !== libxml_get_last_error();
- }
-
- /**
- * Returns the error message for the last XML error that occured.
- *
- * @see libxml_get_last_error
- *
- * @return null|string Last XML error message or null if no error
- */
- private function getLastXMLErrorMessage()
- {
- $errorMessage = null;
- $error = libxml_get_last_error();
-
- if (false !== $error) {
- $errorMessage = trim($error->message);
- }
-
- return $errorMessage;
- }
-}
diff --git a/upstream-3.x/src/Reader/Wrapper/XMLReader.php b/upstream-3.x/src/Reader/Wrapper/XMLReader.php
deleted file mode 100644
index 946ca27..0000000
--- a/upstream-3.x/src/Reader/Wrapper/XMLReader.php
+++ /dev/null
@@ -1,192 +0,0 @@
-getRealPathURIForFileInZip($zipFilePath, $fileInsideZipPath);
-
- // We need to check first that the file we are trying to read really exist because:
- // - PHP emits a warning when trying to open a file that does not exist.
- // - HHVM does not check if file exists within zip file (@link https://github.com/facebook/hhvm/issues/5779)
- if ($this->fileExistsWithinZip($realPathURI)) {
- $wasOpenSuccessful = $this->open($realPathURI, null, LIBXML_NONET);
- }
-
- return $wasOpenSuccessful;
- }
-
- /**
- * Returns the real path for the given path components.
- * This is useful to avoid issues on some Windows setup.
- *
- * @param string $zipFilePath Path to the ZIP file
- * @param string $fileInsideZipPath Relative or absolute path of the file inside the zip
- *
- * @return string The real path URI
- */
- public function getRealPathURIForFileInZip($zipFilePath, $fileInsideZipPath)
- {
- // The file path should not start with a '/', otherwise it won't be found
- $fileInsideZipPathWithoutLeadingSlash = ltrim($fileInsideZipPath, '/');
-
- return self::ZIP_WRAPPER.realpath($zipFilePath).'#'.$fileInsideZipPathWithoutLeadingSlash;
- }
-
- /**
- * Move to next node in document.
- *
- * @see \XMLReader::read
- *
- * @throws \OpenSpout\Reader\Exception\XMLProcessingException If an error/warning occurred
- *
- * @return bool TRUE on success or FALSE on failure
- */
- #[\ReturnTypeWillChange]
- public function read()
- {
- $this->useXMLInternalErrors();
-
- $wasReadSuccessful = parent::read();
-
- $this->resetXMLInternalErrorsSettingAndThrowIfXMLErrorOccured();
-
- return $wasReadSuccessful;
- }
-
- /**
- * Read until the element with the given name is found, or the end of the file.
- *
- * @param string $nodeName Name of the node to find
- *
- * @throws \OpenSpout\Reader\Exception\XMLProcessingException If an error/warning occurred
- *
- * @return bool TRUE on success or FALSE on failure
- */
- public function readUntilNodeFound($nodeName)
- {
- do {
- $wasReadSuccessful = $this->read();
- $isNotPositionedOnStartingNode = !$this->isPositionedOnStartingNode($nodeName);
- } while ($wasReadSuccessful && $isNotPositionedOnStartingNode);
-
- return $wasReadSuccessful;
- }
-
- /**
- * Move cursor to next node skipping all subtrees.
- *
- * @see \XMLReader::next
- *
- * @param null|string $localName The name of the next node to move to
- *
- * @throws \OpenSpout\Reader\Exception\XMLProcessingException If an error/warning occurred
- *
- * @return bool TRUE on success or FALSE on failure
- */
- #[\ReturnTypeWillChange]
- public function next($localName = null)
- {
- $this->useXMLInternalErrors();
-
- $wasNextSuccessful = parent::next($localName);
-
- $this->resetXMLInternalErrorsSettingAndThrowIfXMLErrorOccured();
-
- return $wasNextSuccessful;
- }
-
- /**
- * @param string $nodeName
- *
- * @return bool Whether the XML Reader is currently positioned on the starting node with given name
- */
- public function isPositionedOnStartingNode($nodeName)
- {
- return $this->isPositionedOnNode($nodeName, self::ELEMENT);
- }
-
- /**
- * @param string $nodeName
- *
- * @return bool Whether the XML Reader is currently positioned on the ending node with given name
- */
- public function isPositionedOnEndingNode($nodeName)
- {
- return $this->isPositionedOnNode($nodeName, self::END_ELEMENT);
- }
-
- /**
- * @return string The name of the current node, un-prefixed
- */
- public function getCurrentNodeName()
- {
- return $this->localName;
- }
-
- /**
- * Returns whether the file at the given location exists.
- *
- * @param string $zipStreamURI URI of a zip stream, e.g. "zip://file.zip#path/inside.xml"
- *
- * @return bool TRUE if the file exists, FALSE otherwise
- */
- protected function fileExistsWithinZip($zipStreamURI)
- {
- $doesFileExists = false;
-
- $pattern = '/zip:\/\/([^#]+)#(.*)/';
- if (preg_match($pattern, $zipStreamURI, $matches)) {
- $zipFilePath = $matches[1];
- $innerFilePath = $matches[2];
-
- $zip = new \ZipArchive();
- if (true === $zip->open($zipFilePath)) {
- $doesFileExists = (false !== $zip->locateName($innerFilePath));
- $zip->close();
- }
- }
-
- return $doesFileExists;
- }
-
- /**
- * @param string $nodeName
- * @param int $nodeType
- *
- * @return bool Whether the XML Reader is currently positioned on the node with given name and type
- */
- private function isPositionedOnNode($nodeName, $nodeType)
- {
- /**
- * In some cases, the node has a prefix (for instance, "" can also be "").
- * So if the given node name does not have a prefix, we need to look at the unprefixed name ("localName").
- *
- * @see https://github.com/box/spout/issues/233
- */
- $hasPrefix = (false !== strpos($nodeName, ':'));
- $currentNodeName = ($hasPrefix) ? $this->name : $this->localName;
-
- return $this->nodeType === $nodeType && $currentNodeName === $nodeName;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Creator/HelperFactory.php b/upstream-3.x/src/Reader/XLSX/Creator/HelperFactory.php
deleted file mode 100644
index 3528b23..0000000
--- a/upstream-3.x/src/Reader/XLSX/Creator/HelperFactory.php
+++ /dev/null
@@ -1,38 +0,0 @@
-createStringsEscaper();
-
- return new CellValueFormatter($sharedStringsManager, $styleManager, $shouldFormatDates, $shouldUse1904Dates, $escaper);
- }
-
- /**
- * @return Escaper\XLSX
- */
- public function createStringsEscaper()
- {
- // @noinspection PhpUnnecessaryFullyQualifiedNameInspection
- return new Escaper\XLSX();
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Creator/InternalEntityFactory.php b/upstream-3.x/src/Reader/XLSX/Creator/InternalEntityFactory.php
deleted file mode 100644
index 33b18df..0000000
--- a/upstream-3.x/src/Reader/XLSX/Creator/InternalEntityFactory.php
+++ /dev/null
@@ -1,163 +0,0 @@
-managerFactory = $managerFactory;
- $this->helperFactory = $helperFactory;
- }
-
- /**
- * @param string $filePath Path of the file to be read
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- * @param SharedStringsManager $sharedStringsManager Manages shared strings
- *
- * @return SheetIterator
- */
- public function createSheetIterator($filePath, $optionsManager, $sharedStringsManager)
- {
- $sheetManager = $this->managerFactory->createSheetManager(
- $filePath,
- $optionsManager,
- $sharedStringsManager,
- $this
- );
-
- return new SheetIterator($sheetManager);
- }
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml
- * @param int $sheetIndex Index of the sheet, based on order in the workbook (zero-based)
- * @param string $sheetName Name of the sheet
- * @param bool $isSheetActive Whether the sheet was defined as active
- * @param bool $isSheetVisible Whether the sheet is visible
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- * @param SharedStringsManager $sharedStringsManager Manages shared strings
- *
- * @return Sheet
- */
- public function createSheet(
- $filePath,
- $sheetDataXMLFilePath,
- $sheetIndex,
- $sheetName,
- $isSheetActive,
- $isSheetVisible,
- $optionsManager,
- $sharedStringsManager
- ) {
- $rowIterator = $this->createRowIterator($filePath, $sheetDataXMLFilePath, $optionsManager, $sharedStringsManager);
-
- return new Sheet($rowIterator, $sheetIndex, $sheetName, $isSheetActive, $isSheetVisible);
- }
-
- /**
- * @param Cell[] $cells
- *
- * @return Row
- */
- public function createRow(array $cells = [])
- {
- return new Row($cells, null);
- }
-
- /**
- * @param mixed $cellValue
- *
- * @return Cell
- */
- public function createCell($cellValue)
- {
- return new Cell($cellValue);
- }
-
- /**
- * @return \ZipArchive
- */
- public function createZipArchive()
- {
- return new \ZipArchive();
- }
-
- /**
- * @return XMLReader
- */
- public function createXMLReader()
- {
- return new XMLReader();
- }
-
- /**
- * @param XMLReader $xmlReader
- *
- * @return XMLProcessor
- */
- public function createXMLProcessor($xmlReader)
- {
- return new XMLProcessor($xmlReader);
- }
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- * @param SharedStringsManager $sharedStringsManager Manages shared strings
- *
- * @return RowIterator
- */
- private function createRowIterator($filePath, $sheetDataXMLFilePath, $optionsManager, $sharedStringsManager)
- {
- $xmlReader = $this->createXMLReader();
- $xmlProcessor = $this->createXMLProcessor($xmlReader);
-
- $styleManager = $this->managerFactory->createStyleManager($filePath, $this);
- $rowManager = $this->managerFactory->createRowManager($this);
- $shouldFormatDates = $optionsManager->getOption(Options::SHOULD_FORMAT_DATES);
- $shouldUse1904Dates = $optionsManager->getOption(Options::SHOULD_USE_1904_DATES);
-
- $cellValueFormatter = $this->helperFactory->createCellValueFormatter(
- $sharedStringsManager,
- $styleManager,
- $shouldFormatDates,
- $shouldUse1904Dates
- );
-
- $shouldPreserveEmptyRows = $optionsManager->getOption(Options::SHOULD_PRESERVE_EMPTY_ROWS);
-
- return new RowIterator(
- $filePath,
- $sheetDataXMLFilePath,
- $shouldPreserveEmptyRows,
- $xmlReader,
- $xmlProcessor,
- $cellValueFormatter,
- $rowManager,
- $this
- );
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Creator/ManagerFactory.php b/upstream-3.x/src/Reader/XLSX/Creator/ManagerFactory.php
deleted file mode 100644
index 10a8833..0000000
--- a/upstream-3.x/src/Reader/XLSX/Creator/ManagerFactory.php
+++ /dev/null
@@ -1,109 +0,0 @@
-helperFactory = $helperFactory;
- $this->cachingStrategyFactory = $cachingStrategyFactory;
- }
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param string $tempFolder Temporary folder where the temporary files to store shared strings will be stored
- * @param InternalEntityFactory $entityFactory Factory to create entities
- *
- * @return SharedStringsManager
- */
- public function createSharedStringsManager($filePath, $tempFolder, $entityFactory)
- {
- $workbookRelationshipsManager = $this->createWorkbookRelationshipsManager($filePath, $entityFactory);
-
- return new SharedStringsManager(
- $filePath,
- $tempFolder,
- $workbookRelationshipsManager,
- $entityFactory,
- $this->helperFactory,
- $this->cachingStrategyFactory
- );
- }
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param \OpenSpout\Common\Manager\OptionsManagerInterface $optionsManager Reader's options manager
- * @param \OpenSpout\Reader\XLSX\Manager\SharedStringsManager $sharedStringsManager Manages shared strings
- * @param InternalEntityFactory $entityFactory Factory to create entities
- *
- * @return SheetManager
- */
- public function createSheetManager($filePath, $optionsManager, $sharedStringsManager, $entityFactory)
- {
- $escaper = $this->helperFactory->createStringsEscaper();
-
- return new SheetManager($filePath, $optionsManager, $sharedStringsManager, $escaper, $entityFactory);
- }
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param InternalEntityFactory $entityFactory Factory to create entities
- *
- * @return StyleManager
- */
- public function createStyleManager($filePath, $entityFactory)
- {
- $workbookRelationshipsManager = $this->createWorkbookRelationshipsManager($filePath, $entityFactory);
-
- return new StyleManager($filePath, $workbookRelationshipsManager, $entityFactory);
- }
-
- /**
- * @param InternalEntityFactory $entityFactory Factory to create entities
- *
- * @return RowManager
- */
- public function createRowManager($entityFactory)
- {
- return new RowManager($entityFactory);
- }
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param InternalEntityFactory $entityFactory Factory to create entities
- *
- * @return WorkbookRelationshipsManager
- */
- private function createWorkbookRelationshipsManager($filePath, $entityFactory)
- {
- if (!isset($this->cachedWorkbookRelationshipsManager)) {
- $this->cachedWorkbookRelationshipsManager = new WorkbookRelationshipsManager($filePath, $entityFactory);
- }
-
- return $this->cachedWorkbookRelationshipsManager;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Helper/CellHelper.php b/upstream-3.x/src/Reader/XLSX/Helper/CellHelper.php
deleted file mode 100644
index 827d728..0000000
--- a/upstream-3.x/src/Reader/XLSX/Helper/CellHelper.php
+++ /dev/null
@@ -1,87 +0,0 @@
- 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, 'F' => 5, 'G' => 6,
- 'H' => 7, 'I' => 8, 'J' => 9, 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13,
- 'O' => 14, 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, 'U' => 20,
- 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, 'Z' => 25,
- ];
-
- /**
- * Returns the base 10 column index associated to the cell index (base 26).
- * Excel uses A to Z letters for column indexing, where A is the 1st column,
- * Z is the 26th and AA is the 27th.
- * The mapping is zero based, so that A1 maps to 0, B2 maps to 1, Z13 to 25 and AA4 to 26.
- *
- * @param string $cellIndex The Excel cell index ('A1', 'BC13', ...)
- *
- * @throws \OpenSpout\Common\Exception\InvalidArgumentException When the given cell index is invalid
- *
- * @return int
- */
- public static function getColumnIndexFromCellIndex($cellIndex)
- {
- if (!self::isValidCellIndex($cellIndex)) {
- throw new InvalidArgumentException('Cannot get column index from an invalid cell index.');
- }
-
- $columnIndex = 0;
-
- // Remove row information
- $columnLetters = preg_replace('/\d/', '', $cellIndex);
-
- // strlen() is super slow too... Using isset() is way faster and not too unreadable,
- // since we checked before that there are between 1 and 3 letters.
- $columnLength = isset($columnLetters[1]) ? (isset($columnLetters[2]) ? 3 : 2) : 1;
-
- // Looping over the different letters of the column is slower than this method.
- // Also, not using the pow() function because it's slooooow...
- switch ($columnLength) {
- case 1:
- $columnIndex = (self::$columnLetterToIndexMapping[$columnLetters]);
-
- break;
-
- case 2:
- $firstLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[0]] + 1) * 26;
- $secondLetterIndex = self::$columnLetterToIndexMapping[$columnLetters[1]];
- $columnIndex = $firstLetterIndex + $secondLetterIndex;
-
- break;
-
- case 3:
- $firstLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[0]] + 1) * 676;
- $secondLetterIndex = (self::$columnLetterToIndexMapping[$columnLetters[1]] + 1) * 26;
- $thirdLetterIndex = self::$columnLetterToIndexMapping[$columnLetters[2]];
- $columnIndex = $firstLetterIndex + $secondLetterIndex + $thirdLetterIndex;
-
- break;
- }
-
- return $columnIndex;
- }
-
- /**
- * Returns whether a cell index is valid, in an Excel world.
- * To be valid, the cell index should start with capital letters and be followed by numbers.
- * There can only be 3 letters, as there can only be 16,384 rows, which is equivalent to 'XFE'.
- *
- * @param string $cellIndex The Excel cell index ('A1', 'BC13', ...)
- *
- * @return bool
- */
- protected static function isValidCellIndex($cellIndex)
- {
- return 1 === preg_match('/^[A-Z]{1,3}\d+$/', $cellIndex);
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Helper/CellValueFormatter.php b/upstream-3.x/src/Reader/XLSX/Helper/CellValueFormatter.php
deleted file mode 100644
index 08e5282..0000000
--- a/upstream-3.x/src/Reader/XLSX/Helper/CellValueFormatter.php
+++ /dev/null
@@ -1,319 +0,0 @@
-sharedStringsManager = $sharedStringsManager;
- $this->styleManager = $styleManager;
- $this->shouldFormatDates = $shouldFormatDates;
- $this->shouldUse1904Dates = $shouldUse1904Dates;
- $this->escaper = $escaper;
- }
-
- /**
- * Returns the (unescaped) correctly marshalled, cell value associated to the given XML node.
- *
- * @param \DOMElement $node
- *
- * @throws InvalidValueException If the value is not valid
- *
- * @return bool|\DateTime|float|int|string The value associated with the cell
- */
- public function extractAndFormatNodeValue($node)
- {
- // Default cell type is "n"
- $cellType = $node->getAttribute(self::XML_ATTRIBUTE_TYPE) ?: self::CELL_TYPE_NUMERIC;
- $cellStyleId = (int) $node->getAttribute(self::XML_ATTRIBUTE_STYLE_ID);
- $vNodeValue = $this->getVNodeValue($node);
-
- if (('' === $vNodeValue) && (self::CELL_TYPE_INLINE_STRING !== $cellType)) {
- return $vNodeValue;
- }
-
- switch ($cellType) {
- case self::CELL_TYPE_INLINE_STRING:
- return $this->formatInlineStringCellValue($node);
-
- case self::CELL_TYPE_SHARED_STRING:
- return $this->formatSharedStringCellValue($vNodeValue);
-
- case self::CELL_TYPE_STR:
- return $this->formatStrCellValue($vNodeValue);
-
- case self::CELL_TYPE_BOOLEAN:
- return $this->formatBooleanCellValue($vNodeValue);
-
- case self::CELL_TYPE_NUMERIC:
- return $this->formatNumericCellValue($vNodeValue, $cellStyleId);
-
- case self::CELL_TYPE_DATE:
- return $this->formatDateCellValue($vNodeValue);
-
- default:
- throw new InvalidValueException($vNodeValue);
- }
- }
-
- /**
- * Returns the cell's string value from a node's nested value node.
- *
- * @param \DOMElement $node
- *
- * @return string The value associated with the cell
- */
- protected function getVNodeValue($node)
- {
- // for cell types having a "v" tag containing the value.
- // if not, the returned value should be empty string.
- $vNode = $node->getElementsByTagName(self::XML_NODE_VALUE)->item(0);
-
- return (null !== $vNode) ? $vNode->nodeValue : '';
- }
-
- /**
- * Returns the cell String value where string is inline.
- *
- * @param \DOMElement $node
- *
- * @return string The value associated with the cell
- */
- protected function formatInlineStringCellValue($node)
- {
- // inline strings are formatted this way (they can contain any number of nodes):
- // [INLINE_STRING][INLINE_STRING_2]
- $tNodes = $node->getElementsByTagName(self::XML_NODE_INLINE_STRING_VALUE);
-
- $cellValue = '';
- for ($i = 0; $i < $tNodes->count(); ++$i) {
- $tNode = $tNodes->item($i);
- $cellValue .= $this->escaper->unescape($tNode->nodeValue);
- }
-
- return $cellValue;
- }
-
- /**
- * Returns the cell String value from shared-strings file using nodeValue index.
- *
- * @param string $nodeValue
- *
- * @return string The value associated with the cell
- */
- protected function formatSharedStringCellValue($nodeValue)
- {
- // shared strings are formatted this way:
- // [SHARED_STRING_INDEX]
- $sharedStringIndex = (int) $nodeValue;
- $escapedCellValue = $this->sharedStringsManager->getStringAtIndex($sharedStringIndex);
-
- return $this->escaper->unescape($escapedCellValue);
- }
-
- /**
- * Returns the cell String value, where string is stored in value node.
- *
- * @param string $nodeValue
- *
- * @return string The value associated with the cell
- */
- protected function formatStrCellValue($nodeValue)
- {
- $escapedCellValue = trim($nodeValue);
-
- return $this->escaper->unescape($escapedCellValue);
- }
-
- /**
- * Returns the cell Numeric value from string of nodeValue.
- * The value can also represent a timestamp and a DateTime will be returned.
- *
- * @param string $nodeValue
- * @param int $cellStyleId 0 being the default style
- *
- * @return \DateTime|float|int The value associated with the cell
- */
- protected function formatNumericCellValue($nodeValue, $cellStyleId)
- {
- // Numeric values can represent numbers as well as timestamps.
- // We need to look at the style of the cell to determine whether it is one or the other.
- $shouldFormatAsDate = $this->styleManager->shouldFormatNumericValueAsDate($cellStyleId);
-
- if ($shouldFormatAsDate) {
- $cellValue = $this->formatExcelTimestampValue((float) $nodeValue, $cellStyleId);
- } else {
- $nodeIntValue = (int) $nodeValue;
- $nodeFloatValue = (float) $nodeValue;
- $cellValue = ((float) $nodeIntValue === $nodeFloatValue) ? $nodeIntValue : $nodeFloatValue;
- }
-
- return $cellValue;
- }
-
- /**
- * Returns a cell's PHP Date value, associated to the given timestamp.
- * NOTE: The timestamp is a float representing the number of days since the base Excel date:
- * Dec 30th 1899, 1900 or Jan 1st, 1904, depending on the Workbook setting.
- * NOTE: The timestamp can also represent a time, if it is a value between 0 and 1.
- *
- * @see ECMA-376 Part 1 - §18.17.4
- *
- * @param float $nodeValue
- * @param int $cellStyleId 0 being the default style
- *
- * @throws InvalidValueException If the value is not a valid timestamp
- *
- * @return \DateTime The value associated with the cell
- */
- protected function formatExcelTimestampValue($nodeValue, $cellStyleId)
- {
- if ($this->isValidTimestampValue($nodeValue)) {
- $cellValue = $this->formatExcelTimestampValueAsDateTimeValue($nodeValue, $cellStyleId);
- } else {
- throw new InvalidValueException($nodeValue);
- }
-
- return $cellValue;
- }
-
- /**
- * Returns whether the given timestamp is supported by SpreadsheetML.
- *
- * @see ECMA-376 Part 1 - §18.17.4 - this specifies the timestamp boundaries.
- *
- * @param float $timestampValue
- *
- * @return bool
- */
- protected function isValidTimestampValue($timestampValue)
- {
- // @NOTE: some versions of Excel don't support negative dates (e.g. Excel for Mac 2011)
- return
- $this->shouldUse1904Dates && $timestampValue >= -695055 && $timestampValue <= 2957003.9999884
- || !$this->shouldUse1904Dates && $timestampValue >= -693593 && $timestampValue <= 2958465.9999884
- ;
- }
-
- /**
- * Returns a cell's PHP DateTime value, associated to the given timestamp.
- * Only the time value matters. The date part is set to the base Excel date:
- * Dec 30th 1899, 1900 or Jan 1st, 1904, depending on the Workbook setting.
- *
- * @param float $nodeValue
- * @param int $cellStyleId 0 being the default style
- *
- * @return \DateTime|string The value associated with the cell
- */
- protected function formatExcelTimestampValueAsDateTimeValue($nodeValue, $cellStyleId)
- {
- $baseDate = $this->shouldUse1904Dates ? '1904-01-01' : '1899-12-30';
-
- $daysSinceBaseDate = (int) $nodeValue;
- $timeRemainder = fmod($nodeValue, 1);
- $secondsRemainder = round($timeRemainder * self::NUM_SECONDS_IN_ONE_DAY, 0);
-
- $dateObj = \DateTime::createFromFormat('|Y-m-d', $baseDate);
- $dateObj->modify('+'.$daysSinceBaseDate.'days');
- $dateObj->modify('+'.$secondsRemainder.'seconds');
-
- if ($this->shouldFormatDates) {
- //$styleNumberFormatCode = $this->styleManager->getNumberFormatCode($cellStyleId);
- //$phpDateFormat = DateFormatHelper::toPHPDateFormat($styleNumberFormatCode);
- // Toujours utiliser le format français complet
- $phpDateFormat = "d/m/Y H:i:s";
- $cellValue = $dateObj->format($phpDateFormat);
- // Enlever la composante heure si elle n'existe pas
- $cellValue = preg_replace('/ 00:00:00$/', "", $cellValue);
- } else {
- $cellValue = $dateObj;
- }
-
- return $cellValue;
- }
-
- /**
- * Returns the cell Boolean value from a specific node's Value.
- *
- * @param string $nodeValue
- *
- * @return bool The value associated with the cell
- */
- protected function formatBooleanCellValue($nodeValue)
- {
- return (bool) $nodeValue;
- }
-
- /**
- * Returns a cell's PHP Date value, associated to the given stored nodeValue.
- *
- * @see ECMA-376 Part 1 - §18.17.4
- *
- * @param string $nodeValue ISO 8601 Date string
- *
- * @throws InvalidValueException If the value is not a valid date
- *
- * @return \DateTime|string The value associated with the cell
- */
- protected function formatDateCellValue($nodeValue)
- {
- // Mitigate thrown Exception on invalid date-time format (http://php.net/manual/en/datetime.construct.php)
- try {
- $cellValue = ($this->shouldFormatDates) ? $nodeValue : new \DateTime($nodeValue);
- } catch (\Exception $e) {
- throw new InvalidValueException($nodeValue);
- }
-
- return $cellValue;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Helper/DateFormatHelper.php b/upstream-3.x/src/Reader/XLSX/Helper/DateFormatHelper.php
deleted file mode 100644
index 78fc4f4..0000000
--- a/upstream-3.x/src/Reader/XLSX/Helper/DateFormatHelper.php
+++ /dev/null
@@ -1,122 +0,0 @@
- [
- // Time
- 'am/pm' => 'A', // Uppercase Ante meridiem and Post meridiem
- ':mm' => ':i', // Minutes with leading zeros - if preceded by a ":" (otherwise month)
- 'mm:' => 'i:', // Minutes with leading zeros - if followed by a ":" (otherwise month)
- 'ss' => 's', // Seconds, with leading zeros
- '.s' => '', // Ignore (fractional seconds format does not exist in PHP)
-
- // Date
- 'e' => 'Y', // Full numeric representation of a year, 4 digits
- 'yyyy' => 'Y', // Full numeric representation of a year, 4 digits
- 'yy' => 'y', // Two digit representation of a year
- 'mmmmm' => 'M', // Short textual representation of a month, three letters ("mmmmm" should only contain the 1st letter...)
- 'mmmm' => 'F', // Full textual representation of a month
- 'mmm' => 'M', // Short textual representation of a month, three letters
- 'mm' => 'm', // Numeric representation of a month, with leading zeros
- 'm' => 'n', // Numeric representation of a month, without leading zeros
- 'dddd' => 'l', // Full textual representation of the day of the week
- 'ddd' => 'D', // Textual representation of a day, three letters
- 'dd' => 'd', // Day of the month, 2 digits with leading zeros
- 'd' => 'j', // Day of the month without leading zeros
- ],
- self::KEY_HOUR_12 => [
- 'hh' => 'h', // 12-hour format of an hour without leading zeros
- 'h' => 'g', // 12-hour format of an hour without leading zeros
- ],
- self::KEY_HOUR_24 => [
- 'hh' => 'H', // 24-hour hours with leading zero
- 'h' => 'G', // 24-hour format of an hour without leading zeros
- ],
- ];
-
- /**
- * Converts the given Excel date format to a format understandable by the PHP date function.
- *
- * @param string $excelDateFormat Excel date format
- *
- * @return string PHP date format (as defined here: http://php.net/manual/en/function.date.php)
- */
- public static function toPHPDateFormat($excelDateFormat)
- {
- // Remove brackets potentially present at the beginning of the format string
- // and text portion of the format at the end of it (starting with ";")
- // See §18.8.31 of ECMA-376 for more detail.
- $dateFormat = preg_replace('/^(?:\[\$[^\]]+?\])?([^;]*).*/', '$1', $excelDateFormat);
-
- // Double quotes are used to escape characters that must not be interpreted.
- // For instance, ["Day " dd] should result in "Day 13" and we should not try to interpret "D", "a", "y"
- // By exploding the format string using double quote as a delimiter, we can get all parts
- // that must be transformed (even indexes) and all parts that must not be (odd indexes).
- $dateFormatParts = explode('"', $dateFormat);
-
- foreach ($dateFormatParts as $partIndex => $dateFormatPart) {
- // do not look at odd indexes
- if (1 === $partIndex % 2) {
- continue;
- }
-
- // Make sure all characters are lowercase, as the mapping table is using lowercase characters
- $transformedPart = strtolower($dateFormatPart);
-
- // Remove escapes related to non-format characters
- $transformedPart = str_replace('\\', '', $transformedPart);
-
- // Apply general transformation first...
- $transformedPart = strtr($transformedPart, self::$excelDateFormatToPHPDateFormatMapping[self::KEY_GENERAL]);
-
- // ... then apply hour transformation, for 12-hour or 24-hour format
- if (self::has12HourFormatMarker($dateFormatPart)) {
- $transformedPart = strtr($transformedPart, self::$excelDateFormatToPHPDateFormatMapping[self::KEY_HOUR_12]);
- } else {
- $transformedPart = strtr($transformedPart, self::$excelDateFormatToPHPDateFormatMapping[self::KEY_HOUR_24]);
- }
-
- // overwrite the parts array with the new transformed part
- $dateFormatParts[$partIndex] = $transformedPart;
- }
-
- // Merge all transformed parts back together
- $phpDateFormat = implode('"', $dateFormatParts);
-
- // Finally, to have the date format compatible with the DateTime::format() function, we need to escape
- // all characters that are inside double quotes (and double quotes must be removed).
- // For instance, ["Day " dd] should become [\D\a\y\ dd]
- return preg_replace_callback('/"(.+?)"/', function ($matches) {
- $stringToEscape = $matches[1];
- $letters = preg_split('//u', $stringToEscape, -1, PREG_SPLIT_NO_EMPTY);
-
- return '\\'.implode('\\', $letters);
- }, $phpDateFormat);
- }
-
- /**
- * @param string $excelDateFormat Date format as defined by Excel
- *
- * @return bool Whether the given date format has the 12-hour format marker
- */
- private static function has12HourFormatMarker($excelDateFormat)
- {
- return false !== stripos($excelDateFormat, 'am/pm');
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/OptionsManager.php b/upstream-3.x/src/Reader/XLSX/Manager/OptionsManager.php
deleted file mode 100644
index 5749f65..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/OptionsManager.php
+++ /dev/null
@@ -1,36 +0,0 @@
-setOption(Options::TEMP_FOLDER, sys_get_temp_dir());
- $this->setOption(Options::SHOULD_FORMAT_DATES, true);
- $this->setOption(Options::SHOULD_PRESERVE_EMPTY_ROWS, false);
- $this->setOption(Options::SHOULD_USE_1904_DATES, false);
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/CachingStrategyFactory.php b/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/CachingStrategyFactory.php
deleted file mode 100644
index c2f8c9f..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/CachingStrategyFactory.php
+++ /dev/null
@@ -1,141 +0,0 @@
- 20 * 600 ≈ 12KB
- */
- public const AMOUNT_MEMORY_NEEDED_PER_STRING_IN_KB = 12;
-
- /**
- * To avoid running out of memory when extracting a huge number of shared strings, they can be saved to temporary files
- * instead of in memory. Then, when accessing a string, the corresponding file contents will be loaded in memory
- * and the string will be quickly retrieved.
- * The performance bottleneck is not when creating these temporary files, but rather when loading their content.
- * Because the contents of the last loaded file stays in memory until another file needs to be loaded, it works
- * best when the indexes of the shared strings are sorted in the sheet data.
- * 10,000 was chosen because it creates small files that are fast to be loaded in memory.
- */
- public const MAX_NUM_STRINGS_PER_TEMP_FILE = 10000;
-
- /**
- * Returns the best caching strategy, given the number of unique shared strings
- * and the amount of memory available.
- *
- * @param null|int $sharedStringsUniqueCount Number of unique shared strings (NULL if unknown)
- * @param string $tempFolder Temporary folder where the temporary files to store shared strings will be stored
- * @param HelperFactory $helperFactory Factory to create helpers
- *
- * @return CachingStrategyInterface The best caching strategy
- */
- public function createBestCachingStrategy($sharedStringsUniqueCount, $tempFolder, $helperFactory)
- {
- if ($this->isInMemoryStrategyUsageSafe($sharedStringsUniqueCount)) {
- return new InMemoryStrategy($sharedStringsUniqueCount);
- }
-
- return new FileBasedStrategy($tempFolder, self::MAX_NUM_STRINGS_PER_TEMP_FILE, $helperFactory);
- }
-
- /**
- * Returns whether it is safe to use in-memory caching, given the number of unique shared strings
- * and the amount of memory available.
- *
- * @param null|int $sharedStringsUniqueCount Number of unique shared strings (NULL if unknown)
- *
- * @return bool
- */
- protected function isInMemoryStrategyUsageSafe($sharedStringsUniqueCount)
- {
- // if the number of shared strings in unknown, do not use "in memory" strategy
- if (null === $sharedStringsUniqueCount) {
- return false;
- }
-
- $memoryAvailable = $this->getMemoryLimitInKB();
-
- if (-1 === (int) $memoryAvailable) {
- // if cannot get memory limit or if memory limit set as unlimited, don't trust and play safe
- $isInMemoryStrategyUsageSafe = ($sharedStringsUniqueCount < self::MAX_NUM_STRINGS_PER_TEMP_FILE);
- } else {
- $memoryNeeded = $sharedStringsUniqueCount * self::AMOUNT_MEMORY_NEEDED_PER_STRING_IN_KB;
- $isInMemoryStrategyUsageSafe = ($memoryAvailable > $memoryNeeded);
- }
-
- return $isInMemoryStrategyUsageSafe;
- }
-
- /**
- * Returns the PHP "memory_limit" in Kilobytes.
- *
- * @return float
- */
- protected function getMemoryLimitInKB()
- {
- $memoryLimitFormatted = $this->getMemoryLimitFromIni();
- $memoryLimitFormatted = strtolower(trim($memoryLimitFormatted));
-
- // No memory limit
- if ('-1' === $memoryLimitFormatted) {
- return -1;
- }
-
- if (preg_match('/(\d+)([bkmgt])b?/', $memoryLimitFormatted, $matches)) {
- $amount = (int) ($matches[1]);
- $unit = $matches[2];
-
- switch ($unit) {
- case 'b': return $amount / 1024;
-
- case 'k': return $amount;
-
- case 'm': return $amount * 1024;
-
- case 'g': return $amount * 1024 * 1024;
-
- case 't': return $amount * 1024 * 1024 * 1024;
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the formatted "memory_limit" value.
- *
- * @return string
- */
- protected function getMemoryLimitFromIni()
- {
- return ini_get('memory_limit');
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/CachingStrategyInterface.php b/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/CachingStrategyInterface.php
deleted file mode 100644
index b314827..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/CachingStrategyInterface.php
+++ /dev/null
@@ -1,39 +0,0 @@
-fileSystemHelper = $helperFactory->createFileSystemHelper($tempFolder);
- $this->tempFolder = $this->fileSystemHelper->createFolder($tempFolder, uniqid('sharedstrings'));
-
- $this->maxNumStringsPerTempFile = $maxNumStringsPerTempFile;
-
- $this->globalFunctionsHelper = $helperFactory->createGlobalFunctionsHelper();
- $this->tempFilePointer = null;
- }
-
- /**
- * Adds the given string to the cache.
- *
- * @param string $sharedString The string to be added to the cache
- * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
- */
- public function addStringForIndex($sharedString, $sharedStringIndex)
- {
- $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex);
-
- if (!$this->globalFunctionsHelper->file_exists($tempFilePath)) {
- if ($this->tempFilePointer) {
- $this->globalFunctionsHelper->fclose($this->tempFilePointer);
- }
- $this->tempFilePointer = $this->globalFunctionsHelper->fopen($tempFilePath, 'w');
- }
-
- // The shared string retrieval logic expects each cell data to be on one line only
- // Encoding the line feed character allows to preserve this assumption
- $lineFeedEncodedSharedString = $this->escapeLineFeed($sharedString);
-
- $this->globalFunctionsHelper->fwrite($this->tempFilePointer, $lineFeedEncodedSharedString.PHP_EOL);
- }
-
- /**
- * Closes the cache after the last shared string was added.
- * This prevents any additional string from being added to the cache.
- */
- public function closeCache()
- {
- // close pointer to the last temp file that was written
- if ($this->tempFilePointer) {
- $this->globalFunctionsHelper->fclose($this->tempFilePointer);
- }
- }
-
- /**
- * Returns the string located at the given index from the cache.
- *
- * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
- *
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index
- *
- * @return string The shared string at the given index
- */
- public function getStringAtIndex($sharedStringIndex)
- {
- $tempFilePath = $this->getSharedStringTempFilePath($sharedStringIndex);
- $indexInFile = $sharedStringIndex % $this->maxNumStringsPerTempFile;
-
- if (!$this->globalFunctionsHelper->file_exists($tempFilePath)) {
- throw new SharedStringNotFoundException("Shared string temp file not found: {$tempFilePath} ; for index: {$sharedStringIndex}");
- }
-
- if ($this->inMemoryTempFilePath !== $tempFilePath) {
- $this->inMemoryTempFileContents = explode(PHP_EOL, $this->globalFunctionsHelper->file_get_contents($tempFilePath));
- $this->inMemoryTempFilePath = $tempFilePath;
- }
-
- $sharedString = null;
-
- // Using isset here because it is way faster than array_key_exists...
- if (isset($this->inMemoryTempFileContents[$indexInFile])) {
- $escapedSharedString = $this->inMemoryTempFileContents[$indexInFile];
- $sharedString = $this->unescapeLineFeed($escapedSharedString);
- }
-
- if (null === $sharedString) {
- throw new SharedStringNotFoundException("Shared string not found for index: {$sharedStringIndex}");
- }
-
- return rtrim($sharedString, PHP_EOL);
- }
-
- /**
- * Destroys the cache, freeing memory and removing any created artifacts.
- */
- public function clearCache()
- {
- if ($this->tempFolder) {
- $this->fileSystemHelper->deleteFolderRecursively($this->tempFolder);
- }
- }
-
- /**
- * Returns the path for the temp file that should contain the string for the given index.
- *
- * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
- *
- * @return string The temp file path for the given index
- */
- protected function getSharedStringTempFilePath($sharedStringIndex)
- {
- $numTempFile = (int) ($sharedStringIndex / $this->maxNumStringsPerTempFile);
-
- return $this->tempFolder.'/sharedstrings'.$numTempFile;
- }
-
- /**
- * Escapes the line feed characters (\n).
- *
- * @param string $unescapedString
- *
- * @return string
- */
- private function escapeLineFeed($unescapedString)
- {
- return str_replace("\n", self::ESCAPED_LINE_FEED_CHARACTER, $unescapedString);
- }
-
- /**
- * Unescapes the line feed characters (\n).
- *
- * @param string $escapedString
- *
- * @return string
- */
- private function unescapeLineFeed($escapedString)
- {
- return str_replace(self::ESCAPED_LINE_FEED_CHARACTER, "\n", $escapedString);
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/InMemoryStrategy.php b/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/InMemoryStrategy.php
deleted file mode 100644
index 04312ad..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsCaching/InMemoryStrategy.php
+++ /dev/null
@@ -1,76 +0,0 @@
-inMemoryCache = new \SplFixedArray($sharedStringsUniqueCount);
- $this->isCacheClosed = false;
- }
-
- /**
- * Adds the given string to the cache.
- *
- * @param string $sharedString The string to be added to the cache
- * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
- */
- public function addStringForIndex($sharedString, $sharedStringIndex)
- {
- if (!$this->isCacheClosed) {
- $this->inMemoryCache->offsetSet($sharedStringIndex, $sharedString);
- }
- }
-
- /**
- * Closes the cache after the last shared string was added.
- * This prevents any additional string from being added to the cache.
- */
- public function closeCache()
- {
- $this->isCacheClosed = true;
- }
-
- /**
- * Returns the string located at the given index from the cache.
- *
- * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
- *
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index
- *
- * @return string The shared string at the given index
- */
- public function getStringAtIndex($sharedStringIndex)
- {
- try {
- return $this->inMemoryCache->offsetGet($sharedStringIndex);
- } catch (\RuntimeException $e) {
- throw new SharedStringNotFoundException("Shared string not found for index: {$sharedStringIndex}");
- }
- }
-
- /**
- * Destroys the cache, freeing memory and removing any created artifacts.
- */
- public function clearCache()
- {
- $this->inMemoryCache = new \SplFixedArray(0);
- $this->isCacheClosed = false;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsManager.php b/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsManager.php
deleted file mode 100644
index 120ce68..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/SharedStringsManager.php
+++ /dev/null
@@ -1,252 +0,0 @@
-filePath = $filePath;
- $this->tempFolder = $tempFolder;
- $this->workbookRelationshipsManager = $workbookRelationshipsManager;
- $this->entityFactory = $entityFactory;
- $this->helperFactory = $helperFactory;
- $this->cachingStrategyFactory = $cachingStrategyFactory;
- }
-
- /**
- * Returns whether the XLSX file contains a shared strings XML file.
- *
- * @return bool
- */
- public function hasSharedStrings()
- {
- return $this->workbookRelationshipsManager->hasSharedStringsXMLFile();
- }
-
- /**
- * Builds an in-memory array containing all the shared strings of the sheet.
- * All the strings are stored in a XML file, located at 'xl/sharedStrings.xml'.
- * It is then accessed by the sheet data, via the string index in the built table.
- *
- * More documentation available here: http://msdn.microsoft.com/en-us/library/office/gg278314.aspx
- *
- * The XML file can be really big with sheets containing a lot of data. That is why
- * we need to use a XML reader that provides streaming like the XMLReader library.
- *
- * @throws \OpenSpout\Common\Exception\IOException If shared strings XML file can't be read
- */
- public function extractSharedStrings()
- {
- $sharedStringsXMLFilePath = $this->workbookRelationshipsManager->getSharedStringsXMLFilePath();
- $xmlReader = $this->entityFactory->createXMLReader();
- $sharedStringIndex = 0;
-
- if (false === $xmlReader->openFileInZip($this->filePath, $sharedStringsXMLFilePath)) {
- throw new IOException('Could not open "'.$sharedStringsXMLFilePath.'".');
- }
-
- try {
- $sharedStringsUniqueCount = $this->getSharedStringsUniqueCount($xmlReader);
- $this->cachingStrategy = $this->getBestSharedStringsCachingStrategy($sharedStringsUniqueCount);
-
- $xmlReader->readUntilNodeFound(self::XML_NODE_SI);
-
- while (self::XML_NODE_SI === $xmlReader->getCurrentNodeName()) {
- $this->processSharedStringsItem($xmlReader, $sharedStringIndex);
- ++$sharedStringIndex;
-
- // jump to the next '' tag
- $xmlReader->next(self::XML_NODE_SI);
- }
-
- $this->cachingStrategy->closeCache();
- } catch (XMLProcessingException $exception) {
- throw new IOException("The sharedStrings.xml file is invalid and cannot be read. [{$exception->getMessage()}]");
- }
-
- $xmlReader->close();
- }
-
- /**
- * Returns the shared string at the given index, using the previously chosen caching strategy.
- *
- * @param int $sharedStringIndex Index of the shared string in the sharedStrings.xml file
- *
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If no shared string found for the given index
- *
- * @return string The shared string at the given index
- */
- public function getStringAtIndex($sharedStringIndex)
- {
- return $this->cachingStrategy->getStringAtIndex($sharedStringIndex);
- }
-
- /**
- * Destroys the cache, freeing memory and removing any created artifacts.
- */
- public function cleanup()
- {
- if (null !== $this->cachingStrategy) {
- $this->cachingStrategy->clearCache();
- }
- }
-
- /**
- * Returns the shared strings unique count, as specified in tag.
- *
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader instance
- *
- * @throws \OpenSpout\Common\Exception\IOException If sharedStrings.xml is invalid and can't be read
- *
- * @return null|int Number of unique shared strings in the sharedStrings.xml file
- */
- protected function getSharedStringsUniqueCount($xmlReader)
- {
- $xmlReader->next(self::XML_NODE_SST);
-
- // Iterate over the "sst" elements to get the actual "sst ELEMENT" (skips any DOCTYPE)
- while (self::XML_NODE_SST === $xmlReader->getCurrentNodeName() && XMLReader::ELEMENT !== $xmlReader->nodeType) {
- $xmlReader->read();
- }
-
- $uniqueCount = $xmlReader->getAttribute(self::XML_ATTRIBUTE_UNIQUE_COUNT);
-
- // some software do not add the "uniqueCount" attribute but only use the "count" one
- // @see https://github.com/box/spout/issues/254
- if (null === $uniqueCount) {
- $uniqueCount = $xmlReader->getAttribute(self::XML_ATTRIBUTE_COUNT);
- }
-
- return (null !== $uniqueCount) ? (int) $uniqueCount : null;
- }
-
- /**
- * Returns the best shared strings caching strategy.
- *
- * @param null|int $sharedStringsUniqueCount Number of unique shared strings (NULL if unknown)
- *
- * @return CachingStrategyInterface
- */
- protected function getBestSharedStringsCachingStrategy($sharedStringsUniqueCount)
- {
- return $this->cachingStrategyFactory
- ->createBestCachingStrategy($sharedStringsUniqueCount, $this->tempFolder, $this->helperFactory)
- ;
- }
-
- /**
- * Processes the shared strings item XML node which the given XML reader is positioned on.
- *
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XML Reader positioned on a "" node
- * @param int $sharedStringIndex Index of the processed shared strings item
- */
- protected function processSharedStringsItem($xmlReader, $sharedStringIndex)
- {
- $sharedStringValue = '';
-
- // NOTE: expand() will automatically decode all XML entities of the child nodes
- /** @var \DOMElement $siNode */
- $siNode = $xmlReader->expand();
- $textNodes = $siNode->getElementsByTagName(self::XML_NODE_T);
-
- foreach ($textNodes as $textNode) {
- if ($this->shouldExtractTextNodeValue($textNode)) {
- $textNodeValue = $textNode->nodeValue;
- $shouldPreserveWhitespace = $this->shouldPreserveWhitespace($textNode);
-
- $sharedStringValue .= ($shouldPreserveWhitespace) ? $textNodeValue : trim($textNodeValue);
- }
- }
-
- $this->cachingStrategy->addStringForIndex($sharedStringValue, $sharedStringIndex);
- }
-
- /**
- * Not all text nodes' values must be extracted.
- * Some text nodes are part of a node describing the pronunciation for instance.
- * We'll only consider the nodes whose parents are "" or "".
- *
- * @param \DOMElement $textNode Text node to check
- *
- * @return bool Whether the given text node's value must be extracted
- */
- protected function shouldExtractTextNodeValue($textNode)
- {
- $parentTagName = $textNode->parentNode->localName;
-
- return self::XML_NODE_SI === $parentTagName || self::XML_NODE_R === $parentTagName;
- }
-
- /**
- * If the text node has the attribute 'xml:space="preserve"', then preserve whitespace.
- *
- * @param \DOMElement $textNode The text node element () whose whitespace may be preserved
- *
- * @return bool Whether whitespace should be preserved
- */
- protected function shouldPreserveWhitespace($textNode)
- {
- $spaceValue = $textNode->getAttribute(self::XML_ATTRIBUTE_XML_SPACE);
-
- return self::XML_ATTRIBUTE_VALUE_PRESERVE === $spaceValue;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/SheetManager.php b/upstream-3.x/src/Reader/XLSX/Manager/SheetManager.php
deleted file mode 100644
index e2e173e..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/SheetManager.php
+++ /dev/null
@@ -1,232 +0,0 @@
-filePath = $filePath;
- $this->optionsManager = $optionsManager;
- $this->sharedStringsManager = $sharedStringsManager;
- $this->escaper = $escaper;
- $this->entityFactory = $entityFactory;
- }
-
- /**
- * Returns the sheets metadata of the file located at the previously given file path.
- * The paths to the sheets' data are read from the [Content_Types].xml file.
- *
- * @return Sheet[] Sheets within the XLSX file
- */
- public function getSheets()
- {
- $this->sheets = [];
- $this->currentSheetIndex = 0;
- $this->activeSheetIndex = 0; // By default, the first sheet is active
-
- $xmlReader = $this->entityFactory->createXMLReader();
- $xmlProcessor = $this->entityFactory->createXMLProcessor($xmlReader);
-
- $xmlProcessor->registerCallback(self::XML_NODE_WORKBOOK_PROPERTIES, XMLProcessor::NODE_TYPE_START, [$this, 'processWorkbookPropertiesStartingNode']);
- $xmlProcessor->registerCallback(self::XML_NODE_WORKBOOK_VIEW, XMLProcessor::NODE_TYPE_START, [$this, 'processWorkbookViewStartingNode']);
- $xmlProcessor->registerCallback(self::XML_NODE_SHEET, XMLProcessor::NODE_TYPE_START, [$this, 'processSheetStartingNode']);
- $xmlProcessor->registerCallback(self::XML_NODE_SHEETS, XMLProcessor::NODE_TYPE_END, [$this, 'processSheetsEndingNode']);
-
- if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_XML_FILE_PATH)) {
- $xmlProcessor->readUntilStopped();
- $xmlReader->close();
- }
-
- return $this->sheets;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processWorkbookPropertiesStartingNode($xmlReader)
- {
- // Using "filter_var($x, FILTER_VALIDATE_BOOLEAN)" here because the value of the "date1904" attribute
- // may be the string "false", that is not mapped to the boolean "false" by default...
- $shouldUse1904Dates = filter_var($xmlReader->getAttribute(self::XML_ATTRIBUTE_DATE_1904), FILTER_VALIDATE_BOOLEAN);
- $this->optionsManager->setOption(Options::SHOULD_USE_1904_DATES, $shouldUse1904Dates);
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processWorkbookViewStartingNode($xmlReader)
- {
- // The "workbookView" node is located before "sheet" nodes, ensuring that
- // the active sheet is known before parsing sheets data.
- $this->activeSheetIndex = (int) $xmlReader->getAttribute(self::XML_ATTRIBUTE_ACTIVE_TAB);
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processSheetStartingNode($xmlReader)
- {
- $isSheetActive = ($this->currentSheetIndex === $this->activeSheetIndex);
- $this->sheets[] = $this->getSheetFromSheetXMLNode($xmlReader, $this->currentSheetIndex, $isSheetActive);
- ++$this->currentSheetIndex;
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processSheetsEndingNode()
- {
- return XMLProcessor::PROCESSING_STOP;
- }
-
- /**
- * Returns an instance of a sheet, given the XML node describing the sheet - from "workbook.xml".
- * We can find the XML file path describing the sheet inside "workbook.xml.res", by mapping with the sheet ID
- * ("r:id" in "workbook.xml", "Id" in "workbook.xml.res").
- *
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReaderOnSheetNode XML Reader instance, pointing on the node describing the sheet, as defined in "workbook.xml"
- * @param int $sheetIndexZeroBased Index of the sheet, based on order of appearance in the workbook (zero-based)
- * @param bool $isSheetActive Whether this sheet was defined as active
- *
- * @return \OpenSpout\Reader\XLSX\Sheet Sheet instance
- */
- protected function getSheetFromSheetXMLNode($xmlReaderOnSheetNode, $sheetIndexZeroBased, $isSheetActive)
- {
- $sheetId = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_R_ID);
-
- $sheetState = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_STATE);
- $isSheetVisible = (self::SHEET_STATE_HIDDEN !== $sheetState);
-
- $escapedSheetName = $xmlReaderOnSheetNode->getAttribute(self::XML_ATTRIBUTE_NAME);
- $sheetName = $this->escaper->unescape($escapedSheetName);
-
- $sheetDataXMLFilePath = $this->getSheetDataXMLFilePathForSheetId($sheetId);
-
- return $this->entityFactory->createSheet(
- $this->filePath,
- $sheetDataXMLFilePath,
- $sheetIndexZeroBased,
- $sheetName,
- $isSheetActive,
- $isSheetVisible,
- $this->optionsManager,
- $this->sharedStringsManager
- );
- }
-
- /**
- * @param string $sheetId The sheet ID, as defined in "workbook.xml"
- *
- * @return string The XML file path describing the sheet inside "workbook.xml.res", for the given sheet ID
- */
- protected function getSheetDataXMLFilePathForSheetId($sheetId)
- {
- $sheetDataXMLFilePath = '';
-
- // find the file path of the sheet, by looking at the "workbook.xml.res" file
- $xmlReader = $this->entityFactory->createXMLReader();
- if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_XML_RELS_FILE_PATH)) {
- while ($xmlReader->read()) {
- if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_RELATIONSHIP)) {
- $relationshipSheetId = $xmlReader->getAttribute(self::XML_ATTRIBUTE_ID);
-
- if ($relationshipSheetId === $sheetId) {
- // In workbook.xml.rels, it is only "worksheets/sheet1.xml"
- // In [Content_Types].xml, the path is "/xl/worksheets/sheet1.xml"
- $sheetDataXMLFilePath = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TARGET);
-
- // sometimes, the sheet data file path already contains "/xl/"...
- if (0 !== strpos($sheetDataXMLFilePath, '/xl/')) {
- $sheetDataXMLFilePath = '/xl/'.$sheetDataXMLFilePath;
-
- break;
- }
- }
- }
- }
-
- $xmlReader->close();
- }
-
- return $sheetDataXMLFilePath;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Manager/StyleManager.php b/upstream-3.x/src/Reader/XLSX/Manager/StyleManager.php
deleted file mode 100644
index 4eb9046..0000000
--- a/upstream-3.x/src/Reader/XLSX/Manager/StyleManager.php
+++ /dev/null
@@ -1,349 +0,0 @@
- 'm/d/yyyy', // @NOTE: ECMA spec is 'mm-dd-yy'
- 15 => 'd-mmm-yy',
- 16 => 'd-mmm',
- 17 => 'mmm-yy',
- 18 => 'h:mm AM/PM',
- 19 => 'h:mm:ss AM/PM',
- 20 => 'h:mm',
- 21 => 'h:mm:ss',
- 22 => 'm/d/yyyy h:mm', // @NOTE: ECMA spec is 'm/d/yy h:mm',
- 45 => 'mm:ss',
- 46 => '[h]:mm:ss',
- 47 => 'mm:ss.0', // @NOTE: ECMA spec is 'mmss.0',
- ];
-
- /** @var string Path of the XLSX file being read */
- protected $filePath;
-
- /** @var bool Whether the XLSX file contains a styles XML file */
- protected $hasStylesXMLFile;
-
- /** @var null|string Path of the styles XML file */
- protected $stylesXMLFilePath;
-
- /** @var InternalEntityFactory Factory to create entities */
- protected $entityFactory;
-
- /** @var array Array containing the IDs of built-in number formats indicating a date */
- protected $builtinNumFmtIdIndicatingDates;
-
- /** @var null|array Array containing a mapping NUM_FMT_ID => FORMAT_CODE */
- protected $customNumberFormats;
-
- /** @var null|array Array containing a mapping STYLE_ID => [STYLE_ATTRIBUTES] */
- protected $stylesAttributes;
-
- /** @var array Cache containing a mapping NUM_FMT_ID => IS_DATE_FORMAT. Used to avoid lots of recalculations */
- protected $numFmtIdToIsDateFormatCache = [];
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param WorkbookRelationshipsManager $workbookRelationshipsManager Helps retrieving workbook relationships
- * @param InternalEntityFactory $entityFactory Factory to create entities
- */
- public function __construct($filePath, $workbookRelationshipsManager, $entityFactory)
- {
- $this->filePath = $filePath;
- $this->entityFactory = $entityFactory;
- $this->builtinNumFmtIdIndicatingDates = array_keys(self::$builtinNumFmtIdToNumFormatMapping);
- $this->hasStylesXMLFile = $workbookRelationshipsManager->hasStylesXMLFile();
- if ($this->hasStylesXMLFile) {
- $this->stylesXMLFilePath = $workbookRelationshipsManager->getStylesXMLFilePath();
- }
- }
-
- /**
- * Returns whether the style with the given ID should consider
- * numeric values as timestamps and format the cell as a date.
- *
- * @param int $styleId Zero-based style ID
- *
- * @return bool Whether the cell with the given cell should display a date instead of a numeric value
- */
- public function shouldFormatNumericValueAsDate($styleId)
- {
- if (!$this->hasStylesXMLFile) {
- return false;
- }
-
- $stylesAttributes = $this->getStylesAttributes();
-
- // Default style (0) does not format numeric values as timestamps. Only custom styles do.
- // Also if the style ID does not exist in the styles.xml file, format as numeric value.
- // Using isset here because it is way faster than array_key_exists...
- if (self::DEFAULT_STYLE_ID === $styleId || !isset($stylesAttributes[$styleId])) {
- return false;
- }
-
- $styleAttributes = $stylesAttributes[$styleId];
-
- return $this->doesStyleIndicateDate($styleAttributes);
- }
-
- /**
- * Returns the format as defined in "styles.xml" of the given style.
- * NOTE: It is assumed that the style DOES have a number format associated to it.
- *
- * @param int $styleId Zero-based style ID
- *
- * @return string The number format code associated with the given style
- */
- public function getNumberFormatCode($styleId)
- {
- $stylesAttributes = $this->getStylesAttributes();
- $styleAttributes = $stylesAttributes[$styleId];
- $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID];
-
- if ($this->isNumFmtIdBuiltInDateFormat($numFmtId)) {
- $numberFormatCode = self::$builtinNumFmtIdToNumFormatMapping[$numFmtId];
- } else {
- $customNumberFormats = $this->getCustomNumberFormats();
- $numberFormatCode = $customNumberFormats[$numFmtId];
- }
-
- return $numberFormatCode;
- }
-
- /**
- * Reads the styles.xml file and extract the relevant information from the file.
- */
- protected function extractRelevantInfo()
- {
- $this->customNumberFormats = [];
- $this->stylesAttributes = [];
-
- $xmlReader = $this->entityFactory->createXMLReader();
-
- if ($xmlReader->openFileInZip($this->filePath, $this->stylesXMLFilePath)) {
- while ($xmlReader->read()) {
- if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_NUM_FMTS)) {
- $this->extractNumberFormats($xmlReader);
- } elseif ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_CELL_XFS)) {
- $this->extractStyleAttributes($xmlReader);
- }
- }
-
- $xmlReader->close();
- }
- }
-
- /**
- * Extracts number formats from the "numFmt" nodes.
- * For simplicity, the styles attributes are kept in memory. This is possible thanks
- * to the reuse of formats. So 1 million cells should not use 1 million formats.
- *
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XML Reader positioned on the "numFmts" node
- */
- protected function extractNumberFormats($xmlReader)
- {
- while ($xmlReader->read()) {
- if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_NUM_FMT)) {
- $numFmtId = (int) ($xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_FMT_ID));
- $formatCode = $xmlReader->getAttribute(self::XML_ATTRIBUTE_FORMAT_CODE);
- $this->customNumberFormats[$numFmtId] = $formatCode;
- } elseif ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_NUM_FMTS)) {
- // Once done reading "numFmts" node's children
- break;
- }
- }
- }
-
- /**
- * Extracts style attributes from the "xf" nodes, inside the "cellXfs" section.
- * For simplicity, the styles attributes are kept in memory. This is possible thanks
- * to the reuse of styles. So 1 million cells should not use 1 million styles.
- *
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XML Reader positioned on the "cellXfs" node
- */
- protected function extractStyleAttributes($xmlReader)
- {
- while ($xmlReader->read()) {
- if ($xmlReader->isPositionedOnStartingNode(self::XML_NODE_XF)) {
- $numFmtId = $xmlReader->getAttribute(self::XML_ATTRIBUTE_NUM_FMT_ID);
- $normalizedNumFmtId = (null !== $numFmtId) ? (int) $numFmtId : null;
-
- $applyNumberFormat = $xmlReader->getAttribute(self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT);
- $normalizedApplyNumberFormat = (null !== $applyNumberFormat) ? (bool) $applyNumberFormat : null;
-
- $this->stylesAttributes[] = [
- self::XML_ATTRIBUTE_NUM_FMT_ID => $normalizedNumFmtId,
- self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT => $normalizedApplyNumberFormat,
- ];
- } elseif ($xmlReader->isPositionedOnEndingNode(self::XML_NODE_CELL_XFS)) {
- // Once done reading "cellXfs" node's children
- break;
- }
- }
- }
-
- /**
- * @return array The custom number formats
- */
- protected function getCustomNumberFormats()
- {
- if (!isset($this->customNumberFormats)) {
- $this->extractRelevantInfo();
- }
-
- return $this->customNumberFormats;
- }
-
- /**
- * @return array The styles attributes
- */
- protected function getStylesAttributes()
- {
- if (!isset($this->stylesAttributes)) {
- $this->extractRelevantInfo();
- }
-
- return $this->stylesAttributes;
- }
-
- /**
- * @param array $styleAttributes Array containing the style attributes (2 keys: "applyNumberFormat" and "numFmtId")
- *
- * @return bool Whether the style with the given attributes indicates that the number is a date
- */
- protected function doesStyleIndicateDate($styleAttributes)
- {
- $applyNumberFormat = $styleAttributes[self::XML_ATTRIBUTE_APPLY_NUMBER_FORMAT];
- $numFmtId = $styleAttributes[self::XML_ATTRIBUTE_NUM_FMT_ID];
-
- // A style may apply a date format if it has:
- // - "applyNumberFormat" attribute not set to "false"
- // - "numFmtId" attribute set
- // This is a preliminary check, as having "numFmtId" set just means the style should apply a specific number format,
- // but this is not necessarily a date.
- if (false === $applyNumberFormat || null === $numFmtId) {
- return false;
- }
-
- return $this->doesNumFmtIdIndicateDate($numFmtId);
- }
-
- /**
- * Returns whether the number format ID indicates that the number is a date.
- * The result is cached to avoid recomputing the same thing over and over, as
- * "numFmtId" attributes can be shared between multiple styles.
- *
- * @param int $numFmtId
- *
- * @return bool Whether the number format ID indicates that the number is a date
- */
- protected function doesNumFmtIdIndicateDate($numFmtId)
- {
- if (!isset($this->numFmtIdToIsDateFormatCache[$numFmtId])) {
- $formatCode = $this->getFormatCodeForNumFmtId($numFmtId);
-
- $this->numFmtIdToIsDateFormatCache[$numFmtId] = (
- $this->isNumFmtIdBuiltInDateFormat($numFmtId)
- || $this->isFormatCodeCustomDateFormat($formatCode)
- );
- }
-
- return $this->numFmtIdToIsDateFormatCache[$numFmtId];
- }
-
- /**
- * @param int $numFmtId
- *
- * @return null|string The custom number format or NULL if none defined for the given numFmtId
- */
- protected function getFormatCodeForNumFmtId($numFmtId)
- {
- $customNumberFormats = $this->getCustomNumberFormats();
-
- // Using isset here because it is way faster than array_key_exists...
- return (isset($customNumberFormats[$numFmtId])) ? $customNumberFormats[$numFmtId] : null;
- }
-
- /**
- * @param int $numFmtId
- *
- * @return bool Whether the number format ID indicates that the number is a date
- */
- protected function isNumFmtIdBuiltInDateFormat($numFmtId)
- {
- return \in_array($numFmtId, $this->builtinNumFmtIdIndicatingDates, true);
- }
-
- /**
- * @param null|string $formatCode
- *
- * @return bool Whether the given format code indicates that the number is a date
- */
- protected function isFormatCodeCustomDateFormat($formatCode)
- {
- // if no associated format code or if using the default "General" format
- if (null === $formatCode || 0 === strcasecmp($formatCode, self::NUMBER_FORMAT_GENERAL)) {
- return false;
- }
-
- return $this->isFormatCodeMatchingDateFormatPattern($formatCode);
- }
-
- /**
- * @param string $formatCode
- *
- * @return bool Whether the given format code matches a date format pattern
- */
- protected function isFormatCodeMatchingDateFormatPattern($formatCode)
- {
- // Remove extra formatting (what's between [ ], the brackets should not be preceded by a "\")
- $pattern = '((? [FILE_NAME] */
- private $cachedWorkbookRelationships;
-
- /**
- * @param string $filePath Path of the XLSX file being read
- * @param InternalEntityFactory $entityFactory Factory to create entities
- */
- public function __construct($filePath, $entityFactory)
- {
- $this->filePath = $filePath;
- $this->entityFactory = $entityFactory;
- }
-
- /**
- * @return string The path of the shared string XML file
- */
- public function getSharedStringsXMLFilePath()
- {
- $workbookRelationships = $this->getWorkbookRelationships();
- $sharedStringsXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS]
- ?? $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT];
-
- // the file path can be relative (e.g. "styles.xml") or absolute (e.g. "/xl/styles.xml")
- $doesContainBasePath = (false !== strpos($sharedStringsXMLFilePath, self::BASE_PATH));
- if (!$doesContainBasePath) {
- // make sure we return an absolute file path
- $sharedStringsXMLFilePath = self::BASE_PATH.$sharedStringsXMLFilePath;
- }
-
- return $sharedStringsXMLFilePath;
- }
-
- /**
- * @return bool Whether the XLSX file contains a shared string XML file
- */
- public function hasSharedStringsXMLFile()
- {
- $workbookRelationships = $this->getWorkbookRelationships();
-
- return isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS])
- || isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT]);
- }
-
- /**
- * @return bool Whether the XLSX file contains a styles XML file
- */
- public function hasStylesXMLFile()
- {
- $workbookRelationships = $this->getWorkbookRelationships();
-
- return isset($workbookRelationships[self::RELATIONSHIP_TYPE_STYLES])
- || isset($workbookRelationships[self::RELATIONSHIP_TYPE_STYLES_STRICT]);
- }
-
- /**
- * @return string The path of the styles XML file
- */
- public function getStylesXMLFilePath()
- {
- $workbookRelationships = $this->getWorkbookRelationships();
- $stylesXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES]
- ?? $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES_STRICT];
-
- // the file path can be relative (e.g. "styles.xml") or absolute (e.g. "/xl/styles.xml")
- $doesContainBasePath = (false !== strpos($stylesXMLFilePath, self::BASE_PATH));
- if (!$doesContainBasePath) {
- // make sure we return a full path
- $stylesXMLFilePath = self::BASE_PATH.$stylesXMLFilePath;
- }
-
- return $stylesXMLFilePath;
- }
-
- /**
- * Reads the workbook.xml.rels and extracts the filename associated to the different types.
- * It caches the result so that the file is read only once.
- *
- * @throws \OpenSpout\Common\Exception\IOException If workbook.xml.rels can't be read
- *
- * @return array
- */
- private function getWorkbookRelationships()
- {
- if (!isset($this->cachedWorkbookRelationships)) {
- $xmlReader = $this->entityFactory->createXMLReader();
-
- if (false === $xmlReader->openFileInZip($this->filePath, self::WORKBOOK_RELS_XML_FILE_PATH)) {
- throw new IOException('Could not open "'.self::WORKBOOK_RELS_XML_FILE_PATH.'".');
- }
-
- $this->cachedWorkbookRelationships = [];
-
- while ($xmlReader->readUntilNodeFound(self::XML_NODE_RELATIONSHIP)) {
- $this->processWorkbookRelationship($xmlReader);
- }
- }
-
- return $this->cachedWorkbookRelationships;
- }
-
- /**
- * Extracts and store the data of the current workbook relationship.
- *
- * @param XMLReader $xmlReader
- */
- private function processWorkbookRelationship($xmlReader)
- {
- $type = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TYPE);
- $target = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TARGET);
-
- // @NOTE: if a type is defined more than once, we overwrite the previous value
- // To be changed if we want to get the file paths of sheet XML files for instance.
- $this->cachedWorkbookRelationships[$type] = $target;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Reader.php b/upstream-3.x/src/Reader/XLSX/Reader.php
deleted file mode 100644
index 197c7fc..0000000
--- a/upstream-3.x/src/Reader/XLSX/Reader.php
+++ /dev/null
@@ -1,122 +0,0 @@
-managerFactory = $managerFactory;
- }
-
- /**
- * @param string $tempFolder Temporary folder where the temporary files will be created
- *
- * @return Reader
- */
- public function setTempFolder($tempFolder)
- {
- $this->optionsManager->setOption(Options::TEMP_FOLDER, $tempFolder);
-
- return $this;
- }
-
- /**
- * Returns whether stream wrappers are supported.
- *
- * @return bool
- */
- protected function doesSupportStreamWrapper()
- {
- return false;
- }
-
- /**
- * Opens the file at the given file path to make it ready to be read.
- * It also parses the sharedStrings.xml file to get all the shared strings available in memory
- * and fetches all the available sheets.
- *
- * @param string $filePath Path of the file to be read
- *
- * @throws \OpenSpout\Common\Exception\IOException If the file at the given path or its content cannot be read
- * @throws \OpenSpout\Reader\Exception\NoSheetsFoundException If there are no sheets in the file
- */
- protected function openReader($filePath)
- {
- /** @var InternalEntityFactory $entityFactory */
- $entityFactory = $this->entityFactory;
-
- $this->zip = $entityFactory->createZipArchive();
-
- if (true === $this->zip->open($filePath)) {
- $tempFolder = $this->optionsManager->getOption(Options::TEMP_FOLDER);
- $this->sharedStringsManager = $this->managerFactory->createSharedStringsManager($filePath, $tempFolder, $entityFactory);
-
- if ($this->sharedStringsManager->hasSharedStrings()) {
- // Extracts all the strings from the sheets for easy access in the future
- $this->sharedStringsManager->extractSharedStrings();
- }
-
- $this->sheetIterator = $entityFactory->createSheetIterator(
- $filePath,
- $this->optionsManager,
- $this->sharedStringsManager
- );
- } else {
- throw new IOException("Could not open {$filePath} for reading.");
- }
- }
-
- /**
- * Returns an iterator to iterate over sheets.
- *
- * @return SheetIterator To iterate over sheets
- */
- protected function getConcreteSheetIterator()
- {
- return $this->sheetIterator;
- }
-
- /**
- * Closes the reader. To be used after reading the file.
- */
- protected function closeReader()
- {
- if (null !== $this->zip) {
- $this->zip->close();
- }
-
- if (null !== $this->sharedStringsManager) {
- $this->sharedStringsManager->cleanup();
- }
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/RowIterator.php b/upstream-3.x/src/Reader/XLSX/RowIterator.php
deleted file mode 100644
index de38370..0000000
--- a/upstream-3.x/src/Reader/XLSX/RowIterator.php
+++ /dev/null
@@ -1,429 +0,0 @@
-filePath = $filePath;
- $this->sheetDataXMLFilePath = $this->normalizeSheetDataXMLFilePath($sheetDataXMLFilePath);
- $this->shouldPreserveEmptyRows = $shouldPreserveEmptyRows;
- $this->xmlReader = $xmlReader;
- $this->cellValueFormatter = $cellValueFormatter;
- $this->rowManager = $rowManager;
- $this->entityFactory = $entityFactory;
-
- // Register all callbacks to process different nodes when reading the XML file
- $this->xmlProcessor = $xmlProcessor;
- $this->xmlProcessor->registerCallback(self::XML_NODE_DIMENSION, XMLProcessor::NODE_TYPE_START, [$this, 'processDimensionStartingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_START, [$this, 'processRowStartingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_CELL, XMLProcessor::NODE_TYPE_START, [$this, 'processCellStartingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_ROW, XMLProcessor::NODE_TYPE_END, [$this, 'processRowEndingNode']);
- $this->xmlProcessor->registerCallback(self::XML_NODE_WORKSHEET, XMLProcessor::NODE_TYPE_END, [$this, 'processWorksheetEndingNode']);
- }
-
- /**
- * Rewind the Iterator to the first element.
- * Initializes the XMLReader object that reads the associated sheet data.
- * The XMLReader is configured to be safe from billion laughs attack.
- *
- * @see http://php.net/manual/en/iterator.rewind.php
- *
- * @throws \OpenSpout\Common\Exception\IOException If the sheet data XML cannot be read
- */
- #[\ReturnTypeWillChange]
- public function rewind(): void
- {
- $this->xmlReader->close();
-
- if (false === $this->xmlReader->openFileInZip($this->filePath, $this->sheetDataXMLFilePath)) {
- throw new IOException("Could not open \"{$this->sheetDataXMLFilePath}\".");
- }
-
- $this->numReadRows = 0;
- $this->lastRowIndexProcessed = 0;
- $this->nextRowIndexToBeProcessed = 0;
- $this->rowBuffer = null;
- $this->hasReachedEndOfFile = false;
- $this->numColumns = 0;
-
- $this->next();
- }
-
- /**
- * Checks if current position is valid.
- *
- * @see http://php.net/manual/en/iterator.valid.php
- */
- #[\ReturnTypeWillChange]
- public function valid(): bool
- {
- return !$this->hasReachedEndOfFile;
- }
-
- /**
- * Move forward to next element. Reads data describing the next unprocessed row.
- *
- * @see http://php.net/manual/en/iterator.next.php
- *
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If a shared string was not found
- * @throws \OpenSpout\Common\Exception\IOException If unable to read the sheet data XML
- */
- #[\ReturnTypeWillChange]
- public function next(): void
- {
- ++$this->nextRowIndexToBeProcessed;
-
- if ($this->doesNeedDataForNextRowToBeProcessed()) {
- $this->readDataForNextRow();
- }
- }
-
- /**
- * Return the current element, either an empty row or from the buffer.
- *
- * @see http://php.net/manual/en/iterator.current.php
- */
- #[\ReturnTypeWillChange]
- public function current(): ?Row
- {
- $rowToBeProcessed = $this->rowBuffer;
-
- if ($this->shouldPreserveEmptyRows) {
- // when we need to preserve empty rows, we will either return
- // an empty row or the last row read. This depends whether the
- // index of last row that was read matches the index of the last
- // row whose value should be returned.
- if ($this->lastRowIndexProcessed !== $this->nextRowIndexToBeProcessed) {
- // return empty row if mismatch between last processed row
- // and the row that needs to be returned
- $rowToBeProcessed = $this->entityFactory->createRow();
- }
- }
-
- return $rowToBeProcessed;
- }
-
- /**
- * Return the key of the current element. Here, the row index.
- *
- * @see http://php.net/manual/en/iterator.key.php
- */
- #[\ReturnTypeWillChange]
- public function key(): int
- {
- // TODO: This should return $this->nextRowIndexToBeProcessed
- // but to avoid a breaking change, the return value for
- // this function has been kept as the number of rows read.
- return $this->shouldPreserveEmptyRows ?
- $this->nextRowIndexToBeProcessed :
- $this->numReadRows;
- }
-
- /**
- * Cleans up what was created to iterate over the object.
- */
- #[\ReturnTypeWillChange]
- public function end(): void
- {
- $this->xmlReader->close();
- }
-
- /**
- * @param string $sheetDataXMLFilePath Path of the sheet data XML file as in [Content_Types].xml
- *
- * @return string path of the XML file containing the sheet data,
- * without the leading slash
- */
- protected function normalizeSheetDataXMLFilePath($sheetDataXMLFilePath)
- {
- return ltrim($sheetDataXMLFilePath, '/');
- }
-
- /**
- * Returns whether we need data for the next row to be processed.
- * We don't need to read data if:
- * we have already read at least one row
- * AND
- * we need to preserve empty rows
- * AND
- * the last row that was read is not the row that need to be processed
- * (i.e. if we need to return empty rows).
- *
- * @return bool whether we need data for the next row to be processed
- */
- protected function doesNeedDataForNextRowToBeProcessed()
- {
- $hasReadAtLeastOneRow = (0 !== $this->lastRowIndexProcessed);
-
- return
- !$hasReadAtLeastOneRow
- || !$this->shouldPreserveEmptyRows
- || $this->lastRowIndexProcessed < $this->nextRowIndexToBeProcessed
- ;
- }
-
- /**
- * @throws \OpenSpout\Reader\Exception\SharedStringNotFoundException If a shared string was not found
- * @throws \OpenSpout\Common\Exception\IOException If unable to read the sheet data XML
- */
- protected function readDataForNextRow()
- {
- $this->currentlyProcessedRow = $this->entityFactory->createRow();
-
- try {
- $this->xmlProcessor->readUntilStopped();
- } catch (XMLProcessingException $exception) {
- throw new IOException("The {$this->sheetDataXMLFilePath} file cannot be read. [{$exception->getMessage()}]");
- }
-
- $this->rowBuffer = $this->currentlyProcessedRow;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processDimensionStartingNode($xmlReader)
- {
- // Read dimensions of the sheet
- $dimensionRef = $xmlReader->getAttribute(self::XML_ATTRIBUTE_REF); // returns 'A1:M13' for instance (or 'A1' for empty sheet)
- if (preg_match('/[A-Z]+\d+:([A-Z]+\d+)/', $dimensionRef, $matches)) {
- $this->numColumns = CellHelper::getColumnIndexFromCellIndex($matches[1]) + 1;
- }
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processRowStartingNode($xmlReader)
- {
- // Reset index of the last processed column
- $this->lastColumnIndexProcessed = -1;
-
- // Mark the last processed row as the one currently being read
- $this->lastRowIndexProcessed = $this->getRowIndex($xmlReader);
-
- // Read spans info if present
- $numberOfColumnsForRow = $this->numColumns;
- $spans = $xmlReader->getAttribute(self::XML_ATTRIBUTE_SPANS); // returns '1:5' for instance
- if ($spans) {
- [, $numberOfColumnsForRow] = explode(':', $spans);
- $numberOfColumnsForRow = (int) $numberOfColumnsForRow;
- }
-
- $cells = array_fill(0, $numberOfColumnsForRow, $this->entityFactory->createCell(''));
- $this->currentlyProcessedRow->setCells($cells);
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" starting node
- *
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processCellStartingNode($xmlReader)
- {
- $currentColumnIndex = $this->getColumnIndex($xmlReader);
-
- // NOTE: expand() will automatically decode all XML entities of the child nodes
- /** @var \DOMElement $node */
- $node = $xmlReader->expand();
- $cell = $this->getCell($node);
-
- $this->currentlyProcessedRow->setCellAtIndex($cell, $currentColumnIndex);
- $this->lastColumnIndexProcessed = $currentColumnIndex;
-
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- /**
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processRowEndingNode()
- {
- // if the fetched row is empty and we don't want to preserve it..,
- if (!$this->shouldPreserveEmptyRows && $this->rowManager->isEmpty($this->currentlyProcessedRow)) {
- // ... skip it
- return XMLProcessor::PROCESSING_CONTINUE;
- }
-
- ++$this->numReadRows;
-
- // If needed, we fill the empty cells
- if (0 === $this->numColumns) {
- $this->currentlyProcessedRow = $this->rowManager->fillMissingIndexesWithEmptyCells($this->currentlyProcessedRow);
- }
-
- // at this point, we have all the data we need for the row
- // so that we can populate the buffer
- return XMLProcessor::PROCESSING_STOP;
- }
-
- /**
- * @return int A return code that indicates what action should the processor take next
- */
- protected function processWorksheetEndingNode()
- {
- // The closing "" marks the end of the file
- $this->hasReachedEndOfFile = true;
-
- return XMLProcessor::PROCESSING_STOP;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" node
- *
- * @throws \OpenSpout\Common\Exception\InvalidArgumentException When the given cell index is invalid
- *
- * @return int Row index
- */
- protected function getRowIndex($xmlReader)
- {
- // Get "r" attribute if present (from something like
- $currentRowIndex = $xmlReader->getAttribute(self::XML_ATTRIBUTE_ROW_INDEX);
-
- return (null !== $currentRowIndex) ?
- (int) $currentRowIndex :
- $this->lastRowIndexProcessed + 1;
- }
-
- /**
- * @param \OpenSpout\Reader\Wrapper\XMLReader $xmlReader XMLReader object, positioned on a "" node
- *
- * @throws \OpenSpout\Common\Exception\InvalidArgumentException When the given cell index is invalid
- *
- * @return int Column index
- */
- protected function getColumnIndex($xmlReader)
- {
- // Get "r" attribute if present (from something like
- $currentCellIndex = $xmlReader->getAttribute(self::XML_ATTRIBUTE_CELL_INDEX);
-
- return (null !== $currentCellIndex) ?
- CellHelper::getColumnIndexFromCellIndex($currentCellIndex) :
- $this->lastColumnIndexProcessed + 1;
- }
-
- /**
- * Returns the cell with (unescaped) correctly marshalled, cell value associated to the given XML node.
- *
- * @param \DOMElement $node
- *
- * @return Cell The cell set with the associated with the cell
- */
- protected function getCell($node)
- {
- try {
- $cellValue = $this->cellValueFormatter->extractAndFormatNodeValue($node);
- $cell = $this->entityFactory->createCell($cellValue);
- } catch (InvalidValueException $exception) {
- $cell = $this->entityFactory->createCell($exception->getInvalidValue());
- $cell->setType(Cell::TYPE_ERROR);
- }
-
- return $cell;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/Sheet.php b/upstream-3.x/src/Reader/XLSX/Sheet.php
deleted file mode 100644
index 64d7637..0000000
--- a/upstream-3.x/src/Reader/XLSX/Sheet.php
+++ /dev/null
@@ -1,82 +0,0 @@
-rowIterator = $rowIterator;
- $this->index = $sheetIndex;
- $this->name = $sheetName;
- $this->isActive = $isSheetActive;
- $this->isVisible = $isSheetVisible;
- }
-
- /**
- * @return \OpenSpout\Reader\XLSX\RowIterator
- */
- public function getRowIterator()
- {
- return $this->rowIterator;
- }
-
- /**
- * @return int Index of the sheet, based on order in the workbook (zero-based)
- */
- public function getIndex()
- {
- return $this->index;
- }
-
- /**
- * @return string Name of the sheet
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * @return bool Whether the sheet was defined as active
- */
- public function isActive()
- {
- return $this->isActive;
- }
-
- /**
- * @return bool Whether the sheet is visible
- */
- public function isVisible()
- {
- return $this->isVisible;
- }
-}
diff --git a/upstream-3.x/src/Reader/XLSX/SheetIterator.php b/upstream-3.x/src/Reader/XLSX/SheetIterator.php
deleted file mode 100644
index f58fc67..0000000
--- a/upstream-3.x/src/Reader/XLSX/SheetIterator.php
+++ /dev/null
@@ -1,113 +0,0 @@
-sheets = $sheetManager->getSheets();
-
- if (0 === \count($this->sheets)) {
- throw new NoSheetsFoundException('The file must contain at least one sheet.');
- }
- }
-
- /**
- * Rewind the Iterator to the first element.
- *
- * @see http://php.net/manual/en/iterator.rewind.php
- */
- #[\ReturnTypeWillChange]
- public function rewind()
- {
- $this->currentSheetIndex = 0;
- }
-
- /**
- * Checks if current position is valid.
- *
- * @see http://php.net/manual/en/iterator.valid.php
- *
- * @return bool
- */
- #[\ReturnTypeWillChange]
- public function valid()
- {
- return $this->currentSheetIndex < \count($this->sheets);
- }
-
- /**
- * Move forward to next element.
- *
- * @see http://php.net/manual/en/iterator.next.php
- */
- #[\ReturnTypeWillChange]
- public function next()
- {
- // Using isset here because it is way faster than array_key_exists...
- if (isset($this->sheets[$this->currentSheetIndex])) {
- $currentSheet = $this->sheets[$this->currentSheetIndex];
- $currentSheet->getRowIterator()->end();
-
- ++$this->currentSheetIndex;
- }
- }
-
- /**
- * Return the current element.
- *
- * @see http://php.net/manual/en/iterator.current.php
- *
- * @return \OpenSpout\Reader\XLSX\Sheet
- */
- #[\ReturnTypeWillChange]
- public function current()
- {
- return $this->sheets[$this->currentSheetIndex];
- }
-
- /**
- * Return the key of the current element.
- *
- * @see http://php.net/manual/en/iterator.key.php
- *
- * @return int
- */
- #[\ReturnTypeWillChange]
- public function key()
- {
- return $this->currentSheetIndex + 1;
- }
-
- /**
- * Cleans up what was created to iterate over the object.
- */
- #[\ReturnTypeWillChange]
- public function end()
- {
- // make sure we are not leaking memory in case the iteration stopped before the end
- foreach ($this->sheets as $sheet) {
- $sheet->getRowIterator()->end();
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/CSV/Manager/OptionsManager.php b/upstream-3.x/src/Writer/CSV/Manager/OptionsManager.php
deleted file mode 100644
index c6e25a6..0000000
--- a/upstream-3.x/src/Writer/CSV/Manager/OptionsManager.php
+++ /dev/null
@@ -1,34 +0,0 @@
-setOption(Options::FIELD_DELIMITER, ',');
- $this->setOption(Options::FIELD_ENCLOSURE, '"');
- $this->setOption(Options::SHOULD_ADD_BOM, true);
- }
-}
diff --git a/upstream-3.x/src/Writer/CSV/Writer.php b/upstream-3.x/src/Writer/CSV/Writer.php
deleted file mode 100644
index 2815d0e..0000000
--- a/upstream-3.x/src/Writer/CSV/Writer.php
+++ /dev/null
@@ -1,109 +0,0 @@
-optionsManager->setOption(Options::FIELD_DELIMITER, $fieldDelimiter);
-
- return $this;
- }
-
- /**
- * Sets the field enclosure for the CSV.
- *
- * @param string $fieldEnclosure Character that enclose fields
- *
- * @return Writer
- */
- public function setFieldEnclosure($fieldEnclosure)
- {
- $this->optionsManager->setOption(Options::FIELD_ENCLOSURE, $fieldEnclosure);
-
- return $this;
- }
-
- /**
- * Set if a BOM has to be added to the file.
- *
- * @param bool $shouldAddBOM
- *
- * @return Writer
- */
- public function setShouldAddBOM($shouldAddBOM)
- {
- $this->optionsManager->setOption(Options::SHOULD_ADD_BOM, (bool) $shouldAddBOM);
-
- return $this;
- }
-
- /**
- * Opens the CSV streamer and makes it ready to accept data.
- */
- protected function openWriter()
- {
- if ($this->optionsManager->getOption(Options::SHOULD_ADD_BOM)) {
- // Adds UTF-8 BOM for Unicode compatibility
- $this->globalFunctionsHelper->fputs($this->filePointer, EncodingHelper::BOM_UTF8);
- }
- }
-
- /**
- * Adds a row to the currently opened writer.
- *
- * @param Row $row The row containing cells and styles
- *
- * @throws IOException If unable to write data
- */
- protected function addRowToWriter(Row $row)
- {
- $fieldDelimiter = $this->optionsManager->getOption(Options::FIELD_DELIMITER);
- $fieldEnclosure = $this->optionsManager->getOption(Options::FIELD_ENCLOSURE);
-
- $wasWriteSuccessful = $this->globalFunctionsHelper->fputcsv($this->filePointer, $row->getCells(), $fieldDelimiter, $fieldEnclosure);
- if (false === $wasWriteSuccessful) {
- throw new IOException('Unable to write data');
- }
-
- ++$this->lastWrittenRowIndex;
- if (0 === $this->lastWrittenRowIndex % self::FLUSH_THRESHOLD) {
- $this->globalFunctionsHelper->fflush($this->filePointer);
- }
- }
-
- /**
- * Closes the CSV streamer, preventing any additional writing.
- * If set, sets the headers and redirects output to the browser.
- */
- protected function closeWriter()
- {
- $this->lastWrittenRowIndex = 0;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Creator/InternalEntityFactory.php b/upstream-3.x/src/Writer/Common/Creator/InternalEntityFactory.php
deleted file mode 100644
index 63e96d3..0000000
--- a/upstream-3.x/src/Writer/Common/Creator/InternalEntityFactory.php
+++ /dev/null
@@ -1,52 +0,0 @@
-border = new Border();
- }
-
- /**
- * @param string $color Border A RGB color code
- * @param string $width Border width @see BorderPart::allowedWidths
- * @param string $style Border style @see BorderPart::allowedStyles
- *
- * @return BorderBuilder
- */
- public function setBorderTop($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID)
- {
- $this->border->addPart(new BorderPart(Border::TOP, $color, $width, $style));
-
- return $this;
- }
-
- /**
- * @param string $color Border A RGB color code
- * @param string $width Border width @see BorderPart::allowedWidths
- * @param string $style Border style @see BorderPart::allowedStyles
- *
- * @return BorderBuilder
- */
- public function setBorderRight($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID)
- {
- $this->border->addPart(new BorderPart(Border::RIGHT, $color, $width, $style));
-
- return $this;
- }
-
- /**
- * @param string $color Border A RGB color code
- * @param string $width Border width @see BorderPart::allowedWidths
- * @param string $style Border style @see BorderPart::allowedStyles
- *
- * @return BorderBuilder
- */
- public function setBorderBottom($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID)
- {
- $this->border->addPart(new BorderPart(Border::BOTTOM, $color, $width, $style));
-
- return $this;
- }
-
- /**
- * @param string $color Border A RGB color code
- * @param string $width Border width @see BorderPart::allowedWidths
- * @param string $style Border style @see BorderPart::allowedStyles
- *
- * @return BorderBuilder
- */
- public function setBorderLeft($color = Color::BLACK, $width = Border::WIDTH_MEDIUM, $style = Border::STYLE_SOLID)
- {
- $this->border->addPart(new BorderPart(Border::LEFT, $color, $width, $style));
-
- return $this;
- }
-
- /**
- * @return Border
- */
- public function build()
- {
- return $this->border;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Creator/Style/StyleBuilder.php b/upstream-3.x/src/Writer/Common/Creator/Style/StyleBuilder.php
deleted file mode 100644
index 2ef0d15..0000000
--- a/upstream-3.x/src/Writer/Common/Creator/Style/StyleBuilder.php
+++ /dev/null
@@ -1,214 +0,0 @@
-style = new Style();
- }
-
- /**
- * Makes the font bold.
- *
- * @return StyleBuilder
- */
- public function setFontBold()
- {
- $this->style->setFontBold();
-
- return $this;
- }
-
- /**
- * Makes the font italic.
- *
- * @return StyleBuilder
- */
- public function setFontItalic()
- {
- $this->style->setFontItalic();
-
- return $this;
- }
-
- /**
- * Makes the font underlined.
- *
- * @return StyleBuilder
- */
- public function setFontUnderline()
- {
- $this->style->setFontUnderline();
-
- return $this;
- }
-
- /**
- * Makes the font struck through.
- *
- * @return StyleBuilder
- */
- public function setFontStrikethrough()
- {
- $this->style->setFontStrikethrough();
-
- return $this;
- }
-
- /**
- * Sets the font size.
- *
- * @param int $fontSize Font size, in pixels
- *
- * @return StyleBuilder
- */
- public function setFontSize($fontSize)
- {
- $this->style->setFontSize($fontSize);
-
- return $this;
- }
-
- /**
- * Sets the font color.
- *
- * @param string $fontColor ARGB color (@see Color)
- *
- * @return StyleBuilder
- */
- public function setFontColor($fontColor)
- {
- $this->style->setFontColor($fontColor);
-
- return $this;
- }
-
- /**
- * Sets the font name.
- *
- * @param string $fontName Name of the font to use
- *
- * @return StyleBuilder
- */
- public function setFontName($fontName)
- {
- $this->style->setFontName($fontName);
-
- return $this;
- }
-
- /**
- * Makes the text wrap in the cell if requested.
- *
- * @param bool $shouldWrap Should the text be wrapped
- *
- * @return StyleBuilder
- */
- public function setShouldWrapText($shouldWrap = true)
- {
- $this->style->setShouldWrapText($shouldWrap);
-
- return $this;
- }
-
- /**
- * Sets the cell alignment.
- *
- * @param string $cellAlignment The cell alignment
- *
- * @throws InvalidArgumentException If the given cell alignment is not valid
- *
- * @return StyleBuilder
- */
- public function setCellAlignment($cellAlignment)
- {
- if (!CellAlignment::isValid($cellAlignment)) {
- throw new InvalidArgumentException('Invalid cell alignment value');
- }
-
- $this->style->setCellAlignment($cellAlignment);
-
- return $this;
- }
-
- /**
- * Set a border.
- *
- * @return $this
- */
- public function setBorder(Border $border)
- {
- $this->style->setBorder($border);
-
- return $this;
- }
-
- /**
- * Sets a background color.
- *
- * @param string $color ARGB color (@see Color)
- *
- * @return StyleBuilder
- */
- public function setBackgroundColor($color)
- {
- $this->style->setBackgroundColor($color);
-
- return $this;
- }
-
- /**
- * Sets a format.
- *
- * @param string $format Format
- *
- * @return StyleBuilder
- *
- * @api
- */
- public function setFormat($format)
- {
- $this->style->setFormat($format);
-
- return $this;
- }
-
- /**
- * Set should shrink to fit.
- *
- * @param bool $shrinkToFit
- *
- * @return StyleBuilder
- *
- * @api
- */
- public function setShouldShrinkToFit($shrinkToFit = true)
- {
- $this->style->setShouldShrinkToFit($shrinkToFit);
-
- return $this;
- }
-
- /**
- * Returns the configured style. The style is cached and can be reused.
- *
- * @return Style
- */
- public function build()
- {
- return $this->style;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Creator/WriterEntityFactory.php b/upstream-3.x/src/Writer/Common/Creator/WriterEntityFactory.php
deleted file mode 100644
index da6a43a..0000000
--- a/upstream-3.x/src/Writer/Common/Creator/WriterEntityFactory.php
+++ /dev/null
@@ -1,121 +0,0 @@
-index = $sheetIndex;
- $this->associatedWorkbookId = $associatedWorkbookId;
-
- $this->sheetManager = $sheetManager;
- $this->sheetManager->markWorkbookIdAsUsed($associatedWorkbookId);
-
- $this->setName(self::DEFAULT_SHEET_NAME_PREFIX.($sheetIndex + 1));
- $this->setIsVisible(true);
- }
-
- /**
- * @return int Index of the sheet, based on order in the workbook (zero-based)
- */
- public function getIndex()
- {
- return $this->index;
- }
-
- /**
- * @return string
- */
- public function getAssociatedWorkbookId()
- {
- return $this->associatedWorkbookId;
- }
-
- /**
- * @return string Name of the sheet
- */
- public function getName()
- {
- return $this->name;
- }
-
- /**
- * Sets the name of the sheet. Note that Excel has some restrictions on the name:
- * - it should not be blank
- * - it should not exceed 31 characters
- * - it should not contain these characters: \ / ? * : [ or ]
- * - it should be unique.
- *
- * @param string $name Name of the sheet
- *
- * @throws \OpenSpout\Writer\Exception\InvalidSheetNameException if the sheet's name is invalid
- *
- * @return Sheet
- */
- public function setName($name)
- {
- $this->sheetManager->throwIfNameIsInvalid($name, $this);
-
- $this->name = $name;
-
- $this->sheetManager->markSheetNameAsUsed($this);
-
- return $this;
- }
-
- /**
- * @return bool isVisible Visibility of the sheet
- */
- public function isVisible()
- {
- return $this->isVisible;
- }
-
- /**
- * @param bool $isVisible Visibility of the sheet
- *
- * @return Sheet
- */
- public function setIsVisible($isVisible)
- {
- $this->isVisible = $isVisible;
-
- return $this;
- }
-
- public function getSheetView(): ?SheetView
- {
- return $this->sheetView;
- }
-
- /**
- * @return $this
- */
- public function setSheetView(SheetView $sheetView)
- {
- $this->sheetView = $sheetView;
-
- return $this;
- }
-
- public function hasSheetView(): bool
- {
- return $this->sheetView instanceof SheetView;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Entity/Workbook.php b/upstream-3.x/src/Writer/Common/Entity/Workbook.php
deleted file mode 100644
index 152ded8..0000000
--- a/upstream-3.x/src/Writer/Common/Entity/Workbook.php
+++ /dev/null
@@ -1,47 +0,0 @@
-internalId = uniqid();
- }
-
- /**
- * @return Worksheet[]
- */
- public function getWorksheets()
- {
- return $this->worksheets;
- }
-
- /**
- * @param Worksheet[] $worksheets
- */
- public function setWorksheets($worksheets)
- {
- $this->worksheets = $worksheets;
- }
-
- /**
- * @return string
- */
- public function getInternalId()
- {
- return $this->internalId;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Entity/Worksheet.php b/upstream-3.x/src/Writer/Common/Entity/Worksheet.php
deleted file mode 100644
index 0263429..0000000
--- a/upstream-3.x/src/Writer/Common/Entity/Worksheet.php
+++ /dev/null
@@ -1,131 +0,0 @@
-filePath = $worksheetFilePath;
- $this->filePointer = null;
- $this->externalSheet = $externalSheet;
- $this->maxNumColumns = 0;
- $this->lastWrittenRowIndex = 0;
- $this->sheetDataStarted = false;
- }
-
- /**
- * @return string
- */
- public function getFilePath()
- {
- return $this->filePath;
- }
-
- /**
- * @return resource
- */
- public function getFilePointer()
- {
- return $this->filePointer;
- }
-
- /**
- * @param resource $filePointer
- */
- public function setFilePointer($filePointer)
- {
- $this->filePointer = $filePointer;
- }
-
- /**
- * @return Sheet
- */
- public function getExternalSheet()
- {
- return $this->externalSheet;
- }
-
- /**
- * @return int
- */
- public function getMaxNumColumns()
- {
- return $this->maxNumColumns;
- }
-
- /**
- * @param int $maxNumColumns
- */
- public function setMaxNumColumns($maxNumColumns)
- {
- $this->maxNumColumns = $maxNumColumns;
- }
-
- /**
- * @return int
- */
- public function getLastWrittenRowIndex()
- {
- return $this->lastWrittenRowIndex;
- }
-
- /**
- * @param int $lastWrittenRowIndex
- */
- public function setLastWrittenRowIndex($lastWrittenRowIndex)
- {
- $this->lastWrittenRowIndex = $lastWrittenRowIndex;
- }
-
- /**
- * @return int The ID of the worksheet
- */
- public function getId()
- {
- // sheet index is zero-based, while ID is 1-based
- return $this->externalSheet->getIndex() + 1;
- }
-
- /**
- * @return bool
- */
- public function getSheetDataStarted()
- {
- return $this->sheetDataStarted;
- }
-
- /**
- * @param bool $sheetDataStarted
- */
- public function setSheetDataStarted($sheetDataStarted)
- {
- $this->sheetDataStarted = $sheetDataStarted;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Helper/CellHelper.php b/upstream-3.x/src/Writer/Common/Helper/CellHelper.php
deleted file mode 100644
index 400e82c..0000000
--- a/upstream-3.x/src/Writer/Common/Helper/CellHelper.php
+++ /dev/null
@@ -1,45 +0,0 @@
- column letters */
- private static $columnIndexToColumnLettersCache = [];
-
- /**
- * Returns the column letters (base 26) associated to the base 10 column index.
- * Excel uses A to Z letters for column indexing, where A is the 1st column,
- * Z is the 26th and AA is the 27th.
- * The mapping is zero based, so that 0 maps to A, B maps to 1, Z to 25 and AA to 26.
- *
- * @param int $columnIndexZeroBased The Excel column index (0, 42, ...)
- *
- * @return string The associated cell index ('A', 'BC', ...)
- */
- public static function getColumnLettersFromColumnIndex($columnIndexZeroBased)
- {
- $originalColumnIndex = $columnIndexZeroBased;
-
- // Using isset here because it is way faster than array_key_exists...
- if (!isset(self::$columnIndexToColumnLettersCache[$originalColumnIndex])) {
- $columnLetters = '';
- $capitalAAsciiValue = \ord('A');
-
- do {
- $modulus = $columnIndexZeroBased % 26;
- $columnLetters = \chr($capitalAAsciiValue + $modulus).$columnLetters;
-
- // substracting 1 because it's zero-based
- $columnIndexZeroBased = (int) ($columnIndexZeroBased / 26) - 1;
- } while ($columnIndexZeroBased >= 0);
-
- self::$columnIndexToColumnLettersCache[$originalColumnIndex] = $columnLetters;
- }
-
- return self::$columnIndexToColumnLettersCache[$originalColumnIndex];
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php b/upstream-3.x/src/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php
deleted file mode 100644
index f571ebf..0000000
--- a/upstream-3.x/src/Writer/Common/Helper/FileSystemWithRootFolderHelperInterface.php
+++ /dev/null
@@ -1,24 +0,0 @@
-entityFactory = $entityFactory;
- }
-
- /**
- * Returns a new ZipArchive instance pointing at the given path.
- *
- * @param string $tmpFolderPath Path of the temp folder where the zip file will be created
- *
- * @return \ZipArchive
- */
- public function createZip($tmpFolderPath)
- {
- $zip = $this->entityFactory->createZipArchive();
- $zipFilePath = $tmpFolderPath.self::ZIP_EXTENSION;
-
- $zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
-
- return $zip;
- }
-
- /**
- * @param \ZipArchive $zip An opened zip archive object
- *
- * @return string Path where the zip file of the given folder will be created
- */
- public function getZipFilePath(\ZipArchive $zip)
- {
- return $zip->filename;
- }
-
- /**
- * Adds the given file, located under the given root folder to the archive.
- * The file will be compressed.
- *
- * Example of use:
- * addFileToArchive($zip, '/tmp/xlsx/foo', 'bar/baz.xml');
- * => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml'
- *
- * @param \ZipArchive $zip An opened zip archive object
- * @param string $rootFolderPath path of the root folder that will be ignored in the archive tree
- * @param string $localFilePath Path of the file to be added, under the root folder
- * @param string $existingFileMode Controls what to do when trying to add an existing file
- */
- public function addFileToArchive($zip, $rootFolderPath, $localFilePath, $existingFileMode = self::EXISTING_FILES_OVERWRITE)
- {
- $this->addFileToArchiveWithCompressionMethod(
- $zip,
- $rootFolderPath,
- $localFilePath,
- $existingFileMode,
- \ZipArchive::CM_DEFAULT
- );
- }
-
- /**
- * Adds the given file, located under the given root folder to the archive.
- * The file will NOT be compressed.
- *
- * Example of use:
- * addUncompressedFileToArchive($zip, '/tmp/xlsx/foo', 'bar/baz.xml');
- * => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml'
- *
- * @param \ZipArchive $zip An opened zip archive object
- * @param string $rootFolderPath path of the root folder that will be ignored in the archive tree
- * @param string $localFilePath Path of the file to be added, under the root folder
- * @param string $existingFileMode Controls what to do when trying to add an existing file
- */
- public function addUncompressedFileToArchive($zip, $rootFolderPath, $localFilePath, $existingFileMode = self::EXISTING_FILES_OVERWRITE)
- {
- $this->addFileToArchiveWithCompressionMethod(
- $zip,
- $rootFolderPath,
- $localFilePath,
- $existingFileMode,
- \ZipArchive::CM_STORE
- );
- }
-
- /**
- * @return bool Whether it is possible to choose the desired compression method to be used
- */
- public static function canChooseCompressionMethod()
- {
- // setCompressionName() is a PHP7+ method...
- return method_exists(new \ZipArchive(), 'setCompressionName');
- }
-
- /**
- * @param \ZipArchive $zip An opened zip archive object
- * @param string $folderPath Path to the folder to be zipped
- * @param string $existingFileMode Controls what to do when trying to add an existing file
- */
- public function addFolderToArchive($zip, $folderPath, $existingFileMode = self::EXISTING_FILES_OVERWRITE)
- {
- $folderRealPath = $this->getNormalizedRealPath($folderPath).'/';
- $itemIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
-
- foreach ($itemIterator as $itemInfo) {
- $itemRealPath = $this->getNormalizedRealPath($itemInfo->getPathname());
- $itemLocalPath = str_replace($folderRealPath, '', $itemRealPath);
-
- if ($itemInfo->isFile() && !$this->shouldSkipFile($zip, $itemLocalPath, $existingFileMode)) {
- $zip->addFile($itemRealPath, $itemLocalPath);
- }
- }
- }
-
- /**
- * Closes the archive and copies it into the given stream.
- *
- * @param \ZipArchive $zip An opened zip archive object
- * @param resource $streamPointer Pointer to the stream to copy the zip
- */
- public function closeArchiveAndCopyToStream($zip, $streamPointer)
- {
- $zipFilePath = $zip->filename;
- $zip->close();
-
- $this->copyZipToStream($zipFilePath, $streamPointer);
- }
-
- /**
- * Adds the given file, located under the given root folder to the archive.
- * The file will NOT be compressed.
- *
- * Example of use:
- * addUncompressedFileToArchive($zip, '/tmp/xlsx/foo', 'bar/baz.xml');
- * => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml'
- *
- * @param \ZipArchive $zip An opened zip archive object
- * @param string $rootFolderPath path of the root folder that will be ignored in the archive tree
- * @param string $localFilePath Path of the file to be added, under the root folder
- * @param string $existingFileMode Controls what to do when trying to add an existing file
- * @param int $compressionMethod The compression method
- */
- protected function addFileToArchiveWithCompressionMethod($zip, $rootFolderPath, $localFilePath, $existingFileMode, $compressionMethod)
- {
- if (!$this->shouldSkipFile($zip, $localFilePath, $existingFileMode)) {
- $normalizedFullFilePath = $this->getNormalizedRealPath($rootFolderPath.'/'.$localFilePath);
- $zip->addFile($normalizedFullFilePath, $localFilePath);
-
- if (self::canChooseCompressionMethod()) {
- $zip->setCompressionName($localFilePath, $compressionMethod);
- }
- }
- }
-
- /**
- * @param \ZipArchive $zip
- * @param string $itemLocalPath
- * @param string $existingFileMode
- *
- * @return bool Whether the file should be added to the archive or skipped
- */
- protected function shouldSkipFile($zip, $itemLocalPath, $existingFileMode)
- {
- // Skip files if:
- // - EXISTING_FILES_SKIP mode chosen
- // - File already exists in the archive
- return self::EXISTING_FILES_SKIP === $existingFileMode && false !== $zip->locateName($itemLocalPath);
- }
-
- /**
- * Returns canonicalized absolute pathname, containing only forward slashes.
- *
- * @param string $path Path to normalize
- *
- * @return string Normalized and canonicalized path
- */
- protected function getNormalizedRealPath($path)
- {
- $realPath = realpath($path);
-
- return str_replace(\DIRECTORY_SEPARATOR, '/', $realPath);
- }
-
- /**
- * Streams the contents of the zip file into the given stream.
- *
- * @param string $zipFilePath Path of the zip file
- * @param resource $pointer Pointer to the stream to copy the zip
- */
- protected function copyZipToStream($zipFilePath, $pointer)
- {
- $zipFilePointer = fopen($zipFilePath, 'r');
- stream_copy_to_stream($zipFilePointer, $pointer);
- fclose($zipFilePointer);
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/CellManager.php b/upstream-3.x/src/Writer/Common/Manager/CellManager.php
deleted file mode 100644
index 5ce70d4..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/CellManager.php
+++ /dev/null
@@ -1,29 +0,0 @@
-styleMerger = $styleMerger;
- }
-
- /**
- * Merges a Style into a cell's Style.
- */
- public function applyStyle(Cell $cell, Style $style)
- {
- $mergedStyle = $this->styleMerger->merge($cell->getStyle(), $style);
- $cell->setStyle($mergedStyle);
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/ManagesCellSize.php b/upstream-3.x/src/Writer/Common/Manager/ManagesCellSize.php
deleted file mode 100644
index eb8c4a4..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/ManagesCellSize.php
+++ /dev/null
@@ -1,62 +0,0 @@
-defaultColumnWidth = $width;
- }
-
- /**
- * @param null|float $height
- */
- public function setDefaultRowHeight($height)
- {
- $this->defaultRowHeight = $height;
- }
-
- /**
- * @param int ...$columns One or more columns with this width
- */
- public function setColumnWidth(float $width, ...$columns)
- {
- // Gather sequences
- $sequence = [];
- foreach ($columns as $i) {
- $sequenceLength = \count($sequence);
- if ($sequenceLength > 0) {
- $previousValue = $sequence[$sequenceLength - 1];
- if ($i !== $previousValue + 1) {
- $this->setColumnWidthForRange($width, $sequence[0], $previousValue);
- $sequence = [];
- }
- }
- $sequence[] = $i;
- }
- $this->setColumnWidthForRange($width, $sequence[0], $sequence[\count($sequence) - 1]);
- }
-
- /**
- * @param float $width The width to set
- * @param int $start First column index of the range
- * @param int $end Last column index of the range
- */
- public function setColumnWidthForRange(float $width, int $start, int $end)
- {
- $this->columnWidths[] = [$start, $end, $width];
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/RegisteredStyle.php b/upstream-3.x/src/Writer/Common/Manager/RegisteredStyle.php
deleted file mode 100644
index d3ef877..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/RegisteredStyle.php
+++ /dev/null
@@ -1,37 +0,0 @@
-style = $style;
- $this->isMatchingRowStyle = $isMatchingRowStyle;
- }
-
- public function getStyle(): Style
- {
- return $this->style;
- }
-
- public function isMatchingRowStyle(): bool
- {
- return $this->isMatchingRowStyle;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/RowManager.php b/upstream-3.x/src/Writer/Common/Manager/RowManager.php
deleted file mode 100644
index e702bf7..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/RowManager.php
+++ /dev/null
@@ -1,25 +0,0 @@
-getCells() as $cell) {
- if (!$cell->isEmpty()) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/SheetManager.php b/upstream-3.x/src/Writer/Common/Manager/SheetManager.php
deleted file mode 100644
index 4d6a6c2..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/SheetManager.php
+++ /dev/null
@@ -1,146 +0,0 @@
- [[SHEET_INDEX] => [SHEET_NAME]] keeping track of sheets' name to enforce uniqueness per workbook */
- private static $SHEETS_NAME_USED = [];
-
- /** @var StringHelper */
- private $stringHelper;
-
- /**
- * SheetManager constructor.
- */
- public function __construct(StringHelper $stringHelper)
- {
- $this->stringHelper = $stringHelper;
- }
-
- /**
- * Throws an exception if the given sheet's name is not valid.
- *
- * @see Sheet::setName for validity rules.
- *
- * @param string $name
- * @param Sheet $sheet The sheet whose future name is checked
- *
- * @throws \OpenSpout\Writer\Exception\InvalidSheetNameException if the sheet's name is invalid
- */
- public function throwIfNameIsInvalid($name, Sheet $sheet)
- {
- if (!\is_string($name)) {
- $actualType = \gettype($name);
- $errorMessage = "The sheet's name is invalid. It must be a string ({$actualType} given).";
-
- throw new InvalidSheetNameException($errorMessage);
- }
-
- $failedRequirements = [];
- $nameLength = $this->stringHelper->getStringLength($name);
-
- if (!$this->isNameUnique($name, $sheet)) {
- $failedRequirements[] = 'It should be unique';
- } else {
- if (0 === $nameLength) {
- $failedRequirements[] = 'It should not be blank';
- } else {
- if ($nameLength > self::MAX_LENGTH_SHEET_NAME) {
- $failedRequirements[] = 'It should not exceed 31 characters';
- }
-
- if ($this->doesContainInvalidCharacters($name)) {
- $failedRequirements[] = 'It should not contain these characters: \\ / ? * : [ or ]';
- }
-
- if ($this->doesStartOrEndWithSingleQuote($name)) {
- $failedRequirements[] = 'It should not start or end with a single quote';
- }
- }
- }
-
- if (0 !== \count($failedRequirements)) {
- $errorMessage = "The sheet's name (\"{$name}\") is invalid. It did not respect these rules:\n - ";
- $errorMessage .= implode("\n - ", $failedRequirements);
-
- throw new InvalidSheetNameException($errorMessage);
- }
- }
-
- /**
- * @param string $workbookId Workbook ID associated to a Sheet
- */
- public function markWorkbookIdAsUsed($workbookId)
- {
- if (!isset(self::$SHEETS_NAME_USED[$workbookId])) {
- self::$SHEETS_NAME_USED[$workbookId] = [];
- }
- }
-
- public function markSheetNameAsUsed(Sheet $sheet)
- {
- self::$SHEETS_NAME_USED[$sheet->getAssociatedWorkbookId()][$sheet->getIndex()] = $sheet->getName();
- }
-
- /**
- * Returns whether the given name contains at least one invalid character.
- *
- * @see Sheet::$INVALID_CHARACTERS_IN_SHEET_NAME for the full list.
- *
- * @param string $name
- *
- * @return bool TRUE if the name contains invalid characters, FALSE otherwise
- */
- private function doesContainInvalidCharacters($name)
- {
- return str_replace(self::$INVALID_CHARACTERS_IN_SHEET_NAME, '', $name) !== $name;
- }
-
- /**
- * Returns whether the given name starts or ends with a single quote.
- *
- * @param string $name
- *
- * @return bool TRUE if the name starts or ends with a single quote, FALSE otherwise
- */
- private function doesStartOrEndWithSingleQuote($name)
- {
- $startsWithSingleQuote = (0 === $this->stringHelper->getCharFirstOccurrencePosition('\'', $name));
- $endsWithSingleQuote = ($this->stringHelper->getCharLastOccurrencePosition('\'', $name) === ($this->stringHelper->getStringLength($name) - 1));
-
- return $startsWithSingleQuote || $endsWithSingleQuote;
- }
-
- /**
- * Returns whether the given name is unique.
- *
- * @param string $name
- * @param Sheet $sheet The sheet whose future name is checked
- *
- * @return bool TRUE if the name is unique, FALSE otherwise
- */
- private function isNameUnique($name, Sheet $sheet)
- {
- foreach (self::$SHEETS_NAME_USED[$sheet->getAssociatedWorkbookId()] as $sheetIndex => $sheetName) {
- if ($sheetIndex !== $sheet->getIndex() && $sheetName === $name) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/Style/PossiblyUpdatedStyle.php b/upstream-3.x/src/Writer/Common/Manager/Style/PossiblyUpdatedStyle.php
deleted file mode 100644
index d78dd4b..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/Style/PossiblyUpdatedStyle.php
+++ /dev/null
@@ -1,31 +0,0 @@
-style = $style;
- $this->isUpdated = $isUpdated;
- }
-
- public function getStyle(): Style
- {
- return $this->style;
- }
-
- public function isUpdated(): bool
- {
- return $this->isUpdated;
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/Style/StyleManager.php b/upstream-3.x/src/Writer/Common/Manager/Style/StyleManager.php
deleted file mode 100644
index 47f4d34..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/Style/StyleManager.php
+++ /dev/null
@@ -1,82 +0,0 @@
-styleRegistry = $styleRegistry;
- }
-
- /**
- * Registers the given style as a used style.
- * Duplicate styles won't be registered more than once.
- *
- * @param Style $style The style to be registered
- *
- * @return Style the registered style, updated with an internal ID
- */
- public function registerStyle($style)
- {
- return $this->styleRegistry->registerStyle($style);
- }
-
- /**
- * Apply additional styles if the given row needs it.
- * Typically, set "wrap text" if a cell contains a new line.
- *
- * @return PossiblyUpdatedStyle The eventually updated style
- */
- public function applyExtraStylesIfNeeded(Cell $cell): PossiblyUpdatedStyle
- {
- return $this->applyWrapTextIfCellContainsNewLine($cell);
- }
-
- /**
- * Returns the default style.
- *
- * @return Style Default style
- */
- protected function getDefaultStyle()
- {
- // By construction, the default style has ID 0
- return $this->styleRegistry->getRegisteredStyles()[0];
- }
-
- /**
- * Set the "wrap text" option if a cell of the given row contains a new line.
- *
- * @NOTE: There is a bug on the Mac version of Excel (2011 and below) where new lines
- * are ignored even when the "wrap text" option is set. This only occurs with
- * inline strings (shared strings do work fine).
- * A workaround would be to encode "\n" as "_x000D_" but it does not work
- * on the Windows version of Excel...
- *
- * @param Cell $cell The cell the style should be applied to
- *
- * @return PossiblyUpdatedStyle The eventually updated style
- */
- protected function applyWrapTextIfCellContainsNewLine(Cell $cell): PossiblyUpdatedStyle
- {
- $cellStyle = $cell->getStyle();
-
- // if the "wrap text" option is already set, no-op
- if (!$cellStyle->hasSetWrapText() && $cell->isString() && false !== strpos($cell->getValue(), "\n")) {
- $cellStyle->setShouldWrapText();
-
- return new PossiblyUpdatedStyle($cellStyle, true);
- }
-
- return new PossiblyUpdatedStyle($cellStyle, false);
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/Style/StyleManagerInterface.php b/upstream-3.x/src/Writer/Common/Manager/Style/StyleManagerInterface.php
deleted file mode 100644
index 0418f3d..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/Style/StyleManagerInterface.php
+++ /dev/null
@@ -1,30 +0,0 @@
-mergeFontStyles($mergedStyle, $style, $baseStyle);
- $this->mergeOtherFontProperties($mergedStyle, $style, $baseStyle);
- $this->mergeCellProperties($mergedStyle, $style, $baseStyle);
-
- return $mergedStyle;
- }
-
- /**
- * @param Style $styleToUpdate (passed as reference)
- */
- private function mergeFontStyles(Style $styleToUpdate, Style $style, Style $baseStyle)
- {
- if (!$style->hasSetFontBold() && $baseStyle->isFontBold()) {
- $styleToUpdate->setFontBold();
- }
- if (!$style->hasSetFontItalic() && $baseStyle->isFontItalic()) {
- $styleToUpdate->setFontItalic();
- }
- if (!$style->hasSetFontUnderline() && $baseStyle->isFontUnderline()) {
- $styleToUpdate->setFontUnderline();
- }
- if (!$style->hasSetFontStrikethrough() && $baseStyle->isFontStrikethrough()) {
- $styleToUpdate->setFontStrikethrough();
- }
- }
-
- /**
- * @param Style $styleToUpdate Style to update (passed as reference)
- */
- private function mergeOtherFontProperties(Style $styleToUpdate, Style $style, Style $baseStyle)
- {
- if (!$style->hasSetFontSize() && Style::DEFAULT_FONT_SIZE !== $baseStyle->getFontSize()) {
- $styleToUpdate->setFontSize($baseStyle->getFontSize());
- }
- if (!$style->hasSetFontColor() && Style::DEFAULT_FONT_COLOR !== $baseStyle->getFontColor()) {
- $styleToUpdate->setFontColor($baseStyle->getFontColor());
- }
- if (!$style->hasSetFontName() && Style::DEFAULT_FONT_NAME !== $baseStyle->getFontName()) {
- $styleToUpdate->setFontName($baseStyle->getFontName());
- }
- }
-
- /**
- * @param Style $styleToUpdate Style to update (passed as reference)
- */
- private function mergeCellProperties(Style $styleToUpdate, Style $style, Style $baseStyle)
- {
- if (!$style->hasSetWrapText() && $baseStyle->shouldWrapText()) {
- $styleToUpdate->setShouldWrapText();
- }
- if (!$style->hasSetShrinkToFit() && $baseStyle->shouldShrinkToFit()) {
- $styleToUpdate->setShouldShrinkToFit();
- }
- if (!$style->hasSetCellAlignment() && $baseStyle->shouldApplyCellAlignment()) {
- $styleToUpdate->setCellAlignment($baseStyle->getCellAlignment());
- }
- if (null === $style->getBorder() && $baseStyle->shouldApplyBorder()) {
- $styleToUpdate->setBorder($baseStyle->getBorder());
- }
- if (null === $style->getFormat() && $baseStyle->shouldApplyFormat()) {
- $styleToUpdate->setFormat($baseStyle->getFormat());
- }
- if (!$style->shouldApplyBackgroundColor() && $baseStyle->shouldApplyBackgroundColor()) {
- $styleToUpdate->setBackgroundColor($baseStyle->getBackgroundColor());
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/Style/StyleRegistry.php b/upstream-3.x/src/Writer/Common/Manager/Style/StyleRegistry.php
deleted file mode 100644
index b3782a0..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/Style/StyleRegistry.php
+++ /dev/null
@@ -1,111 +0,0 @@
- [STYLE_ID] mapping table, keeping track of the registered styles */
- protected $serializedStyleToStyleIdMappingTable = [];
-
- /** @var array [STYLE_ID] => [STYLE] mapping table, keeping track of the registered styles */
- protected $styleIdToStyleMappingTable = [];
-
- public function __construct(Style $defaultStyle)
- {
- // This ensures that the default style is the first one to be registered
- $this->registerStyle($defaultStyle);
- }
-
- /**
- * Registers the given style as a used style.
- * Duplicate styles won't be registered more than once.
- *
- * @param Style $style The style to be registered
- *
- * @return Style the registered style, updated with an internal ID
- */
- public function registerStyle(Style $style)
- {
- $serializedStyle = $this->serialize($style);
-
- if (!$this->hasSerializedStyleAlreadyBeenRegistered($serializedStyle)) {
- $nextStyleId = \count($this->serializedStyleToStyleIdMappingTable);
- $style->markAsRegistered($nextStyleId);
-
- $this->serializedStyleToStyleIdMappingTable[$serializedStyle] = $nextStyleId;
- $this->styleIdToStyleMappingTable[$nextStyleId] = $style;
- }
-
- return $this->getStyleFromSerializedStyle($serializedStyle);
- }
-
- /**
- * @return Style[] List of registered styles
- */
- public function getRegisteredStyles()
- {
- return array_values($this->styleIdToStyleMappingTable);
- }
-
- /**
- * @param int $styleId
- *
- * @return Style
- */
- public function getStyleFromStyleId($styleId)
- {
- return $this->styleIdToStyleMappingTable[$styleId];
- }
-
- /**
- * Serializes the style for future comparison with other styles.
- * The ID is excluded from the comparison, as we only care about
- * actual style properties.
- *
- * @return string The serialized style
- */
- public function serialize(Style $style)
- {
- // In order to be able to properly compare style, set static ID value and reset registration
- $currentId = $style->getId();
- $style->unmarkAsRegistered();
-
- $serializedStyle = serialize($style);
-
- $style->markAsRegistered($currentId);
-
- return $serializedStyle;
- }
-
- /**
- * Returns whether the serialized style has already been registered.
- *
- * @param string $serializedStyle The serialized style
- *
- * @return bool
- */
- protected function hasSerializedStyleAlreadyBeenRegistered(string $serializedStyle)
- {
- // Using isset here because it is way faster than array_key_exists...
- return isset($this->serializedStyleToStyleIdMappingTable[$serializedStyle]);
- }
-
- /**
- * Returns the registered style associated to the given serialization.
- *
- * @param string $serializedStyle The serialized style from which the actual style should be fetched from
- *
- * @return Style
- */
- protected function getStyleFromSerializedStyle($serializedStyle)
- {
- $styleId = $this->serializedStyleToStyleIdMappingTable[$serializedStyle];
-
- return $this->styleIdToStyleMappingTable[$styleId];
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/WorkbookManagerAbstract.php b/upstream-3.x/src/Writer/Common/Manager/WorkbookManagerAbstract.php
deleted file mode 100644
index 8ffd7e9..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/WorkbookManagerAbstract.php
+++ /dev/null
@@ -1,352 +0,0 @@
-workbook = $workbook;
- $this->optionsManager = $optionsManager;
- $this->worksheetManager = $worksheetManager;
- $this->styleManager = $styleManager;
- $this->styleMerger = $styleMerger;
- $this->fileSystemHelper = $fileSystemHelper;
- $this->entityFactory = $entityFactory;
- $this->managerFactory = $managerFactory;
- }
-
- /**
- * @return null|Workbook
- */
- public function getWorkbook()
- {
- return $this->workbook;
- }
-
- /**
- * Creates a new sheet in the workbook and make it the current sheet.
- * The writing will resume where it stopped (i.e. data won't be truncated).
- *
- * @return Worksheet The created sheet
- */
- public function addNewSheetAndMakeItCurrent()
- {
- $worksheet = $this->addNewSheet();
- $this->setCurrentWorksheet($worksheet);
-
- return $worksheet;
- }
-
- /**
- * @return Worksheet[] All the workbook's sheets
- */
- public function getWorksheets()
- {
- return $this->workbook->getWorksheets();
- }
-
- /**
- * Returns the current sheet.
- *
- * @return Worksheet The current sheet
- */
- public function getCurrentWorksheet()
- {
- return $this->currentWorksheet;
- }
-
- /**
- * Starts the current sheet and opens the file pointer.
- *
- * @throws IOException
- */
- public function startCurrentSheet()
- {
- $this->worksheetManager->startSheet($this->getCurrentWorksheet());
- }
-
- /**
- * Sets the given sheet as the current one. New data will be written to this sheet.
- * The writing will resume where it stopped (i.e. data won't be truncated).
- *
- * @param Sheet $sheet The "external" sheet to set as current
- *
- * @throws SheetNotFoundException If the given sheet does not exist in the workbook
- */
- public function setCurrentSheet(Sheet $sheet)
- {
- $worksheet = $this->getWorksheetFromExternalSheet($sheet);
- if (null !== $worksheet) {
- $this->currentWorksheet = $worksheet;
- } else {
- throw new SheetNotFoundException('The given sheet does not exist in the workbook.');
- }
- }
-
- /**
- * Adds a row to the current sheet.
- * If shouldCreateNewSheetsAutomatically option is set to true, it will handle pagination
- * with the creation of new worksheets if one worksheet has reached its maximum capicity.
- *
- * @param Row $row The row to be added
- *
- * @throws IOException If trying to create a new sheet and unable to open the sheet for writing
- * @throws \OpenSpout\Common\Exception\InvalidArgumentException
- */
- public function addRowToCurrentWorksheet(Row $row)
- {
- $currentWorksheet = $this->getCurrentWorksheet();
- $hasReachedMaxRows = $this->hasCurrentWorksheetReachedMaxRows();
-
- // if we reached the maximum number of rows for the current sheet...
- if ($hasReachedMaxRows) {
- // ... continue writing in a new sheet if option set
- if ($this->optionsManager->getOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY)) {
- $currentWorksheet = $this->addNewSheetAndMakeItCurrent();
-
- $this->addRowToWorksheet($currentWorksheet, $row);
- }
- // otherwise, do nothing as the data won't be written anyways
- } else {
- $this->addRowToWorksheet($currentWorksheet, $row);
- }
- }
-
- public function setDefaultColumnWidth(float $width)
- {
- $this->worksheetManager->setDefaultColumnWidth($width);
- }
-
- public function setDefaultRowHeight(float $height)
- {
- $this->worksheetManager->setDefaultRowHeight($height);
- }
-
- /**
- * @param int ...$columns One or more columns with this width
- */
- public function setColumnWidth(float $width, ...$columns)
- {
- $this->worksheetManager->setColumnWidth($width, ...$columns);
- }
-
- /**
- * @param float $width The width to set
- * @param int $start First column index of the range
- * @param int $end Last column index of the range
- */
- public function setColumnWidthForRange(float $width, int $start, int $end)
- {
- $this->worksheetManager->setColumnWidthForRange($width, $start, $end);
- }
-
- /**
- * Closes the workbook and all its associated sheets.
- * All the necessary files are written to disk and zipped together to create the final file.
- * All the temporary files are then deleted.
- *
- * @param resource $finalFilePointer Pointer to the spreadsheet that will be created
- */
- public function close($finalFilePointer)
- {
- $this->closeAllWorksheets();
- $this->closeRemainingObjects();
- $this->writeAllFilesToDiskAndZipThem($finalFilePointer);
- $this->cleanupTempFolder();
- }
-
- /**
- * @return int Maximum number of rows/columns a sheet can contain
- */
- abstract protected function getMaxRowsPerWorksheet();
-
- /**
- * @return string The file path where the data for the given sheet will be stored
- */
- abstract protected function getWorksheetFilePath(Sheet $sheet);
-
- /**
- * Closes custom objects that are still opened.
- */
- protected function closeRemainingObjects()
- {
- // do nothing by default
- }
-
- /**
- * Writes all the necessary files to disk and zip them together to create the final file.
- *
- * @param resource $finalFilePointer Pointer to the spreadsheet that will be created
- */
- abstract protected function writeAllFilesToDiskAndZipThem($finalFilePointer);
-
- /**
- * Deletes the root folder created in the temp folder and all its contents.
- */
- protected function cleanupTempFolder()
- {
- $rootFolder = $this->fileSystemHelper->getRootFolder();
- $this->fileSystemHelper->deleteFolderRecursively($rootFolder);
- }
-
- /**
- * Creates a new sheet in the workbook. The current sheet remains unchanged.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to open the sheet for writing
- *
- * @return Worksheet The created sheet
- */
- private function addNewSheet()
- {
- $worksheets = $this->getWorksheets();
-
- $newSheetIndex = \count($worksheets);
- $sheetManager = $this->managerFactory->createSheetManager();
- $sheet = $this->entityFactory->createSheet($newSheetIndex, $this->workbook->getInternalId(), $sheetManager);
-
- $worksheetFilePath = $this->getWorksheetFilePath($sheet);
- $worksheet = $this->entityFactory->createWorksheet($worksheetFilePath, $sheet);
-
- $this->worksheetManager->startSheet($worksheet);
-
- $worksheets[] = $worksheet;
- $this->workbook->setWorksheets($worksheets);
-
- return $worksheet;
- }
-
- /**
- * @param Worksheet $worksheet
- */
- private function setCurrentWorksheet($worksheet)
- {
- $this->currentWorksheet = $worksheet;
- }
-
- /**
- * Returns the worksheet associated to the given external sheet.
- *
- * @param Sheet $sheet
- *
- * @return null|Worksheet the worksheet associated to the given external sheet or null if not found
- */
- private function getWorksheetFromExternalSheet($sheet)
- {
- $worksheetFound = null;
-
- foreach ($this->getWorksheets() as $worksheet) {
- if ($worksheet->getExternalSheet() === $sheet) {
- $worksheetFound = $worksheet;
-
- break;
- }
- }
-
- return $worksheetFound;
- }
-
- /**
- * @return bool whether the current worksheet has reached the maximum number of rows per sheet
- */
- private function hasCurrentWorksheetReachedMaxRows()
- {
- $currentWorksheet = $this->getCurrentWorksheet();
-
- return $currentWorksheet->getLastWrittenRowIndex() >= $this->getMaxRowsPerWorksheet();
- }
-
- /**
- * Adds a row to the given sheet.
- *
- * @param Worksheet $worksheet Worksheet to write the row to
- * @param Row $row The row to be added
- *
- * @throws IOException
- * @throws \OpenSpout\Common\Exception\InvalidArgumentException
- */
- private function addRowToWorksheet(Worksheet $worksheet, Row $row)
- {
- $this->applyDefaultRowStyle($row);
- $this->worksheetManager->addRow($worksheet, $row);
-
- // update max num columns for the worksheet
- $currentMaxNumColumns = $worksheet->getMaxNumColumns();
- $cellsCount = $row->getNumCells();
- $worksheet->setMaxNumColumns(max($currentMaxNumColumns, $cellsCount));
- }
-
- private function applyDefaultRowStyle(Row $row)
- {
- $defaultRowStyle = $this->optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
-
- if (null !== $defaultRowStyle) {
- $mergedStyle = $this->styleMerger->merge($row->getStyle(), $defaultRowStyle);
- $row->setStyle($mergedStyle);
- }
- }
-
- /**
- * Closes all workbook's associated sheets.
- */
- private function closeAllWorksheets()
- {
- $worksheets = $this->getWorksheets();
-
- foreach ($worksheets as $worksheet) {
- $this->worksheetManager->close($worksheet);
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/Common/Manager/WorkbookManagerInterface.php b/upstream-3.x/src/Writer/Common/Manager/WorkbookManagerInterface.php
deleted file mode 100644
index 209abc6..0000000
--- a/upstream-3.x/src/Writer/Common/Manager/WorkbookManagerInterface.php
+++ /dev/null
@@ -1,97 +0,0 @@
-getOption(Options::TEMP_FOLDER);
- $zipHelper = $this->createZipHelper($entityFactory);
-
- return new FileSystemHelper($tempFolder, $zipHelper);
- }
-
- /**
- * @return Escaper\ODS
- */
- public function createStringsEscaper()
- {
- return new Escaper\ODS();
- }
-
- /**
- * @return StringHelper
- */
- public function createStringHelper()
- {
- return new StringHelper();
- }
-
- /**
- * @param InternalEntityFactory $entityFactory
- *
- * @return ZipHelper
- */
- private function createZipHelper($entityFactory)
- {
- return new ZipHelper($entityFactory);
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Creator/ManagerFactory.php b/upstream-3.x/src/Writer/ODS/Creator/ManagerFactory.php
deleted file mode 100644
index a514286..0000000
--- a/upstream-3.x/src/Writer/ODS/Creator/ManagerFactory.php
+++ /dev/null
@@ -1,107 +0,0 @@
-entityFactory = $entityFactory;
- $this->helperFactory = $helperFactory;
- }
-
- /**
- * @return WorkbookManager
- */
- public function createWorkbookManager(OptionsManagerInterface $optionsManager)
- {
- $workbook = $this->entityFactory->createWorkbook();
-
- $fileSystemHelper = $this->helperFactory->createSpecificFileSystemHelper($optionsManager, $this->entityFactory);
- $fileSystemHelper->createBaseFilesAndFolders();
-
- $styleMerger = $this->createStyleMerger();
- $styleManager = $this->createStyleManager($optionsManager);
- $worksheetManager = $this->createWorksheetManager($styleManager, $styleMerger);
-
- return new WorkbookManager(
- $workbook,
- $optionsManager,
- $worksheetManager,
- $styleManager,
- $styleMerger,
- $fileSystemHelper,
- $this->entityFactory,
- $this
- );
- }
-
- /**
- * @return SheetManager
- */
- public function createSheetManager()
- {
- $stringHelper = $this->helperFactory->createStringHelper();
-
- return new SheetManager($stringHelper);
- }
-
- /**
- * @return WorksheetManager
- */
- private function createWorksheetManager(StyleManager $styleManager, StyleMerger $styleMerger)
- {
- $stringsEscaper = $this->helperFactory->createStringsEscaper();
- $stringsHelper = $this->helperFactory->createStringHelper();
-
- return new WorksheetManager($styleManager, $styleMerger, $stringsEscaper, $stringsHelper);
- }
-
- /**
- * @return StyleManager
- */
- private function createStyleManager(OptionsManagerInterface $optionsManager)
- {
- $styleRegistry = $this->createStyleRegistry($optionsManager);
-
- return new StyleManager($styleRegistry, $optionsManager);
- }
-
- /**
- * @return StyleRegistry
- */
- private function createStyleRegistry(OptionsManagerInterface $optionsManager)
- {
- $defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
-
- return new StyleRegistry($defaultRowStyle);
- }
-
- /**
- * @return StyleMerger
- */
- private function createStyleMerger()
- {
- return new StyleMerger();
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Helper/BorderHelper.php b/upstream-3.x/src/Writer/ODS/Helper/BorderHelper.php
deleted file mode 100644
index caaf954..0000000
--- a/upstream-3.x/src/Writer/ODS/Helper/BorderHelper.php
+++ /dev/null
@@ -1,65 +0,0 @@
-
- */
-class BorderHelper
-{
- /**
- * Width mappings.
- *
- * @var array
- */
- protected static $widthMap = [
- Border::WIDTH_THIN => '0.75pt',
- Border::WIDTH_MEDIUM => '1.75pt',
- Border::WIDTH_THICK => '2.5pt',
- ];
-
- /**
- * Style mapping.
- *
- * @var array
- */
- protected static $styleMap = [
- Border::STYLE_SOLID => 'solid',
- Border::STYLE_DASHED => 'dashed',
- Border::STYLE_DOTTED => 'dotted',
- Border::STYLE_DOUBLE => 'double',
- ];
-
- /**
- * @return string
- */
- public static function serializeBorderPart(BorderPart $borderPart)
- {
- $definition = 'fo:border-%s="%s"';
-
- if (Border::STYLE_NONE === $borderPart->getStyle()) {
- $borderPartDefinition = sprintf($definition, $borderPart->getName(), 'none');
- } else {
- $attributes = [
- self::$widthMap[$borderPart->getWidth()],
- self::$styleMap[$borderPart->getStyle()],
- '#'.$borderPart->getColor(),
- ];
- $borderPartDefinition = sprintf($definition, $borderPart->getName(), implode(' ', $attributes));
- }
-
- return $borderPartDefinition;
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Helper/FileSystemHelper.php b/upstream-3.x/src/Writer/ODS/Helper/FileSystemHelper.php
deleted file mode 100644
index b3280b6..0000000
--- a/upstream-3.x/src/Writer/ODS/Helper/FileSystemHelper.php
+++ /dev/null
@@ -1,304 +0,0 @@
-zipHelper = $zipHelper;
- }
-
- /**
- * @return string
- */
- public function getRootFolder()
- {
- return $this->rootFolder;
- }
-
- /**
- * @return string
- */
- public function getSheetsContentTempFolder()
- {
- return $this->sheetsContentTempFolder;
- }
-
- /**
- * Creates all the folders needed to create a ODS file, as well as the files that won't change.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create at least one of the base folders
- */
- public function createBaseFilesAndFolders()
- {
- $this
- ->createRootFolder()
- ->createMetaInfoFolderAndFile()
- ->createSheetsContentTempFolder()
- ->createMetaFile()
- ->createMimetypeFile()
- ;
- }
-
- /**
- * Creates the "content.xml" file under the root folder.
- *
- * @param WorksheetManager $worksheetManager
- * @param StyleManager $styleManager
- * @param Worksheet[] $worksheets
- *
- * @return FileSystemHelper
- */
- public function createContentFile($worksheetManager, $styleManager, $worksheets)
- {
- $contentXmlFileContents = <<<'EOD'
-
-
- EOD;
-
- $contentXmlFileContents .= $styleManager->getContentXmlFontFaceSectionContent();
- $contentXmlFileContents .= $styleManager->getContentXmlAutomaticStylesSectionContent($worksheets);
-
- $contentXmlFileContents .= '';
-
- $this->createFileWithContents($this->rootFolder, self::CONTENT_XML_FILE_NAME, $contentXmlFileContents);
-
- // Append sheets content to "content.xml"
- $contentXmlFilePath = $this->rootFolder.'/'.self::CONTENT_XML_FILE_NAME;
- $contentXmlHandle = fopen($contentXmlFilePath, 'a');
-
- foreach ($worksheets as $worksheet) {
- // write the "" node, with the final sheet's name
- fwrite($contentXmlHandle, $worksheetManager->getTableElementStartAsString($worksheet));
-
- $worksheetFilePath = $worksheet->getFilePath();
- $this->copyFileContentsToTarget($worksheetFilePath, $contentXmlHandle);
-
- fwrite($contentXmlHandle, '');
- }
-
- $contentXmlFileContents = '';
-
- fwrite($contentXmlHandle, $contentXmlFileContents);
- fclose($contentXmlHandle);
-
- return $this;
- }
-
- /**
- * Deletes the temporary folder where sheets content was stored.
- *
- * @return FileSystemHelper
- */
- public function deleteWorksheetTempFolder()
- {
- $this->deleteFolderRecursively($this->sheetsContentTempFolder);
-
- return $this;
- }
-
- /**
- * Creates the "styles.xml" file under the root folder.
- *
- * @param StyleManager $styleManager
- * @param int $numWorksheets Number of created worksheets
- *
- * @return FileSystemHelper
- */
- public function createStylesFile($styleManager, $numWorksheets)
- {
- $stylesXmlFileContents = $styleManager->getStylesXMLFileContent($numWorksheets);
- $this->createFileWithContents($this->rootFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents);
-
- return $this;
- }
-
- /**
- * Zips the root folder and streams the contents of the zip into the given stream.
- *
- * @param resource $streamPointer Pointer to the stream to copy the zip
- */
- public function zipRootFolderAndCopyToStream($streamPointer)
- {
- $zip = $this->zipHelper->createZip($this->rootFolder);
-
- $zipFilePath = $this->zipHelper->getZipFilePath($zip);
-
- // In order to have the file's mime type detected properly, files need to be added
- // to the zip file in a particular order.
- // @see http://www.jejik.com/articles/2010/03/how_to_correctly_create_odf_documents_using_zip/
- $this->zipHelper->addUncompressedFileToArchive($zip, $this->rootFolder, self::MIMETYPE_FILE_NAME);
-
- $this->zipHelper->addFolderToArchive($zip, $this->rootFolder, ZipHelper::EXISTING_FILES_SKIP);
- $this->zipHelper->closeArchiveAndCopyToStream($zip, $streamPointer);
-
- // once the zip is copied, remove it
- $this->deleteFile($zipFilePath);
- }
-
- /**
- * Creates the folder that will be used as root.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder
- *
- * @return FileSystemHelper
- */
- protected function createRootFolder()
- {
- $this->rootFolder = $this->createFolder($this->baseFolderRealPath, uniqid('ods'));
-
- return $this;
- }
-
- /**
- * Creates the "META-INF" folder under the root folder as well as the "manifest.xml" file in it.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder or the "manifest.xml" file
- *
- * @return FileSystemHelper
- */
- protected function createMetaInfoFolderAndFile()
- {
- $this->metaInfFolder = $this->createFolder($this->rootFolder, self::META_INF_FOLDER_NAME);
-
- $this->createManifestFile();
-
- return $this;
- }
-
- /**
- * Creates the "manifest.xml" file under the "META-INF" folder (under root).
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file
- *
- * @return FileSystemHelper
- */
- protected function createManifestFile()
- {
- $manifestXmlFileContents = <<<'EOD'
-
-
-
-
-
-
-
- EOD;
-
- $this->createFileWithContents($this->metaInfFolder, self::MANIFEST_XML_FILE_NAME, $manifestXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the temp folder where specific sheets content will be written to.
- * This folder is not part of the final ODS file and is only used to be able to jump between sheets.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder
- *
- * @return FileSystemHelper
- */
- protected function createSheetsContentTempFolder()
- {
- $this->sheetsContentTempFolder = $this->createFolder($this->rootFolder, self::SHEETS_CONTENT_TEMP_FOLDER_NAME);
-
- return $this;
- }
-
- /**
- * Creates the "meta.xml" file under the root folder.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file
- *
- * @return FileSystemHelper
- */
- protected function createMetaFile()
- {
- $appName = self::APP_NAME;
- $createdDate = (new \DateTime())->format(\DateTime::W3C);
-
- $metaXmlFileContents = <<
-
-
- {$appName}
- {$createdDate}
- {$createdDate}
-
-
- EOD;
-
- $this->createFileWithContents($this->rootFolder, self::META_XML_FILE_NAME, $metaXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "mimetype" file under the root folder.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file
- *
- * @return FileSystemHelper
- */
- protected function createMimetypeFile()
- {
- $this->createFileWithContents($this->rootFolder, self::MIMETYPE_FILE_NAME, self::MIMETYPE);
-
- return $this;
- }
-
- /**
- * Streams the content of the file at the given path into the target resource.
- * Depending on which mode the target resource was created with, it will truncate then copy
- * or append the content to the target file.
- *
- * @param string $sourceFilePath Path of the file whose content will be copied
- * @param resource $targetResource Target resource that will receive the content
- */
- protected function copyFileContentsToTarget($sourceFilePath, $targetResource)
- {
- $sourceHandle = fopen($sourceFilePath, 'r');
- stream_copy_to_stream($sourceHandle, $targetResource);
- fclose($sourceHandle);
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Manager/OptionsManager.php b/upstream-3.x/src/Writer/ODS/Manager/OptionsManager.php
deleted file mode 100644
index d098abf..0000000
--- a/upstream-3.x/src/Writer/ODS/Manager/OptionsManager.php
+++ /dev/null
@@ -1,50 +0,0 @@
-styleBuilder = $styleBuilder;
- parent::__construct();
- }
-
- /**
- * {@inheritdoc}
- */
- protected function getSupportedOptions()
- {
- return [
- Options::TEMP_FOLDER,
- Options::DEFAULT_ROW_STYLE,
- Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
- Options::DEFAULT_COLUMN_WIDTH,
- Options::DEFAULT_ROW_HEIGHT,
- Options::COLUMN_WIDTHS,
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- protected function setDefaultOptions()
- {
- $this->setOption(Options::TEMP_FOLDER, sys_get_temp_dir());
- $this->setOption(Options::DEFAULT_ROW_STYLE, $this->styleBuilder->build());
- $this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true);
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Manager/Style/StyleManager.php b/upstream-3.x/src/Writer/ODS/Manager/Style/StyleManager.php
deleted file mode 100644
index e1d9976..0000000
--- a/upstream-3.x/src/Writer/ODS/Manager/Style/StyleManager.php
+++ /dev/null
@@ -1,462 +0,0 @@
-setDefaultColumnWidth($optionsManager->getOption(Options::DEFAULT_COLUMN_WIDTH));
- $this->setDefaultRowHeight($optionsManager->getOption(Options::DEFAULT_ROW_HEIGHT));
- $this->columnWidths = $optionsManager->getOption(Options::COLUMN_WIDTHS) ?? [];
- }
-
- /**
- * Returns the content of the "styles.xml" file, given a list of styles.
- *
- * @param int $numWorksheets Number of worksheets created
- *
- * @return string
- */
- public function getStylesXMLFileContent($numWorksheets)
- {
- $content = <<<'EOD'
-
-
- EOD;
-
- $content .= $this->getFontFaceSectionContent();
- $content .= $this->getStylesSectionContent();
- $content .= $this->getAutomaticStylesSectionContent($numWorksheets);
- $content .= $this->getMasterStylesSectionContent($numWorksheets);
-
- $content .= <<<'EOD'
-
- EOD;
-
- return $content;
- }
-
- /**
- * Returns the contents of the "" section, inside "content.xml" file.
- *
- * @return string
- */
- public function getContentXmlFontFaceSectionContent()
- {
- $content = '';
- foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
- $content .= '';
- }
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the contents of the "" section, inside "content.xml" file.
- *
- * @param Worksheet[] $worksheets
- *
- * @return string
- */
- public function getContentXmlAutomaticStylesSectionContent($worksheets)
- {
- $content = '';
-
- foreach ($this->styleRegistry->getRegisteredStyles() as $style) {
- $content .= $this->getStyleSectionContent($style);
- }
-
- $useOptimalRowHeight = empty($this->defaultRowHeight) ? 'true' : 'false';
- $defaultRowHeight = empty($this->defaultRowHeight) ? '15pt' : "{$this->defaultRowHeight}pt";
- $defaultColumnWidth = empty($this->defaultColumnWidth) ? '' : "style:column-width=\"{$this->defaultColumnWidth}pt\"";
-
- $content .= <<
-
-
-
-
-
- EOD;
-
- foreach ($worksheets as $worksheet) {
- $worksheetId = $worksheet->getId();
- $isSheetVisible = $worksheet->getExternalSheet()->isVisible() ? 'true' : 'false';
-
- $content .= <<
-
-
- EOD;
- }
-
- // Sort column widths since ODS cares about order
- usort($this->columnWidths, function ($a, $b) {
- if ($a[0] === $b[0]) {
- return 0;
- }
-
- return ($a[0] < $b[0]) ? -1 : 1;
- });
- $content .= $this->getTableColumnStylesXMLContent();
-
- $content .= '';
-
- return $content;
- }
-
- public function getTableColumnStylesXMLContent(): string
- {
- if (empty($this->columnWidths)) {
- return '';
- }
-
- $content = '';
- foreach ($this->columnWidths as $styleIndex => $entry) {
- $content .= <<
-
-
- EOD;
- }
-
- return $content;
- }
-
- public function getStyledTableColumnXMLContent(int $maxNumColumns): string
- {
- if (empty($this->columnWidths)) {
- return '';
- }
-
- $content = '';
- foreach ($this->columnWidths as $styleIndex => $entry) {
- $numCols = $entry[1] - $entry[0] + 1;
- $content .= <<
- EOD;
- }
- // Note: This assumes the column widths are contiguous and default width is
- // only applied to columns after the last custom column with a custom width
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section, inside "styles.xml" file.
- *
- * @return string
- */
- protected function getFontFaceSectionContent()
- {
- $content = '';
- foreach ($this->styleRegistry->getUsedFonts() as $fontName) {
- $content .= '';
- }
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section, inside "styles.xml" file.
- *
- * @return string
- */
- protected function getStylesSectionContent()
- {
- $defaultStyle = $this->getDefaultStyle();
-
- return <<
-
-
-
-
-
-
-
-
- EOD;
- }
-
- /**
- * Returns the content of the "" section, inside "styles.xml" file.
- *
- * @param int $numWorksheets Number of worksheets created
- *
- * @return string
- */
- protected function getAutomaticStylesSectionContent($numWorksheets)
- {
- $content = '';
-
- for ($i = 1; $i <= $numWorksheets; ++$i) {
- $content .= <<
-
-
-
-
- EOD;
- }
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section, inside "styles.xml" file.
- *
- * @param int $numWorksheets Number of worksheets created
- *
- * @return string
- */
- protected function getMasterStylesSectionContent($numWorksheets)
- {
- $content = '';
-
- for ($i = 1; $i <= $numWorksheets; ++$i) {
- $content .= <<
-
-
-
-
-
- EOD;
- }
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the contents of the "" section, inside "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- protected function getStyleSectionContent($style)
- {
- $styleIndex = $style->getId() + 1; // 1-based
-
- $content = '';
-
- $content .= $this->getTextPropertiesSectionContent($style);
- $content .= $this->getParagraphPropertiesSectionContent($style);
- $content .= $this->getTableCellPropertiesSectionContent($style);
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the contents of the "" section, inside "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getTextPropertiesSectionContent($style)
- {
- if (!$style->shouldApplyFont()) {
- return '';
- }
-
- return 'getFontSectionContent($style)
- .'/>';
- }
-
- /**
- * Returns the contents of the fonts definition section, inside "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getFontSectionContent($style)
- {
- $defaultStyle = $this->getDefaultStyle();
- $content = '';
-
- $fontColor = $style->getFontColor();
- if ($fontColor !== $defaultStyle->getFontColor()) {
- $content .= ' fo:color="#'.$fontColor.'"';
- }
-
- $fontName = $style->getFontName();
- if ($fontName !== $defaultStyle->getFontName()) {
- $content .= ' style:font-name="'.$fontName.'" style:font-name-asian="'.$fontName.'" style:font-name-complex="'.$fontName.'"';
- }
-
- $fontSize = $style->getFontSize();
- if ($fontSize !== $defaultStyle->getFontSize()) {
- $content .= ' fo:font-size="'.$fontSize.'pt" style:font-size-asian="'.$fontSize.'pt" style:font-size-complex="'.$fontSize.'pt"';
- }
-
- if ($style->isFontBold()) {
- $content .= ' fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"';
- }
- if ($style->isFontItalic()) {
- $content .= ' fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"';
- }
- if ($style->isFontUnderline()) {
- $content .= ' style:text-underline-style="solid" style:text-underline-type="single"';
- }
- if ($style->isFontStrikethrough()) {
- $content .= ' style:text-line-through-style="solid"';
- }
-
- return $content;
- }
-
- /**
- * Returns the contents of the "" section, inside "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getParagraphPropertiesSectionContent($style)
- {
- if (!$style->shouldApplyCellAlignment()) {
- return '';
- }
-
- return 'getCellAlignmentSectionContent($style)
- .'/>';
- }
-
- /**
- * Returns the contents of the cell alignment definition for the "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getCellAlignmentSectionContent($style)
- {
- return sprintf(
- ' fo:text-align="%s" ',
- $this->transformCellAlignment($style->getCellAlignment())
- );
- }
-
- /**
- * Even though "left" and "right" alignments are part of the spec, and interpreted
- * respectively as "start" and "end", using the recommended values increase compatibility
- * with software that will read the created ODS file.
- *
- * @param string $cellAlignment
- *
- * @return string
- */
- private function transformCellAlignment($cellAlignment)
- {
- switch ($cellAlignment) {
- case CellAlignment::LEFT:
- return 'start';
-
- case CellAlignment::RIGHT:
- return 'end';
-
- default:
- return $cellAlignment;
- }
- }
-
- /**
- * Returns the contents of the "" section, inside "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getTableCellPropertiesSectionContent($style)
- {
- $content = 'shouldWrapText()) {
- $content .= $this->getWrapTextXMLContent();
- }
-
- if ($style->shouldApplyBorder()) {
- $content .= $this->getBorderXMLContent($style);
- }
-
- if ($style->shouldApplyBackgroundColor()) {
- $content .= $this->getBackgroundColorXMLContent($style);
- }
-
- $content .= '/>';
-
- return $content;
- }
-
- /**
- * Returns the contents of the wrap text definition for the "" section.
- *
- * @return string
- */
- private function getWrapTextXMLContent()
- {
- return ' fo:wrap-option="wrap" style:vertical-align="automatic" ';
- }
-
- /**
- * Returns the contents of the borders definition for the "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getBorderXMLContent($style)
- {
- $borders = array_map(function (BorderPart $borderPart) {
- return BorderHelper::serializeBorderPart($borderPart);
- }, $style->getBorder()->getParts());
-
- return sprintf(' %s ', implode(' ', $borders));
- }
-
- /**
- * Returns the contents of the background color definition for the "" section.
- *
- * @param \OpenSpout\Common\Entity\Style\Style $style
- *
- * @return string
- */
- private function getBackgroundColorXMLContent($style)
- {
- return sprintf(' fo:background-color="#%s" ', $style->getBackgroundColor());
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Manager/Style/StyleRegistry.php b/upstream-3.x/src/Writer/ODS/Manager/Style/StyleRegistry.php
deleted file mode 100644
index e90dc96..0000000
--- a/upstream-3.x/src/Writer/ODS/Manager/Style/StyleRegistry.php
+++ /dev/null
@@ -1,42 +0,0 @@
- [] Map whose keys contain all the fonts used */
- protected $usedFontsSet = [];
-
- /**
- * Registers the given style as a used style.
- * Duplicate styles won't be registered more than once.
- *
- * @param Style $style The style to be registered
- *
- * @return Style the registered style, updated with an internal ID
- */
- public function registerStyle(Style $style)
- {
- if ($style->isRegistered()) {
- return $style;
- }
-
- $registeredStyle = parent::registerStyle($style);
- $this->usedFontsSet[$style->getFontName()] = true;
-
- return $registeredStyle;
- }
-
- /**
- * @return string[] List of used fonts name
- */
- public function getUsedFonts()
- {
- return array_keys($this->usedFontsSet);
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Manager/WorkbookManager.php b/upstream-3.x/src/Writer/ODS/Manager/WorkbookManager.php
deleted file mode 100644
index 90dc0e4..0000000
--- a/upstream-3.x/src/Writer/ODS/Manager/WorkbookManager.php
+++ /dev/null
@@ -1,66 +0,0 @@
-fileSystemHelper->getSheetsContentTempFolder();
-
- return $sheetsContentTempFolder.'/sheet'.$sheet->getIndex().'.xml';
- }
-
- /**
- * @return int Maximum number of rows/columns a sheet can contain
- */
- protected function getMaxRowsPerWorksheet()
- {
- return self::$maxRowsPerWorksheet;
- }
-
- /**
- * Writes all the necessary files to disk and zip them together to create the final file.
- *
- * @param resource $finalFilePointer Pointer to the spreadsheet that will be created
- */
- protected function writeAllFilesToDiskAndZipThem($finalFilePointer)
- {
- $worksheets = $this->getWorksheets();
- $numWorksheets = \count($worksheets);
-
- $this->fileSystemHelper
- ->createContentFile($this->worksheetManager, $this->styleManager, $worksheets)
- ->deleteWorksheetTempFolder()
- ->createStylesFile($this->styleManager, $numWorksheets)
- ->zipRootFolderAndCopyToStream($finalFilePointer)
- ;
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Manager/WorksheetManager.php b/upstream-3.x/src/Writer/ODS/Manager/WorksheetManager.php
deleted file mode 100644
index 3eeca5f..0000000
--- a/upstream-3.x/src/Writer/ODS/Manager/WorksheetManager.php
+++ /dev/null
@@ -1,308 +0,0 @@
-styleManager = $styleManager;
- $this->styleMerger = $styleMerger;
- $this->stringsEscaper = $stringsEscaper;
- $this->stringHelper = $stringHelper;
- }
-
- /**
- * Prepares the worksheet to accept data.
- *
- * @param Worksheet $worksheet The worksheet to start
- *
- * @throws \OpenSpout\Common\Exception\IOException If the sheet data file cannot be opened for writing
- */
- public function startSheet(Worksheet $worksheet)
- {
- $sheetFilePointer = fopen($worksheet->getFilePath(), 'w');
- $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
-
- $worksheet->setFilePointer($sheetFilePointer);
- }
-
- /**
- * Returns the table XML root node as string.
- *
- * @return string "" node as string
- */
- public function getTableElementStartAsString(Worksheet $worksheet)
- {
- $externalSheet = $worksheet->getExternalSheet();
- $escapedSheetName = $this->stringsEscaper->escape($externalSheet->getName());
- $tableStyleName = 'ta'.($externalSheet->getIndex() + 1);
-
- $tableElement = '';
- $tableElement .= $this->styleManager->getStyledTableColumnXMLContent($worksheet->getMaxNumColumns());
-
- return $tableElement;
- }
-
- /**
- * Adds a row to the given worksheet.
- *
- * @param Worksheet $worksheet The worksheet to add the row to
- * @param Row $row The row to be added
- *
- * @throws InvalidArgumentException If a cell value's type is not supported
- * @throws IOException If the data cannot be written
- */
- public function addRow(Worksheet $worksheet, Row $row)
- {
- $cells = $row->getCells();
- $rowStyle = $row->getStyle();
-
- $data = '';
-
- $currentCellIndex = 0;
- $nextCellIndex = 1;
-
- for ($i = 0; $i < $row->getNumCells(); ++$i) {
- /** @var Cell $cell */
- $cell = $cells[$currentCellIndex];
- /** @var null|Cell $nextCell */
- $nextCell = $cells[$nextCellIndex] ?? null;
-
- if (null === $nextCell || $cell->getValue() !== $nextCell->getValue()) {
- $registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle);
- $cellStyle = $registeredStyle->getStyle();
- if ($registeredStyle->isMatchingRowStyle()) {
- $rowStyle = $cellStyle; // Replace actual rowStyle (possibly with null id) by registered style (with id)
- }
-
- $data .= $this->getCellXMLWithStyle($cell, $cellStyle, $currentCellIndex, $nextCellIndex);
- $currentCellIndex = $nextCellIndex;
- }
-
- ++$nextCellIndex;
- }
-
- $data .= '';
-
- $wasWriteSuccessful = fwrite($worksheet->getFilePointer(), $data);
- if (false === $wasWriteSuccessful) {
- throw new IOException("Unable to write data in {$worksheet->getFilePath()}");
- }
-
- // only update the count if the write worked
- $lastWrittenRowIndex = $worksheet->getLastWrittenRowIndex();
- $worksheet->setLastWrittenRowIndex($lastWrittenRowIndex + 1);
- }
-
- /**
- * Closes the worksheet.
- */
- public function close(Worksheet $worksheet)
- {
- $worksheetFilePointer = $worksheet->getFilePointer();
-
- if (!\is_resource($worksheetFilePointer)) {
- return;
- }
-
- fclose($worksheetFilePointer);
- }
-
- /**
- * @param null|float $width
- */
- public function setDefaultColumnWidth($width)
- {
- $this->styleManager->setDefaultColumnWidth($width);
- }
-
- /**
- * @param null|float $height
- */
- public function setDefaultRowHeight($height)
- {
- $this->styleManager->setDefaultRowHeight($height);
- }
-
- /**
- * @param int ...$columns One or more columns with this width
- */
- public function setColumnWidth(float $width, ...$columns)
- {
- $this->styleManager->setColumnWidth($width, ...$columns);
- }
-
- /**
- * @param float $width The width to set
- * @param int $start First column index of the range
- * @param int $end Last column index of the range
- */
- public function setColumnWidthForRange(float $width, int $start, int $end)
- {
- $this->styleManager->setColumnWidthForRange($width, $start, $end);
- }
-
- /**
- * Checks if the sheet has been sucessfully created. Throws an exception if not.
- *
- * @param bool|resource $sheetFilePointer Pointer to the sheet data file or FALSE if unable to open the file
- *
- * @throws IOException If the sheet data file cannot be opened for writing
- */
- private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer)
- {
- if (!$sheetFilePointer) {
- throw new IOException('Unable to open sheet for writing.');
- }
- }
-
- /**
- * Applies styles to the given style, merging the cell's style with its row's style.
- *
- * @throws InvalidArgumentException If a cell value's type is not supported
- */
- private function applyStyleAndRegister(Cell $cell, Style $rowStyle): RegisteredStyle
- {
- $isMatchingRowStyle = false;
- if ($cell->getStyle()->isEmpty()) {
- $cell->setStyle($rowStyle);
-
- $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell);
-
- if ($possiblyUpdatedStyle->isUpdated()) {
- $registeredStyle = $this->styleManager->registerStyle($possiblyUpdatedStyle->getStyle());
- } else {
- $registeredStyle = $this->styleManager->registerStyle($rowStyle);
- $isMatchingRowStyle = true;
- }
- } else {
- $mergedCellAndRowStyle = $this->styleMerger->merge($cell->getStyle(), $rowStyle);
- $cell->setStyle($mergedCellAndRowStyle);
-
- $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell);
- if ($possiblyUpdatedStyle->isUpdated()) {
- $newCellStyle = $possiblyUpdatedStyle->getStyle();
- } else {
- $newCellStyle = $mergedCellAndRowStyle;
- }
-
- $registeredStyle = $this->styleManager->registerStyle($newCellStyle);
- }
-
- return new RegisteredStyle($registeredStyle, $isMatchingRowStyle);
- }
-
- private function getCellXMLWithStyle(Cell $cell, Style $style, int $currentCellIndex, int $nextCellIndex): string
- {
- $styleIndex = $style->getId() + 1; // 1-based
-
- $numTimesValueRepeated = ($nextCellIndex - $currentCellIndex);
-
- return $this->getCellXML($cell, $styleIndex, $numTimesValueRepeated);
- }
-
- /**
- * Returns the cell XML content, given its value.
- *
- * @param Cell $cell The cell to be written
- * @param int $styleIndex Index of the used style
- * @param int $numTimesValueRepeated Number of times the value is consecutively repeated
- *
- * @throws InvalidArgumentException If a cell value's type is not supported
- *
- * @return string The cell XML content
- */
- private function getCellXML(Cell $cell, $styleIndex, $numTimesValueRepeated)
- {
- $data = 'isString()) {
- $data .= ' office:value-type="string" calcext:value-type="string">';
-
- $cellValueLines = explode("\n", $cell->getValue());
- foreach ($cellValueLines as $cellValueLine) {
- $data .= ''.$this->stringsEscaper->escape($cellValueLine).'';
- }
-
- $data .= '';
- } elseif ($cell->isBoolean()) {
- $value = $cell->getValue() ? 'true' : 'false'; // boolean-value spec: http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#datatype-boolean
- $data .= ' office:value-type="boolean" calcext:value-type="boolean" office:boolean-value="'.$value.'">';
- $data .= ''.$cell->getValue().'';
- $data .= '';
- } elseif ($cell->isNumeric()) {
- $cellValue = $this->stringHelper->formatNumericValue($cell->getValue());
- $data .= ' office:value-type="float" calcext:value-type="float" office:value="'.$cellValue.'">';
- $data .= ''.$cellValue.'';
- $data .= '';
- } elseif ($cell->isDate()) {
- $value = $cell->getValue();
- if ($value instanceof \DateTimeInterface) {
- $datevalue = substr((new \DateTimeImmutable('@'.$value->getTimestamp()))->format(\DateTimeInterface::W3C), 0, -6);
- $data .= ' office:value-type="date" calcext:value-type="date" office:date-value="'.$datevalue.'Z">';
- $data .= ''.$datevalue.'Z';
- } elseif ($value instanceof \DateInterval) {
- // workaround for missing DateInterval::format('c'), see https://stackoverflow.com/a/61088115/53538
- static $f = ['M0S', 'H0M', 'DT0H', 'M0D', 'Y0M', 'P0Y', 'Y0M', 'P0M'];
- static $r = ['M', 'H', 'DT', 'M', 'Y0M', 'P', 'Y', 'P'];
- $value = rtrim(str_replace($f, $r, $value->format('P%yY%mM%dDT%hH%iM%sS')), 'PT') ?: 'PT0S';
- $data .= ' office:value-type="time" office:time-value="'.$value.'">';
- $data .= ''.$value.'';
- } else {
- throw new InvalidArgumentException('Trying to add a date value with an unsupported type: '.\gettype($cell->getValue()));
- }
- $data .= '';
- } elseif ($cell->isError() && \is_string($cell->getValueEvenIfError())) {
- // only writes the error value if it's a string
- $data .= ' office:value-type="string" calcext:value-type="error" office:value="">';
- $data .= ''.$cell->getValueEvenIfError().'';
- $data .= '';
- } elseif ($cell->isEmpty()) {
- $data .= '/>';
- } else {
- throw new InvalidArgumentException('Trying to add a value with an unsupported type: '.\gettype($cell->getValue()));
- }
-
- return $data;
- }
-}
diff --git a/upstream-3.x/src/Writer/ODS/Writer.php b/upstream-3.x/src/Writer/ODS/Writer.php
deleted file mode 100644
index 5f510e6..0000000
--- a/upstream-3.x/src/Writer/ODS/Writer.php
+++ /dev/null
@@ -1,34 +0,0 @@
-throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
-
- $this->optionsManager->setOption(Options::TEMP_FOLDER, $tempFolder);
-
- return $this;
- }
-}
diff --git a/upstream-3.x/src/Writer/WriterAbstract.php b/upstream-3.x/src/Writer/WriterAbstract.php
deleted file mode 100644
index a2a5e37..0000000
--- a/upstream-3.x/src/Writer/WriterAbstract.php
+++ /dev/null
@@ -1,270 +0,0 @@
-optionsManager = $optionsManager;
- $this->globalFunctionsHelper = $globalFunctionsHelper;
- $this->helperFactory = $helperFactory;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setDefaultRowStyle(Style $defaultStyle)
- {
- $this->optionsManager->setOption(Options::DEFAULT_ROW_STYLE, $defaultStyle);
-
- return $this;
- }
-
- public function writeToStream($filePointer)
- {
- $this->outputFilePath = null;
-
- $this->filePointer = $filePointer;
- $this->dontCloseFilePointer = true;
- $this->throwIfFilePointerIsNotAvailable();
-
- $this->openWriter();
- $this->isWriterOpened = true;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function openToFile($outputFilePath)
- {
- $this->outputFilePath = $outputFilePath;
-
- $this->filePointer = $this->globalFunctionsHelper->fopen($this->outputFilePath, 'w');
- $this->throwIfFilePointerIsNotAvailable();
-
- $this->openWriter();
- $this->isWriterOpened = true;
-
- return $this;
- }
-
- /**
- * @codeCoverageIgnore
- * {@inheritdoc}
- */
- public function openToBrowser($outputFileName)
- {
- $this->outputFilePath = $this->globalFunctionsHelper->basename($outputFileName);
-
- $this->filePointer = $this->globalFunctionsHelper->fopen('php://output', 'w');
- $this->throwIfFilePointerIsNotAvailable();
-
- // Clear any previous output (otherwise the generated file will be corrupted)
- // @see https://github.com/box/spout/issues/241
- $this->globalFunctionsHelper->ob_end_clean();
-
- /*
- * Set headers
- *
- * For newer browsers such as Firefox, Chrome, Opera, Safari, etc., they all support and use `filename*`
- * specified by the new standard, even if they do not automatically decode filename; it does not matter;
- * and for older versions of Internet Explorer, they are not recognized `filename*`, will automatically
- * ignore it and use the old `filename` (the only minor flaw is that there must be an English suffix name).
- * In this way, the multi-browser multi-language compatibility problem is perfectly solved, which does not
- * require UA judgment and is more in line with the standard.
- *
- * @see https://github.com/box/spout/issues/745
- * @see https://tools.ietf.org/html/rfc6266
- * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
- */
- $this->globalFunctionsHelper->header('Content-Type: '.static::$headerContentType);
- $this->globalFunctionsHelper->header(
- 'Content-Disposition: attachment; '.
- 'filename="'.rawurlencode($this->outputFilePath).'"; '.
- 'filename*=UTF-8\'\''.rawurlencode($this->outputFilePath)
- );
-
- /*
- * When forcing the download of a file over SSL,IE8 and lower browsers fail
- * if the Cache-Control and Pragma headers are not set.
- *
- * @see http://support.microsoft.com/KB/323308
- * @see https://github.com/liuggio/ExcelBundle/issues/45
- */
- $this->globalFunctionsHelper->header('Cache-Control: max-age=0');
- $this->globalFunctionsHelper->header('Pragma: public');
-
- $this->openWriter();
- $this->isWriterOpened = true;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addRow(Row $row)
- {
- if ($this->isWriterOpened) {
- try {
- $this->addRowToWriter($row);
- } catch (SpoutException $e) {
- // if an exception occurs while writing data,
- // close the writer and remove all files created so far.
- $this->closeAndAttemptToCleanupAllFiles();
-
- // re-throw the exception to alert developers of the error
- throw $e;
- }
- } else {
- throw new WriterNotOpenedException('The writer needs to be opened before adding row.');
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function addRows(array $rows)
- {
- foreach ($rows as $row) {
- if (!$row instanceof Row) {
- $this->closeAndAttemptToCleanupAllFiles();
-
- throw new InvalidArgumentException('The input should be an array of Row');
- }
-
- $this->addRow($row);
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function close()
- {
- if (!$this->isWriterOpened) {
- return;
- }
-
- $this->closeWriter();
-
- if (!$this->dontCloseFilePointer && \is_resource($this->filePointer)) {
- $this->globalFunctionsHelper->fclose($this->filePointer);
- }
-
- $this->isWriterOpened = false;
- }
-
- /**
- * Opens the streamer and makes it ready to accept data.
- *
- * @throws IOException If the writer cannot be opened
- */
- abstract protected function openWriter();
-
- /**
- * Adds a row to the currently opened writer.
- *
- * @param Row $row The row containing cells and styles
- *
- * @throws WriterNotOpenedException If the workbook is not created yet
- * @throws IOException If unable to write data
- */
- abstract protected function addRowToWriter(Row $row);
-
- /**
- * Closes the streamer, preventing any additional writing.
- */
- abstract protected function closeWriter();
-
- /**
- * Checks if the pointer to the file/stream to write to is available.
- * Will throw an exception if not available.
- *
- * @throws IOException If the pointer is not available
- */
- protected function throwIfFilePointerIsNotAvailable()
- {
- if (!\is_resource($this->filePointer)) {
- throw new IOException('File pointer has not be opened');
- }
- }
-
- /**
- * Checks if the writer has already been opened, since some actions must be done before it gets opened.
- * Throws an exception if already opened.
- *
- * @param string $message Error message
- *
- * @throws WriterAlreadyOpenedException if the writer was already opened and must not be
- */
- protected function throwIfWriterAlreadyOpened($message)
- {
- if ($this->isWriterOpened) {
- throw new WriterAlreadyOpenedException($message);
- }
- }
-
- /**
- * Closes the writer and attempts to cleanup all files that were
- * created during the writing process (temp files & final file).
- */
- private function closeAndAttemptToCleanupAllFiles()
- {
- // close the writer, which should remove all temp files
- $this->close();
-
- // remove output file if it was created
- if ($this->globalFunctionsHelper->file_exists($this->outputFilePath)) {
- $outputFolderPath = \dirname($this->outputFilePath);
- $fileSystemHelper = $this->helperFactory->createFileSystemHelper($outputFolderPath);
- $fileSystemHelper->deleteFile($this->outputFilePath);
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/WriterInterface.php b/upstream-3.x/src/Writer/WriterInterface.php
deleted file mode 100644
index 71a298e..0000000
--- a/upstream-3.x/src/Writer/WriterInterface.php
+++ /dev/null
@@ -1,77 +0,0 @@
-managerFactory = $managerFactory;
- }
-
- /**
- * Sets whether new sheets should be automatically created when the max rows limit per sheet is reached.
- * This must be set before opening the writer.
- *
- * @param bool $shouldCreateNewSheetsAutomatically Whether new sheets should be automatically created when the max rows limit per sheet is reached
- *
- * @throws WriterAlreadyOpenedException If the writer was already opened
- *
- * @return WriterMultiSheetsAbstract
- */
- public function setShouldCreateNewSheetsAutomatically($shouldCreateNewSheetsAutomatically)
- {
- $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
-
- $this->optionsManager->setOption(
- Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
- $shouldCreateNewSheetsAutomatically
- );
-
- return $this;
- }
-
- /**
- * Returns all the workbook's sheets.
- *
- * @throws WriterNotOpenedException If the writer has not been opened yet
- *
- * @return Sheet[] All the workbook's sheets
- */
- public function getSheets()
- {
- $this->throwIfWorkbookIsNotAvailable();
-
- $externalSheets = [];
- $worksheets = $this->workbookManager->getWorksheets();
-
- foreach ($worksheets as $worksheet) {
- $externalSheets[] = $worksheet->getExternalSheet();
- }
-
- return $externalSheets;
- }
-
- /**
- * Creates a new sheet and make it the current sheet. The data will now be written to this sheet.
- *
- * @throws IOException
- * @throws WriterNotOpenedException If the writer has not been opened yet
- *
- * @return Sheet The created sheet
- */
- public function addNewSheetAndMakeItCurrent()
- {
- $this->throwIfWorkbookIsNotAvailable();
- $worksheet = $this->workbookManager->addNewSheetAndMakeItCurrent();
-
- return $worksheet->getExternalSheet();
- }
-
- /**
- * Returns the current sheet.
- *
- * @throws WriterNotOpenedException If the writer has not been opened yet
- *
- * @return Sheet The current sheet
- */
- public function getCurrentSheet()
- {
- $this->throwIfWorkbookIsNotAvailable();
-
- return $this->workbookManager->getCurrentWorksheet()->getExternalSheet();
- }
-
- /**
- * Sets the given sheet as the current one. New data will be written to this sheet.
- * The writing will resume where it stopped (i.e. data won't be truncated).
- *
- * @param Sheet $sheet The sheet to set as current
- *
- * @throws SheetNotFoundException If the given sheet does not exist in the workbook
- * @throws WriterNotOpenedException If the writer has not been opened yet
- */
- public function setCurrentSheet($sheet)
- {
- $this->throwIfWorkbookIsNotAvailable();
- $this->workbookManager->setCurrentSheet($sheet);
- }
-
- /**
- * @throws WriterAlreadyOpenedException
- */
- public function setDefaultColumnWidth(float $width)
- {
- $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
- $this->optionsManager->setOption(
- Options::DEFAULT_COLUMN_WIDTH,
- $width
- );
- }
-
- /**
- * @throws WriterAlreadyOpenedException
- */
- public function setDefaultRowHeight(float $height)
- {
- $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
- $this->optionsManager->setOption(
- Options::DEFAULT_ROW_HEIGHT,
- $height
- );
- }
-
- /**
- * @param null|float $width
- * @param int ...$columns One or more columns with this width
- *
- * @throws WriterNotOpenedException
- */
- public function setColumnWidth($width, ...$columns)
- {
- $this->throwIfWorkbookIsNotAvailable();
- $this->workbookManager->setColumnWidth($width, ...$columns);
- }
-
- /**
- * @param float $width The width to set
- * @param int $start First column index of the range
- * @param int $end Last column index of the range
- *
- * @throws WriterNotOpenedException
- */
- public function setColumnWidthForRange(float $width, int $start, int $end)
- {
- $this->throwIfWorkbookIsNotAvailable();
- $this->workbookManager->setColumnWidthForRange($width, $start, $end);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function openWriter()
- {
- if (null === $this->workbookManager) {
- $this->workbookManager = $this->managerFactory->createWorkbookManager($this->optionsManager);
- $this->workbookManager->addNewSheetAndMakeItCurrent();
- }
- }
-
- /**
- * Checks if the workbook has been created. Throws an exception if not created yet.
- *
- * @throws WriterNotOpenedException If the workbook is not created yet
- */
- protected function throwIfWorkbookIsNotAvailable()
- {
- if (!$this->workbookManager->getWorkbook()) {
- throw new WriterNotOpenedException('The writer must be opened before performing this action.');
- }
- }
-
- /**
- * {@inheritdoc}
- *
- * @throws Exception\WriterException
- */
- protected function addRowToWriter(Row $row)
- {
- $this->throwIfWorkbookIsNotAvailable();
- $this->workbookManager->addRowToCurrentWorksheet($row);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function closeWriter()
- {
- if (null !== $this->workbookManager) {
- $this->workbookManager->close($this->filePointer);
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Creator/HelperFactory.php b/upstream-3.x/src/Writer/XLSX/Creator/HelperFactory.php
deleted file mode 100644
index 38a7f0d..0000000
--- a/upstream-3.x/src/Writer/XLSX/Creator/HelperFactory.php
+++ /dev/null
@@ -1,53 +0,0 @@
-getOption(Options::TEMP_FOLDER);
- $zipHelper = $this->createZipHelper($entityFactory);
- $escaper = $this->createStringsEscaper();
-
- return new FileSystemHelper($tempFolder, $zipHelper, $escaper);
- }
-
- /**
- * @return Escaper\XLSX
- */
- public function createStringsEscaper()
- {
- return new Escaper\XLSX();
- }
-
- /**
- * @return StringHelper
- */
- public function createStringHelper()
- {
- return new StringHelper();
- }
-
- /**
- * @return ZipHelper
- */
- private function createZipHelper(InternalEntityFactory $entityFactory)
- {
- return new ZipHelper($entityFactory);
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Creator/ManagerFactory.php b/upstream-3.x/src/Writer/XLSX/Creator/ManagerFactory.php
deleted file mode 100644
index 47e60ce..0000000
--- a/upstream-3.x/src/Writer/XLSX/Creator/ManagerFactory.php
+++ /dev/null
@@ -1,145 +0,0 @@
-entityFactory = $entityFactory;
- $this->helperFactory = $helperFactory;
- }
-
- /**
- * @return WorkbookManager
- */
- public function createWorkbookManager(OptionsManagerInterface $optionsManager)
- {
- $workbook = $this->entityFactory->createWorkbook();
-
- $fileSystemHelper = $this->helperFactory->createSpecificFileSystemHelper($optionsManager, $this->entityFactory);
- $fileSystemHelper->createBaseFilesAndFolders();
-
- $xlFolder = $fileSystemHelper->getXlFolder();
- $sharedStringsManager = $this->createSharedStringsManager($xlFolder);
-
- $styleMerger = $this->createStyleMerger();
- $styleManager = $this->createStyleManager($optionsManager);
- $worksheetManager = $this->createWorksheetManager($optionsManager, $styleManager, $styleMerger, $sharedStringsManager);
-
- return new WorkbookManager(
- $workbook,
- $optionsManager,
- $worksheetManager,
- $styleManager,
- $styleMerger,
- $fileSystemHelper,
- $this->entityFactory,
- $this
- );
- }
-
- /**
- * @return SheetManager
- */
- public function createSheetManager()
- {
- $stringHelper = $this->helperFactory->createStringHelper();
-
- return new SheetManager($stringHelper);
- }
-
- /**
- * @return RowManager
- */
- public function createRowManager()
- {
- return new RowManager();
- }
-
- /**
- * @return WorksheetManager
- */
- private function createWorksheetManager(
- OptionsManagerInterface $optionsManager,
- StyleManager $styleManager,
- StyleMerger $styleMerger,
- SharedStringsManager $sharedStringsManager
- ) {
- $rowManager = $this->createRowManager();
- $stringsEscaper = $this->helperFactory->createStringsEscaper();
- $stringsHelper = $this->helperFactory->createStringHelper();
-
- return new WorksheetManager(
- $optionsManager,
- $rowManager,
- $styleManager,
- $styleMerger,
- $sharedStringsManager,
- $stringsEscaper,
- $stringsHelper
- );
- }
-
- /**
- * @return StyleManager
- */
- private function createStyleManager(OptionsManagerInterface $optionsManager)
- {
- $styleRegistry = $this->createStyleRegistry($optionsManager);
-
- return new StyleManager($styleRegistry);
- }
-
- /**
- * @return StyleRegistry
- */
- private function createStyleRegistry(OptionsManagerInterface $optionsManager)
- {
- $defaultRowStyle = $optionsManager->getOption(Options::DEFAULT_ROW_STYLE);
-
- return new StyleRegistry($defaultRowStyle);
- }
-
- /**
- * @return StyleMerger
- */
- private function createStyleMerger()
- {
- return new StyleMerger();
- }
-
- /**
- * @param string $xlFolder Path to the "xl" folder
- *
- * @return SharedStringsManager
- */
- private function createSharedStringsManager($xlFolder)
- {
- $stringEscaper = $this->helperFactory->createStringsEscaper();
-
- return new SharedStringsManager($xlFolder, $stringEscaper);
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Entity/SheetView.php b/upstream-3.x/src/Writer/XLSX/Entity/SheetView.php
deleted file mode 100644
index 7141615..0000000
--- a/upstream-3.x/src/Writer/XLSX/Entity/SheetView.php
+++ /dev/null
@@ -1,289 +0,0 @@
-showFormulas = $showFormulas;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setShowGridLines(bool $showGridLines): self
- {
- $this->showGridLines = $showGridLines;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setShowRowColHeaders(bool $showRowColHeaders): self
- {
- $this->showRowColHeaders = $showRowColHeaders;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setShowZeroes(bool $showZeroes): self
- {
- $this->showZeroes = $showZeroes;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setRightToLeft(bool $rightToLeft): self
- {
- $this->rightToLeft = $rightToLeft;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setTabSelected(bool $tabSelected): self
- {
- $this->tabSelected = $tabSelected;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setShowOutlineSymbols(bool $showOutlineSymbols): self
- {
- $this->showOutlineSymbols = $showOutlineSymbols;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setDefaultGridColor(bool $defaultGridColor): self
- {
- $this->defaultGridColor = $defaultGridColor;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setView(string $view): self
- {
- $this->view = $view;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setTopLeftCell(string $topLeftCell): self
- {
- $this->topLeftCell = $topLeftCell;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setColorId(int $colorId): self
- {
- $this->colorId = $colorId;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setZoomScale(int $zoomScale): self
- {
- $this->zoomScale = $zoomScale;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setZoomScaleNormal(int $zoomScaleNormal): self
- {
- $this->zoomScaleNormal = $zoomScaleNormal;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setZoomScalePageLayoutView(int $zoomScalePageLayoutView): self
- {
- $this->zoomScalePageLayoutView = $zoomScalePageLayoutView;
-
- return $this;
- }
-
- /**
- * @return $this
- */
- public function setWorkbookViewId(int $workbookViewId): self
- {
- $this->workbookViewId = $workbookViewId;
-
- return $this;
- }
-
- /**
- * @param int $freezeRow Set to 2 to fix the first row
- *
- * @return $this
- */
- public function setFreezeRow(int $freezeRow): self
- {
- if ($freezeRow < 1) {
- throw new InvalidArgumentException('Freeze row must be a positive integer', 1589543073);
- }
-
- $this->freezeRow = $freezeRow;
-
- return $this;
- }
-
- /**
- * @param string $freezeColumn Set to B to fix the first column
- *
- * @return $this
- */
- public function setFreezeColumn(string $freezeColumn): self
- {
- $this->freezeColumn = strtoupper($freezeColumn);
-
- return $this;
- }
-
- public function getXml(): string
- {
- return 'getSheetViewAttributes().'>'.
- $this->getFreezeCellPaneXml().
- '';
- }
-
- protected function getSheetViewAttributes(): string
- {
- // Get class properties
- $propertyValues = get_object_vars($this);
- unset($propertyValues['freezeRow'], $propertyValues['freezeColumn']);
-
- return $this->generateAttributes($propertyValues);
- }
-
- protected function getFreezeCellPaneXml(): string
- {
- if ($this->freezeRow < 2 && 'A' === $this->freezeColumn) {
- return '';
- }
-
- $columnIndex = CellHelper::getColumnIndexFromCellIndex($this->freezeColumn.'1');
-
- return 'generateAttributes([
- 'xSplit' => $columnIndex,
- 'ySplit' => $this->freezeRow - 1,
- 'topLeftCell' => $this->freezeColumn.$this->freezeRow,
- 'activePane' => 'bottomRight',
- 'state' => 'frozen',
- ]).'/>';
- }
-
- /**
- * @param array $data with key containing the attribute name and value containing the attribute value
- */
- protected function generateAttributes(array $data): string
- {
- // Create attribute for each key
- $attributes = array_map(function ($key, $value) {
- if (\is_bool($value)) {
- $value = $value ? 'true' : 'false';
- }
-
- return $key.'="'.$value.'"';
- }, array_keys($data), $data);
-
- // Append all attributes
- return ' '.implode(' ', $attributes);
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Helper/BorderHelper.php b/upstream-3.x/src/Writer/XLSX/Helper/BorderHelper.php
deleted file mode 100644
index 1df43b9..0000000
--- a/upstream-3.x/src/Writer/XLSX/Helper/BorderHelper.php
+++ /dev/null
@@ -1,66 +0,0 @@
- [
- Border::WIDTH_THIN => 'thin',
- Border::WIDTH_MEDIUM => 'medium',
- Border::WIDTH_THICK => 'thick',
- ],
- Border::STYLE_DOTTED => [
- Border::WIDTH_THIN => 'dotted',
- Border::WIDTH_MEDIUM => 'dotted',
- Border::WIDTH_THICK => 'dotted',
- ],
- Border::STYLE_DASHED => [
- Border::WIDTH_THIN => 'dashed',
- Border::WIDTH_MEDIUM => 'mediumDashed',
- Border::WIDTH_THICK => 'mediumDashed',
- ],
- Border::STYLE_DOUBLE => [
- Border::WIDTH_THIN => 'double',
- Border::WIDTH_MEDIUM => 'double',
- Border::WIDTH_THICK => 'double',
- ],
- Border::STYLE_NONE => [
- Border::WIDTH_THIN => 'none',
- Border::WIDTH_MEDIUM => 'none',
- Border::WIDTH_THICK => 'none',
- ],
- ];
-
- /**
- * @return string
- */
- public static function serializeBorderPart(BorderPart $borderPart)
- {
- $borderStyle = self::getBorderStyle($borderPart);
-
- $colorEl = $borderPart->getColor() ? sprintf('', $borderPart->getColor()) : '';
- $partEl = sprintf(
- '<%s style="%s">%s%s>',
- $borderPart->getName(),
- $borderStyle,
- $colorEl,
- $borderPart->getName()
- );
-
- return $partEl.PHP_EOL;
- }
-
- /**
- * Get the style definition from the style map.
- *
- * @return string
- */
- protected static function getBorderStyle(BorderPart $borderPart)
- {
- return self::$xlsxStyleMap[$borderPart->getStyle()][$borderPart->getWidth()];
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Helper/DateHelper.php b/upstream-3.x/src/Writer/XLSX/Helper/DateHelper.php
deleted file mode 100644
index fb72df5..0000000
--- a/upstream-3.x/src/Writer/XLSX/Helper/DateHelper.php
+++ /dev/null
@@ -1,45 +0,0 @@
-format('Y');
- $month = (int) $dateTime->format('m');
- $day = (int) $dateTime->format('d');
- $hours = (int) $dateTime->format('H');
- $minutes = (int) $dateTime->format('i');
- $seconds = (int) $dateTime->format('s');
- // Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
- // This affects every date following 28th February 1900
- $excel1900isLeapYear = true;
- if ((1900 === $year) && ($month <= 2)) {
- $excel1900isLeapYear = false;
- }
- $myexcelBaseDate = 2415020;
-
- // Julian base date Adjustment
- if ($month > 2) {
- $month -= 3;
- } else {
- $month += 9;
- --$year;
- }
-
- // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0)
- $century = (int) substr((string) $year, 0, 2);
- $decade = (int) substr((string) $year, 2, 2);
- $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myexcelBaseDate + $excel1900isLeapYear;
-
- $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400;
-
- return (float) $excelDate + $excelTime;
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Helper/FileSystemHelper.php b/upstream-3.x/src/Writer/XLSX/Helper/FileSystemHelper.php
deleted file mode 100644
index 12e4d79..0000000
--- a/upstream-3.x/src/Writer/XLSX/Helper/FileSystemHelper.php
+++ /dev/null
@@ -1,403 +0,0 @@
-zipHelper = $zipHelper;
- $this->escaper = $escaper;
- }
-
- /**
- * @return string
- */
- public function getRootFolder()
- {
- return $this->rootFolder;
- }
-
- /**
- * @return string
- */
- public function getXlFolder()
- {
- return $this->xlFolder;
- }
-
- /**
- * @return string
- */
- public function getXlWorksheetsFolder()
- {
- return $this->xlWorksheetsFolder;
- }
-
- /**
- * Creates all the folders needed to create a XLSX file, as well as the files that won't change.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create at least one of the base folders
- */
- public function createBaseFilesAndFolders()
- {
- $this
- ->createRootFolder()
- ->createRelsFolderAndFile()
- ->createDocPropsFolderAndFiles()
- ->createXlFolderAndSubFolders()
- ;
- }
-
- /**
- * Creates the "[Content_Types].xml" file under the root folder.
- *
- * @param Worksheet[] $worksheets
- *
- * @return FileSystemHelper
- */
- public function createContentTypesFile($worksheets)
- {
- $contentTypesXmlFileContents = <<<'EOD'
-
-
-
-
-
- EOD;
-
- /** @var Worksheet $worksheet */
- foreach ($worksheets as $worksheet) {
- $contentTypesXmlFileContents .= '';
- }
-
- $contentTypesXmlFileContents .= <<<'EOD'
-
-
-
-
-
- EOD;
-
- $this->createFileWithContents($this->rootFolder, self::CONTENT_TYPES_XML_FILE_NAME, $contentTypesXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "workbook.xml" file under the "xl" folder.
- *
- * @param Worksheet[] $worksheets
- *
- * @return FileSystemHelper
- */
- public function createWorkbookFile($worksheets)
- {
- $workbookXmlFileContents = <<<'EOD'
-
-
-
- EOD;
-
- /** @var Worksheet $worksheet */
- foreach ($worksheets as $worksheet) {
- $worksheetName = $worksheet->getExternalSheet()->getName();
- $worksheetVisibility = $worksheet->getExternalSheet()->isVisible() ? 'visible' : 'hidden';
- $worksheetId = $worksheet->getId();
- $workbookXmlFileContents .= '';
- }
-
- $workbookXmlFileContents .= <<<'EOD'
-
-
- EOD;
-
- $this->createFileWithContents($this->xlFolder, self::WORKBOOK_XML_FILE_NAME, $workbookXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "workbook.xml.res" file under the "xl/_res" folder.
- *
- * @param Worksheet[] $worksheets
- *
- * @return FileSystemHelper
- */
- public function createWorkbookRelsFile($worksheets)
- {
- $workbookRelsXmlFileContents = <<<'EOD'
-
-
-
-
- EOD;
-
- /** @var Worksheet $worksheet */
- foreach ($worksheets as $worksheet) {
- $worksheetId = $worksheet->getId();
- $workbookRelsXmlFileContents .= '';
- }
-
- $workbookRelsXmlFileContents .= '';
-
- $this->createFileWithContents($this->xlRelsFolder, self::WORKBOOK_RELS_XML_FILE_NAME, $workbookRelsXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "styles.xml" file under the "xl" folder.
- *
- * @param StyleManager $styleManager
- *
- * @return FileSystemHelper
- */
- public function createStylesFile($styleManager)
- {
- $stylesXmlFileContents = $styleManager->getStylesXMLFileContent();
- $this->createFileWithContents($this->xlFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents);
-
- return $this;
- }
-
- /**
- * Zips the root folder and streams the contents of the zip into the given stream.
- *
- * @param resource $streamPointer Pointer to the stream to copy the zip
- */
- public function zipRootFolderAndCopyToStream($streamPointer)
- {
- $zip = $this->zipHelper->createZip($this->rootFolder);
-
- $zipFilePath = $this->zipHelper->getZipFilePath($zip);
-
- // In order to have the file's mime type detected properly, files need to be added
- // to the zip file in a particular order.
- // "[Content_Types].xml" then at least 2 files located in "xl" folder should be zipped first.
- $this->zipHelper->addFileToArchive($zip, $this->rootFolder, self::CONTENT_TYPES_XML_FILE_NAME);
- $this->zipHelper->addFileToArchive($zip, $this->rootFolder, self::XL_FOLDER_NAME.'/'.self::WORKBOOK_XML_FILE_NAME);
- $this->zipHelper->addFileToArchive($zip, $this->rootFolder, self::XL_FOLDER_NAME.'/'.self::STYLES_XML_FILE_NAME);
-
- $this->zipHelper->addFolderToArchive($zip, $this->rootFolder, ZipHelper::EXISTING_FILES_SKIP);
- $this->zipHelper->closeArchiveAndCopyToStream($zip, $streamPointer);
-
- // once the zip is copied, remove it
- $this->deleteFile($zipFilePath);
- }
-
- /**
- * Creates the folder that will be used as root.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder
- *
- * @return FileSystemHelper
- */
- private function createRootFolder()
- {
- $this->rootFolder = $this->createFolder($this->baseFolderRealPath, uniqid('xlsx', true));
-
- return $this;
- }
-
- /**
- * Creates the "_rels" folder under the root folder as well as the ".rels" file in it.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder or the ".rels" file
- *
- * @return FileSystemHelper
- */
- private function createRelsFolderAndFile()
- {
- $this->relsFolder = $this->createFolder($this->rootFolder, self::RELS_FOLDER_NAME);
-
- $this->createRelsFile();
-
- return $this;
- }
-
- /**
- * Creates the ".rels" file under the "_rels" folder (under root).
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file
- *
- * @return FileSystemHelper
- */
- private function createRelsFile()
- {
- $relsFileContents = <<<'EOD'
-
-
-
-
-
-
- EOD;
-
- $this->createFileWithContents($this->relsFolder, self::RELS_FILE_NAME, $relsFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "docProps" folder under the root folder as well as the "app.xml" and "core.xml" files in it.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder or one of the files
- *
- * @return FileSystemHelper
- */
- private function createDocPropsFolderAndFiles()
- {
- $this->docPropsFolder = $this->createFolder($this->rootFolder, self::DOC_PROPS_FOLDER_NAME);
-
- $this->createAppXmlFile();
- $this->createCoreXmlFile();
-
- return $this;
- }
-
- /**
- * Creates the "app.xml" file under the "docProps" folder.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file
- *
- * @return FileSystemHelper
- */
- private function createAppXmlFile()
- {
- $appName = self::APP_NAME;
- $appXmlFileContents = <<
-
- {$appName}
- 0
-
- EOD;
-
- $this->createFileWithContents($this->docPropsFolder, self::APP_XML_FILE_NAME, $appXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "core.xml" file under the "docProps" folder.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the file
- *
- * @return FileSystemHelper
- */
- private function createCoreXmlFile()
- {
- $createdDate = (new \DateTime())->format(\DateTime::W3C);
- $coreXmlFileContents = <<
-
- {$createdDate}
- {$createdDate}
- 0
-
- EOD;
-
- $this->createFileWithContents($this->docPropsFolder, self::CORE_XML_FILE_NAME, $coreXmlFileContents);
-
- return $this;
- }
-
- /**
- * Creates the "xl" folder under the root folder as well as its subfolders.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create at least one of the folders
- *
- * @return FileSystemHelper
- */
- private function createXlFolderAndSubFolders()
- {
- $this->xlFolder = $this->createFolder($this->rootFolder, self::XL_FOLDER_NAME);
- $this->createXlRelsFolder();
- $this->createXlWorksheetsFolder();
-
- return $this;
- }
-
- /**
- * Creates the "_rels" folder under the "xl" folder.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder
- *
- * @return FileSystemHelper
- */
- private function createXlRelsFolder()
- {
- $this->xlRelsFolder = $this->createFolder($this->xlFolder, self::RELS_FOLDER_NAME);
-
- return $this;
- }
-
- /**
- * Creates the "worksheets" folder under the "xl" folder.
- *
- * @throws \OpenSpout\Common\Exception\IOException If unable to create the folder
- *
- * @return FileSystemHelper
- */
- private function createXlWorksheetsFolder()
- {
- $this->xlWorksheetsFolder = $this->createFolder($this->xlFolder, self::WORKSHEETS_FOLDER_NAME);
-
- return $this;
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Manager/OptionsManager.php b/upstream-3.x/src/Writer/XLSX/Manager/OptionsManager.php
deleted file mode 100644
index b7e7eae..0000000
--- a/upstream-3.x/src/Writer/XLSX/Manager/OptionsManager.php
+++ /dev/null
@@ -1,64 +0,0 @@
-styleBuilder = $styleBuilder;
- parent::__construct();
- }
-
- /**
- * {@inheritdoc}
- */
- protected function getSupportedOptions()
- {
- return [
- Options::TEMP_FOLDER,
- Options::DEFAULT_ROW_STYLE,
- Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY,
- Options::SHOULD_USE_INLINE_STRINGS,
- Options::DEFAULT_COLUMN_WIDTH,
- Options::DEFAULT_ROW_HEIGHT,
- Options::COLUMN_WIDTHS,
- Options::MERGE_CELLS,
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- protected function setDefaultOptions()
- {
- $defaultRowStyle = $this->styleBuilder
- ->setFontSize(self::DEFAULT_FONT_SIZE)
- ->setFontName(self::DEFAULT_FONT_NAME)
- ->build()
- ;
-
- $this->setOption(Options::TEMP_FOLDER, sys_get_temp_dir());
- $this->setOption(Options::DEFAULT_ROW_STYLE, $defaultRowStyle);
- $this->setOption(Options::SHOULD_CREATE_NEW_SHEETS_AUTOMATICALLY, true);
- $this->setOption(Options::SHOULD_USE_INLINE_STRINGS, true);
- $this->setOption(Options::MERGE_CELLS, []);
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Manager/SharedStringsManager.php b/upstream-3.x/src/Writer/XLSX/Manager/SharedStringsManager.php
deleted file mode 100644
index 9739556..0000000
--- a/upstream-3.x/src/Writer/XLSX/Manager/SharedStringsManager.php
+++ /dev/null
@@ -1,103 +0,0 @@
-
- sharedStringsFilePointer = fopen($sharedStringsFilePath, 'w');
-
- $this->throwIfSharedStringsFilePointerIsNotAvailable();
-
- // the headers is split into different parts so that we can fseek and put in the correct count and uniqueCount later
- $header = self::SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER.' '.self::DEFAULT_STRINGS_COUNT_PART.'>';
- fwrite($this->sharedStringsFilePointer, $header);
-
- $this->stringsEscaper = $stringsEscaper;
- }
-
- /**
- * Writes the given string into the sharedStrings.xml file.
- * Starting and ending whitespaces are preserved.
- *
- * @param string $string
- *
- * @return int ID of the written shared string
- */
- public function writeString($string)
- {
- fwrite($this->sharedStringsFilePointer, ''.$this->stringsEscaper->escape($string).'');
- ++$this->numSharedStrings;
-
- // Shared string ID is zero-based
- return $this->numSharedStrings - 1;
- }
-
- /**
- * Finishes writing the data in the sharedStrings.xml file and closes the file.
- */
- public function close()
- {
- if (!\is_resource($this->sharedStringsFilePointer)) {
- return;
- }
-
- fwrite($this->sharedStringsFilePointer, '');
-
- // Replace the default strings count with the actual number of shared strings in the file header
- $firstPartHeaderLength = \strlen(self::SHARED_STRINGS_XML_FILE_FIRST_PART_HEADER);
- $defaultStringsCountPartLength = \strlen(self::DEFAULT_STRINGS_COUNT_PART);
-
- // Adding 1 to take into account the space between the last xml attribute and "count"
- fseek($this->sharedStringsFilePointer, $firstPartHeaderLength + 1);
- fwrite($this->sharedStringsFilePointer, sprintf("%-{$defaultStringsCountPartLength}s", 'count="'.$this->numSharedStrings.'" uniqueCount="'.$this->numSharedStrings.'"'));
-
- fclose($this->sharedStringsFilePointer);
- }
-
- /**
- * Checks if the book has been created. Throws an exception if not created yet.
- *
- * @throws \OpenSpout\Common\Exception\IOException If the sheet data file cannot be opened for writing
- */
- protected function throwIfSharedStringsFilePointerIsNotAvailable()
- {
- if (!\is_resource($this->sharedStringsFilePointer)) {
- throw new IOException('Unable to open shared strings file for writing.');
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Manager/Style/StyleManager.php b/upstream-3.x/src/Writer/XLSX/Manager/Style/StyleManager.php
deleted file mode 100644
index 5f284b9..0000000
--- a/upstream-3.x/src/Writer/XLSX/Manager/Style/StyleManager.php
+++ /dev/null
@@ -1,342 +0,0 @@
-styleRegistry->getFillIdForStyleId($styleId);
- $hasStyleCustomFill = (null !== $associatedFillId && 0 !== $associatedFillId);
-
- $associatedBorderId = $this->styleRegistry->getBorderIdForStyleId($styleId);
- $hasStyleCustomBorders = (null !== $associatedBorderId && 0 !== $associatedBorderId);
-
- $associatedFormatId = $this->styleRegistry->getFormatIdForStyleId($styleId);
- $hasStyleCustomFormats = (null !== $associatedFormatId && 0 !== $associatedFormatId);
-
- return $hasStyleCustomFill || $hasStyleCustomBorders || $hasStyleCustomFormats;
- }
-
- /**
- * Returns the content of the "styles.xml" file, given a list of styles.
- *
- * @return string
- */
- public function getStylesXMLFileContent()
- {
- $content = <<<'EOD'
-
-
- EOD;
-
- $content .= $this->getFormatsSectionContent();
- $content .= $this->getFontsSectionContent();
- $content .= $this->getFillsSectionContent();
- $content .= $this->getBordersSectionContent();
- $content .= $this->getCellStyleXfsSectionContent();
- $content .= $this->getCellXfsSectionContent();
- $content .= $this->getCellStylesSectionContent();
-
- $content .= <<<'EOD'
-
- EOD;
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getFormatsSectionContent()
- {
- $tags = [];
- $registeredFormats = $this->styleRegistry->getRegisteredFormats();
- foreach ($registeredFormats as $styleId) {
- $numFmtId = $this->styleRegistry->getFormatIdForStyleId($styleId);
-
- //Built-in formats do not need to be declared, skip them
- if ($numFmtId < 164) {
- continue;
- }
-
- /** @var Style $style */
- $style = $this->styleRegistry->getStyleFromStyleId($styleId);
- $format = $style->getFormat();
- $tags[] = '';
- }
- $content = '';
- $content .= implode('', $tags);
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getFontsSectionContent()
- {
- $registeredStyles = $this->styleRegistry->getRegisteredStyles();
-
- $content = '';
-
- /** @var Style $style */
- foreach ($registeredStyles as $style) {
- $content .= '';
-
- $content .= '';
- $content .= '';
- $content .= '';
-
- if ($style->isFontBold()) {
- $content .= '';
- }
- if ($style->isFontItalic()) {
- $content .= '';
- }
- if ($style->isFontUnderline()) {
- $content .= '';
- }
- if ($style->isFontStrikethrough()) {
- $content .= '';
- }
-
- $content .= '';
- }
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getFillsSectionContent()
- {
- $registeredFills = $this->styleRegistry->getRegisteredFills();
-
- // Excel reserves two default fills
- $fillsCount = \count($registeredFills) + 2;
- $content = sprintf('', $fillsCount);
-
- $content .= '';
- $content .= '';
-
- // The other fills are actually registered by setting a background color
- foreach ($registeredFills as $styleId) {
- /** @var Style $style */
- $style = $this->styleRegistry->getStyleFromStyleId($styleId);
-
- $backgroundColor = $style->getBackgroundColor();
- $content .= sprintf(
- '',
- $backgroundColor
- );
- }
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getBordersSectionContent()
- {
- $registeredBorders = $this->styleRegistry->getRegisteredBorders();
-
- // There is one default border with index 0
- $borderCount = \count($registeredBorders) + 1;
-
- $content = '';
-
- // Default border starting at index 0
- $content .= '';
-
- foreach ($registeredBorders as $styleId) {
- /** @var Style $style */
- $style = $this->styleRegistry->getStyleFromStyleId($styleId);
- $border = $style->getBorder();
- $content .= '';
-
- /** @see https://github.com/box/spout/issues/271 */
- $sortOrder = ['left', 'right', 'top', 'bottom'];
-
- foreach ($sortOrder as $partName) {
- if ($border->hasPart($partName)) {
- /** @var BorderPart $part */
- $part = $border->getPart($partName);
- $content .= BorderHelper::serializeBorderPart($part);
- }
- }
-
- $content .= '';
- }
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getCellStyleXfsSectionContent()
- {
- return <<<'EOD'
-
-
-
- EOD;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getCellXfsSectionContent()
- {
- $registeredStyles = $this->styleRegistry->getRegisteredStyles();
-
- $content = '';
-
- foreach ($registeredStyles as $style) {
- $styleId = $style->getId();
- $fillId = $this->getFillIdForStyleId($styleId);
- $borderId = $this->getBorderIdForStyleId($styleId);
- $numFmtId = $this->getFormatIdForStyleId($styleId);
-
- $content .= 'shouldApplyFont()) {
- $content .= ' applyFont="1"';
- }
-
- $content .= sprintf(' applyBorder="%d"', $style->shouldApplyBorder() ? 1 : 0);
-
- if ($style->shouldApplyCellAlignment() || $style->shouldWrapText() || $style->shouldShrinkToFit()) {
- $content .= ' applyAlignment="1">';
- $content .= 'shouldApplyCellAlignment()) {
- $content .= sprintf(' horizontal="%s"', $style->getCellAlignment());
- }
- if ($style->shouldWrapText()) {
- $content .= ' wrapText="1"';
- }
- if ($style->shouldShrinkToFit()) {
- $content .= ' shrinkToFit="true"';
- }
-
- $content .= '/>';
- $content .= '';
- } else {
- $content .= '/>';
- }
- }
-
- $content .= '';
-
- return $content;
- }
-
- /**
- * Returns the content of the "" section.
- *
- * @return string
- */
- protected function getCellStylesSectionContent()
- {
- return <<<'EOD'
-
-
-
- EOD;
- }
-
- /**
- * Returns the fill ID associated to the given style ID.
- * For the default style, we don't a fill.
- *
- * @param int $styleId
- *
- * @return int
- */
- private function getFillIdForStyleId($styleId)
- {
- // For the default style (ID = 0), we don't want to override the fill.
- // Otherwise all cells of the spreadsheet will have a background color.
- $isDefaultStyle = (0 === $styleId);
-
- return $isDefaultStyle ? 0 : ($this->styleRegistry->getFillIdForStyleId($styleId) ?: 0);
- }
-
- /**
- * Returns the fill ID associated to the given style ID.
- * For the default style, we don't a border.
- *
- * @param int $styleId
- *
- * @return int
- */
- private function getBorderIdForStyleId($styleId)
- {
- // For the default style (ID = 0), we don't want to override the border.
- // Otherwise all cells of the spreadsheet will have a border.
- $isDefaultStyle = (0 === $styleId);
-
- return $isDefaultStyle ? 0 : ($this->styleRegistry->getBorderIdForStyleId($styleId) ?: 0);
- }
-
- /**
- * Returns the format ID associated to the given style ID.
- * For the default style use general format.
- *
- * @param int $styleId
- *
- * @return int
- */
- private function getFormatIdForStyleId($styleId)
- {
- // For the default style (ID = 0), we don't want to override the format.
- // Otherwise all cells of the spreadsheet will have a format.
- $isDefaultStyle = (0 === $styleId);
-
- return $isDefaultStyle ? 0 : ($this->styleRegistry->getFormatIdForStyleId($styleId) ?: 0);
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Manager/Style/StyleRegistry.php b/upstream-3.x/src/Writer/XLSX/Manager/Style/StyleRegistry.php
deleted file mode 100644
index 259d4e8..0000000
--- a/upstream-3.x/src/Writer/XLSX/Manager/Style/StyleRegistry.php
+++ /dev/null
@@ -1,276 +0,0 @@
- 0,
- '0' => 1,
- '0.00' => 2,
- '#,##0' => 3,
- '#,##0.00' => 4,
- '$#,##0,\-$#,##0' => 5,
- '$#,##0,[Red]\-$#,##0' => 6,
- '$#,##0.00,\-$#,##0.00' => 7,
- '$#,##0.00,[Red]\-$#,##0.00' => 8,
- '0%' => 9,
- '0.00%' => 10,
- '0.00E+00' => 11,
- '# ?/?' => 12,
- '# ??/??' => 13,
- 'mm-dd-yy' => 14,
- 'd-mmm-yy' => 15,
- 'd-mmm' => 16,
- 'mmm-yy' => 17,
- 'h:mm AM/PM' => 18,
- 'h:mm:ss AM/PM' => 19,
- 'h:mm' => 20,
- 'h:mm:ss' => 21,
- 'm/d/yy h:mm' => 22,
-
- '#,##0 ,(#,##0)' => 37,
- '#,##0 ,[Red](#,##0)' => 38,
- '#,##0.00,(#,##0.00)' => 39,
- '#,##0.00,[Red](#,##0.00)' => 40,
-
- '_("$"* #,##0.00_),_("$"* \(#,##0.00\),_("$"* "-"??_),_(@_)' => 44,
- 'mm:ss' => 45,
- '[h]:mm:ss' => 46,
- 'mm:ss.0' => 47,
-
- '##0.0E+0' => 48,
- '@' => 49,
-
- '[$-404]e/m/d' => 27,
- 'm/d/yy' => 30,
- 't0' => 59,
- 't0.00' => 60,
- 't#,##0' => 61,
- 't#,##0.00' => 62,
- 't0%' => 67,
- 't0.00%' => 68,
- 't# ?/?' => 69,
- 't# ??/??' => 70,
- ];
-
- /**
- * @var array
- */
- protected $registeredFormats = [];
-
- /**
- * @var array [STYLE_ID] => [FORMAT_ID] maps a style to a format declaration
- */
- protected $styleIdToFormatsMappingTable = [];
-
- /**
- * If the numFmtId is lower than 0xA4 (164 in decimal)
- * then it's a built-in number format.
- * Since Excel is the dominant vendor - we play along here.
- *
- * @var int the fill index counter for custom fills
- */
- protected $formatIndex = 164;
-
- /**
- * @var array
- */
- protected $registeredFills = [];
-
- /**
- * @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
- */
- protected $styleIdToFillMappingTable = [];
-
- /**
- * Excel preserves two default fills with index 0 and 1
- * Since Excel is the dominant vendor - we play along here.
- *
- * @var int the fill index counter for custom fills
- */
- protected $fillIndex = 2;
-
- /**
- * @var array
- */
- protected $registeredBorders = [];
-
- /**
- * @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration
- */
- protected $styleIdToBorderMappingTable = [];
-
- /**
- * XLSX specific operations on the registered styles.
- *
- * @return Style
- */
- public function registerStyle(Style $style)
- {
- if ($style->isRegistered()) {
- return $style;
- }
-
- $registeredStyle = parent::registerStyle($style);
- $this->registerFill($registeredStyle);
- $this->registerFormat($registeredStyle);
- $this->registerBorder($registeredStyle);
-
- return $registeredStyle;
- }
-
- /**
- * @param int $styleId
- *
- * @return null|int Format ID associated to the given style ID
- */
- public function getFormatIdForStyleId($styleId)
- {
- return $this->styleIdToFormatsMappingTable[$styleId] ?? null;
- }
-
- /**
- * @param int $styleId
- *
- * @return null|int Fill ID associated to the given style ID
- */
- public function getFillIdForStyleId($styleId)
- {
- return (isset($this->styleIdToFillMappingTable[$styleId])) ?
- $this->styleIdToFillMappingTable[$styleId] :
- null;
- }
-
- /**
- * @param int $styleId
- *
- * @return null|int Fill ID associated to the given style ID
- */
- public function getBorderIdForStyleId($styleId)
- {
- return (isset($this->styleIdToBorderMappingTable[$styleId])) ?
- $this->styleIdToBorderMappingTable[$styleId] :
- null;
- }
-
- /**
- * @return array
- */
- public function getRegisteredFills()
- {
- return $this->registeredFills;
- }
-
- /**
- * @return array
- */
- public function getRegisteredBorders()
- {
- return $this->registeredBorders;
- }
-
- /**
- * @return array
- */
- public function getRegisteredFormats()
- {
- return $this->registeredFormats;
- }
-
- /**
- * Register a format definition.
- */
- protected function registerFormat(Style $style)
- {
- $styleId = $style->getId();
-
- $format = $style->getFormat();
- if ($format) {
- $isFormatRegistered = isset($this->registeredFormats[$format]);
-
- // We need to track the already registered format definitions
- if ($isFormatRegistered) {
- $registeredStyleId = $this->registeredFormats[$format];
- $registeredFormatId = $this->styleIdToFormatsMappingTable[$registeredStyleId];
- $this->styleIdToFormatsMappingTable[$styleId] = $registeredFormatId;
- } else {
- $this->registeredFormats[$format] = $styleId;
-
- $id = self::$builtinNumFormatToIdMapping[$format] ?? $this->formatIndex++;
- $this->styleIdToFormatsMappingTable[$styleId] = $id;
- }
- } else {
- // The formatId maps a style to a format declaration
- // When there is no format definition - we default to 0 ( General )
- $this->styleIdToFormatsMappingTable[$styleId] = 0;
- }
- }
-
- /**
- * Register a fill definition.
- */
- private function registerFill(Style $style)
- {
- $styleId = $style->getId();
-
- // Currently - only solid backgrounds are supported
- // so $backgroundColor is a scalar value (RGB Color)
- $backgroundColor = $style->getBackgroundColor();
-
- if ($backgroundColor) {
- $isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]);
-
- // We need to track the already registered background definitions
- if ($isBackgroundColorRegistered) {
- $registeredStyleId = $this->registeredFills[$backgroundColor];
- $registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId];
- $this->styleIdToFillMappingTable[$styleId] = $registeredFillId;
- } else {
- $this->registeredFills[$backgroundColor] = $styleId;
- $this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++;
- }
- } else {
- // The fillId maps a style to a fill declaration
- // When there is no background color definition - we default to 0
- $this->styleIdToFillMappingTable[$styleId] = 0;
- }
- }
-
- /**
- * Register a border definition.
- */
- private function registerBorder(Style $style)
- {
- $styleId = $style->getId();
-
- if ($style->shouldApplyBorder()) {
- $border = $style->getBorder();
- $serializedBorder = serialize($border);
-
- $isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]);
-
- if ($isBorderAlreadyRegistered) {
- $registeredStyleId = $this->registeredBorders[$serializedBorder];
- $registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId];
- $this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId;
- } else {
- $this->registeredBorders[$serializedBorder] = $styleId;
- $this->styleIdToBorderMappingTable[$styleId] = \count($this->registeredBorders);
- }
- } else {
- // If no border should be applied - the mapping is the default border: 0
- $this->styleIdToBorderMappingTable[$styleId] = 0;
- }
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Manager/WorkbookManager.php b/upstream-3.x/src/Writer/XLSX/Manager/WorkbookManager.php
deleted file mode 100644
index 2feb331..0000000
--- a/upstream-3.x/src/Writer/XLSX/Manager/WorkbookManager.php
+++ /dev/null
@@ -1,74 +0,0 @@
-fileSystemHelper->getXlWorksheetsFolder();
-
- return $worksheetFilesFolder.'/'.strtolower($sheet->getName()).'.xml';
- }
-
- /**
- * @return int Maximum number of rows/columns a sheet can contain
- */
- protected function getMaxRowsPerWorksheet()
- {
- return self::$maxRowsPerWorksheet;
- }
-
- /**
- * Closes custom objects that are still opened.
- */
- protected function closeRemainingObjects()
- {
- $this->worksheetManager->getSharedStringsManager()->close();
- }
-
- /**
- * Writes all the necessary files to disk and zip them together to create the final file.
- *
- * @param resource $finalFilePointer Pointer to the spreadsheet that will be created
- */
- protected function writeAllFilesToDiskAndZipThem($finalFilePointer)
- {
- $worksheets = $this->getWorksheets();
-
- $this->fileSystemHelper
- ->createContentTypesFile($worksheets)
- ->createWorkbookFile($worksheets)
- ->createWorkbookRelsFile($worksheets)
- ->createStylesFile($this->styleManager)
- ->zipRootFolderAndCopyToStream($finalFilePointer)
- ;
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Manager/WorksheetManager.php b/upstream-3.x/src/Writer/XLSX/Manager/WorksheetManager.php
deleted file mode 100644
index c84be5a..0000000
--- a/upstream-3.x/src/Writer/XLSX/Manager/WorksheetManager.php
+++ /dev/null
@@ -1,376 +0,0 @@
-
-
- EOD;
-
- /** @var bool Whether inline or shared strings should be used */
- protected $shouldUseInlineStrings;
-
- /** @var OptionsManagerInterface */
- private $optionsManager;
-
- /** @var RowManager Manages rows */
- private $rowManager;
-
- /** @var StyleManager Manages styles */
- private $styleManager;
-
- /** @var StyleMerger Helper to merge styles together */
- private $styleMerger;
-
- /** @var SharedStringsManager Helper to write shared strings */
- private $sharedStringsManager;
-
- /** @var XLSXEscaper Strings escaper */
- private $stringsEscaper;
-
- /** @var StringHelper String helper */
- private $stringHelper;
-
- /**
- * WorksheetManager constructor.
- */
- public function __construct(
- OptionsManagerInterface $optionsManager,
- RowManager $rowManager,
- StyleManager $styleManager,
- StyleMerger $styleMerger,
- SharedStringsManager $sharedStringsManager,
- XLSXEscaper $stringsEscaper,
- StringHelper $stringHelper
- ) {
- $this->optionsManager = $optionsManager;
- $this->shouldUseInlineStrings = $optionsManager->getOption(Options::SHOULD_USE_INLINE_STRINGS);
- $this->setDefaultColumnWidth($optionsManager->getOption(Options::DEFAULT_COLUMN_WIDTH));
- $this->setDefaultRowHeight($optionsManager->getOption(Options::DEFAULT_ROW_HEIGHT));
- $this->columnWidths = $optionsManager->getOption(Options::COLUMN_WIDTHS) ?? [];
- $this->rowManager = $rowManager;
- $this->styleManager = $styleManager;
- $this->styleMerger = $styleMerger;
- $this->sharedStringsManager = $sharedStringsManager;
- $this->stringsEscaper = $stringsEscaper;
- $this->stringHelper = $stringHelper;
- }
-
- /**
- * @return SharedStringsManager
- */
- public function getSharedStringsManager()
- {
- return $this->sharedStringsManager;
- }
-
- /**
- * {@inheritdoc}
- */
- public function startSheet(Worksheet $worksheet)
- {
- $sheetFilePointer = fopen($worksheet->getFilePath(), 'w');
- $this->throwIfSheetFilePointerIsNotAvailable($sheetFilePointer);
-
- $worksheet->setFilePointer($sheetFilePointer);
-
- fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER);
- }
-
- /**
- * {@inheritdoc}
- */
- public function addRow(Worksheet $worksheet, Row $row)
- {
- if (!$this->rowManager->isEmpty($row)) {
- $this->addNonEmptyRow($worksheet, $row);
- }
-
- $worksheet->setLastWrittenRowIndex($worksheet->getLastWrittenRowIndex() + 1);
- }
-
- /**
- * Construct column width references xml to inject into worksheet xml file.
- *
- * @return string
- */
- public function getXMLFragmentForColumnWidths()
- {
- if (empty($this->columnWidths)) {
- return '';
- }
- $xml = '';
- foreach ($this->columnWidths as $entry) {
- $xml .= '';
- }
- $xml .= '';
-
- return $xml;
- }
-
- /**
- * Constructs default row height and width xml to inject into worksheet xml file.
- *
- * @return string
- */
- public function getXMLFragmentForDefaultCellSizing()
- {
- $rowHeightXml = empty($this->defaultRowHeight) ? '' : " defaultRowHeight=\"{$this->defaultRowHeight}\"";
- $colWidthXml = empty($this->defaultColumnWidth) ? '' : " defaultColWidth=\"{$this->defaultColumnWidth}\"";
- if (empty($colWidthXml) && empty($rowHeightXml)) {
- return '';
- }
- // Ensure that the required defaultRowHeight is set
- $rowHeightXml = empty($rowHeightXml) ? ' defaultRowHeight="0"' : $rowHeightXml;
-
- return "";
- }
-
- /**
- * {@inheritdoc}
- */
- public function close(Worksheet $worksheet)
- {
- $worksheetFilePointer = $worksheet->getFilePointer();
-
- if (!\is_resource($worksheetFilePointer)) {
- return;
- }
- $this->ensureSheetDataStated($worksheet);
- fwrite($worksheetFilePointer, '');
-
- // create nodes for merge cells
- if ($this->optionsManager->getOption(Options::MERGE_CELLS)) {
- $mergeCellString = '';
- foreach ($this->optionsManager->getOption(Options::MERGE_CELLS) as $values) {
- $output = array_map(function ($value) {
- return CellHelper::getColumnLettersFromColumnIndex($value[0]).$value[1];
- }, $values);
- $mergeCellString .= '';
- }
- $mergeCellString .= '';
- fwrite($worksheet->getFilePointer(), $mergeCellString);
- }
-
- fwrite($worksheetFilePointer, '');
- fclose($worksheetFilePointer);
- }
-
- /**
- * Writes the sheet data header.
- *
- * @param Worksheet $worksheet The worksheet to add the row to
- */
- private function ensureSheetDataStated(Worksheet $worksheet)
- {
- if (!$worksheet->getSheetDataStarted()) {
- $worksheetFilePointer = $worksheet->getFilePointer();
- $sheet = $worksheet->getExternalSheet();
- if ($sheet->hasSheetView()) {
- fwrite($worksheetFilePointer, ''.$sheet->getSheetView()->getXml().'');
- }
- fwrite($worksheetFilePointer, $this->getXMLFragmentForDefaultCellSizing());
- fwrite($worksheetFilePointer, $this->getXMLFragmentForColumnWidths());
- fwrite($worksheetFilePointer, '');
- $worksheet->setSheetDataStarted(true);
- }
- }
-
- /**
- * Checks if the sheet has been sucessfully created. Throws an exception if not.
- *
- * @param bool|resource $sheetFilePointer Pointer to the sheet data file or FALSE if unable to open the file
- *
- * @throws IOException If the sheet data file cannot be opened for writing
- */
- private function throwIfSheetFilePointerIsNotAvailable($sheetFilePointer)
- {
- if (!$sheetFilePointer) {
- throw new IOException('Unable to open sheet for writing.');
- }
- }
-
- /**
- * Adds non empty row to the worksheet.
- *
- * @param Worksheet $worksheet The worksheet to add the row to
- * @param Row $row The row to be written
- *
- * @throws InvalidArgumentException If a cell value's type is not supported
- * @throws IOException If the data cannot be written
- */
- private function addNonEmptyRow(Worksheet $worksheet, Row $row)
- {
- $this->ensureSheetDataStated($worksheet);
- $sheetFilePointer = $worksheet->getFilePointer();
- $rowStyle = $row->getStyle();
- $rowIndexOneBased = $worksheet->getLastWrittenRowIndex() + 1;
- $numCells = $row->getNumCells();
-
- $hasCustomHeight = $this->defaultRowHeight > 0 ? '1' : '0';
- $rowXML = "";
-
- foreach ($row->getCells() as $columnIndexZeroBased => $cell) {
- $registeredStyle = $this->applyStyleAndRegister($cell, $rowStyle);
- $cellStyle = $registeredStyle->getStyle();
- if ($registeredStyle->isMatchingRowStyle()) {
- $rowStyle = $cellStyle; // Replace actual rowStyle (possibly with null id) by registered style (with id)
- }
- $rowXML .= $this->getCellXML($rowIndexOneBased, $columnIndexZeroBased, $cell, $cellStyle->getId());
- }
-
- $rowXML .= ' ';
-
- $wasWriteSuccessful = fwrite($sheetFilePointer, $rowXML);
- if (false === $wasWriteSuccessful) {
- throw new IOException("Unable to write data in {$worksheet->getFilePath()}");
- }
- }
-
- /**
- * Applies styles to the given style, merging the cell's style with its row's style.
- *
- * @throws InvalidArgumentException If the given value cannot be processed
- */
- private function applyStyleAndRegister(Cell $cell, Style $rowStyle): RegisteredStyle
- {
- $isMatchingRowStyle = false;
- if ($cell->getStyle()->isEmpty()) {
- $cell->setStyle($rowStyle);
-
- $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell);
-
- if ($possiblyUpdatedStyle->isUpdated()) {
- $registeredStyle = $this->styleManager->registerStyle($possiblyUpdatedStyle->getStyle());
- } else {
- $registeredStyle = $this->styleManager->registerStyle($rowStyle);
- $isMatchingRowStyle = true;
- }
- } else {
- $mergedCellAndRowStyle = $this->styleMerger->merge($cell->getStyle(), $rowStyle);
- $cell->setStyle($mergedCellAndRowStyle);
-
- $possiblyUpdatedStyle = $this->styleManager->applyExtraStylesIfNeeded($cell);
-
- if ($possiblyUpdatedStyle->isUpdated()) {
- $newCellStyle = $possiblyUpdatedStyle->getStyle();
- } else {
- $newCellStyle = $mergedCellAndRowStyle;
- }
-
- $registeredStyle = $this->styleManager->registerStyle($newCellStyle);
- }
-
- return new RegisteredStyle($registeredStyle, $isMatchingRowStyle);
- }
-
- /**
- * Builds and returns xml for a single cell.
- *
- * @param int $rowIndexOneBased
- * @param int $columnIndexZeroBased
- * @param int $styleId
- *
- * @throws InvalidArgumentException If the given value cannot be processed
- *
- * @return string
- */
- private function getCellXML($rowIndexOneBased, $columnIndexZeroBased, Cell $cell, $styleId)
- {
- $columnLetters = CellHelper::getColumnLettersFromColumnIndex($columnIndexZeroBased);
- $cellXML = 'isString()) {
- $cellXML .= $this->getCellXMLFragmentForNonEmptyString($cell->getValue());
- } elseif ($cell->isBoolean()) {
- $cellXML .= ' t="b">'.(int) ($cell->getValue()).'';
- } elseif ($cell->isNumeric()) {
- $cellXML .= '>'.$this->stringHelper->formatNumericValue($cell->getValue()).'';
- } elseif ($cell->isFormula()) {
- $cellXML .= '>'.substr($cell->getValue(), 1).'';
- } elseif ($cell->isDate()) {
- $value = $cell->getValue();
- if ($value instanceof \DateTimeInterface) {
- $cellXML .= '>'.(string) DateHelper::toExcel($value).'';
- } else {
- throw new InvalidArgumentException('Trying to add a date value with an unsupported type: '.\gettype($value));
- }
- } elseif ($cell->isError() && \is_string($cell->getValueEvenIfError())) {
- // only writes the error value if it's a string
- $cellXML .= ' t="e">'.$cell->getValueEvenIfError().'';
- } elseif ($cell->isEmpty()) {
- if ($this->styleManager->shouldApplyStyleOnEmptyCell($styleId)) {
- $cellXML .= '/>';
- } else {
- // don't write empty cells that do no need styling
- // NOTE: not appending to $cellXML is the right behavior!!
- $cellXML = '';
- }
- } else {
- throw new InvalidArgumentException('Trying to add a value with an unsupported type: '.\gettype($cell->getValue()));
- }
-
- return $cellXML;
- }
-
- /**
- * Returns the XML fragment for a cell containing a non empty string.
- *
- * @param string $cellValue The cell value
- *
- * @throws InvalidArgumentException If the string exceeds the maximum number of characters allowed per cell
- *
- * @return string The XML fragment representing the cell
- */
- private function getCellXMLFragmentForNonEmptyString($cellValue)
- {
- if ($this->stringHelper->getStringLength($cellValue) > self::MAX_CHARACTERS_PER_CELL) {
- throw new InvalidArgumentException('Trying to add a value that exceeds the maximum number of characters allowed in a cell (32,767)');
- }
-
- if ($this->shouldUseInlineStrings) {
- $cellXMLFragment = ' t="inlineStr">'.$this->stringsEscaper->escape($cellValue).'';
- } else {
- $sharedStringId = $this->sharedStringsManager->writeString($cellValue);
- $cellXMLFragment = ' t="s">'.$sharedStringId.'';
- }
-
- return $cellXMLFragment;
- }
-}
diff --git a/upstream-3.x/src/Writer/XLSX/Writer.php b/upstream-3.x/src/Writer/XLSX/Writer.php
deleted file mode 100644
index fa3a054..0000000
--- a/upstream-3.x/src/Writer/XLSX/Writer.php
+++ /dev/null
@@ -1,72 +0,0 @@
-throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
-
- $this->optionsManager->setOption(Options::TEMP_FOLDER, $tempFolder);
-
- return $this;
- }
-
- /**
- * Use inline string to be more memory efficient. If set to false, it will use shared strings.
- * This must be set before opening the writer.
- *
- * @param bool $shouldUseInlineStrings Whether inline or shared strings should be used
- *
- * @throws \OpenSpout\Writer\Exception\WriterAlreadyOpenedException If the writer was already opened
- *
- * @return Writer
- */
- public function setShouldUseInlineStrings($shouldUseInlineStrings)
- {
- $this->throwIfWriterAlreadyOpened('Writer must be configured before opening it.');
-
- $this->optionsManager->setOption(Options::SHOULD_USE_INLINE_STRINGS, $shouldUseInlineStrings);
-
- return $this;
- }
-
- /**
- * Merge cells.
- * Row coordinates are indexed from 1, columns from 0 (A = 0),
- * so a merge B2:G2 looks like $writer->mergeCells([1,2], [6, 2]);.
- *
- * You may use CellHelper::getColumnLettersFromColumnIndex() to convert from "B2" to "[1,2]"
- *
- * @param int[] $range1 - top left cell's coordinate [column, row]
- * @param int[] $range2 - bottom right cell's coordinate [column, row]
- *
- * @return $this
- */
- public function mergeCells(array $range1, array $range2)
- {
- $this->optionsManager->addOption(Options::MERGE_CELLS, [$range1, $range2]);
-
- return $this;
- }
-}
|