Merge branch 'w51_MDL-35356_m25_excel' of git://github.com/skodak/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 8 Jan 2013 22:11:54 +0000 (23:11 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 8 Jan 2013 22:11:54 +0000 (23:11 +0100)
Conflicts:
lib/odslib.class.php

240 files changed:
lib/excellib.class.php
lib/odslib.class.php
lib/pear/OLE/PPS.php [deleted file]
lib/pear/OLE/PPS/File.php [deleted file]
lib/pear/OLE/PPS/Root.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer/BIFFwriter.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer/Format.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer/Parser.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer/Validator.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer/Workbook.php [deleted file]
lib/pear/Spreadsheet/Excel/Writer/Worksheet.php [deleted file]
lib/phpexcel/PHPExcel.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Autoloader.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/APC.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/CacheBase.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/DiscISAM.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/ICache.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/Igbinary.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/Memcache.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/Memory.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/MemoryGZip.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/MemorySerialized.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/PHPTemp.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/SQLite.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/SQLite3.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorage/Wincache.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/CachedObjectStorageFactory.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Database.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/DateTime.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Engineering.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Exception.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/ExceptionHandler.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Financial.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/FormulaParser.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/FormulaToken.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Function.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Functions.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Logical.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/LookupRef.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/MathTrig.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Statistical.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/TextData.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/Token/Stack.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Calculation/functionlist.txt [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell/AdvancedValueBinder.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell/DataType.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell/DataValidation.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell/DefaultValueBinder.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell/Hyperlink.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Cell/IValueBinder.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/DataSeries.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/DataSeriesValues.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/Exception.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/Layout.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/Legend.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/PlotArea.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/Renderer/jpgraph.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Chart/Title.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Comment.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/DocumentProperties.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/DocumentSecurity.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Exception.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/HashTable.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/IComparable.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/IOFactory.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/NamedRange.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/CSV.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/DefaultReadFilter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Excel2003XML.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Excel2007.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Excel2007/Chart.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Excel2007/Theme.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Excel5.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Excel5/Escher.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/Gnumeric.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/HTML.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/IReadFilter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/IReader.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/OOCalc.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Reader/SYLK.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/ReferenceHelper.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/RichText.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/RichText/ITextElement.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/RichText/Run.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/RichText/TextElement.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Settings.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/CodePage.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Date.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Drawing.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DgContainer.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DggContainer.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Excel5.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/File.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/Font.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/CHANGELOG.TXT [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/CholeskyDecomposition.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/EigenvalueDecomposition.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/LUDecomposition.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/Matrix.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/QRDecomposition.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/SingularValueDecomposition.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/LMQuadTest.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/LagrangeInterpolation2.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/LevenbergMarquardt.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/MagicSquareExample.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/Stats.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/benchmark.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/polyfit.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/examples/tile.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/tests/TestMatrix.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/utils/Error.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/JAMA/utils/Maths.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/OLE.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/OLE/ChainedBlockStream.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/OLE/PPS.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/OLE/PPS/File.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/OLE/PPS/Root.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/OLERead.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/PCLZip/gnu-lgpl.txt [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/PCLZip/pclzip.lib.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/PCLZip/readme.txt [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/PasswordHasher.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/String.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/XMLWriter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/ZipArchive.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/ZipStreamWrapper.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/bestFitClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/exponentialBestFitClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/linearBestFitClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/logarithmicBestFitClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/polynomialBestFitClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/powerBestFitClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Shared/trend/trendClass.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Alignment.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Border.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Borders.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Color.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Conditional.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Fill.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Font.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/NumberFormat.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Style/Protection.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/AutoFilter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/AutoFilter/Column.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/AutoFilter/Column/Rule.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/BaseDrawing.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/CellIterator.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/ColumnDimension.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/Drawing.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/Drawing/Shadow.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/HeaderFooter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/HeaderFooterDrawing.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/MemoryDrawing.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/PageMargins.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/PageSetup.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/Protection.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/Row.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/RowDimension.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/RowIterator.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Worksheet/SheetView.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/WorksheetIterator.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/CSV.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Chart.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Comments.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/ContentTypes.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/DocProps.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Drawing.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Rels.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/StringTable.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Style.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Theme.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Workbook.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/Worksheet.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel2007/WriterPart.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/BIFFwriter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/Escher.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/Font.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/Parser.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/Workbook.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/Worksheet.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/Excel5/Xf.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/HTML.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/IWriter.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/PDF.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/PDF/Core.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/PDF/DomPDF.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/PDF/mPDF.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/Writer/PDF/tcPDF.php [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/cs/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/cs/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/da/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/da/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/de/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/de/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/en/uk/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/es/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/es/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/fi/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/fi/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/fr/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/fr/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/hu/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/hu/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/it/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/it/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/nl/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/nl/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/no/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/no/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/pl/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/pl/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/pt/br/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/pt/br/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/pt/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/pt/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/ru/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/ru/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/sv/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/sv/functions [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/tr/config [new file with mode: 0755]
lib/phpexcel/PHPExcel/locale/tr/functions [new file with mode: 0755]
lib/phpexcel/readme_moodle.txt [new file with mode: 0644]
lib/tests/other/spreadsheettestpage.php [new file with mode: 0644]
lib/thirdpartylibs.xml

index 69205d9..3103885 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * excellib.class.php
+ * Excel writer abstraction layer.
  *
  * @copyright  (C) 2001-3001 Eloy Lafuente (stronk7) {@link http://contiento.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  * @package    core
- * @subpackage lib
  */
 
 defined('MOODLE_INTERNAL') || die();
 
-/** setup.php includes our hacked pear libs first */
-require_once 'Spreadsheet/Excel/Writer.php';
-
 /**
  * Define and operate over one Moodle Workbook.
  *
- * A big part of this class acts as a wrapper over the PEAR
- * Spreadsheet_Excel_Writer_Workbook and OLE libraries
+ * This class acts as a wrapper around another library
  * maintaining Moodle functions isolated from underlying code.
  *
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
@@ -41,321 +35,346 @@ require_once 'Spreadsheet/Excel/Writer.php';
  * @package moodlecore
  */
 class MoodleExcelWorkbook {
-    /** @var object */
-    var $pear_excel_workbook;
-    /** @var bool */
-    var $latin_output;
+    /** @var PHPExcel */
+    protected $objPHPExcel;
+
+    /** @var string */
+    protected $filename;
+
+    /** @var string format type */
+    protected $type;
 
     /**
      * Constructs one Moodle Workbook.
      *
-     * @global object
      * @param string $filename The name of the file
+     * @param string $type file format type 'Excel5' or 'Excel2007'
      */
-    function MoodleExcelWorkbook($filename) {
+    public function __construct($filename, $type = 'Excel2007') {
         global $CFG;
-    /// Internally, create one PEAR Spreadsheet_Excel_Writer_Workbook class
-        $this->pear_excel_workbook = new Spreadsheet_Excel_Writer($filename);
-    /// Prepare it to accept UTF-16LE data and to encode it properly
-        if (empty($CFG->latinexcelexport)) { /// Only if don't want to use latin (win1252) stronger output
-            $this->pear_excel_workbook->setVersion(8);
-            $this->latin_output = false;
-        } else { /// We want latin (win1252) output
-            $this->latin_output = true;
+        require_once("$CFG->libdir/phpexcel/PHPExcel.php");
+
+        $this->objPHPExcel = new PHPExcel();
+        $this->objPHPExcel->removeSheetByIndex(0);
+
+        $this->filename = $filename;
+
+        if (strtolower($type) === 'excel5') {
+            $this->type = 'Excel5';
+        } else {
+            $this->type = 'Excel2007';
         }
-    /// Choose our temporary directory - see MDL-7176, found by paulo.matos
-        make_temp_directory('excel');
-        $this->pear_excel_workbook->setTempDir($CFG->tempdir.'/excel');
     }
 
     /**
      * Create one Moodle Worksheet
      *
      * @param string $name Name of the sheet
-     * @return object MoodleExcelWorksheet
+     * @return MoodleExcelWorksheet
      */
-    function add_worksheet($name = '') {
-        // Create the Moodle Worksheet. Returns one pointer to it
-        $ws = new MoodleExcelWorksheet ($name, $this->pear_excel_workbook, $this->latin_output);
-        return $ws;
+    public function add_worksheet($name = '') {
+        return new MoodleExcelWorksheet($name, $this->objPHPExcel);
     }
 
     /**
-     * Create one Moodle Format
+     * Create one cell Format.
      *
      * @param array $properties array of properties [name]=value;
      *                          valid names are set_XXXX existing
      *                          functions without the set_ part
      *                          i.e: [bold]=1 for set_bold(1)...Optional!
-     * @return object MoodleExcelFormat
+     * @return MoodleExcelFormat
      */
-    function &add_format($properties = array()) {
-    /// Create the Moodle Format. Returns one pointer to it
-        $ft = new MoodleExcelFormat ($this->pear_excel_workbook, $properties);
-        return $ft;
+    public function add_format($properties = array()) {
+        return new MoodleExcelFormat($properties);
     }
 
     /**
      * Close the Moodle Workbook
      */
-    function close() {
-        $this->pear_excel_workbook->close();
+    public function close() {
+        global $CFG;
+
+        foreach ($this->objPHPExcel->getAllSheets() as $sheet){
+            $sheet->setSelectedCells('A1');
+        }
+        $this->objPHPExcel->setActiveSheetIndex(0);
+
+        $filename = preg_replace('/\.xlsx?$/i', '', $this->filename);
+
+        if ($this->type === 'Excel5') {
+            $mimetype = 'application/vnd.ms-excel';
+            $filename = $filename.'.xls';
+        } else {
+            $mimetype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
+            $filename = $filename.'.xlsx';
+        }
+
+        if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431
+            header('Cache-Control: max-age=10');
+            header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
+            header('Pragma: ');
+        } else { //normal http - prevent caching at all cost
+            header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
+            header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
+            header('Pragma: no-cache');
+        }
+
+        if (check_browser_version('MSIE')) {
+            $filename = rawurlencode($filename);
+        } else {
+            $filename = s($filename);
+        }
+
+        header('Content-Type: '.$mimetype);
+        header('Content-Disposition: attachment;filename="'.$filename.'"');
+
+        $objWriter = PHPExcel_IOFactory::createWriter($this->objPHPExcel, $this->type);
+        $objWriter->save('php://output');
     }
 
     /**
-     * Write the correct HTTP headers
-     *
+     * Not required to use.
      * @param string $filename Name of the downloaded file
      */
-    function send($filename) {
-        $this->pear_excel_workbook->send($filename);
+    public function send($filename) {
+        $this->filename = $filename;
     }
 }
 
 /**
  * Define and operate over one Worksheet.
  *
- * A big part of this class acts as a wrapper over the PEAR
- * Spreadsheet_Excel_Writer_Workbook and OLE libraries
+ * This class acts as a wrapper around another library
  * maintaining Moodle functions isolated from underlying code.
  *
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @package moodlecore
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package   core
  */
 class MoodleExcelWorksheet {
-    /** @var object */
-    var $pear_excel_worksheet;
-    /** @var bool Only if don't want to use latin (win1252) stronger output */
-    var $latin_output;
+    /** @var PHPExcel_Worksheet */
+    protected $worksheet;
 
     /**
      * Constructs one Moodle Worksheet.
      *
-     * @param string $filename The name of the file
-     * @param object $workbook The internal PEAR Workbook onject we are creating
-     * @param bool $latin_output Only if don't want to use latin (win1252) stronger output
+     * @param string $name The name of the file
+     * @param PHPExcel $workbook The internal Workbook object we are creating.
      */
-    function MoodleExcelWorksheet($name, &$workbook, $latin_output=false) {
-
+    public function __construct($name, PHPExcel $workbook) {
         // Replace any characters in the name that Excel cannot cope with.
         $name = strtr($name, '[]*/\?:', '       ');
+        // Shorten the title if necessary.
+        $name = textlib::substr($name, 0, 31);
 
-        if (strlen($name) > 31) {
-            // Excel does not seem able to cope with sheet names > 31 chars.
-            // With $latin_output = false, it does not cope at all.
-            // With $latin_output = true it is supposed to work, but in our experience,
-            // it doesn't. Therefore, truncate in all circumstances.
-            $name = textlib::substr($name, 0, 31);
+        if ($name === '') {
+            // Name is required!
+            $name = 'Sheet'.($workbook->getSheetCount()+1);
         }
 
-    /// Internally, add one sheet to the workbook
-        $this->pear_excel_worksheet =& $workbook->addWorksheet($name);
-        $this->latin_output = $latin_output;
-    /// Set encoding to UTF-16LE
-        if (!$this->latin_output) { /// Only if don't want to use latin (win1252) stronger output
-            $this->pear_excel_worksheet->setInputEncoding('UTF-16LE');
-        }
+        $this->worksheet = new PHPExcel_Worksheet($workbook, $name);
+        $this->worksheet->setPrintGridlines(false);
+
+        $workbook->addSheet($this->worksheet);
     }
 
     /**
-     * Write one string somewhere in the worksheet
+     * Write one string somewhere in the worksheet.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $str    The string to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_string($row, $col, $str, $format=null) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Convert the text from its original encoding to UTF-16LE
-        if (!$this->latin_output) { /// Only if don't want to use latin (win1252) stronger output
-            $str = textlib::convert($str, 'utf-8', 'utf-16le');
-        } else { /// else, convert to latin (win1252)
-            $str = textlib::convert($str, 'utf-8', 'windows-1252');
-        }
-    /// Add the string safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->writeString($row, $col, $str, $format);
+    public function write_string($row, $col, $str, $format = null) {
+        $this->worksheet->getStyleByColumnAndRow($col, $row+1)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_TEXT);
+        $this->worksheet->setCellValueExplicitByColumnAndRow($col, $row+1, $str, PHPExcel_Cell_DataType::TYPE_STRING);
+        $this->apply_format($row, $col, $format);
     }
 
     /**
-     * Write one number somewhere in the worksheet
+     * Write one number somewhere in the worksheet.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param float   $num    The number to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_number($row, $col, $num, $format=null) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Add  the number safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->writeNumber($row, $col, $num, $format);
+    public function write_number($row, $col, $num, $format = null) {
+        $this->worksheet->getStyleByColumnAndRow($col, $row+1)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_GENERAL);
+        $this->worksheet->setCellValueExplicitByColumnAndRow($col, $row+1, $num, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+        $this->apply_format($row, $col, $format);
     }
 
     /**
-     * Write one url somewhere in the worksheet
+     * Write one url somewhere in the worksheet.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $url    The url to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_url($row, $col, $url, $format=null) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Add  the url safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->writeUrl($row, $col, $url, $format);
+    public function write_url($row, $col, $url, $format = null) {
+        $this->worksheet->setCellValueByColumnAndRow($col, $row+1, $url);
+        $this->worksheet->getCellByColumnAndRow($col, $row+1)->getHyperlink()->setUrl($url);
+        $this->apply_format($row, $col, $format);
     }
 
     /**
-     * Write one date somewhere in the worksheet
+     * Write one date somewhere in the worksheet.
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $date   The date to write in UNIX timestamp format
      * @param mixed   $format The XF format for the cell
      */
-    function write_date($row, $col, $date, $format=null) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Convert the date to Excel format
-        $timezone = get_user_timezone_offset();
-        if ($timezone == 99) {
-            // system timezone offset in seconds
-            $offset = (int)date('Z');
-        } else {
-            $offset = (int)($timezone * HOURSECS * 2);
-        }
-        $value = ((usertime($date) + $offset) / 86400) + 25569;
-    /// Add  the date safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->writeNumber($row, $col, $value, $format);
+    public function write_date($row, $col, $date, $format = null) {
+        $getdate = usergetdate($date);
+        $exceldate = PHPExcel_Shared_Date::FormattedPHPToExcel(
+            $getdate['year'],
+            $getdate['mon'],
+            $getdate['mday'],
+            $getdate['hours'],
+            $getdate['minutes'],
+            $getdate['seconds']
+        );
+
+        $this->worksheet->setCellValueByColumnAndRow($col, $row+1, $exceldate);
+        $this->worksheet->getStyleByColumnAndRow($col, $row+1)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22);
+        $this->apply_format($row, $col, $format);
     }
 
     /**
-     * Write one formula somewhere in the worksheet
+     * Write one formula somewhere in the worksheet.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $formula The formula to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_formula($row, $col, $formula, $format=null) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Add  the formula safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->writeFormula($row, $col, $formula, $format);
+    public function write_formula($row, $col, $formula, $format = null) {
+        $this->worksheet->setCellValueExplicitByColumnAndRow($col, $row+1, $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
+        $this->apply_format($row, $col, $format);
     }
 
     /**
-     * Write one blanck somewhere in the worksheet
+     * Write one blank somewhere in the worksheet.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param mixed   $format The XF format for the cell
      */
-    function write_blank($row, $col, $format=null) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Add  the blank safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->writeBlank($row, $col, $format);
+    public function write_blank($row, $col, $format = null) {
+        $this->worksheet->setCellValueByColumnAndRow($col, $row+1, '');
+        $this->apply_format($row, $col, $format);
     }
 
     /**
-     * Write anything somewhere in the worksheet
-     * Type will be automatically detected
+     * Write anything somewhere in the worksheet,
+     * type will be automatically detected.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param mixed   $token  What we are writing
      * @param mixed   $format The XF format for the cell
-     * @return void
      */
-    function write($row, $col, $token, $format=null) {
-
-    /// Analyse what are we trying to send
+    public function write($row, $col, $token, $format = null) {
+        // Analyse what are we trying to send.
         if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
-        /// Match number
+            // Match number
             return $this->write_number($row, $col, $token, $format);
         } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
-        /// Match http or ftp URL
+            // Match http or ftp URL
             return $this->write_url($row, $col, $token, '', $format);
         } elseif (preg_match("/^mailto:/", $token)) {
-        /// Match mailto:
+            // Match mailto:
             return $this->write_url($row, $col, $token, '', $format);
         } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
-        /// Match internal or external sheet link
+            // Match internal or external sheet link
             return $this->write_url($row, $col, $token, '', $format);
         } elseif (preg_match("/^=/", $token)) {
-        /// Match formula
+            // Match formula
             return $this->write_formula($row, $col, $token, $format);
         } elseif (preg_match("/^@/", $token)) {
-        /// Match formula
+            // Match formula
             return $this->write_formula($row, $col, $token, $format);
         } elseif ($token == '') {
-        /// Match blank
+            // Match blank
             return $this->write_blank($row, $col, $format);
         } else {
-        /// Default: match string
+            // Default: match string
             return $this->write_string($row, $col, $token, $format);
         }
     }
 
     /**
-     * Sets the height (and other settings) of one row
+     * Sets the height (and other settings) of one row.
      *
      * @param integer $row    The row to set
-     * @param integer $height Height we are giving to the row (null to set just format withouth setting the height)
-     * @param mixed   $format The optional XF format we are giving to the row
+     * @param integer $height Height we are giving to the row (null to set just format without setting the height)
+     * @param mixed   $format The optional format we are giving to the row
      * @param bool    $hidden The optional hidden attribute
      * @param integer $level  The optional outline level (0-7)
      */
-    function set_row ($row, $height, $format = null, $hidden = false, $level = 0) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Set the row safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->setRow($row, $height, $format, $hidden, $level);
+    public function set_row($row, $height, $format = null, $hidden = false, $level = 0) {
+        if ($level < 0) {
+            $level = 0;
+        } else if ($level > 7) {
+            $level = 7;
+        }
+        if (isset($height)) {
+            $this->worksheet->getRowDimension($row+1)->setRowHeight($height);
+        }
+        $this->worksheet->getRowDimension($row+1)->setVisible(!$hidden);
+        $this->worksheet->getRowDimension($row+1)->setOutlineLevel($level);
+        $this->apply_row_format($row, $format);
     }
 
     /**
-     * Sets the width (and other settings) of one column
+     * Sets the width (and other settings) of one column.
      *
      * @param integer $firstcol first column on the range
      * @param integer $lastcol  last column on the range
-     * @param integer $width    width to set
-     * @param mixed   $format   The optional XF format to apply to the columns
-     * @param integer $hidden   The optional hidden atribute
+     * @param integer $width    width to set  (null to set just format without setting the width)
+     * @param mixed   $format   The optional format to apply to the columns
+     * @param bool    $hidden   The optional hidden attribute
      * @param integer $level    The optional outline level (0-7)
      */
-    function set_column ($firstcol, $lastcol, $width, $format = null, $hidden = false, $level = 0) {
-    /// Calculate the internal PEAR format
-        $format = $this->MoodleExcelFormat2PearExcelFormat($format);
-    /// Set the column safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->setColumn($firstcol, $lastcol, $width, $format, $hidden, $level);
+    public function set_column($firstcol, $lastcol, $width, $format = null, $hidden = false, $level = 0) {
+        if ($level < 0) {
+            $level = 0;
+        } else if ($level > 7) {
+            $level = 7;
+        }
+        $i = $firstcol;
+        while($i <= $lastcol) {
+            if (isset($width)) {
+                $this->worksheet->getColumnDimensionByColumn($i)->setWidth($width);
+            }
+            $this->worksheet->getColumnDimensionByColumn($i)->setVisible(!$hidden);
+            $this->worksheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
+            $this->apply_column_format($i, $format);
+            $i++;
+        }
     }
 
-    /**
-    * Set the option to hide gridlines on the printed page.
-    *
-    * @access public
+   /**
+    * Set the option to hide grid lines on the printed page.
     */
-    function hide_gridlines() {
-        $this->pear_excel_worksheet->hideGridLines();
+    public function hide_gridlines() {
+        // Not implemented - always off.
     }
 
-    /**
+   /**
     * Set the option to hide gridlines on the worksheet (as seen on the screen).
-    *
-    * @access public
     */
-    function hide_screen_gridlines() {
-        $this->pear_excel_worksheet->hideScreenGridlines();
+    public function hide_screen_gridlines() {
+        $this->worksheet->setShowGridlines(false);
     }
 
-    /**
-    * Insert a 24bit bitmap image in a worksheet.
+   /**
+    * Insert an image in a worksheet.
     *
-    * @access public
     * @param integer $row     The row we are going to insert the bitmap into
     * @param integer $col     The column we are going to insert the bitmap into
     * @param string  $bitmap  The bitmap filename
@@ -364,39 +383,60 @@ class MoodleExcelWorksheet {
     * @param integer $scale_x The horizontal scale
     * @param integer $scale_y The vertical scale
     */
-    function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
-    /// Add the bitmap safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->insertBitmap($row, $col, $bitmap, $x, $y, $scale_x, $scale_y);
+    public function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
+        $objDrawing = new PHPExcel_Worksheet_Drawing();
+        $objDrawing->setPath($bitmap);
+        $objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex($col) . ($row+1));
+        $objDrawing->setOffsetX($x);
+        $objDrawing->setOffsetY($y);
+        $objDrawing->setWorksheet($this->worksheet);
+        if ($scale_x != 1) {
+            $objDrawing->setResizeProportional(false);
+            $objDrawing->getWidth($objDrawing->getWidth()*$scale_x);
+        }
+        if ($scale_y != 1) {
+            $objDrawing->setResizeProportional(false);
+            $objDrawing->setHeight($objDrawing->getHeight()*$scale_y);
+        }
     }
 
-    /**
+   /**
     * Merges the area given by its arguments.
-    * This is an Excel97/2000 method. It is required to perform more complicated
-    * merging than the normal setAlign('merge').
     *
-    * @access public
     * @param integer $first_row First row of the area to merge
     * @param integer $first_col First column of the area to merge
     * @param integer $last_row  Last row of the area to merge
     * @param integer $last_col  Last column of the area to merge
     */
-    function merge_cells($first_row, $first_col, $last_row, $last_col) {
-        /// Merge cells safely to the PEAR Worksheet
-        $this->pear_excel_worksheet->mergeCells($first_row, $first_col, $last_row, $last_col);
+    public function merge_cells($first_row, $first_col, $last_row, $last_col) {
+        $this->worksheet->mergeCellsByColumnAndRow($first_col, $first_row+1, $last_col, $last_row+1);
     }
 
-    /**
-     * Returns the PEAR Excel Format for one Moodle Excel Format
-     *
-     * @param mixed $format MoodleExcelFormat object
-     * @return mixed PEAR Excel Format object
-     */
-    function MoodleExcelFormat2PearExcelFormat($format) {
-        if ($format) {
-            return $format->pear_excel_format;
-        } else {
-            return null;
+    protected function apply_format($row, $col, $format = null) {
+        if (!$format) {
+            $format = new MoodleExcelFormat();
+        } else if (is_array($format)) {
+            $format = new MoodleExcelFormat($format);
+        }
+        $this->worksheet->getStyleByColumnAndRow($col, $row+1)->applyFromArray($format->get_format_array());
+    }
+
+    protected function apply_column_format($col, $format = null) {
+        if (!$format) {
+            $format = new MoodleExcelFormat();
+        } else if (is_array($format)) {
+            $format = new MoodleExcelFormat($format);
+        }
+        $this->worksheet->getStyle(PHPExcel_Cell::stringFromColumnIndex($col))->applyFromArray($format->get_format_array());
+    }
+
+    protected function apply_row_format($row, $format = null) {
+        if (!$format) {
+            $format = new MoodleExcelFormat();
+        } else if (is_array($format)) {
+            $format = new MoodleExcelFormat($format);
         }
+        $this->worksheet->getStyle($row+1)->applyFromArray($format->get_format_array());
     }
 }
 
@@ -413,19 +453,16 @@ class MoodleExcelWorksheet {
  * @package moodlecore
  */
 class MoodleExcelFormat {
-    /** @var object */
-    var $pear_excel_format;
+    /** @var array */
+    protected $format = array('font'=>array('size'=>10, 'name'=>'Arial'));
 
     /**
      * Constructs one Moodle Format.
      *
-     * @param object $workbook The internal PEAR Workbook onject we are creating
      * @param array $properties
      */
-    function MoodleExcelFormat(&$workbook, $properties = array()) {
-    /// Internally, add one sheet to the workbook
-        $this->pear_excel_format =& $workbook->addFormat();
-    /// If we have something in the array of properties, compute them
+    public function __construct($properties = array()) {
+        // If we have something in the array of properties, compute them
         foreach($properties as $property => $value) {
             if(method_exists($this,"set_$property")) {
                 $aux = 'set_'.$property;
@@ -434,81 +471,98 @@ class MoodleExcelFormat {
         }
     }
 
+    /**
+     * Returns standardised Excel format array.
+     * @private
+     *
+     * @return array
+     */
+    public function get_format_array() {
+        return $this->format;
+    }
     /**
      * Set the size of the text in the format (in pixels).
-     * By default all texts in generated sheets are 10px.
+     * By default all texts in generated sheets are 10pt.
      *
-     * @param integer $size Size of the text (in pixels)
+     * @param integer $size Size of the text (in points)
      */
-    function set_size($size) {
-    /// Set the size safely to the PEAR Format
-        $this->pear_excel_format->setSize($size);
+    public function set_size($size) {
+        $this->format['font']['size'] = $size;
     }
 
     /**
-     * Set weight of the format
+     * Set weight of the format.
      *
      * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
      *                        1 maps to 700 (bold text). Valid range is: 100-1000.
      *                        It's Optional, default is 1 (bold).
      */
-    function set_bold($weight = 1) {
-    /// Set the bold safely to the PEAR Format
-        $this->pear_excel_format->setBold($weight);
+    public function set_bold($weight = 1) {
+        if ($weight == 1) {
+            $weight = 700;
+        }
+        $this->format['font']['bold'] = ($weight > 400);
     }
 
     /**
-     * Set underline of the format
+     * Set underline of the format.
      *
      * @param integer $underline The value for underline. Possible values are:
      *                           1 => underline, 2 => double underline
      */
-    function set_underline($underline) {
-    /// Set the underline safely to the PEAR Format
-        $this->pear_excel_format->setUnderline($underline);
+    public function set_underline($underline) {
+        if ($underline == 1) {
+            $this->format['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_SINGLE;
+        } else if ($underline == 2) {
+            $this->format['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_DOUBLE;
+        } else {
+            $this->format['font']['underline'] = PHPExcel_Style_Font::UNDERLINE_NONE;
+        }
     }
 
     /**
-     * Set italic of the format
+     * Set italic of the format.
      */
-    function set_italic() {
-    /// Set the italic safely to the PEAR Format
-        $this->pear_excel_format->setItalic();
+    public function set_italic() {
+        $this->format['font']['italic'] = true;
     }
 
     /**
-     * Set strikeout of the format
+     * Set strikeout of the format.
      */
-    function set_strikeout() {
-    /// Set the strikeout safely to the PEAR Format
-        $this->pear_excel_format->setStrikeOut();
+    public function set_strikeout() {
+        $this->format['font']['strike'] = true;
     }
 
     /**
-     * Set outlining of the format
+     * Set outlining of the format.
      */
-    function set_outline() {
-    /// Set the outlining safely to the PEAR Format
-        $this->pear_excel_format->setOutLine();
+    public function set_outline() {
+        // Not implemented.
     }
 
     /**
-     * Set shadow of the format
+     * Set shadow of the format.
      */
-    function set_shadow() {
-    /// Set the shadow safely to the PEAR Format
-        $this->pear_excel_format->setShadow();
+    public function set_shadow() {
+        // Not implemented.
     }
 
     /**
-     * Set the script of the text
+     * Set the script of the text.
      *
      * @param integer $script The value for script type. Possible values are:
      *                        1 => superscript, 2 => subscript
      */
-    function set_script($script) {
-    /// Set the script safely to the PEAR Format
-        $this->pear_excel_format->setScript($script);
+    public function set_script($script) {
+        if ($script == 1) {
+            $this->format['font']['superScript'] = true;
+        } else if ($script == 2) {
+            $this->format['font']['subScript'] = true;
+        } else {
+            $this->format['font']['superScript'] = false;
+            $this->format['font']['subScript'] = false;
+        }
     }
 
     /**
@@ -516,145 +570,292 @@ class MoodleExcelFormat {
      *
      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
      */
-    function set_color($color) {
-    /// Set the background color safely to the PEAR Format
-        $this->pear_excel_format->setColor($color);
+    public function set_color($color) {
+        $this->format['font']['color']['rgb'] = $this->parse_color($color);
     }
 
     /**
-     * Set foreground color (top layer) of the format. About formatting colors note that cells backgrounds
-     * have TWO layers, in order to support patterns and paint them with two diferent colors.
-     * This method set the color of the TOP layer of the background format. So, when filling
-     * cells with plain colors (no patterns) this is the method to use.
+     * Standardise colour name.
      *
-     * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
+     * @param mixed $color name of the color (i.e.: 'blue', 'red', etc..), or an integer (range is [8...63]).
+     * @return string the RGB color value
+     */
+    protected function parse_color($color) {
+        if (strpos($color, '#') === 0) {
+            // No conversion should be needed.
+            return substr($color, 1);
+        }
+
+        if ($color > 7 and $color < 53) {
+            $numbers = array(
+                8  => 'black',
+                12 => 'blue',
+                16 => 'brown',
+                15 => 'cyan',
+                23 => 'gray',
+                17 => 'green',
+                11 => 'lime',
+                14 => 'magenta',
+                18 => 'navy',
+                53 => 'orange',
+                33 => 'pink',
+                20 => 'purple',
+                10 => 'red',
+                22 => 'silver',
+                9  => 'white',
+                13 => 'yellow',
+            );
+            if (isset($numbers[$color])) {
+                $color = $numbers[$color];
+            } else {
+                $color = 'black';
+            }
+        }
+
+        $colors = array(
+            'aqua'    => '00FFFF',
+            'black'   => '000000',
+            'blue'    => '0000FF',
+            'brown'   => 'A52A2A',
+            'cyan'    => '00FFFF',
+            'fuchsia' => 'FF00FF',
+            'gray'    => '808080',
+            'grey'    => '808080',
+            'green'   => '00FF00',
+            'lime'    => '00FF00',
+            'magenta' => 'FF00FF',
+            'maroon'  => '800000',
+            'navy'    => '000080',
+            'orange'  => 'FFA500',
+            'olive'   => '808000',
+            'pink'    => 'FAAFBE',
+            'purple'  => '800080',
+            'red'     => 'FF0000',
+            'silver'  => 'C0C0C0',
+            'teal'    => '008080',
+            'white'   => 'FFFFFF',
+            'yellow'  => 'FFFF00',
+        );
+
+        if (isset($colors[$color])) {
+            return($colors[$color]);
+        }
+
+        return($colors['black']);
+    }
+
+    /**
+     * Not used.
+     *
+     * @param mixed $color
      */
-    function set_fg_color($color) {
-    /// Set the foreground color safely to the PEAR Format
-        $this->pear_excel_format->setFgColor($color);
+    public function set_fg_color($color) {
+        // Not implemented.
     }
 
     /**
-     * Set background color (bottom layer) of the format. About formatting colors note that cells backgrounds
-     * have TWO layers, in order to support patterns and paint them with two diferent colors.
-     * This method set the color of the BOTTOM layer of the background format. So, the color
-     * specified here only will be visible if using patterns. Use set_fg_color() to fill
-     * cells with plain colors (no patterns).
+     * Set background color of the cell.
      *
      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
      */
-    function set_bg_color($color) {
-    /// Set the background color safely to the PEAR Format
-        $this->pear_excel_format->setBgColor($color);
+    public function set_bg_color($color) {
+        if (!isset($this->format['fill']['type'])) {
+            $this->format['fill']['type'] = PHPExcel_Style_Fill::FILL_SOLID;
+        }
+        $this->format['fill']['color']['rgb'] = $this->parse_color($color);
     }
 
     /**
-     * Set the fill pattern of the format
-     * @param integer Optional. Defaults to 1. Meaningful values are: 0-18
-     *                0 meaning no background.
+     * Set the cell fill pattern.
+     *
+     * @deprecated use set_bg_color() instead.
+     * @param integer
      */
-    function set_pattern($pattern=1) {
-    /// Set the fill pattern safely to the PEAR Format
-        $this->pear_excel_format->setPattern($pattern);
+    public function set_pattern($pattern=1) {
+        if ($pattern > 0) {
+            if (!isset($this->format['fill']['color']['rgb'])) {
+                $this->set_bg_color('black');
+            }
+        } else {
+            unset($this->format['fill']['color']['rgb']);
+            unset($this->format['fill']['type']);
+        }
     }
 
     /**
-     * Set text wrap of the format
+     * Set text wrap of the format.
      */
-    function set_text_wrap() {
-    /// Set the shadow safely to the PEAR Format
-        $this->pear_excel_format->setTextWrap();
+    public function set_text_wrap() {
+        $this->format['alignment']['wrap'] = true;
     }
 
     /**
-     * Set the cell alignment of the format
+     * Set the cell alignment of the format.
      *
-     * @param string $location alignment for the cell ('left', 'right', etc...)
+     * @param string $location alignment for the cell ('left', 'right', 'justify', etc...)
      */
-    function set_align($location) {
-    /// Set the alignment of the cell safely to the PEAR Format
-        $this->pear_excel_format->setAlign($location);
+    public function set_align($location) {
+        if (in_array($location, array('left', 'centre', 'center', 'right', 'fill', 'merge', 'justify', 'equal_space'))) {
+            $this->set_h_align($location);
+
+        } else if (in_array($location, array('top', 'vcentre', 'vcenter', 'bottom', 'vjustify', 'vequal_space'))) {
+            $this->set_v_align($location);
+        }
     }
 
     /**
-     * Set the cell horizontal alignment of the format
+     * Set the cell horizontal alignment of the format.
      *
-     * @param string $location alignment for the cell ('left', 'right', etc...)
-     */
-    function set_h_align($location) {
-    /// Set the alignment of the cell safely to the PEAR Format
-        $this->pear_excel_format->setHAlign($location);
+     * @param string $location alignment for the cell ('left', 'right', 'justify', etc...)
+     */
+    public function set_h_align($location) {
+        switch ($location) {
+            case 'left':
+                $this->format['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_LEFT;
+                break;
+            case 'center':
+            case 'centre':
+                $this->format['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_CENTER;
+                break;
+            case 'right':
+                $this->format['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_RIGHT;
+                break;
+            case 'justify':
+                $this->format['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY;
+                break;
+            default:
+                $this->format['alignment']['horizontal'] = PHPExcel_Style_Alignment::HORIZONTAL_GENERAL;
+        }
     }
 
     /**
-     * Set the cell vertical alignment of the format
+     * Set the cell vertical alignment of the format.
      *
-     * @param string $location alignment for the cell ('top', 'vleft', etc...)
-     */
-    function set_v_align($location) {
-    /// Set the alignment of the cell safely to the PEAR Format
-        $this->pear_excel_format->setVAlign($location);
+     * @param string $location alignment for the cell ('top', 'bottom', 'center', 'justify')
+     */
+    public function set_v_align($location) {
+        switch ($location) {
+            case 'top':
+                $this->format['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_TOP;
+                break;
+            case 'vcentre':
+            case 'vcenter':
+            case 'centre':
+            case 'center':
+                $this->format['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_CENTER;
+                break;
+            case 'vjustify':
+            case 'justify':
+                $this->format['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_JUSTIFY;
+                break;
+            default:
+                $this->format['alignment']['vertical'] = PHPExcel_Style_Alignment::VERTICAL_BOTTOM;
+        }
     }
 
     /**
-     * Set the top border of the format
+     * Set the top border of the format.
      *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_top($style) {
-    /// Set the top border of the cell safely to the PEAR Format
-        $this->pear_excel_format->setTop($style);
+    public function set_top($style) {
+        if ($style == 1) {
+            $this->format['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_THIN;
+        } else if ($style == 2) {
+            $this->format['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_THICK;
+        } else {
+            $this->format['borders']['top']['style'] = PHPExcel_Style_Border::BORDER_NONE;
+        }
     }
 
     /**
-     * Set the bottom border of the format
+     * Set the bottom border of the format.
      *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_bottom($style) {
-    /// Set the bottom border of the cell safely to the PEAR Format
-        $this->pear_excel_format->setBottom($style);
+    public function set_bottom($style) {
+        if ($style == 1) {
+            $this->format['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_THIN;
+        } else if ($style == 2) {
+            $this->format['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_THICK;
+        } else {
+            $this->format['borders']['bottom']['style'] = PHPExcel_Style_Border::BORDER_NONE;
+        }
     }
 
     /**
-     * Set the left border of the format
+     * Set the left border of the format.
      *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_left($style) {
-    /// Set the left border of the cell safely to the PEAR Format
-        $this->pear_excel_format->setLeft($style);
+    public function set_left($style) {
+        if ($style == 1) {
+            $this->format['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_THIN;
+        } else if ($style == 2) {
+            $this->format['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_THICK;
+        } else {
+            $this->format['borders']['left']['style'] = PHPExcel_Style_Border::BORDER_NONE;
+        }
     }
 
     /**
-     * Set the right border of the format
+     * Set the right border of the format.
      *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_right($style) {
-    /// Set the right border of the cell safely to the PEAR Format
-        $this->pear_excel_format->setRight($style);
+    public function set_right($style) {
+        if ($style == 1) {
+            $this->format['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_THIN;
+        } else if ($style == 2) {
+            $this->format['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_THICK;
+        } else {
+            $this->format['borders']['right']['style'] = PHPExcel_Style_Border::BORDER_NONE;
+        }
     }
 
     /**
-     * Set cells borders to the same style
+     * Set cells borders to the same style.
      *
      * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
      */
-    function set_border($style) {
-    /// Set all the borders of the cell safely to the PEAR Format
-        $this->pear_excel_format->setBorder($style);
+    public function set_border($style) {
+        $this->set_top($style);
+        $this->set_bottom($style);
+        $this->set_left($style);
+        $this->set_right($style);
     }
 
     /**
-     * Set the numerical format of the format
+     * Set the numerical format of the format.
      * It can be date, time, currency, etc...
      *
-     * @param integer $num_format The numeric format
-     */
-    function set_num_format($num_format) {
-    /// Set the numerical format safely to the PEAR Format
-        $this->pear_excel_format->setNumFormat($num_format);
-    }
+     * @param mixed $num_format The numeric format
+     */
+    public function set_num_format($num_format) {
+        $numbers = array();
+
+        $numbers[1] = '0';
+        $numbers[2] = '0.00';
+        $numbers[3] = '#,##0';
+        $numbers[4] = '#,##0.00';
+        $numbers[11] = '0.00E+00';
+        $numbers[12] = '# ?/?';
+        $numbers[13] = '# ??/??';
+        $numbers[14] = 'mm-dd-yy';
+        $numbers[15] = 'd-mmm-yy';
+        $numbers[16] = 'd-mmm';
+        $numbers[17] = 'mmm-yy';
+        $numbers[22] = 'm/d/yy h:mm';
+        $numbers[49] = '@';
+
+        if ($num_format !== 0 and in_array($num_format, $numbers)) {
+            $this->format['numberformat']['code'] = $num_format;
+        }
 
+        if (!isset($numbers[$num_format])) {
+            return;
+        }
+
+        $this->format['numberformat']['code'] = $numbers[$num_format];
+    }
 }
index f22eb72..c5d5afd 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Major Contributors:
- *     - Eloy Lafuente (stronk7) {@link  http://contiento.com}
- *     - Petr Skoda (skodak)
+ * ODS file writer.
+ * The xml used here is derived from output of LibreOffice 3.6.4
+ *
+ * The design is based on Excel writer abstraction by Eloy Lafuente and others.
  *
- * @package    core
- * @subpackage lib
- * @copyright  (C) 2001-3001 Eloy Lafuente (stronk7) {@link http://contiento.com}
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package   core
+ * @copyright 2006 Petr Skoda {@link http://skodak.org}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
+
 /**
- * The xml used here is derived from output of KSpread 1.6.1
- *
- * Known problems:
- *  - missing formatting
- *  - write_date() works fine in OOo, but it does not work in KOffice - it knows only date or time but not both :-(
+ * ODS workbook abstraction.
  *
- * @package   moodlecore
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @package   core
+ * @copyright 2006 Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class MoodleODSWorkbook {
-    var $worksheets = array();
-    var $filename;
+    protected $worksheets = array();
+    protected $filename;
 
-    function MoodleODSWorkbook($filename) {
+    public function __construct($filename) {
         $this->filename = $filename;
     }
 
-    /* Create one Moodle Worksheet
+    /**
+     * Create one Moodle Worksheet.
+     *
      * @param string $name Name of the sheet
+     * @return MoodleODSWorksheet
      */
-    function add_worksheet($name = '') {
-    /// Create the Moodle Worksheet. Returns one pointer to it
-        $ws = new MoodleODSWorksheet($name);
-        $this->worksheets[] =& $ws;
+    public function add_worksheet($name = '') {
+        $ws = new MoodleODSWorksheet($name, $this->worksheets);
+        $this->worksheets[] = $ws;
         return $ws;
     }
 
-    /* Create one Moodle Format
+    /**
+     * Create one Moodle Format.
+     *
      * @param array $properties array of properties [name]=value;
      *                          valid names are set_XXXX existing
      *                          functions without the set_ part
      *                          i.e: [bold]=1 for set_bold(1)...Optional!
+     * @return MoodleODSFormat
      */
-    function &add_format($properties = array()) {
-        $format = new MoodleODSFormat($properties);
-        return $format;
+    public function add_format($properties = array()) {
+        return new MoodleODSFormat($properties);
     }
 
-    /* Close the Moodle Workbook
+    /**
+     * Close the Moodle Workbook.
      */
-    function close() {
-        global $CFG;
-        require_once($CFG->libdir.'/filelib.php');
-
-        $dir = 'ods/'.time();
-        make_temp_directory($dir);
-        make_temp_directory($dir.'/META-INF');
-        $dir = "$CFG->tempdir/$dir";
-        $files = array();
+    public function close() {
+        $writer = new MoodleODSWriter($this->worksheets);
+        $contents = $writer->get_file_content();
 
-        $handle = fopen("$dir/mimetype", 'w');
-        fwrite($handle, get_ods_mimetype());
-        $files[] = "$dir/mimetype";
-
-        $handle = fopen("$dir/content.xml", 'w');
-        fwrite($handle, get_ods_content($this->worksheets));
-        $files[] = "$dir/content.xml";
-
-        $handle = fopen("$dir/meta.xml", 'w');
-        fwrite($handle, get_ods_meta());
-        $files[] = "$dir/meta.xml";
-
-        $handle = fopen("$dir/styles.xml", 'w');
-        fwrite($handle, get_ods_styles());
-        $files[] = "$dir/styles.xml";
-
-        $handle = fopen("$dir/META-INF/manifest.xml", 'w');
-        fwrite($handle, get_ods_manifest());
-        $files[] = "$dir/META-INF";
-
-        $filename = "$dir/result.ods";
-        zip_files($files, $filename);
-
-        $handle = fopen($filename, 'rb');
-        $contents = fread($handle, filesize($filename));
-        fclose($handle);
-
-        remove_dir($dir); // cleanup the temp directory
-
-        send_file($contents, $this->filename, 0, 0, true, true, 'application/vnd.oasis.opendocument.spreadsheet');
+        send_file($contents, $this->filename, 0, 0, true, true, $writer->get_ods_mimetype());
     }
 
-    /* Not required to use
-     * @param string $name Name of the downloaded file
+    /**
+     * Not required to use.
+     * @param string $filename Name of the downloaded file
      */
-    function send($filename) {
+    public function send($filename) {
         $this->filename = $filename;
     }
 
 }
 
+
 /**
+ * ODS Cell abstraction.
  *
- * @package   moodlecore
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @package   core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class MoodleODSWorksheet {
-    var $data = array();
-    var $columns = array();
-    var $rows = array();
-    var $name;
+class MoodleODSCell {
+    public $value;
+    public $type;
+    public $format;
+    public $formula;
+}
 
 
-    /* Constructs one Moodle Worksheet.
-     * @param string $filename The name of the file
+/**
+ * ODS Worksheet abstraction.
+ *
+ * @package   core
+ * @copyright 2006 Petr Skoda {@link http://skodak.org}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class MoodleODSWorksheet {
+    public $data = array();
+    public $columns = array();
+    public $rows = array();
+    public $showgrid = true;
+    public $name;
+
+    /**
+     * Constructs one Moodle Worksheet.
+     *
+     * @param string $name The name of the file
+     * @param array $worksheets existing worksheets
      */
-    function MoodleODSWorksheet($name) {
+    public function __construct($name, array $worksheets) {
+        // Replace any characters in the name that Excel cannot cope with.
+        $name = strtr($name, '[]*/\?:', '       ');
+
+        if ($name === '') {
+            // Name is required!
+            $name = 'Sheet'.(count($worksheets)+1);
+        }
+
         $this->name = $name;
     }
 
-    /* Write one string somewhere in the worksheet
+    /**
+     * Write one string somewhere in the worksheet.
+     *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $str    The string to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_string($row, $col, $str, $format=0) {
-        if (!array_key_exists($row, $this->data)) {
-            $this->data[$row] = array();
+    public function write_string($row, $col, $str, $format = null) {
+        if (!isset($this->data[$row][$col])) {
+            $this->data[$row][$col] = new MoodleODSCell();
+        }
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
         }
-        $this->data[$row][$col] = new stdClass();
         $this->data[$row][$col]->value = $str;
         $this->data[$row][$col]->type = 'string';
         $this->data[$row][$col]->format = $format;
+        $this->data[$row][$col]->formula = null;
     }
 
-    /* Write one number somewhere in the worksheet
+    /**
+     * Write one number somewhere in the worksheet.
+     *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param float   $num    The number to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_number($row, $col, $num, $format=0) {
-        if (!array_key_exists($row, $this->data)) {
-            $this->data[$row] = array();
+    public function write_number($row, $col, $num, $format = null) {
+        if (!isset($this->data[$row][$col])) {
+            $this->data[$row][$col] = new MoodleODSCell();
+        }
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
         }
-        $this->data[$row][$col] = new stdClass();
         $this->data[$row][$col]->value = $num;
         $this->data[$row][$col]->type = 'float';
         $this->data[$row][$col]->format = $format;
+        $this->data[$row][$col]->formula = null;
     }
 
-    /* Write one url somewhere in the worksheet
+    /**
+     * Write one url somewhere in the worksheet.
+     *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $url    The url to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_url($row, $col, $url, $format=0) {
-        if (!array_key_exists($row, $this->data)) {
-            $this->data[$row] = array();
+    public function write_url($row, $col, $url, $format = null) {
+        if (!isset($this->data[$row][$col])) {
+            $this->data[$row][$col] = new MoodleODSCell();
+        }
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
         }
-        $this->data[$row][$col] = new stdClass();
         $this->data[$row][$col]->value = $url;
         $this->data[$row][$col]->type = 'string';
         $this->data[$row][$col]->format = $format;
+        $this->data[$row][$col]->formula = null;
     }
 
-    /* Write one date somewhere in the worksheet
+    /**
+     * Write one date somewhere in the worksheet.
+     *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
-     * @param string  $url    The url to write
+     * @param string  $date    The url to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_date($row, $col, $date, $format=0) {
-        if (!array_key_exists($row, $this->data)) {
-            $this->data[$row] = array();
+    public function write_date($row, $col, $date, $format = null) {
+        if (!isset($this->data[$row][$col])) {
+            $this->data[$row][$col] = new MoodleODSCell();
+        }
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
         }
-        $this->data[$row][$col] = new stdClass();
         $this->data[$row][$col]->value = $date;
         $this->data[$row][$col]->type = 'date';
         $this->data[$row][$col]->format = $format;
+        $this->data[$row][$col]->formula = null;
     }
 
     /**
-     * Write one formula somewhere in the worksheet
+     * Write one formula somewhere in the worksheet.
      *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param string  $formula The formula to write
      * @param mixed   $format The XF format for the cell
      */
-    function write_formula($row, $col, $formula, $format=null) {
-        // not implement
+    public function write_formula($row, $col, $formula, $format = null) {
+        if (!isset($this->data[$row][$col])) {
+            $this->data[$row][$col] = new MoodleODSCell();
+        }
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
+        }
+        $this->data[$row][$col]->formula = $formula;
+        $this->data[$row][$col]->format = $format;
+        $this->data[$row][$col]->value = null;
+        $this->data[$row][$col]->format = null;
     }
 
-    /* Write one blanck somewhere in the worksheet
+    /**
+     * Write one blank somewhere in the worksheet.
+     *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param mixed   $format The XF format for the cell
      */
-    function write_blank($row, $col, $format=0) {
-        if (array_key_exists($row, $this->data)) {
-            unset($this->data[$row][$col]);
+    public function write_blank($row, $col, $format = null) {
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
         }
+        $this->write_string($row, $col, '', $format);
     }
 
-    /* Write anything somewhere in the worksheet
-     * Type will be automatically detected
+    /**
+     * Write anything somewhere in the worksheet,
+     * type will be automatically detected.
+     *
      * @param integer $row    Zero indexed row
      * @param integer $col    Zero indexed column
      * @param mixed   $token  What we are writing
      * @param mixed   $format The XF format for the cell
      */
-    function write($row, $col, $token, $format=0) {
-
-    /// Analyse what are we trying to send
+    public function write($row, $col, $token, $format = null) {
+        // Analyse what are we trying to send.
         if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
-        /// Match number
+            // Match number
             return $this->write_number($row, $col, $token, $format);
         } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
-        /// Match http or ftp URL
+            // Match http or ftp URL
             return $this->write_url($row, $col, $token, '', $format);
         } elseif (preg_match("/^mailto:/", $token)) {
-        /// Match mailto:
+            // Match mailto:
             return $this->write_url($row, $col, $token, '', $format);
         } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
-        /// Match internal or external sheet link
+            // Match internal or external sheet link
             return $this->write_url($row, $col, $token, '', $format);
         } elseif (preg_match("/^=/", $token)) {
-        /// Match formula
+            // Match formula
             return $this->write_formula($row, $col, $token, $format);
         } elseif (preg_match("/^@/", $token)) {
-        /// Match formula
+            // Match formula
             return $this->write_formula($row, $col, $token, $format);
         } elseif ($token == '') {
-        /// Match blank
+            // Match blank
             return $this->write_blank($row, $col, $format);
         } else {
-        /// Default: match string
+            // Default: match string
             return $this->write_string($row, $col, $token, $format);
         }
     }
 
-    /* Sets the height (and other settings) of one row
+    /**
+     * Sets the height (and other settings) of one row.
+     *
      * @param integer $row    The row to set
-     * @param integer $height Height we are giving to the row (null to set just format withouth setting the height)
-     * @param mixed   $format The optional XF format we are giving to the row
+     * @param integer $height Height we are giving to the row (null to set just format without setting the height)
+     * @param mixed   $format The optional format we are giving to the row
      * @param bool    $hidden The optional hidden attribute
      * @param integer $level  The optional outline level (0-7)
      */
-    function set_row($row, $height, $format = 0, $hidden = false, $level = 0) {
-        $this->rows[$row] = new stdClass();
-        $this->rows[$row]->height = $height;
-        //$this->rows[$row]->format = $format; // TODO: fix and enable
+    public function set_row($row, $height, $format = null, $hidden = false, $level = 0) {
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
+        }
+        if ($level < 0) {
+            $level = 0;
+        } else if ($level > 7) {
+            $level = 7;
+        }
+        if (!isset($this->rows[$row])) {
+            $this->rows[$row] = new stdClass();
+        }
+        if (isset($height)) {
+            $this->rows[$row]->height = $height;
+        }
+        $this->rows[$row]->format = $format;
         $this->rows[$row]->hidden = $hidden;
+        $this->rows[$row]->level  = $level;
     }
 
-    /* Sets the width (and other settings) of one column
+    /**
+     * Sets the width (and other settings) of one column.
+     *
      * @param integer $firstcol first column on the range
      * @param integer $lastcol  last column on the range
-     * @param integer $width    width to set
-     * @param mixed   $format   The optional XF format to apply to the columns
-     * @param integer $hidden   The optional hidden atribute
+     * @param integer $width    width to set (null to set just format without setting the width)
+     * @param mixed   $format   The optional format to apply to the columns
+     * @param bool    $hidden   The optional hidden attribute
      * @param integer $level    The optional outline level (0-7)
      */
-    function set_column($firstcol, $lastcol, $width, $format = 0, $hidden = false, $level = 0) {
+    public function set_column($firstcol, $lastcol, $width, $format = null, $hidden = false, $level = 0) {
+        if (is_array($format)) {
+            $format = new MoodleODSFormat($format);
+        }
+        if ($level < 0) {
+            $level = 0;
+        } else if ($level > 7) {
+            $level = 7;
+        }
         for($i=$firstcol; $i<=$lastcol; $i++) {
-            $this->columns[$i] = new stdClass();
-            $this->columns[$i]->width = $width;
-            //$this->columns[$i]->format = $format; // TODO: fix and enable
+            if (!isset($this->columns[$i])) {
+                $this->columns[$i] = new stdClass();
+            }
+            if (isset($width)) {
+                $this->columns[$i]->width = $width*6.15; // 6.15 is a magic constant here!
+            }
+            $this->columns[$i]->format = $format;
             $this->columns[$i]->hidden = $hidden;
-
+            $this->columns[$i]->level  = $level;
         }
     }
 
     /**
-    * Set the option to hide gridlines on the printed page.
-    *
-    * @access public
-    */
-    function hide_gridlines() {
-        // not implement
+     * Set the option to hide gridlines on the printed page.
+     */
+    public function hide_gridlines() {
+        // Not implemented - always off.
     }
 
     /**
-    * Set the option to hide gridlines on the worksheet (as seen on the screen).
-    *
-    * @access public
-    */
-    function hide_screen_gridlines() {
-        // not implement
+     * Set the option to hide gridlines on the worksheet (as seen on the screen).
+     */
+    public function hide_screen_gridlines() {
+        $this->showgrid = false;
     }
 
     /**
-    * Insert a 24bit bitmap image in a worksheet.
-    *
-    * @access public
-    * @param integer $row     The row we are going to insert the bitmap into
-    * @param integer $col     The column we are going to insert the bitmap into
-    * @param string  $bitmap  The bitmap filename
-    * @param integer $x       The horizontal position (offset) of the image inside the cell.
-    * @param integer $y       The vertical position (offset) of the image inside the cell.
-    * @param integer $scale_x The horizontal scale
-    * @param integer $scale_y The vertical scale
-    */
-    function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
-        // not implement
+     * Insert a 24bit bitmap image in a worksheet.
+     *
+     * @param integer $row     The row we are going to insert the bitmap into
+     * @param integer $col     The column we are going to insert the bitmap into
+     * @param string  $bitmap  The bitmap filename
+     * @param integer $x       The horizontal position (offset) of the image inside the cell.
+     * @param integer $y       The vertical position (offset) of the image inside the cell.
+     * @param integer $scale_x The horizontal scale
+     * @param integer $scale_y The vertical scale
+     */
+    public function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
+        // Not implemented.
     }
+
     /**
-    * Merges the area given by its arguments.
-    * merging than the normal setAlign('merge').
-    *
-    * @access public
-    * @param integer $first_row First row of the area to merge
-    * @param integer $first_col First column of the area to merge
-    * @param integer $last_row  Last row of the area to merge
-    * @param integer $last_col  Last column of the area to merge
-    */
-    function merge_cells($first_row, $first_col, $last_row, $last_col) {
-        // not implement
+     * Merges the area given by its arguments.
+     *
+     * @param integer $first_row First row of the area to merge
+     * @param integer $first_col First column of the area to merge
+     * @param integer $last_row  Last row of the area to merge
+     * @param integer $last_col  Last column of the area to merge
+     */
+    public function merge_cells($first_row, $first_col, $last_row, $last_col) {
+        if ($first_row > $last_row or $first_col > $last_col) {
+            return;
+        }
+
+        if (!isset($this->data[$first_row][$first_col])) {
+            $this->data[$first_row][$first_col] = new MoodleODSCell();
+        }
+
+        $this->data[$first_row][$first_col]->merge = array('rows'=>($last_row-$first_row+1), 'columns'=>($last_col-$first_col+1));
     }
 }
+
+
 /**
- * Define and operate over one Format.
+ * ODS cell format abstraction.
  *
- * @package   moodlecore
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @package   core
+ * @copyright 2006 Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class MoodleODSFormat {
-    var $id;
-    var $properties;
+    public $id;
+    public $properties = array();
 
-    /* Constructs one Moodle Format.
-     * @param object $workbook The internal PEAR Workbook onject we are creating
+    /**
+     * Constructs one Moodle Format.
+     *
+     * @param array $properties
      */
-    function MoodleODSFormat($properties = array()) {
+    public function __construct($properties = array()) {
         static $fid = 1;
 
         $this->id = $fid++;
 
         foreach($properties as $property => $value) {
-            if(method_exists($this,"set_$property")) {
+            if (method_exists($this, "set_$property")) {
                 $aux = 'set_'.$property;
                 $this->$aux($value);
             }
         }
     }
 
-    /* Set weight of the format
+    /**
+     * Set the size of the text in the format (in pixels).
+     * By default all texts in generated sheets are 10pt.
+     *
+     * @param integer $size Size of the text (in points)
+     */
+    public function set_size($size) {
+        $this->properties['size'] = $size;
+    }
+
+    /**
+     * Set weight of the format.
+     *
      * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
      *                        1 maps to 700 (bold text). Valid range is: 100-1000.
      *                        It's Optional, default is 1 (bold).
      */
-    function set_bold($weight = 1) {
-        $this->properties['bold'] = $weight;
+    public function set_bold($weight = 1) {
+        if ($weight == 1) {
+            $weight = 700;
+        }
+        $this->properties['bold'] = ($weight > 400);
     }
 
-    /* Set underline of the format
+    /**
+     * Set underline of the format.
+     *
      * @param integer $underline The value for underline. Possible values are:
      *                           1 => underline, 2 => double underline
      */
-    function set_underline($underline = 1) {
-        $this->properties['underline'] = $underline;
+    public function set_underline($underline = 1) {
+        if ($underline == 1) {
+            $this->properties['underline'] = 1;
+        } else if ($underline == 2) {
+            $this->properties['underline'] = 2;
+        } else {
+            unset($this->properties['underline']);
+        }
     }
 
-    /* Set italic of the format
+    /**
+     * Set italic of the format.
      */
-    function set_italic() {
+    public function set_italic() {
         $this->properties['italic'] = true;
     }
 
-    /* Set strikeout of the format
+    /**
+     * Set strikeout of the format
      */
-    function set_strikeout() {
+    public function set_strikeout() {
         $this->properties['strikeout'] = true;
     }
 
-    /* Set outlining of the format
+    /**
+     * Set outlining of the format.
      */
-    function set_outline() {
+    public function set_outline() {
+        // Not implemented.
     }
 
-    /* Set shadow of the format
+    /**
+     * Set shadow of the format.
      */
-    function set_shadow() {
+    public function set_shadow() {
+        // Not implemented.
     }
 
-    /* Set the script of the text
+    /**
+     * Set the script of the text.
+     *
      * @param integer $script The value for script type. Possible values are:
      *                        1 => superscript, 2 => subscript
      */
-    function set_script($script) {
+    public function set_script($script) {
+        if ($script == 1) {
+            $this->properties['super_script'] = true;
+            unset($this->properties['sub_script']);
+
+        } else if ($script == 2) {
+            $this->properties['sub_script'] = true;
+            unset($this->properties['super_script']);
+
+        } else {
+            unset($this->properties['sub_script']);
+            unset($this->properties['super_script']);
+        }
     }
 
-    /* Set color of the format
+    /**
+     * Set color of the format.
+     *
      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
      */
-    function set_color($color) {
-        $this->properties['color'] = $this->_get_color($color);
+    public function set_color($color) {
+        $this->properties['color'] = $this->parse_color($color);
     }
 
-    /* Set foreground color of the format
-     * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
+    /**
+     * Not used.
+     *
+     * @param mixed $color
      */
-    function set_fg_color($color) {
+    public function set_fg_color($color) {
+        // Not implemented.
     }
 
-    /* Set background color of the format
+    /**
+     * Set background color of the cell.
+     *
      * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
      */
-    function set_bg_color($color) {
-        $this->properties['bg_color'] = $this->_get_color($color);
+    public function set_bg_color($color) {
+        $this->properties['bg_color'] = $this->parse_color($color);
+    }
+
+    /**
+     * Set the cell fill pattern.
+     *
+     * @deprecated use set_bg_color() instead.
+     * @param integer
+     */
+    public function set_pattern($pattern=1) {
+        if ($pattern > 0) {
+            if (!isset($this->properties['bg_color'])) {
+                $this->properties['bg_color'] = $this->parse_color('black');
+            }
+        } else {
+            unset($this->properties['bg_color']);
+        }
+
     }
 
-    /* Set the fill pattern of the format
-     * @param integer Optional. Defaults to 1. Meaningful values are: 0-18
-     *                0 meaning no background.
+    /**
+     * Set text wrap of the format
      */
-    function set_pattern($pattern=1) {
+    public function set_text_wrap() {
+        $this->properties['wrap'] = true;
     }
 
-    /* Set text wrap of the format
+    /**
+     * Set the cell alignment of the format.
+     *
+     * @param string $location alignment for the cell ('left', 'right', 'justify', etc...)
      */
-    function set_text_wrap() {
+    public function set_align($location) {
+        if (in_array($location, array('left', 'centre', 'center', 'right', 'fill', 'merge', 'justify', 'equal_space'))) {
+            $this->set_h_align($location);
+
+        } else if (in_array($location, array('top', 'vcentre', 'vcenter', 'bottom', 'vjustify', 'vequal_space'))) {
+            $this->set_v_align($location);
+        }
     }
 
-    /* Set the cell alignment of the format
-     * @param string $location alignment for the cell ('left', 'right', etc...)
+    /**
+     * Set the cell horizontal alignment of the format.
+     *
+     * @param string $location alignment for the cell ('left', 'right', 'justify', etc...)
      */
-    function set_align($location) {
+    public function set_h_align($location) {
         switch ($location) {
-            case 'start':
             case 'left':
                 $this->properties['align'] = 'start';
                 break;
             case 'center':
-                $this->properties['align'] = 'center';
+            case 'centre':
+            $this->properties['align'] = 'center';
                 break;
-            case 'end':
             case 'right':
                 $this->properties['align'] = 'end';
                 break;
-            default:
-                //ignore the rest == start
         }
     }
 
-    /* Set the cell horizontal alignment of the format
-     * @param string $location alignment for the cell ('left', 'right', etc...)
-     */
-    function set_h_align($location) {
-        $this->set_align($location);
-    }
-
-    /* Set the cell vertical alignment of the format
-     * @param string $location alignment for the cell ('top', 'vleft', etc...)
+    /**
+     * Set the cell vertical alignment of the format.
+     *
+     * @param string $location alignment for the cell ('top', 'bottom', 'center', 'justify')
      */
-    function set_v_align($location) {
+    public function set_v_align($location) {
         switch ($location) {
             case 'top':
                 $this->properties['v_align'] = 'top';
                 break;
-            case 'bottom':
-                $this->properties['v_align'] = 'bottom';
+            case 'vcentre':
+            case 'vcenter':
+            case 'centre':
+            case 'center':
+                $this->properties['v_align'] = 'middle';
                 break;
             default:
-                //ignore the rest == middle
+                $this->properties['v_align'] = 'bottom';
         }
     }
 
-    /* Set the top border of the format
+    /**
+     * Set the top border of the format.
+     *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_top($style) {
+    public function set_top($style) {
+        if ($style == 1) {
+            $style = 0.2;
+        } else if ($style == 2) {
+            $style = 0.5;
+        } else {
+            return;
+        }
+        $this->properties['border_top'] = $style;
     }
 
-    /* Set the bottom border of the format
+    /**
+     * Set the bottom border of the format.
+     *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_bottom($style) {
+    public function set_bottom($style) {
+        if ($style == 1) {
+            $style = 0.2;
+        } else if ($style == 2) {
+            $style = 0.5;
+        } else {
+            return;
+        }
+        $this->properties['border_bottom'] = $style;
     }
 
-    /* Set the left border of the format
+    /**
+     * Set the left border of the format.
+     *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_left($style) {
+    public function set_left($style) {
+        if ($style == 1) {
+            $style = 0.2;
+        } else if ($style == 2) {
+            $style = 0.5;
+        } else {
+            return;
+        }
+        $this->properties['border_left'] = $style;
     }
 
-    /* Set the right border of the format
+    /**
+     * Set the right border of the format.
+     *
      * @param integer $style style for the cell. 1 => thin, 2 => thick
      */
-    function set_right($style) {
+    public function set_right($style) {
+        if ($style == 1) {
+            $style = 0.2;
+        } else if ($style == 2) {
+            $style = 0.5;
+        } else {
+            return;
+        }
+        $this->properties['border_right'] = $style;
     }
 
     /**
      * Set cells borders to the same style
      * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
      */
-    function set_border($style) {
+    public function set_border($style) {
+        $this->set_top($style);
+        $this->set_bottom($style);
+        $this->set_left($style);
+        $this->set_right($style);
     }
 
-    /* Set the numerical format of the format
-     * It can be date, time, currency, etc...
-    /* Set the numerical format of the format
+    /**
+     * Set the numerical format of the format.
      * It can be date, time, currency, etc...
-     * @param integer $num_format The numeric format
-     */
-    function set_num_format($num_format) {
-    }
-
-    function _get_color($name_color = '') {
-        if (strpos($name_color, '#') === 0) {
-            return $name_color; // no conversion needed
-        }
-
-        $colors = array('aqua'    => '#00FFFF',
-                        'cyan'    => '#00FFFF',
-                        'black'   => '#FFFFFF',
-                        'blue'    => '#0000FF',
-                        'brown'   => '#A52A2A',
-                        'magenta' => '#FF00FF',
-                        'fuchsia' => '#FF00FF',
-                        'gray'    => '#A0A0A0',
-                        'grey'    => '#A0A0A0',
-                        'green'   => '#00FF00',
-                        'lime'    => '#00FF00',
-                        'navy'    => '#000080',
-                        'orange'  => '#FF8000',
-                        'purple'  => '#800080',
-                        'red'     => '#FF0000',
-                        'silver'  => '#DCDCDC',
-                        'white'   => '#FFFFFF',
-                        'yellow'  => '#FFFF00');
-
-        if(array_key_exists($name_color, $colors)) {
-            return $colors[$name_color];
-        } else {
-            return false;
+     *
+     * @param mixed $num_format The numeric format
+     */
+    public function set_num_format($num_format) {
+
+        $numbers = array();
+
+        $numbers[1] = '0';
+        $numbers[2] = '0.00';
+        $numbers[3] = '#,##0';
+        $numbers[4] = '#,##0.00';
+        $numbers[11] = '0.00E+00';
+        $numbers[12] = '# ?/?';
+        $numbers[13] = '# ??/??';
+        $numbers[14] = 'mm-dd-yy';
+        $numbers[15] = 'd-mmm-yy';
+        $numbers[16] = 'd-mmm';
+        $numbers[17] = 'mmm-yy';
+        $numbers[22] = 'm/d/yy h:mm';
+        $numbers[49] = '@';
+
+        if ($num_format !== 0 and in_array($num_format, $numbers)) {
+            $flipped = array_flip($numbers);
+            $this->properties['num_format'] = $flipped[$num_format];
+        }
+        if (!isset($numbers[$num_format])) {
+            return;
+        }
+
+        $this->properties['num_format'] = $num_format;
+    }
+
+    /**
+     * Standardise colour name.
+     *
+     * @param mixed $color name of the color (i.e.: 'blue', 'red', etc..), or an integer (range is [8...63]).
+     * @return string the RGB color value
+     */
+    protected function parse_color($color) {
+        if (strpos($color, '#') === 0) {
+            // No conversion should be needed.
+            return $color;
+        }
+
+        if ($color > 7 and $color < 53) {
+            $numbers = array(
+                8  => 'black',
+                12 => 'blue',
+                16 => 'brown',
+                15 => 'cyan',
+                23 => 'gray',
+                17 => 'green',
+                11 => 'lime',
+                14 => 'magenta',
+                18 => 'navy',
+                53 => 'orange',
+                33 => 'pink',
+                20 => 'purple',
+                10 => 'red',
+                22 => 'silver',
+                9  => 'white',
+                13 => 'yellow',
+            );
+            if (isset($numbers[$color])) {
+                $color = $numbers[$color];
+            } else {
+                $color = 'black';
+            }
         }
+
+        $colors = array(
+            'aqua'    => '00FFFF',
+            'black'   => '000000',
+            'blue'    => '0000FF',
+            'brown'   => 'A52A2A',
+            'cyan'    => '00FFFF',
+            'fuchsia' => 'FF00FF',
+            'gray'    => '808080',
+            'grey'    => '808080',
+            'green'   => '00FF00',
+            'lime'    => '00FF00',
+            'magenta' => 'FF00FF',
+            'maroon'  => '800000',
+            'navy'    => '000080',
+            'orange'  => 'FFA500',
+            'olive'   => '808000',
+            'pink'    => 'FAAFBE',
+            'purple'  => '800080',
+            'red'     => 'FF0000',
+            'silver'  => 'C0C0C0',
+            'teal'    => '008080',
+            'white'   => 'FFFFFF',
+            'yellow'  => 'FFFF00',
+        );
+
+        if (isset($colors[$color])) {
+            return('#'.$colors[$color]);
+        }
+
+        return('#'.$colors['black']);
     }
 }
 
 
-//=============================
-// OpenDocument XML functions
-//=============================
-function get_ods_content(&$worksheets) {
+/**
+ * ODS file writer.
+ *
+ * @package   core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class MoodleODSWriter {
+    protected $worksheets;
 
+    public function __construct(array $worksheets) {
+        $this->worksheets = $worksheets;
+    }
 
-    // find out the size of worksheets and used styles
-    $formats = array();
-    $formatstyles = '';
-    $rowstyles = '';
-    $colstyles = '';
+    public function get_file_content() {
+        global $CFG;
 
-    foreach($worksheets as $wsnum=>$ws) {
-        $worksheets[$wsnum]->maxr = 0;
-        $worksheets[$wsnum]->maxc = 0;
-        foreach($ws->data as $rnum=>$row) {
-            if ($rnum > $worksheets[$wsnum]->maxr) {
-                $worksheets[$wsnum]->maxr = $rnum;
-            }
-            foreach($row as $cnum=>$cell) {
-                if ($cnum > $worksheets[$wsnum]->maxc) {
-                    $worksheets[$wsnum]->maxc = $cnum;
+        require_once($CFG->libdir.'/filelib.php');
+
+        do {
+            $dir = 'ods/'.time().'_'.rand(0, 10000);
+        } while (file_exists($CFG->tempdir.'/'.$dir));
+
+        make_temp_directory($dir);
+        make_temp_directory($dir.'/META-INF');
+        $dir = "$CFG->tempdir/$dir";
+        $files = array();
+
+        $handle = fopen("$dir/mimetype", 'w');
+        fwrite($handle, $this->get_ods_mimetype());
+        $files[] = "$dir/mimetype";
+
+        $handle = fopen("$dir/content.xml", 'w');
+        fwrite($handle, $this->get_ods_content($this->worksheets));
+        $files[] = "$dir/content.xml";
+
+        $handle = fopen("$dir/meta.xml", 'w');
+        fwrite($handle, $this->get_ods_meta());
+        $files[] = "$dir/meta.xml";
+
+        $handle = fopen("$dir/styles.xml", 'w');
+        fwrite($handle, $this->get_ods_styles());
+        $files[] = "$dir/styles.xml";
+
+        $handle = fopen("$dir/settings.xml", 'w');
+        fwrite($handle, $this->get_ods_settings());
+        $files[] = "$dir/settings.xml";
+
+        $handle = fopen("$dir/META-INF/manifest.xml", 'w');
+        fwrite($handle, $this->get_ods_manifest());
+        $files[] = "$dir/META-INF";
+
+        $filename = "$dir/result.ods";
+        zip_files($files, $filename);
+
+        $handle = fopen($filename, 'rb');
+        $contents = fread($handle, filesize($filename));
+        fclose($handle);
+
+        remove_dir($dir); // Cleanup the temp directory.
+
+        return $contents;
+    }
+
+    protected function get_ods_content() {
+
+        // Find out the size of worksheets and used styles.
+        $formats = array();
+        $formatstyles = '';
+        $rowstyles = '';
+        $colstyles = '';
+
+        foreach($this->worksheets as $wsnum=>$ws) {
+            $this->worksheets[$wsnum]->maxr = 0;
+            $this->worksheets[$wsnum]->maxc = 0;
+            foreach($ws->data as $rnum=>$row) {
+                if ($rnum > $this->worksheets[$wsnum]->maxr) {
+                    $this->worksheets[$wsnum]->maxr = $rnum;
                 }
-                if (!empty($cell->format)) {
-                    if (!array_key_exists($cell->format->id, $formats)) {
-                        $formats[$cell->format->id] = $cell->format;
+                foreach($row as $cnum=>$cell) {
+                    if ($cnum > $this->worksheets[$wsnum]->maxc) {
+                        $this->worksheets[$wsnum]->maxc = $cnum;
+                    }
+                    if (!empty($cell->format)) {
+                        if (!array_key_exists($cell->format->id, $formats)) {
+                            $formats[$cell->format->id] = $cell->format;
+                        }
                     }
                 }
             }
-        }
 
-        foreach($ws->rows as $rnum=>$row) {
-            if (!empty($row->format)) {
-                if (!array_key_exists($row->format->id, $formats)) {
-                    $formats[$row->format->id] = $row->format;
+            foreach($ws->rows as $rnum=>$row) {
+                if (!empty($row->format)) {
+                    if (!array_key_exists($row->format->id, $formats)) {
+                        $formats[$row->format->id] = $row->format;
+                    }
                 }
-            }
-            if ($rnum > $worksheets[$wsnum]->maxr) {
-                $worksheets[$wsnum]->maxr = $rnum;
-            }
-            //define all column styles
-            if (!empty($ws->rows[$rnum])) {
-                $rowstyles .= '
-  <style:style style:name="ws'.$wsnum.'ro'.$rnum.'" style:family="table-row">
-   <style:table-row-properties style:row-height="'.$row->height.'pt"/>
-  </style:style>';
-            }
-        }
-
-        foreach($ws->columns as $cnum=>$col) {
-            if (!empty($col->format)) {
-                if (!array_key_exists($col->format->id, $formats)) {
-                    $formats[$col->format->id] = $col->format;
+                if ($rnum > $this->worksheets[$wsnum]->maxr) {
+                    $this->worksheets[$wsnum]->maxr = $rnum;
+                }
+                // Define all column styles.
+                if (!empty($ws->rows[$rnum])) {
+                    $rowstyles .= '<style:style style:name="ws'.$wsnum.'ro'.$rnum.'" style:family="table-row">';
+                    if (isset($row->height)) {
+                        $rowstyles .= '<style:table-row-properties style:row-height="'.$row->height.'pt"/>';
+                    }
+                    $rowstyles .= '</style:style>';
                 }
             }
-            if ($cnum > $worksheets[$wsnum]->maxc) {
-                $worksheets[$wsnum]->maxc = $cnum;
-            }
-            //define all column styles
-            if (!empty($ws->columns[$cnum])) {
-                $colstyles .= '
-  <style:style style:name="ws'.$wsnum.'co'.$cnum.'" style:family="table-column">
-   <style:table-column-properties style:column-width="'.$col->width.'pt"/>
-  </style:style>';
-            }
-        }
-    }
 
-    foreach($formats as $format) {
-        $textprop = '';
-        $cellprop = '';
-        $parprop  = '';
-        foreach($format->properties as $pname=>$pvalue) {
-            switch ($pname) {
-                case 'bold':
-                    if (!empty($pvalue)) {
-                        $textprop .= ' fo:font-weight="bold"';
-                    }
-                    break;
-                case 'italic':
-                    if (!empty($pvalue)) {
-                        $textprop .= ' fo:font-style="italic"';
-                    }
-                    break;
-                case 'underline':
-                    if (!empty($pvalue)) {
-                        $textprop .= ' style:text-underline-color="font-color" style:text-underline-style="solid" style:text-underline-width="auto"';
+            foreach($ws->columns as $cnum=>$col) {
+                if (!empty($col->format)) {
+                    if (!array_key_exists($col->format->id, $formats)) {
+                        $formats[$col->format->id] = $col->format;
                     }
-                    break;
-                case 'strikeout':
-                    if (!empty($pvalue)) {
-                        $textprop .= ' style:text-line-through-style="solid"';
-                    }
-                    break;
-                case 'color':
-                    if ($pvalue !== false) {
-                        $textprop .= ' fo:color="'.$pvalue.'"';
-                    }
-                    break;
-                case 'bg_color':
-                    if ($pvalue !== false) {
-                        $cellprop .= ' fo:background-color="'.$pvalue.'"';
+                }
+                if ($cnum > $this->worksheets[$wsnum]->maxc) {
+                    $this->worksheets[$wsnum]->maxc = $cnum;
+                }
+                // Define all column styles.
+                if (!empty($ws->columns[$cnum])) {
+                    $colstyles .= '<style:style style:name="ws'.$wsnum.'co'.$cnum.'" style:family="table-column">';
+                    if (isset($col->width)) {
+                        $colstyles .= '<style:table-column-properties style:column-width="'.$col->width.'pt"/>';
                     }
-                    break;
-                case 'align':
-                    $parprop .= ' fo:text-align="'.$pvalue.'"';
-                    break;
-                case 'v_align':
-                    $cellprop .= ' style:vertical-align="'.$pvalue.'"';
-                    break;
+                    $colstyles .= '</style:style>';
+                }
             }
         }
-        if (!empty($textprop)) {
-            $textprop = '
+
+        foreach($formats as $format) {
+            $textprop = '';
+            $cellprop = '';
+            $parprop  = '';
+            $dataformat = '';
+            foreach($format->properties as $pname=>$pvalue) {
+                switch ($pname) {
+                    case 'size':
+                        if (!empty($pvalue)) {
+                            $textprop .= ' fo:font-size="'.$pvalue.'pt"';
+                        }
+                        break;
+                    case 'bold':
+                        if (!empty($pvalue)) {
+                            $textprop .= ' fo:font-weight="bold"';
+                        }
+                        break;
+                    case 'italic':
+                        if (!empty($pvalue)) {
+                            $textprop .= ' fo:font-style="italic"';
+                        }
+                        break;
+                    case 'underline':
+                        if (!empty($pvalue)) {
+                            $textprop .= ' style:text-underline-color="font-color" style:text-underline-style="solid" style:text-underline-width="auto"';
+                            if ($pvalue == 2) {
+                                $textprop .= ' style:text-underline-type="double"';
+                            }
+                        }
+                        break;
+                    case 'strikeout':
+                        if (!empty($pvalue)) {
+                            $textprop .= ' style:text-line-through-style="solid"';
+                        }
+                        break;
+                    case 'color':
+                        if ($pvalue !== false) {
+                            $textprop .= ' fo:color="'.$pvalue.'"';
+                        }
+                        break;
+                    case 'bg_color':
+                        if ($pvalue !== false) {
+                            $cellprop .= ' fo:background-color="'.$pvalue.'"';
+                        }
+                        break;
+                    case 'align':
+                        $parprop .= ' fo:text-align="'.$pvalue.'"';
+                        break;
+                    case 'v_align':
+                        $cellprop .= ' style:vertical-align="'.$pvalue.'"';
+                        break;
+                    case 'wrap':
+                        if ($pvalue) {
+                            $cellprop .= ' fo:wrap-option="wrap"';
+                        }
+                        break;
+                    case 'border_top':
+                        $cellprop .= ' fo:border-top="'.$pvalue.'pt solid #000000"';
+                        break;
+                    case 'border_left':
+                        $cellprop .= ' fo:border-left="'.$pvalue.'pt solid #000000"';
+                        break;
+                    case 'border_bottom':
+                        $cellprop .= ' fo:border-bottom="'.$pvalue.'pt solid #000000"';
+                        break;
+                    case 'border_right':
+                        $cellprop .= ' fo:border-right="'.$pvalue.'pt solid #000000"';
+                        break;
+                    case 'num_format':
+                        $dataformat = ' style:data-style-name="NUM'.$pvalue.'"';
+                        break;
+                }
+            }
+            if (!empty($textprop)) {
+                $textprop = '
    <style:text-properties'.$textprop.'/>';
-        }
+            }
 
-        if (!empty($cellprop)) {
-            $cellprop = '
+            if (!empty($cellprop)) {
+                $cellprop = '
    <style:table-cell-properties'.$cellprop.'/>';
-        }
+            }
 
-        if (!empty($parprop)) {
-            $parprop = '
+            if (!empty($parprop)) {
+                $parprop = '
    <style:paragraph-properties'.$parprop.'/>';
-        }
+            }
 
-        $formatstyles .= '
-  <style:style style:name="format'.$format->id.'" style:family="table-cell">'.$textprop.$cellprop.$parprop.'
+            $formatstyles .= '
+  <style:style style:name="format'.$format->id.'" style:family="table-cell"'.$dataformat.'>'.$textprop.$cellprop.$parprop.'
   </style:style>';
-    }
+        }
 
-/// header
-    $buffer =
-'<?xml version="1.0" encoding="UTF-8"?>
-<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink">
<office:automatic-styles>
-  <style:style style:name="ta1" style:family="table" style:master-page-name="Standard1">
-   <style:table-properties table:display="true"/>
+        // The text styles may be breaking older ODF validators.
+        $scriptstyles ='
+  <style:style style:name="T1" style:family="text">
+    <style:text-properties style:text-position="33% 58%"/>
 </style:style>
+  <style:style style:name="T2" style:family="text">
+    <style:text-properties style:text-position="-33% 58%"/>
   </style:style>
-  <style:style style:name="date0" style:family="table-cell"/>';
-
-$buffer .= $formatstyles;
-$buffer .= $rowstyles;
-$buffer .= $colstyles;
-
- $buffer .= '
- </office:automatic-styles>
- <office:body>
-  <office:spreadsheet>
+';
+        // Header.
+        $buffer =
+'<?xml version="1.0" encoding="UTF-8"?>
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+                         xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+                         xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+                         xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+                         xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+                         xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+                         xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/"
+                         xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
+                         xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
+                         xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+                         xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
+                         xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+                         xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+                         xmlns:math="http://www.w3.org/1998/Math/MathML"
+                         xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
+                         xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
+                         xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer"
+                         xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events"
+                         xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                         xmlns:rpt="http://openoffice.org/2005/report"
+                         xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
+                         xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#"
+                         xmlns:tableooo="http://openoffice.org/2009/table"
+                         xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
+                         xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"
+                         xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
+                         xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2">
+  <office:scripts/>
+  <office:font-face-decls>
+    <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss"
+                     style:font-pitch="variable"/>
+    <style:font-face style:name="Arial Unicode MS" svg:font-family="&apos;Arial Unicode MS&apos;"
+                     style:font-family-generic="system" style:font-pitch="variable"/>
+    <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system"
+                     style:font-pitch="variable"/>
+  </office:font-face-decls>
+  <office:automatic-styles>';
+        $buffer .= $this->get_num_styles();
+        $buffer .= '
+    <style:style style:name="ta1" style:family="table" style:master-page-name="Standard1">
+      <style:table-properties table:display="true"/>
+    </style:style>';
+
+        $buffer .= $formatstyles;
+        $buffer .= $rowstyles;
+        $buffer .= $colstyles;
+        $buffer .= $scriptstyles;
+
+         $buffer .= '
+  </office:automatic-styles>
+  <office:body>
+    <office:spreadsheet>
 ';
 
-    foreach($worksheets as $wsnum=>$ws) {
+        foreach($this->worksheets as $wsnum=>$ws) {
 
-    /// worksheet header
-        $buffer .= '<table:table table:name="' . htmlspecialchars($ws->name) . '" table:style-name="ta1">'."\n";
+            // Worksheet header.
+            $buffer .= '<table:table table:name="' . htmlspecialchars($ws->name, ENT_QUOTES, 'utf-8') . '" table:style-name="ta1">'."\n";
 
-        // define column properties
-        for($c=0; $c<=$ws->maxc; $c++) {
-            if (array_key_exists($c, $ws->columns)) {
-                $extra = '';
-                if (!empty($ws->columns[$c]->format)) {
-                    $extra .= ' table:default-cell-style-name="format'.$ws->columns[$c]->format->id.'"';
-                }
-                if ($ws->columns[$c]->hidden) {
-                    $extra .= ' table:visibility="collapse"';
+            // Define column properties.
+            $level = 0;
+            for($c=0; $c<=$ws->maxc; $c++) {
+                if (array_key_exists($c, $ws->columns)) {
+                    $column = $ws->columns[$c];
+                    if ($column->level > $level) {
+                        while ($column->level > $level) {
+                            $buffer .= '<table:table-column-group>';
+                            $level++;
+                        }
+                    } else if ($column->level < $level) {
+                        while ($column->level < $level) {
+                            $buffer .= '</table:table-column-group>';
+                            $level--;
+                        }
+                    }
+                    $extra = '';
+                    if (!empty($column->format)) {
+                        $extra .= ' table:default-cell-style-name="format'.$column->format->id.'"';
+                    }
+                    if ($column->hidden) {
+                        $extra .= ' table:visibility="collapse"';
+                    }
+                    $buffer .= '<table:table-column table:style-name="ws'.$wsnum.'co'.$c.'"'.$extra.'/>'."\n";
+                } else {
+                    while ($level > 0) {
+                        $buffer .= '</table:table-column-group>';
+                        $level--;
+                    }
+                    $buffer .= '<table:table-column/>'."\n";
                 }
-                $buffer .= '<table:table-column table:style-name="ws'.$wsnum.'co'.$c.'"'.$extra.'/>'."\n";
-            } else {
-                $buffer .= '<table:table-column/>'."\n";
             }
-        }
-
-        // print all rows
-        for($r=0; $r<=$ws->maxr; $r++) {
-            if (array_key_exists($r, $ws->rows)) {
-                $extra = '';
-                if (!empty($ws->rows[$r]->format)) {
-                    $extra .= ' table:default-cell-style-name="format'.$ws->rows[$r]->format->id.'"';
-                }
-                if ($ws->rows[$r]->hidden) {
-                    $extra .= ' table:visibility="collapse"';
-                }
-                $buffer .= '<table:table-row table:style-name="ws'.$wsnum.'ro'.$r.'"'.$extra.'>'."\n";
-            } else {
-                $buffer .= '<table:table-row>'."\n";
+            while ($level > 0) {
+                $buffer .= '</table:table-column-group>';
+                $level--;
             }
-            for($c=0; $c<=$ws->maxc; $c++) {
-                if (isset($ws->data[$r][$c])) {
-                    $cell = $ws->data[$r][$c];
-                    $extra = ' ';
-                    if (!empty($cell->format)) {
-                        $extra = ' table:style-name="format'.$cell->format->id.'"';
+
+            // Print all rows.
+            $level = 0;
+            for($r=0; $r<=$ws->maxr; $r++) {
+                if (array_key_exists($r, $ws->rows)) {
+                    $row = $ws->rows[$r];
+                    if ($row->level > $level) {
+                        while ($row->level > $level) {
+                            $buffer .= '<table:table-row-group>';
+                            $level++;
+                        }
+                    } else if ($row->level < $level) {
+                        while ($row->level < $level) {
+                            $buffer .= '</table:table-row-group>';
+                            $level--;
+                        }
                     }
-                    if ($cell->type == 'date') {
-                        $buffer .= '<table:table-cell office:value-type="date" table:style-name="date0" office:date-value="' . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . '"'.$extra.'>'
-                                 . '<text:p>' . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . '</text:p>'
-                                 . '</table:table-cell>'."\n";
-                    } else if ($cell->type == 'float') {
-                        $buffer .= '<table:table-cell office:value-type="float" office:value="' . htmlspecialchars($cell->value) . '"'.$extra.'>'
-                                 . '<text:p>' . htmlspecialchars($cell->value) . '</text:p>'
-                                 . '</table:table-cell>'."\n";
-                    } else if ($cell->type == 'string') {
-                        $buffer .= '<table:table-cell office:value-type="string" office:string-value="' . htmlspecialchars($cell->value) . '"'.$extra.'>'
-                                 . '<text:p>' . htmlspecialchars($cell->value) . '</text:p>'
-                                 . '</table:table-cell>'."\n";
-                    } else {
-                        $buffer .= '<table:table-cell office:value-type="string"'.$extra.'>'
-                                 . '<text:p>!!Error - unknown type!!</text:p>'
-                                 . '</table:table-cell>'."\n";
+                    $extra = '';
+                    if (!empty($row->format)) {
+                        $extra .= ' table:default-cell-style-name="format'.$row->format->id.'"';
+                    }
+                    if ($row->hidden) {
+                        $extra .= ' table:visibility="collapse"';
                     }
+                    $buffer .= '<table:table-row table:style-name="ws'.$wsnum.'ro'.$r.'"'.$extra.'>'."\n";
                 } else {
-                    $buffer .= '<table:table-cell/>'."\n";
+                    while ($level > 0) {
+                        $buffer .= '</table:table-row-group>';
+                        $level--;
+                    }
+                    $buffer .= '<table:table-row>'."\n";
                 }
+                for($c=0; $c<=$ws->maxc; $c++) {
+                    if (isset($ws->data[$r][$c])) {
+                        $cell = $ws->data[$r][$c];
+                        $extra = '';
+                        if (!empty($cell->format)) {
+                            $extra .= ' table:style-name="format'.$cell->format->id.'"';
+                        }
+                        if (!empty($cell->merge)) {
+                            $extra .= ' table:number-columns-spanned="'.$cell->merge['columns'].'" table:number-rows-spanned="'.$cell->merge['rows'].'"';
+                        }
+                        $pretext = '<text:p>';
+                        $posttext = '</text:p>';
+                        if (!empty($cell->format->properties['sub_script'])) {
+                            $pretext = $pretext.'<text:span text:style-name="T2">';
+                            $posttext = '</text:span>'.$posttext;
+                        } else if (!empty($cell->format->properties['super_script'])) {
+                            $pretext = $pretext.'<text:span text:style-name="T1">';
+                            $posttext = '</text:span>'.$posttext;
+                        }
+
+                        if (isset($cell->formula)) {
+                            $buffer .= '<table:table-cell table:formula="of:'.$cell->formula.'"'.$extra.'></table:table-cell>'."\n";
+                        } else if ($cell->type == 'date') {
+                            $buffer .= '<table:table-cell office:value-type="date" office:date-value="' . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . '"'.$extra.'>'
+                                     . $pretext . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . $posttext
+                                     . '</table:table-cell>'."\n";
+                        } else if ($cell->type == 'float') {
+                            $buffer .= '<table:table-cell office:value-type="float" office:value="' . htmlspecialchars($cell->value, ENT_QUOTES, 'utf-8') . '"'.$extra.'>'
+                                     . $pretext . htmlspecialchars($cell->value, ENT_QUOTES, 'utf-8') . $posttext
+                                     . '</table:table-cell>'."\n";
+                        } else if ($cell->type == 'string') {
+                            $buffer .= '<table:table-cell office:value-type="string"'.$extra.'>'
+                                     . $pretext . htmlspecialchars($cell->value, ENT_QUOTES, 'utf-8') . $posttext
+                                     . '</table:table-cell>'."\n";
+                        } else {
+                            $buffer .= '<table:table-cell office:value-type="string"'.$extra.'>'
+                                     . $pretext . '!!Error - unknown type!!' . $posttext
+                                     . '</table:table-cell>'."\n";
+                        }
+                    } else {
+                        $buffer .= '<table:table-cell/>'."\n";
+                    }
+                }
+                $buffer .= '</table:table-row>'."\n";
             }
-            $buffer .= '</table:table-row>'."\n";
-        }
-    /// worksheet footer
-        $buffer .= '</table:table>'."\n";
+            while ($level > 0) {
+                $buffer .= '</table:table-row-group>';
+                $level--;
+            }
+            $buffer .= '</table:table>'."\n";
 
-    }
+        }
 
-/// footer
-    $buffer .=
-'  </office:spreadsheet>
- </office:body>
+        // Footer.
+        $buffer .= '
+    </office:spreadsheet>
 </office:body>
 </office:document-content>';
 
-    return $buffer;
-}
+        return $buffer;
+    }
 
-function get_ods_mimetype() {
-    return 'application/vnd.oasis.opendocument.spreadsheet';
-}
+    public function get_ods_mimetype() {
+        return 'application/vnd.oasis.opendocument.spreadsheet';
+    }
 
-function get_ods_meta() {
-    global $CFG, $USER;
+    protected function get_ods_settings() {
+        $buffer =
+'<?xml version="1.0" encoding="UTF-8"?>
+<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+                          xmlns:xlink="http://www.w3.org/1999/xlink"
+                          xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"
+                          xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2">
+    <office:settings>
+      <config:config-item-set config:name="ooo:view-settings">
+        <config:config-item config:name="VisibleAreaTop" config:type="int">0</config:config-item>
+        <config:config-item config:name="VisibleAreaLeft" config:type="int">0</config:config-item>
+        <config:config-item-map-indexed config:name="Views">
+          <config:config-item-map-entry>
+            <config:config-item config:name="ViewId" config:type="string">view1</config:config-item>
+            <config:config-item-map-named config:name="Tables">
+';
+        foreach ($this->worksheets as $ws) {
+            $buffer .= '               <config:config-item-map-entry config:name="'.htmlspecialchars($ws->name, ENT_QUOTES, 'utf-8').'">'."\n";
+            $buffer .= '                 <config:config-item config:name="ShowGrid" config:type="boolean">'.($ws->showgrid ? 'true' : 'false').'</config:config-item>'."\n";
+            $buffer .= '               </config:config-item-map-entry>."\n"';
+        }
+            $buffer .=
+'           </config:config-item-map-named>
+          </config:config-item-map-entry>
+        </config:config-item-map-indexed>
+      </config:config-item-set>
+      <config:config-item-set config:name="ooo:configuration-settings">
+        <config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
+      </config:config-item-set>
+    </office:settings>
+</office:document-settings>';
+
+        return $buffer;
+    }
+    protected function get_ods_meta() {
+        global $CFG, $USER;
 
-    return
+        return
 '<?xml version="1.0" encoding="UTF-8"?>
-<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink">
- <office:meta>
-  <meta:generator>Moodle '.$CFG->version.'</meta:generator>
-  <meta:initial-creator>'.fullname($USER, true).'</meta:initial-creator>
-  <meta:editing-cycles>1</meta:editing-cycles>
-  <meta:creation-date>'.strftime('%Y-%m-%dT%H:%M:%S').'</meta:creation-date>
-  <dc:date>'.strftime('%Y-%m-%dT%H:%M:%S').'</dc:date>
-  <dc:creator>'.fullname($USER, true).'</dc:creator>
- </office:meta>
+<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+                      xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/"
+                      xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
+                      xmlns:ooo="http://openoffice.org/2004/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#"
+                      office:version="1.2">
+    <office:meta>
+        <meta:generator>Moodle '.$CFG->release.'</meta:generator>
+        <meta:initial-creator>'.fullname($USER, true).'</meta:initial-creator>
+        <meta:creation-date>'.strftime('%Y-%m-%dT%H:%M:%S').'</meta:creation-date>
+        <meta:document-statistic meta:table-count="1" meta:cell-count="0" meta:object-count="0"/>
+    </office:meta>
 </office:document-meta>';
-}
+    }
 
-function get_ods_styles() {
-    return
+    protected function get_ods_styles() {
+        return
 '<?xml version="1.0" encoding="UTF-8"?>
-<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink">
- <office:styles>
-  <style:default-style style:family="table-column">
-   <style:table-column-properties style:column-width="75pt"/>
-  </style:default-style>
-  <style:default-style style:family="table-row">
-   <style:table-row-properties style:row-height="15pt"/>
-  </style:default-style>
-  <style:default-style style:family="table-cell">
-   <style:table-cell-properties fo:background-color="#ffffff" style:cell-protect="protected" style:vertical-align="middle"/>
-   <style:text-properties fo:color="#000000" fo:font-family="Arial" fo:font-size="12pt"/>
-  </style:default-style>
- </office:styles>
- <office:automatic-styles>
-  <style:page-layout style:name="pm1">
-   <style:page-layout-properties fo:margin-bottom="56.6930116pt" fo:margin-left="56.6930116pt" fo:margin-right="56.6930116pt" fo:margin-top="56.6930116pt" fo:page-height="841.89122226pt" fo:page-width="595.2766218pt" style:print="objects charts drawings zero-values" style:print-orientation="portrait"/>
-  </style:page-layout>
- </office:automatic-styles>
- <office:master-styles>
-  <style:master-page style:name="Standard1" style:page-layout-name="pm1">
-   <style:header>
- <text:p>
-  <text:sheet-name>???</text:sheet-name>
- </text:p>
-</style:header><style:footer>
- <text:p>
-  <text:sheet-name>Page </text:sheet-name>
-  <text:page-number>1</text:page-number>
- </text:p>
-</style:footer>
-  </style:master-page>
- </office:master-styles>
-</office:document-styles>
-';
-}
+<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+                        xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+                        xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+                        xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+                        xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+                        xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+                        xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/"
+                        xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
+                        xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
+                        xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+                        xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
+                        xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+                        xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+                        xmlns:math="http://www.w3.org/1998/Math/MathML"
+                        xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
+                        xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
+                        xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer"
+                        xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events"
+                        xmlns:rpt="http://openoffice.org/2005/report"
+                        xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
+                        xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#"
+                        xmlns:tableooo="http://openoffice.org/2009/table"
+                        xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
+                        xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2">
+    <office:font-face-decls>
+        <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss"
+                         style:font-pitch="variable"/>
+        <style:font-face style:name="Arial Unicode MS" svg:font-family="&apos;Arial Unicode MS&apos;"
+                         style:font-family-generic="system" style:font-pitch="variable"/>
+        <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system"
+                         style:font-pitch="variable"/>
+    </office:font-face-decls>
+    <office:styles>
+        <style:default-style style:family="table-cell">
+            <style:paragraph-properties style:tab-stop-distance="1.25cm"/>
+        </style:default-style>
+        <number:number-style style:name="N0">
+            <number:number number:min-integer-digits="1"/>
+        </number:number-style>
+        <style:style style:name="Default" style:family="table-cell">
+            <style:text-properties style:font-name-asian="Arial Unicode MS" style:font-name-complex="Arial Unicode MS"/>
+        </style:style>
+        <style:style style:name="Result" style:family="table-cell" style:parent-style-name="Default">
+            <style:text-properties fo:font-style="italic" style:text-underline-style="solid"
+                                   style:text-underline-width="auto" style:text-underline-color="font-color"
+                                   fo:font-weight="bold"/>
+        </style:style>
+        <style:style style:name="Result2" style:family="table-cell" style:parent-style-name="Result"
+                     style:data-style-name="N104"/>
+        <style:style style:name="Heading" style:family="table-cell" style:parent-style-name="Default">
+            <style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/>
+            <style:paragraph-properties fo:text-align="center"/>
+            <style:text-properties fo:font-size="16pt" fo:font-style="italic" fo:font-weight="bold"/>
+        </style:style>
+        <style:style style:name="Heading1" style:family="table-cell" style:parent-style-name="Heading">
+            <style:table-cell-properties style:rotation-angle="90"/>
+        </style:style>
+    </office:styles>
+    <office:automatic-styles>
+        <style:page-layout style:name="Mpm1">
+            <style:page-layout-properties style:writing-mode="lr-tb"/>
+            <style:header-style>
+                <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm"
+                                                fo:margin-bottom="0.25cm"/>
+            </style:header-style>
+            <style:footer-style>
+                <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm"
+                                                fo:margin-top="0.25cm"/>
+            </style:footer-style>
+        </style:page-layout>
+        <style:page-layout style:name="Mpm2">
+            <style:page-layout-properties style:writing-mode="lr-tb"/>
+            <style:header-style>
+                <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm"
+                                                fo:margin-bottom="0.25cm" fo:border="2.49pt solid #000000"
+                                                fo:padding="0.018cm" fo:background-color="#c0c0c0">
+                    <style:background-image/>
+                </style:header-footer-properties>
+            </style:header-style>
+            <style:footer-style>
+                <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm"
+                                                fo:margin-top="0.25cm" fo:border="2.49pt solid #000000"
+                                                fo:padding="0.018cm" fo:background-color="#c0c0c0">
+                    <style:background-image/>
+                </style:header-footer-properties>
+            </style:footer-style>
+        </style:page-layout>
+    </office:automatic-styles>
+    <office:master-styles>
+        <style:master-page style:name="Default" style:page-layout-name="Mpm1">
+            <style:header>
+                <text:p>
+                    <text:sheet-name>???</text:sheet-name>
+                </text:p>
+            </style:header>
+            <style:header-left style:display="false"/>
+            <style:footer>
+                <text:p>Page
+                    <text:page-number>1</text:page-number>
+                </text:p>
+            </style:footer>
+            <style:footer-left style:display="false"/>
+        </style:master-page>
+        <style:master-page style:name="Report" style:page-layout-name="Mpm2">
+            <style:header>
+                <style:region-left>
+                    <text:p>
+                        <text:sheet-name>???</text:sheet-name>
+                        (<text:title>???</text:title>)
+                    </text:p>
+                </style:region-left>
+                <style:region-right>
+                    <text:p><text:date style:data-style-name="N2" text:date-value="2013-01-05">00.00.0000</text:date>,
+                        <text:time>00:00:00</text:time>
+                    </text:p>
+                </style:region-right>
+            </style:header>
+            <style:header-left style:display="false"/>
+            <style:footer>
+                <text:p>Page
+                    <text:page-number>1</text:page-number>
+                    /
+                    <text:page-count>99</text:page-count>
+                </text:p>
+            </style:footer>
+            <style:footer-left style:display="false"/>
+        </style:master-page>
+    </office:master-styles>
+</office:document-styles>';
+    }
 
-function get_ods_manifest() {
-    return
+    protected function get_ods_manifest() {
+        return
 '<?xml version="1.0" encoding="UTF-8"?>
-<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0">
- <manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.spreadsheet" manifest:full-path="/"/>
- <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
- <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/>
- <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml"/>
+<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">
+ <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>
+ <manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"/>
+ <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>
+ <manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"/>
+ <manifest:file-entry manifest:full-path="settings.xml" manifest:media-type="text/xml"/>
 </manifest:manifest>';
+    }
+
+    protected function get_num_styles() {
+        return '
+        <number:number-style style:name="NUM1">
+            <number:number number:decimal-places="0" number:min-integer-digits="1"/>
+        </number:number-style>
+        <number:number-style style:name="NUM2">
+            <number:number number:decimal-places="2" number:min-integer-digits="1"/>
+        </number:number-style>
+        <number:number-style style:name="NUM3">
+            <number:number number:decimal-places="0" number:min-integer-digits="1" number:grouping="true"/>
+        </number:number-style>
+        <number:number-style style:name="NUM4">
+            <number:number number:decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
+        </number:number-style>
+        <number:number-style style:name="NUM11">
+            <number:scientific-number number:decimal-places="2" number:min-integer-digits="1"
+                                      number:min-exponent-digits="2"/>
+        </number:number-style>
+        <number:number-style style:name="NUM12">
+            <number:fraction number:min-integer-digits="0" number:min-numerator-digits="1"
+                             number:min-denominator-digits="1"/>
+        </number:number-style>
+        <number:number-style style:name="NUM13">
+            <number:fraction number:min-integer-digits="0" number:min-numerator-digits="2"
+                             number:min-denominator-digits="2"/>
+        </number:number-style>
+        <number:date-style style:name="NUM14" number:automatic-order="true">
+            <number:month number:style="long"/>
+            <number:text>/</number:text>
+            <number:day number:style="long"/>
+            <number:text>/</number:text>
+            <number:year/>
+        </number:date-style>
+        <number:date-style style:name="NUM15">
+            <number:day/>
+            <number:text>.</number:text>
+            <number:month number:textual="true"/>
+            <number:text>.</number:text>
+            <number:year number:style="long"/>
+        </number:date-style>
+        <number:date-style style:name="NUM16" number:automatic-order="true">
+            <number:month number:textual="true"/>
+            <number:text></number:text>
+            <number:day number:style="long"/>
+        </number:date-style>
+        <number:date-style style:name="NUM17">
+            <number:month number:style="long"/>
+            <number:text>-</number:text>
+            <number:day number:style="long"/>
+        </number:date-style>
+        <number:date-style style:name="NUM22" number:automatic-order="true"
+                           number:format-source="language">
+            <number:month/>
+            <number:text>/</number:text>
+            <number:day/>
+            <number:text>/</number:text>
+            <number:year/>
+            <number:text></number:text>
+            <number:hours number:style="long"/>
+            <number:text>:</number:text>
+            <number:minutes number:style="long"/>
+            <number:text></number:text>
+            <number:am-pm/>
+        </number:date-style>
+        <number:text-style style:name="NUM49">
+            <number:text-content/>
+        </number:text-style>
+';
+    }
 }
diff --git a/lib/pear/OLE/PPS.php b/lib/pear/OLE/PPS.php
deleted file mode 100644 (file)
index 6ab4849..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2002 The PHP Group                                |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license,      |
-// | that is bundled with this package in the file LICENSE, and is        |
-// | available at through the world-wide-web at                           |
-// | http://www.php.net/license/2_02.txt.                                 |
-// | If you did not receive a copy of the PHP license and are unable to   |
-// | obtain it through the world-wide-web, please send a note to          |
-// | license@php.net so we can mail you a copy immediately.               |
-// +----------------------------------------------------------------------+
-// | Author: Xavier Noguer <xnoguer@php.net>                              |
-// | Based on OLE::Storage_Lite by Kawai, Takanori                        |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-
-require_once('PEAR.php');
-require_once('OLE.php');
-
-/**
-* Class for creating PPS's for OLE containers
-*
-* @author   Xavier Noguer <xnoguer@php.net>
-* @category Structures
-* @package  OLE
-*/
-class OLE_PPS extends PEAR
-{
-    /**
-    * The PPS index
-    * @var integer
-    */
-    var $No;
-
-    /**
-    * The PPS name (in Unicode)
-    * @var string
-    */
-    var $Name;
-    /**
-    * The PPS type. Dir, Root or File
-    * @var integer
-    */
-    var $Type;
-    /**
-    * The index of the previous PPS
-    * @var integer
-    */
-    var $PrevPps;
-    /**
-    * The index of the next PPS
-    * @var integer
-    */
-    var $NextPps;
-    /**
-    * The index of it's first child if this is a Dir or Root PPS
-    * @var integer
-    */
-    var $DirPps;
-    /**
-    * A timestamp
-    * @var integer
-    */
-    var $Time1st;
-
-    /**
-    * A timestamp
-    * @var integer
-    */
-    var $Time2nd;
-
-    /**
-    * Starting block (small or big) for this PPS's data  inside the container
-    * @var integer
-    */
-    var $_StartBlock;
-
-    /**
-    * The size of the PPS's data (in bytes)
-    * @var integer
-    */
-    var $Size;
-
-    /**
-    * The PPS's data (only used if it's not using a temporary file)
-    * @var string
-    */
-    var $_data;
-
-    /**
-    * Array of child PPS's (only used by Root and Dir PPS's)
-    * @var array
-    */
-    var $children = array();
-
-    /**
-    * The constructor
-    *
-    * @access public
-    * @param integer $No   The PPS index
-    * @param string $name  The PPS name (in Unicode)
-    * @param integer $type The PPS type. Dir, Root or File
-    * @param integer $prev The index of the previous PPS
-    * @param integer $next The index of the next PPS
-    * @param integer $dir  The index of it's first child if this is a Dir or Root PPS
-    * @param integer $time_1st A timestamp
-    * @param integer $time_2nd A timestamp
-    * @param array   $children Array containing children PPS for this PPS
-    */
-    function OLE_PPS($No, $name, $type, $prev, $next, $dir, $time_1st, $time_2nd, $data, $children)
-    {
-        $this->No      = $No;
-        $this->Name    = $name;
-        $this->Type    = $type;
-        $this->PrevPps = $prev;
-        $this->NextPps = $next;
-        $this->DirPps  = $dir;
-        $this->Time1st = $time_1st;
-        $this->Time2nd = $time_2nd;
-        $this->_data      = $data;
-        $this->children   = $children;
-        if ($data != '') {
-            $this->Size = strlen($data);
-        }
-        else {
-            $this->Size = 0;
-        }
-    }
-
-    /**
-    * Returns the amount of data saved for this PPS
-    *
-    * @access private
-    * @return integer The amount of data (in bytes)
-    */
-    function _DataLen()
-    {
-        if (!isset($this->_data)) {
-            return 0;
-        }
-        if (isset($this->_PPS_FILE))
-        {
-            fseek($this->_PPS_FILE, 0);
-            $stats = fstat($this->_PPS_FILE);
-            return $stats[7];
-        }
-        else {
-            return strlen($this->_data);
-        }
-    }
-
-    /**
-    * Returns a string with the PPS's WK (What is a WK?)
-    *
-    * @access private
-    * @return string The binary string
-    */
-    function _getPpsWk()
-    {
-        $ret = $this->Name;
-        for ($i = 0; $i < (64 - strlen($this->Name)); $i++) {
-            $ret .= "\x00";
-        }
-        $ret .= pack("v", strlen($this->Name) + 2)  // 66
-              . pack("c", $this->Type)              // 67
-              . pack("c", 0x00) //UK                // 68
-              . pack("V", $this->PrevPps) //Prev    // 72
-              . pack("V", $this->NextPps) //Next    // 76
-              . pack("V", $this->DirPps)  //Dir     // 80
-              . "\x00\x09\x02\x00"                  // 84
-              . "\x00\x00\x00\x00"                  // 88
-              . "\xc0\x00\x00\x00"                  // 92
-              . "\x00\x00\x00\x46"                  // 96 // Seems to be ok only for Root
-              . "\x00\x00\x00\x00"                  // 100
-              . OLE::LocalDate2OLE($this->Time1st)       // 108
-              . OLE::LocalDate2OLE($this->Time2nd)       // 116
-              . pack("V", isset($this->_StartBlock)? 
-                        $this->_StartBlock:0)        // 120
-              . pack("V", $this->Size)               // 124
-              . pack("V", 0);                        // 128
-        return $ret;
-    }
-
-    /**
-    * Updates index and pointers to previous, next and children PPS's for this
-    * PPS. I don't think it'll work with Dir PPS's.
-    *
-    * @access private
-    * @param array &$pps_array Reference to the array of PPS's for the whole OLE
-    *                          container 
-    * @return integer          The index for this PPS
-    */
-    function _savePpsSetPnt(&$pps_array) 
-    {
-        $pps_array[count($pps_array)] = &$this;
-        $this->No = count($pps_array) - 1;
-        $this->PrevPps = 0xFFFFFFFF;
-        $this->NextPps = 0xFFFFFFFF;
-        if (count($this->children) > 0) {
-            $this->DirPps = $this->children[0]->_savePpsSetPnt($pps_array);
-        }
-        else {
-            $this->DirPps = 0xFFFFFFFF;
-        }
-        return $this->No;
-    }
-}
-?>
diff --git a/lib/pear/OLE/PPS/File.php b/lib/pear/OLE/PPS/File.php
deleted file mode 100644 (file)
index 02f72e8..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2002 The PHP Group                                |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license,      |
-// | that is bundled with this package in the file LICENSE, and is        |
-// | available at through the world-wide-web at                           |
-// | http://www.php.net/license/2_02.txt.                                 |
-// | If you did not receive a copy of the PHP license and are unable to   |
-// | obtain it through the world-wide-web, please send a note to          |
-// | license@php.net so we can mail you a copy immediately.               |
-// +----------------------------------------------------------------------+
-// | Author: Xavier Noguer <xnoguer@php.net>                              |
-// | Based on OLE::Storage_Lite by Kawai, Takanori                        |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-
-require_once ('OLE/PPS.php');
-
-/**
-* Class for creating File PPS's for OLE containers
-*
-* @author   Xavier Noguer <xnoguer@php.net>
-* @category Structures
-* @package  OLE
-*/
-class OLE_PPS_File extends OLE_PPS
-{
-    /**
-    * The temporary dir for storing the OLE file
-    * @var string
-    */
-    var $_tmp_dir;
-
-    /**
-    * The constructor
-    *
-    * @access public
-    * @param string $name The name of the file (in Unicode)
-    * @see OLE::Asc2Ucs()
-    */
-    function OLE_PPS_File($name)
-    {
-        $this->_tmp_dir = '';
-        $this->OLE_PPS(
-            null, 
-            $name,
-            OLE_PPS_TYPE_FILE,
-            null,
-            null,
-            null,
-            null,
-            null,
-            '',
-            array());
-    }
-
-    /**
-    * Sets the temp dir used for storing the OLE file
-    *
-    * @access public
-    * @param string $dir The dir to be used as temp dir
-    * @return true if given dir is valid, false otherwise
-    */
-    function setTempDir($dir)
-    {
-        if (is_dir($dir)) {
-            $this->_tmp_dir = $dir;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-    * Initialization method. Has to be called right after OLE_PPS_File().
-    *
-    * @access public
-    * @return mixed true on success. PEAR_Error on failure
-    */
-    function init()
-    {
-        $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_File");
-        $fh = @fopen($this->_tmp_filename, "w+b");
-        if ($fh == false) {
-            return $this->raiseError("Can't create temporary file");
-        }
-        $this->_PPS_FILE = $fh;
-        if ($this->_PPS_FILE) {
-            fseek($this->_PPS_FILE, 0);
-        }
-    }
-    
-    /**
-    * Append data to PPS
-    *
-    * @access public
-    * @param string $data The data to append
-    */
-    function append($data)
-    {
-        if ($this->_PPS_FILE) {
-            fwrite($this->_PPS_FILE, $data);
-        }
-        else {
-            $this->_data .= $data;
-        }
-    }
-}
-?>
diff --git a/lib/pear/OLE/PPS/Root.php b/lib/pear/OLE/PPS/Root.php
deleted file mode 100644 (file)
index 33b6017..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-<?php
-/* vim: set expandtab tabstop=4 shiftwidth=4: */
-// +----------------------------------------------------------------------+
-// | PHP Version 4                                                        |
-// +----------------------------------------------------------------------+
-// | Copyright (c) 1997-2002 The PHP Group                                |
-// +----------------------------------------------------------------------+
-// | This source file is subject to version 2.02 of the PHP license,      |
-// | that is bundled with this package in the file LICENSE, and is        |
-// | available at through the world-wide-web at                           |
-// | http://www.php.net/license/2_02.txt.                                 |
-// | If you did not receive a copy of the PHP license and are unable to   |
-// | obtain it through the world-wide-web, please send a note to          |
-// | license@php.net so we can mail you a copy immediately.               |
-// +----------------------------------------------------------------------+
-// | Author: Xavier Noguer <xnoguer@php.net>                              |
-// | Based on OLE::Storage_Lite by Kawai, Takanori                        |
-// +----------------------------------------------------------------------+
-//
-// $Id$
-
-
-require_once ('OLE/PPS.php');
-
-/**
-* Class for creating Root PPS's for OLE containers
-*
-* @author   Xavier Noguer <xnoguer@php.net>
-* @category Structures
-* @package  OLE
-*/
-class OLE_PPS_Root extends OLE_PPS
-{
-    /**
-    * The temporary dir for storing the OLE file
-    * @var string
-    */
-    var $_tmp_dir;
-    
-    /**
-    * Constructor
-    *
-    * @access public
-    * @param integer $time_1st A timestamp
-    * @param integer $time_2nd A timestamp
-    */
-    function OLE_PPS_Root($time_1st, $time_2nd, $raChild)
-    {
-        $this->_tmp_dir = '';
-        $this->OLE_PPS(
-           null, 
-           OLE::Asc2Ucs('Root Entry'),
-           OLE_PPS_TYPE_ROOT,
-           null,
-           null,
-           null,
-           $time_1st,
-           $time_2nd,
-           null,
-           $raChild);
-    }
-
-    /**
-    * Sets the temp dir used for storing the OLE file
-    *
-    * @access public
-    * @param string $dir The dir to be used as temp dir
-    * @return true if given dir is valid, false otherwise
-    */
-    function setTempDir($dir)
-    {
-        if (is_dir($dir)) {
-            $this->_tmp_dir = $dir;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-    * Method for saving the whole OLE container (including files).
-    * In fact, if called with an empty argument (or '-'), it saves to a
-    * temporary file and then outputs it's contents to stdout.
-    *
-    * @param string $filename The name of the file where to save the OLE container
-    * @access public
-    * @return mixed true on success, PEAR_Error on failure
-    */
-    function save($filename)
-    {
-        // Initial Setting for saving
-        $this->_BIG_BLOCK_SIZE  = pow(2,
-                      ((isset($this->_BIG_BLOCK_SIZE))? $this->_adjust2($this->_BIG_BLOCK_SIZE)  : 9));
-        $this->_SMALL_BLOCK_SIZE= pow(2, 
-                      ((isset($this->_SMALL_BLOCK_SIZE))?  $this->_adjust2($this->_SMALL_BLOCK_SIZE): 6));
-        // Open temp file if we are sending output to stdout
-        if (($filename == '-') or ($filename == ''))
-        {
-            $this->_tmp_filename = tempnam($this->_tmp_dir, "OLE_PPS_Root");
-            $this->_FILEH_ = @fopen($this->_tmp_filename,"w+b");
-            if ($this->_FILEH_ == false) {
-                return $this->raiseError("Can't create temporary file.");
-            }
-        }
-        else
-        {
-            $this->_FILEH_ = @fopen($filename, "wb");
-            if ($this->_FILEH_ == false) {
-                return $this->raiseError("Can't open $filename. It may be in use or protected.");
-            }
-        }
-        // Make an array of PPS's (for Save)
-        $aList = array();
-        $this->_savePpsSetPnt($aList);
-        // calculate values for header
-        list($iSBDcnt, $iBBcnt, $iPPScnt) = $this->_calcSize($aList); //, $rhInfo);
-        // Save Header
-        $this->_saveHeader($iSBDcnt, $iBBcnt, $iPPScnt);
-  
-        // Make Small Data string (write SBD)
-        $this->_data = $this->_makeSmallData($aList);
-  
-        // Write BB
-        $this->_saveBigData($iSBDcnt, $aList);
-        // Write PPS
-        $this->_savePps($aList);
-        // Write Big Block Depot and BDList and Adding Header informations
-        $this->_saveBbd($iSBDcnt, $iBBcnt, $iPPScnt);
-        // Close File, send it to stdout if necessary
-        if(($filename == '-') or ($filename == ''))
-        {
-            fseek($this->_FILEH_, 0);
-            fpassthru($this->_FILEH_);
-            @fclose($this->_FILEH_);
-            // Delete the temporary file.
-            @unlink($this->_tmp_filename);
-        }
-        else {
-            @fclose($this->_FILEH_);
-        }
-        return true;
-    }
-
-    /**
-    * Calculate some numbers
-    *
-    * @access private
-    * @param array $raList Reference to an array of PPS's
-    * @return array The array of numbers
-    */
-    function _calcSize(&$raList) 
-    {
-        // Calculate Basic Setting
-        list($iSBDcnt, $iBBcnt, $iPPScnt) = array(0,0,0);
-        $iSmallLen = 0;
-        $iSBcnt = 0;
-        for ($i = 0; $i < count($raList); $i++) {
-            if($raList[$i]->Type == OLE_PPS_TYPE_FILE) {
-                $raList[$i]->Size = $raList[$i]->_DataLen();
-                if($raList[$i]->Size < OLE_DATA_SIZE_SMALL) {
-                    $iSBcnt += floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
-                                  + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
-                }
-                else {
-                    $iBBcnt += (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
-                        (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
-                }
-            }
-        }
-        $iSmallLen = $iSBcnt * $this->_SMALL_BLOCK_SIZE;
-        $iSlCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE);
-        $iSBDcnt = floor($iSBcnt / $iSlCnt) + (($iSBcnt % $iSlCnt)? 1:0);
-        $iBBcnt +=  (floor($iSmallLen / $this->_BIG_BLOCK_SIZE) +
-                      (( $iSmallLen % $this->_BIG_BLOCK_SIZE)? 1: 0));
-        $iCnt = count($raList);
-        $iBdCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE;
-        $iPPScnt = (floor($iCnt/$iBdCnt) + (($iCnt % $iBdCnt)? 1: 0));
-   
-        return array($iSBDcnt, $iBBcnt, $iPPScnt);
-    }
-
-    /**
-    * Helper function for caculating a magic value for block sizes
-    *
-    * @access private
-    * @param integer $i2 The argument
-    * @see save()
-    * @return integer
-    */
-    function _adjust2($i2)
-    {
-        $iWk = log($i2)/log(2);
-        return ($iWk > floor($iWk))? floor($iWk)+1:$iWk;
-    }
-
-    /**
-    * Save OLE header
-    *
-    * @access private
-    * @param integer $iSBDcnt
-    * @param integer $iBBcnt
-    * @param integer $iPPScnt
-    */
-    function _saveHeader($iSBDcnt, $iBBcnt, $iPPScnt)
-    {
-        $FILE = $this->_FILEH_;
-  
-        // Calculate Basic Setting
-        $iBlCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE;
-        $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE;
-  
-        $iBdExL = 0;
-        $iAll = $iBBcnt + $iPPScnt + $iSBDcnt;
-        $iAllW = $iAll;
-        $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
-        $iBdCnt = floor(($iAll + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
-  
-        // Calculate BD count
-        if ($iBdCnt >$i1stBdL)
-        {
-            while (1)
-            {
-                $iBdExL++;
-                $iAllW++;
-                $iBdCntW = floor($iAllW / $iBlCnt) + (($iAllW % $iBlCnt)? 1: 0);
-                $iBdCnt = floor(($iAllW + $iBdCntW) / $iBlCnt) + ((($iAllW+$iBdCntW) % $iBlCnt)? 1: 0);
-                if ($iBdCnt <= ($iBdExL*$iBlCnt+ $i1stBdL)) {
-                    break;
-                }
-            }
-        }
-  
-        // Save Header
-        fwrite($FILE,
-                  "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"
-                  . "\x00\x00\x00\x00"
-                  . "\x00\x00\x00\x00"
-                  . "\x00\x00\x00\x00"
-                  . "\x00\x00\x00\x00"
-                  . pack("v", 0x3b)
-                  . pack("v", 0x03)
-                  . pack("v", -2)
-                  . pack("v", 9)
-                  . pack("v", 6)
-                  . pack("v", 0)
-                  . "\x00\x00\x00\x00"
-                  . "\x00\x00\x00\x00"
-                  . pack("V", $iBdCnt) 
-                  . pack("V", $iBBcnt+$iSBDcnt) //ROOT START
-                  . pack("V", 0)
-                  . pack("V", 0x1000)
-                  . pack("V", 0)                  //Small Block Depot
-                  . pack("V", 1)
-          );
-        // Extra BDList Start, Count
-        if ($iBdCnt < $i1stBdL)
-        {
-            fwrite($FILE,
-                      pack("V", -2).      // Extra BDList Start
-                      pack("V", 0)        // Extra BDList Count
-                  );
-        }
-        else
-        {
-            fwrite($FILE, pack("V", $iAll+$iBdCnt) . pack("V", $iBdExL));
-        }
-
-        // BDList
-        for ($i=0; $i<$i1stBdL and $i < $iBdCnt; $i++) {
-            fwrite($FILE, pack("V", $iAll+$i));
-        }
-        if ($i < $i1stBdL)
-        {
-            for ($j = 0; $j < ($i1stBdL-$i); $j++) {
-                fwrite($FILE, (pack("V", -1)));
-            }
-        }
-    }
-
-    /**
-    * Saving big data (PPS's with data bigger than OLE_DATA_SIZE_SMALL)
-    *
-    * @access private
-    * @param integer $iStBlk
-    * @param array &$raList Reference to array of PPS's
-    */
-    function _saveBigData($iStBlk, &$raList)
-    {
-        $FILE = $this->_FILEH_;
-   
-        // cycle through PPS's
-        for ($i = 0; $i < count($raList); $i++)
-        {
-            if($raList[$i]->Type != OLE_PPS_TYPE_DIR)
-            {
-                $raList[$i]->Size = $raList[$i]->_DataLen();
-                if(($raList[$i]->Size >= OLE_DATA_SIZE_SMALL) or
-                    (($raList[$i]->Type == OLE_PPS_TYPE_ROOT) and isset($raList[$i]->_data)))
-                {
-                    // Write Data
-                    if(isset($raList[$i]->_PPS_FILE))
-                    {
-                        $iLen = 0;
-                        fseek($raList[$i]->_PPS_FILE, 0); // To The Top
-                        while($sBuff = fread($raList[$i]->_PPS_FILE, 4096))
-                        {
-                            $iLen += strlen($sBuff);
-                            fwrite($FILE, $sBuff);
-                        }
-                    }
-                    else {
-                        fwrite($FILE, $raList[$i]->_data);
-                    }
-           
-                    if ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)
-                    {
-                        for ($j = 0; $j < ($this->_BIG_BLOCK_SIZE - ($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)); $j++) {
-                            fwrite($FILE, "\x00");
-                        }
-                    }
-                    // Set For PPS
-                    $raList[$i]->_StartBlock = $iStBlk;
-                    $iStBlk += 
-                            (floor($raList[$i]->Size / $this->_BIG_BLOCK_SIZE) +
-                                (($raList[$i]->Size % $this->_BIG_BLOCK_SIZE)? 1: 0));
-                }
-                // Close file for each PPS, and unlink it
-                if (isset($raList[$i]->_PPS_FILE))
-                {
-                    @fclose($raList[$i]->_PPS_FILE);
-                    $raList[$i]->_PPS_FILE = null;
-                    @unlink($raList[$i]->_tmp_filename);
-                }
-            }
-        }
-    }
-
-    /**
-    * get small data (PPS's with data smaller than OLE_DATA_SIZE_SMALL)
-    *
-    * @access private
-    * @param array &$raList Reference to array of PPS's
-    */
-    function _makeSmallData(&$raList)
-    {
-        $sRes = '';
-        $FILE = $this->_FILEH_;
-        $iSmBlk = 0;
-   
-        for ($i = 0; $i < count($raList); $i++)
-        {
-            // Make SBD, small data string
-            if ($raList[$i]->Type == OLE_PPS_TYPE_FILE)
-            {
-                if ($raList[$i]->Size <= 0) {
-                    continue;
-                }
-                if ($raList[$i]->Size < OLE_DATA_SIZE_SMALL)
-                {
-                    $iSmbCnt = floor($raList[$i]->Size / $this->_SMALL_BLOCK_SIZE)
-                                  + (($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)? 1: 0);
-                    // Add to SBD
-                    for ($j = 0; $j < ($iSmbCnt-1); $j++) {
-                        fwrite($FILE, pack("V", $j+$iSmBlk+1));
-                    }
-                    fwrite($FILE, pack("V", -2));
-                   
-                    // Add to Data String(this will be written for RootEntry)
-                    if ($raList[$i]->_PPS_FILE)
-                    {
-                        fseek($raList[$i]->_PPS_FILE, 0); // To The Top
-                        while ($sBuff = fread($raList[$i]->_PPS_FILE, 4096)) {
-                            $sRes .= $sBuff;
-                        }
-                    }
-                    else {
-                        $sRes .= $raList[$i]->_data;
-                    }
-                    if($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)
-                    {
-                        for ($j = 0; $j < ($this->_SMALL_BLOCK_SIZE - ($raList[$i]->Size % $this->_SMALL_BLOCK_SIZE)); $j++) {
-                            $sRes .= "\x00";
-                        }
-                    }
-                    // Set for PPS
-                    $raList[$i]->_StartBlock = $iSmBlk;
-                    $iSmBlk += $iSmbCnt;
-                }
-            }
-        }
-        $iSbCnt = floor($this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE);
-        if($iSmBlk % $iSbCnt)
-        {
-            for ($i = 0; $i < ($iSbCnt - ($iSmBlk % $iSbCnt)); $i++) {
-                fwrite($FILE, pack("V", -1));
-            }
-        }
-        return $sRes;
-    }
-
-    /**
-    * Saves all the PPS's WKs
-    *
-    * @access private
-    * @param array $raList Reference to an array with all PPS's
-    */
-    function _savePps(&$raList) 
-    {
-        // Save each PPS WK
-        for ($i = 0; $i < count($raList); $i++) {
-            fwrite($this->_FILEH_, $raList[$i]->_getPpsWk());
-        }
-        // Adjust for Block
-        $iCnt = count($raList);
-        $iBCnt = $this->_BIG_BLOCK_SIZE / OLE_PPS_SIZE;
-        if ($iCnt % $iBCnt)
-        {
-            for ($i = 0; $i < (($iBCnt - ($iCnt % $iBCnt)) * OLE_PPS_SIZE); $i++) {
-                fwrite($this->_FILEH_, "\x00");
-            }
-        }
-    }
-
-    /**
-    * Saving Big Block Depot
-    *
-    * @access private
-    * @param integer $iSbdSize
-    * @param integer $iBsize
-    * @param integer $iPpsCnt
-    */
-    function _saveBbd($iSbdSize, $iBsize, $iPpsCnt) 
-    {
-        $FILE = $this->_FILEH_;
-        // Calculate Basic Setting
-        $iBbCnt = $this->_BIG_BLOCK_SIZE / OLE_LONG_INT_SIZE;
-        $i1stBdL = ($this->_BIG_BLOCK_SIZE - 0x4C) / OLE_LONG_INT_SIZE;
-      
-        $iBdExL = 0;
-        $iAll = $iBsize + $iPpsCnt + $iSbdSize;
-        $iAllW = $iAll;
-        $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
-        $iBdCnt = floor(($iAll + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
-        // Calculate BD count
-        if ($iBdCnt >$i1stBdL)
-        {
-            while (1)
-            {
-                $iBdExL++;
-                $iAllW++;
-                $iBdCntW = floor($iAllW / $iBbCnt) + (($iAllW % $iBbCnt)? 1: 0);
-                $iBdCnt = floor(($iAllW + $iBdCntW) / $iBbCnt) + ((($iAllW+$iBdCntW) % $iBbCnt)? 1: 0);
-                if ($iBdCnt <= ($iBdExL*$iBbCnt+ $i1stBdL)) {
-                    break;
-                }
-            }
-        }
-      
-        // Making BD
-        // Set for SBD
-        if ($iSbdSize > 0)
-        {
-            for ($i = 0; $i<($iSbdSize-1); $i++) {
-                fwrite($FILE, pack("V", $i+1));
-            }
-            fwrite($FILE, pack("V", -2));
-        }
-        // Set for B
-        for ($i = 0; $i<($iBsize-1); $i++) {
-            fwrite($FILE, pack("V", $i+$iSbdSize+1));
-        }
-        fwrite($FILE, pack("V", -2));
-      
-        // Set for PPS
-        for ($i = 0; $i<($iPpsCnt-1); $i++) {
-            fwrite($FILE, pack("V", $i+$iSbdSize+$iBsize+1));
-        }
-        fwrite($FILE, pack("V", -2));
-        // Set for BBD itself ( 0xFFFFFFFD : BBD)
-        for ($i=0; $i<$iBdCnt;$i++) {
-            fwrite($FILE, pack("V", 0xFFFFFFFD));
-        }
-        // Set for ExtraBDList
-        for ($i=0; $i<$iBdExL;$i++) {
-            fwrite($FILE, pack("V", 0xFFFFFFFC));
-        }
-        // Adjust for Block
-        if (($iAllW + $iBdCnt) % $iBbCnt)
-        {
-            for ($i = 0; $i < ($iBbCnt - (($iAllW + $iBdCnt) % $iBbCnt)); $i++) {
-                fwrite($FILE, pack("V", -1));
-            }
-        }
-        // Extra BDList
-        if ($iBdCnt > $i1stBdL)
-        {
-            $iN=0;
-            $iNb=0;
-            for ($i=$i1stBdL;$i<$iBdCnt; $i++, $iN++)
-            {
-                if ($iN>=($iBbCnt-1))
-                {
-                    $iN = 0;
-                    $iNb++;
-                    fwrite($FILE, pack("V", $iAll+$iBdCnt+$iNb));
-                }
-                fwrite($FILE, pack("V", $iBsize+$iSbdSize+$iPpsCnt+$i));
-            }
-            if (($iBdCnt-$i1stBdL) % ($iBbCnt-1))
-            {
-                for ($i = 0; $i < (($iBbCnt-1) - (($iBdCnt-$i1stBdL) % ($iBbCnt-1))); $i++) {
-                    fwrite($FILE, pack("V", -1)); 
-                }
-            }
-            fwrite($FILE, pack("V", -2));
-        }
-    }
-}
-?>
diff --git a/lib/pear/Spreadsheet/Excel/Writer.php b/lib/pear/Spreadsheet/Excel/Writer.php
deleted file mode 100644 (file)
index d62e9cf..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-<?php
-/*
-*  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
-*
-*  PERL Spreadsheet::WriteExcel module.
-*
-*  The author of the Spreadsheet::WriteExcel module is John McNamara
-*  <jmcnamara@cpan.org>
-*
-*  I _DO_ maintain this code, and John McNamara has nothing to do with the
-*  porting of this code to PHP.  Any questions directly related to this
-*  class library should be directed to me.
-*
-*  License Information:
-*
-*    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
-*    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
-*
-*    This library is free software; you can redistribute it and/or
-*    modify it under the terms of the GNU Lesser General Public
-*    License as published by the Free Software Foundation; either
-*    version 2.1 of the License, or (at your option) any later version.
-*
-*    This library is distributed in the hope that it will be useful,
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-*    Lesser General Public License for more details.
-*
-*    You should have received a copy of the GNU Lesser General Public
-*    License along with this library; if not, write to the Free Software
-*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-require_once 'PEAR.php';
-require_once 'Spreadsheet/Excel/Writer/Workbook.php';
-
-/**
-* Class for writing Excel Spreadsheets. This class should change COMPLETELY.
-*
-* @author   Xavier Noguer <xnoguer@rezebra.com>
-* @category FileFormats
-* @package  Spreadsheet_Excel_Writer
-*/
-
-class Spreadsheet_Excel_Writer extends Spreadsheet_Excel_Writer_Workbook
-{
-    /**
-    * The constructor. It just creates a Workbook
-    *
-    * @param string $filename The optional filename for the Workbook.
-    * @return Spreadsheet_Excel_Writer_Workbook The Workbook created
-    */
-    function Spreadsheet_Excel_Writer($filename = '')
-    {
-        $this->_filename = $filename;
-        $this->Spreadsheet_Excel_Writer_Workbook($filename);
-    }
-
-    /**
-    * Send HTTP headers for the Excel file.
-    *
-    * @param string $filename The filename to use for HTTP headers
-    * @access public
-    */
-    function send($filename)
-    {
-        header("Content-type: application/vnd.ms-excel");
-        header("Content-Disposition: attachment; filename=\"$filename\"");
-        header("Expires: 0");
-        header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
-        header("Pragma: public");
-    }
-
-    /**
-    * Utility function for writing formulas
-    * Converts a cell's coordinates to the A1 format.
-    *
-    * @access public
-    * @static
-    * @param integer $row Row for the cell to convert (0-indexed).
-    * @param integer $col Column for the cell to convert (0-indexed).
-    * @return string The cell identifier in A1 format
-    */
-    function rowcolToCell($row, $col)
-    {
-        if ($col > 255) { //maximum column value exceeded
-            return new PEAR_Error("Maximum column value exceeded: $col");
-        }
-
-        $int = (int)($col / 26);
-        $frac = $col % 26;
-        $chr1 = '';
-
-        if ($int > 0) {
-            $chr1 = chr(ord('A') + $int - 1);
-        }
-
-        $chr2 = chr(ord('A') + $frac);
-        $row++;
-
-        return $chr1 . $chr2 . $row;
-    }
-}
-?>
diff --git a/lib/pear/Spreadsheet/Excel/Writer/BIFFwriter.php b/lib/pear/Spreadsheet/Excel/Writer/BIFFwriter.php
deleted file mode 100644 (file)
index 64885f2..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-<?php
-/*
-*  Module written/ported by Xavier Noguer <xnoguer@php.net>
-*
-*  The majority of this is _NOT_ my code.  I simply ported it from the
-*  PERL Spreadsheet::WriteExcel module.
-*
-*  The author of the Spreadsheet::WriteExcel module is John McNamara
-*  <jmcnamara@cpan.org>
-*
-*  I _DO_ maintain this code, and John McNamara has nothing to do with the
-*  porting of this code to PHP.  Any questions directly related to this
-*  class library should be directed to me.
-*
-*  License Information:
-*
-*    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
-*    Copyright (c) 2002-2003 Xavier Noguer xnoguer@php.net
-*
-*    This library is free software; you can redistribute it and/or
-*    modify it under the terms of the GNU Lesser General Public
-*    License as published by the Free Software Foundation; either
-*    version 2.1 of the License, or (at your option) any later version.
-*
-*    This library is distributed in the hope that it will be useful,
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-*    Lesser General Public License for more details.
-*
-*    You should have received a copy of the GNU Lesser General Public
-*    License along with this library; if not, write to the Free Software
-*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-require_once 'PEAR.php';
-
-/**
-* Class for writing Excel BIFF records.
-*
-* From "MICROSOFT EXCEL BINARY FILE FORMAT" by Mark O'Brien (Microsoft Corporation):
-*
-* BIFF (BInary File Format) is the file format in which Excel documents are
-* saved on disk.  A BIFF file is a complete description of an Excel document.
-* BIFF files consist of sequences of variable-length records. There are many
-* different types of BIFF records.  For example, one record type describes a
-* formula entered into a cell; one describes the size and location of a
-* window into a document; another describes a picture format.
-*
-* @author   Xavier Noguer <xnoguer@php.net>
-* @category FileFormats
-* @package  Spreadsheet_Excel_Writer
-*/
-
-class Spreadsheet_Excel_Writer_BIFFwriter extends PEAR
-{
-    /**
-    * The BIFF/Excel version (5).
-    * @var integer
-    */
-    var $_BIFF_version = 0x0500;
-
-    /**
-    * The byte order of this architecture. 0 => little endian, 1 => big endian
-    * @var integer
-    */
-    var $_byte_order;
-
-    /**
-    * The string containing the data of the BIFF stream
-    * @var string
-    */
-    var $_data;
-
-    /**
-    * The size of the data in bytes. Should be the same as strlen($this->_data)
-    * @var integer
-    */
-    var $_datasize;
-
-    /**
-    * The maximun length for a BIFF record. See _addContinue()
-    * @var integer
-    * @see _addContinue()
-    */
-    var $_limit;
-
-    /**
-    * Constructor
-    *
-    * @access public
-    */
-    function Spreadsheet_Excel_Writer_BIFFwriter()
-    {
-        $this->_byte_order = '';
-        $this->_data       = '';
-        $this->_datasize   = 0;
-        $this->_limit      = 2080;
-        // Set the byte order
-        $this->_setByteOrder();
-    }
-
-    /**
-    * Determine the byte order and store it as class data to avoid
-    * recalculating it for each call to new().
-    *
-    * @access private
-    */
-    function _setByteOrder()
-    {
-        // Check if "pack" gives the required IEEE 64bit float
-        $teststr = pack("d", 1.2345);
-        $number  = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
-        if ($number == $teststr) {
-            $byte_order = 0;    // Little Endian
-        } elseif ($number == strrev($teststr)){
-            $byte_order = 1;    // Big Endian
-        } else {
-            // Give up. I'll fix this in a later version.
-            return $this->raiseError("Required floating point format ".
-                                     "not supported on this platform.");
-        }
-        $this->_byte_order = $byte_order;
-    }
-
-    /**
-    * General storage function
-    *
-    * @param string $data binary data to prepend
-    * @access private
-    */
-    function _prepend($data)
-    {
-        if (strlen($data) > $this->_limit) {
-            $data = $this->_addContinue($data);
-        }
-        $this->_data      = $data.$this->_data;
-        $this->_datasize += strlen($data);
-    }
-
-    /**
-    * General storage function
-    *
-    * @param string $data binary data to append
-    * @access private
-    */
-    function _append($data)
-    {
-        if (strlen($data) > $this->_limit) {
-            $data = $this->_addContinue($data);
-        }
-        $this->_data      = $this->_data.$data;
-        $this->_datasize += strlen($data);
-    }
-
-    /**
-    * Writes Excel BOF record to indicate the beginning of a stream or
-    * sub-stream in the BIFF file.
-    *
-    * @param  integer $type Type of BIFF file to write: 0x0005 Workbook,
-    *                       0x0010 Worksheet.
-    * @access private
-    */
-    function _storeBof($type)
-    {
-        $record  = 0x0809;        // Record identifier
-
-        // According to the SDK $build and $year should be set to zero.
-        // However, this throws a warning in Excel 5. So, use magic numbers.
-        if ($this->_BIFF_version == 0x0500) {
-            $length  = 0x0008;
-            $unknown = '';
-            $build   = 0x096C;
-            $year    = 0x07C9;
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $length  = 0x0010;
-            $unknown = pack("VV", 0x00000041, 0x00000006); //unknown last 8 bytes for BIFF8
-            $build   = 0x0DBB;
-            $year    = 0x07CC;
-        }
-        $version = $this->_BIFF_version;
-
-        $header  = pack("vv",   $record, $length);
-        $data    = pack("vvvv", $version, $type, $build, $year);
-        $this->_prepend($header . $data . $unknown);
-    }
-
-    /**
-    * Writes Excel EOF record to indicate the end of a BIFF stream.
-    *
-    * @access private
-    */
-    function _storeEof()
-    {
-        $record    = 0x000A;   // Record identifier
-        $length    = 0x0000;   // Number of bytes to follow
-        $header    = pack("vv", $record, $length);
-        $this->_append($header);
-    }
-
-    /**
-    * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
-    * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
-    * must be split up into CONTINUE blocks.
-    *
-    * This function takes a long BIFF record and inserts CONTINUE records as
-    * necessary.
-    *
-    * @param  string  $data The original binary data to be written
-    * @return string        A very convenient string of continue blocks
-    * @access private
-    */
-    function _addContinue($data)
-    {
-        $limit  = $this->_limit;
-        $record = 0x003C;         // Record identifier
-
-        // The first 2080/8224 bytes remain intact. However, we have to change
-        // the length field of the record.
-        $tmp = substr($data, 0, 2).pack("v", $limit-4).substr($data, 4, $limit - 4);
-
-        $header = pack("vv", $record, $limit);  // Headers for continue records
-
-        // Retrieve chunks of 2080/8224 bytes +4 for the header.
-        $data_length = strlen($data);
-        for ($i = $limit; $i <  ($data_length - $limit); $i += $limit) {
-            $tmp .= $header;
-            $tmp .= substr($data, $i, $limit);
-        }
-
-        // Retrieve the last chunk of data
-        $header  = pack("vv", $record, strlen($data) - $i);
-        $tmp    .= $header;
-        $tmp    .= substr($data, $i, strlen($data) - $i);
-
-        return $tmp;
-    }
-}
-?>
diff --git a/lib/pear/Spreadsheet/Excel/Writer/Format.php b/lib/pear/Spreadsheet/Excel/Writer/Format.php
deleted file mode 100644 (file)
index a036148..0000000
+++ /dev/null
@@ -1,1102 +0,0 @@
-<?php
-/*
-*  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
-*
-*  The majority of this is _NOT_ my code.  I simply ported it from the
-*  PERL Spreadsheet::WriteExcel module.
-*
-*  The author of the Spreadsheet::WriteExcel module is John McNamara
-*  <jmcnamara@cpan.org>
-*
-*  I _DO_ maintain this code, and John McNamara has nothing to do with the
-*  porting of this code to PHP.  Any questions directly related to this
-*  class library should be directed to me.
-*
-*  License Information:
-*
-*    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
-*    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
-*
-*    This library is free software; you can redistribute it and/or
-*    modify it under the terms of the GNU Lesser General Public
-*    License as published by the Free Software Foundation; either
-*    version 2.1 of the License, or (at your option) any later version.
-*
-*    This library is distributed in the hope that it will be useful,
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-*    Lesser General Public License for more details.
-*
-*    You should have received a copy of the GNU Lesser General Public
-*    License along with this library; if not, write to the Free Software
-*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-require_once 'PEAR.php';
-
-/**
-* Class for generating Excel XF records (formats)
-*
-* @author   Xavier Noguer <xnoguer@rezebra.com>
-* @category FileFormats
-* @package  Spreadsheet_Excel_Writer
-*/
-
-class Spreadsheet_Excel_Writer_Format extends PEAR
-{
-    /**
-    * The index given by the workbook when creating a new format.
-    * @var integer
-    */
-    var $_xf_index;
-
-    /**
-    * Index to the FONT record.
-    * @var integer
-    */
-    var $font_index;
-
-    /**
-    * The font name (ASCII).
-    * @var string
-    */
-    var $_font_name;
-
-    /**
-    * Height of font (1/20 of a point)
-    * @var integer
-    */
-    var $_size;
-
-    /**
-    * Bold style
-    * @var integer
-    */
-    var $_bold;
-
-    /**
-    * Bit specifiying if the font is italic.
-    * @var integer
-    */
-    var $_italic;
-
-    /**
-    * Index to the cell's color
-    * @var integer
-    */
-    var $_color;
-
-    /**
-    * The text underline property
-    * @var integer
-    */
-    var $_underline;
-
-    /**
-    * Bit specifiying if the font has strikeout.
-    * @var integer
-    */
-    var $_font_strikeout;
-
-    /**
-    * Bit specifiying if the font has outline.
-    * @var integer
-    */
-    var $_font_outline;
-
-    /**
-    * Bit specifiying if the font has shadow.
-    * @var integer
-    */
-    var $_font_shadow;
-
-    /**
-    * 2 bytes specifiying the script type for the font.
-    * @var integer
-    */
-    var $_font_script;
-
-    /**
-    * Byte specifiying the font family.
-    * @var integer
-    */
-    var $_font_family;
-
-    /**
-    * Byte specifiying the font charset.
-    * @var integer
-    */
-    var $_font_charset;
-
-    /**
-    * An index (2 bytes) to a FORMAT record (number format).
-    * @var integer
-    */
-    var $_num_format;
-
-    /**
-    * Bit specifying if formulas are hidden.
-    * @var integer
-    */
-    var $_hidden;
-
-    /**
-    * Bit specifying if the cell is locked.
-    * @var integer
-    */
-    var $_locked;
-
-    /**
-    * The three bits specifying the text horizontal alignment.
-    * @var integer
-    */
-    var $_text_h_align;
-
-    /**
-    * Bit specifying if the text is wrapped at the right border.
-    * @var integer
-    */
-    var $_text_wrap;
-
-    /**
-    * The three bits specifying the text vertical alignment.
-    * @var integer
-    */
-    var $_text_v_align;
-
-    /**
-    * 1 bit, apparently not used.
-    * @var integer
-    */
-    var $_text_justlast;
-
-    /**
-    * The two bits specifying the text rotation.
-    * @var integer
-    */
-    var $_rotation;
-
-    /**
-    * The cell's foreground color.
-    * @var integer
-    */
-    var $_fg_color;
-
-    /**
-    * The cell's background color.
-    * @var integer
-    */
-    var $_bg_color;
-
-    /**
-    * The cell's background fill pattern.
-    * @var integer
-    */
-    var $_pattern;
-
-    /**
-    * Style of the bottom border of the cell
-    * @var integer
-    */
-    var $_bottom;
-
-    /**
-    * Color of the bottom border of the cell.
-    * @var integer
-    */
-    var $_bottom_color;
-
-    /**
-    * Style of the top border of the cell
-    * @var integer
-    */
-    var $_top;
-
-    /**
-    * Color of the top border of the cell.
-    * @var integer
-    */
-    var $_top_color;
-
-    /**
-    * Style of the left border of the cell
-    * @var integer
-    */
-    var $_left;
-
-    /**
-    * Color of the left border of the cell.
-    * @var integer
-    */
-    var $_left_color;
-
-    /**
-    * Style of the right border of the cell
-    * @var integer
-    */
-    var $_right;
-
-    /**
-    * Color of the right border of the cell.
-    * @var integer
-    */
-    var $_right_color;
-
-    /**
-    * Constructor
-    *
-    * @access private
-    * @param integer $index the XF index for the format.
-    * @param array   $properties array with properties to be set on initialization.
-    */
-    function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties =  array())
-    {
-        $this->_xf_index       = $index;
-        $this->_BIFF_version   = $BIFF_version;
-        $this->font_index      = 0;
-        $this->_font_name      = 'Arial';
-        $this->_size           = 10;
-        $this->_bold           = 0x0190;
-        $this->_italic         = 0;
-        $this->_color          = 0x7FFF;
-        $this->_underline      = 0;
-        $this->_font_strikeout = 0;
-        $this->_font_outline   = 0;
-        $this->_font_shadow    = 0;
-        $this->_font_script    = 0;
-        $this->_font_family    = 0;
-        $this->_font_charset   = 0;
-
-        $this->_num_format     = 0;
-
-        $this->_hidden         = 0;
-        $this->_locked         = 0;
-
-        $this->_text_h_align   = 0;
-        $this->_text_wrap      = 0;
-        $this->_text_v_align   = 2;
-        $this->_text_justlast  = 0;
-        $this->_rotation       = 0;
-
-        $this->_fg_color       = 0x40;
-        $this->_bg_color       = 0x41;
-
-        $this->_pattern        = 0;
-
-        $this->_bottom         = 0;
-        $this->_top            = 0;
-        $this->_left           = 0;
-        $this->_right          = 0;
-        $this->_diag           = 0;
-
-        $this->_bottom_color   = 0x40;
-        $this->_top_color      = 0x40;
-        $this->_left_color     = 0x40;
-        $this->_right_color    = 0x40;
-        $this->_diag_color     = 0x40;
-
-        // Set properties passed to Spreadsheet_Excel_Writer_Workbook::addFormat()
-        foreach ($properties as $property => $value)
-        {
-            if (method_exists($this, 'set'.ucwords($property))) {
-                $method_name = 'set'.ucwords($property);
-                $this->$method_name($value);
-            }
-        }
-    }
-
-
-    /**
-    * Generate an Excel BIFF XF record (style or cell).
-    *
-    * @param string $style The type of the XF record ('style' or 'cell').
-    * @return string The XF record
-    */
-    function getXf($style)
-    {
-        // Set the type of the XF record and some of the attributes.
-        if ($style == 'style') {
-            $style = 0xFFF5;
-        } else {
-            $style   = $this->_locked;
-            $style  |= $this->_hidden << 1;
-        }
-
-        // Flags to indicate if attributes have been set.
-        $atr_num     = ($this->_num_format != 0)?1:0;
-        $atr_fnt     = ($this->font_index != 0)?1:0;
-        $atr_alc     = ($this->_text_wrap)?1:0;
-        $atr_bdr     = ($this->_bottom   ||
-                        $this->_top      ||
-                        $this->_left     ||
-                        $this->_right)?1:0;
-        $atr_pat     = (($this->_fg_color != 0x40) ||
-                        ($this->_bg_color != 0x41) ||
-                        $this->_pattern)?1:0;
-        $atr_prot    = $this->_locked | $this->_hidden;
-
-        // Zero the default border colour if the border has not been set.
-        if ($this->_bottom == 0) {
-            $this->_bottom_color = 0;
-        }
-        if ($this->_top  == 0) {
-            $this->_top_color = 0;
-        }
-        if ($this->_right == 0) {
-            $this->_right_color = 0;
-        }
-        if ($this->_left == 0) {
-            $this->_left_color = 0;
-        }
-        if ($this->_diag == 0) {
-            $this->_diag_color = 0;
-        }
-
-        $record         = 0x00E0;              // Record identifier
-        if ($this->_BIFF_version == 0x0500) {
-            $length         = 0x0010;              // Number of bytes to follow
-        }
-        if ($this->_BIFF_version == 0x0600) {
-            $length         = 0x0014;
-        }
-
-        $ifnt           = $this->font_index;   // Index to FONT record
-        $ifmt           = $this->_num_format;  // Index to FORMAT record
-        if ($this->_BIFF_version == 0x0500) {
-            $align          = $this->_text_h_align;       // Alignment
-            $align         |= $this->_text_wrap     << 3;
-            $align         |= $this->_text_v_align  << 4;
-            $align         |= $this->_text_justlast << 7;
-            $align         |= $this->_rotation      << 8;
-            $align         |= $atr_num                << 10;
-            $align         |= $atr_fnt                << 11;
-            $align         |= $atr_alc                << 12;
-            $align         |= $atr_bdr                << 13;
-            $align         |= $atr_pat                << 14;
-            $align         |= $atr_prot               << 15;
-
-            $icv            = $this->_fg_color;       // fg and bg pattern colors
-            $icv           |= $this->_bg_color      << 7;
-
-            $fill           = $this->_pattern;        // Fill and border line style
-            $fill          |= $this->_bottom        << 6;
-            $fill          |= $this->_bottom_color  << 9;
-
-            $border1        = $this->_top;            // Border line style and color
-            $border1       |= $this->_left          << 3;
-            $border1       |= $this->_right         << 6;
-            $border1       |= $this->_top_color     << 9;
-
-            $border2        = $this->_left_color;     // Border color
-            $border2       |= $this->_right_color   << 7;
-
-            $header      = pack("vv",       $record, $length);
-            $data        = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align,
-                                            $icv, $fill,
-                                            $border1, $border2);
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $align          = $this->_text_h_align;       // Alignment
-            $align         |= $this->_text_wrap     << 3;
-            $align         |= $this->_text_v_align  << 4;
-            $align         |= $this->_text_justlast << 7;
-
-            $used_attrib    = $atr_num              << 2;
-            $used_attrib   |= $atr_fnt              << 3;
-            $used_attrib   |= $atr_alc              << 4;
-            $used_attrib   |= $atr_bdr              << 5;
-            $used_attrib   |= $atr_pat              << 6;
-            $used_attrib   |= $atr_prot             << 7;
-
-            $icv            = $this->_fg_color;      // fg and bg pattern colors
-            $icv           |= $this->_bg_color      << 7;
-
-            $border1        = $this->_left;          // Border line style and color
-            $border1       |= $this->_right         << 4;
-            $border1       |= $this->_top           << 8;
-            $border1       |= $this->_bottom        << 12;
-            $border1       |= $this->_left_color    << 16;
-            $border1       |= $this->_right_color   << 23;
-            $diag_tl_to_rb = 0; // FIXME: add method
-            $diag_tr_to_lb = 0; // FIXME: add method
-            $border1       |= $diag_tl_to_rb        << 30;
-            $border1       |= $diag_tr_to_lb        << 31;
-
-            $border2        = $this->_top_color;    // Border color
-            $border2       |= $this->_bottom_color   << 7;
-            $border2       |= $this->_diag_color     << 14;
-            $border2       |= $this->_diag           << 21;
-            $border2       |= $this->_pattern        << 26;
-
-            $header      = pack("vv",       $record, $length);
-
-            $rotation      = 0x00;
-            $biff8_options = 0x00;
-            $data  = pack("vvvC", $ifnt, $ifmt, $style, $align);
-            $data .= pack("CCC", $rotation, $biff8_options, $used_attrib);
-            $data .= pack("VVv", $border1, $border2, $icv);
-        }
-
-        return($header . $data);
-    }
-
-    /**
-    * Generate an Excel BIFF FONT record.
-    *
-    * @return string The FONT record
-    */
-    function getFont()
-    {
-        $dyHeight   = $this->_size * 20;    // Height of font (1/20 of a point)
-        $icv        = $this->_color;        // Index to color palette
-        $bls        = $this->_bold;         // Bold style
-        $sss        = $this->_font_script;  // Superscript/subscript
-        $uls        = $this->_underline;    // Underline
-        $bFamily    = $this->_font_family;  // Font family
-        $bCharSet   = $this->_font_charset; // Character set
-        $encoding   = 0;                    // TODO: Unicode support
-
-        $cch        = strlen($this->_font_name); // Length of font name
-        $record     = 0x31;                      // Record identifier
-        if ($this->_BIFF_version == 0x0500) {
-            $length     = 0x0F + $cch;            // Record length
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $length     = 0x10 + $cch;
-        }
-        $reserved   = 0x00;                // Reserved
-        $grbit      = 0x00;                // Font attributes
-        if ($this->_italic) {
-            $grbit     |= 0x02;
-        }
-        if ($this->_font_strikeout) {
-            $grbit     |= 0x08;
-        }
-        if ($this->_font_outline) {
-            $grbit     |= 0x10;
-        }
-        if ($this->_font_shadow) {
-            $grbit     |= 0x20;
-        }
-
-        $header  = pack("vv",         $record, $length);
-        if ($this->_BIFF_version == 0x0500) {
-            $data    = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls,
-                                          $sss, $uls, $bFamily,
-                                          $bCharSet, $reserved, $cch);
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $data    = pack("vvvvvCCCCCC", $dyHeight, $grbit, $icv, $bls,
-                                           $sss, $uls, $bFamily,
-                                           $bCharSet, $reserved, $cch, $encoding);
-        }
-        return($header . $data . $this->_font_name);
-    }
-
-    /**
-    * Returns a unique hash key for a font.
-    * Used by Spreadsheet_Excel_Writer_Workbook::_storeAllFonts()
-    *
-    * The elements that form the key are arranged to increase the probability of
-    * generating a unique key. Elements that hold a large range of numbers
-    * (eg. _color) are placed between two binary elements such as _italic
-    *
-    * @return string A key for this font
-    */
-    function getFontKey()
-    {
-        $key  = "$this->_font_name$this->_size";
-        $key .= "$this->_font_script$this->_underline";
-        $key .= "$this->_font_strikeout$this->_bold$this->_font_outline";
-        $key .= "$this->_font_family$this->_font_charset";
-        $key .= "$this->_font_shadow$this->_color$this->_italic";
-        $key  = str_replace(' ', '_', $key);
-        return ($key);
-    }
-
-    /**
-    * Returns the index used by Spreadsheet_Excel_Writer_Worksheet::_XF()
-    *
-    * @return integer The index for the XF record
-    */
-    function getXfIndex()
-    {
-        return($this->_xf_index);
-    }
-
-    /**
-    * Used in conjunction with the set_xxx_color methods to convert a color
-    * string into a number. Color range is 0..63 but we will restrict it
-    * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
-    *
-    * @access private
-    * @param string $name_color name of the color (i.e.: 'blue', 'red', etc..). Optional.
-    * @return integer The color index
-    */
-    function _getColor($name_color = '')
-    {
-        $colors = array(
-                        'aqua'    => 0x0F,
-                        'cyan'    => 0x0F,
-                        'black'   => 0x08,
-                        'blue'    => 0x0C,
-                        'brown'   => 0x10,
-                        'magenta' => 0x0E,
-                        'fuchsia' => 0x0E,
-                        'gray'    => 0x17,
-                        'grey'    => 0x17,
-                        'green'   => 0x11,
-                        'lime'    => 0x0B,
-                        'navy'    => 0x12,
-                        'orange'  => 0x35,
-                        'purple'  => 0x14,
-                        'red'     => 0x0A,
-                        'silver'  => 0x16,
-                        'white'   => 0x09,
-                        'yellow'  => 0x0D
-                       );
-
-        // Return the default color, 0x7FFF, if undef,
-        if ($name_color == '') {
-            return(0x7FFF);
-        }
-
-        // or the color string converted to an integer,
-        if (isset($colors[$name_color])) {
-            return($colors[$name_color]);
-        }
-
-        // or the default color if string is unrecognised,
-        if (preg_match("/\D/",$name_color)) {
-            return(0x7FFF);
-        }
-
-        // or an index < 8 mapped into the correct range,
-        if ($name_color < 8) {
-            return($name_color + 8);
-        }
-
-        // or the default color if arg is outside range,
-        if ($name_color > 63) {
-            return(0x7FFF);
-        }
-
-        // or an integer in the valid range
-        return($name_color);
-    }
-
-    /**
-    * Set cell alignment.
-    *
-    * @access public
-    * @param string $location alignment for the cell ('left', 'right', etc...).
-    */
-    function setAlign($location)
-    {
-        if (preg_match("/\d/",$location)) {
-            return;                      // Ignore numbers
-        }
-
-        $location = strtolower($location);
-
-        if ($location == 'left') {
-            $this->_text_h_align = 1;
-        }
-        if ($location == 'centre') {
-            $this->_text_h_align = 2;
-        }
-        if ($location == 'center') {
-            $this->_text_h_align = 2;
-        }
-        if ($location == 'right') {
-            $this->_text_h_align = 3;
-        }
-        if ($location == 'fill') {
-            $this->_text_h_align = 4;
-        }
-        if ($location == 'justify') {
-            $this->_text_h_align = 5;
-        }
-        if ($location == 'merge') {
-            $this->_text_h_align = 6;
-        }
-        if ($location == 'equal_space') { // For T.K.
-            $this->_text_h_align = 7;
-        }
-        if ($location == 'top') {
-            $this->_text_v_align = 0;
-        }
-        if ($location == 'vcentre') {
-            $this->_text_v_align = 1;
-        }
-        if ($location == 'vcenter') {
-            $this->_text_v_align = 1;
-        }
-        if ($location == 'bottom') {
-            $this->_text_v_align = 2;
-        }
-        if ($location == 'vjustify') {
-            $this->_text_v_align = 3;
-        }
-        if ($location == 'vequal_space') { // For T.K.
-            $this->_text_v_align = 4;
-        }
-    }
-
-    /**
-    * Set cell horizontal alignment.
-    *
-    * @access public
-    * @param string $location alignment for the cell ('left', 'right', etc...).
-    */
-    function setHAlign($location)
-    {
-        if (preg_match("/\d/",$location)) {
-            return;                      // Ignore numbers
-        }
-    
-        $location = strtolower($location);
-    
-        if ($location == 'left') {
-            $this->_text_h_align = 1;
-        }
-        if ($location == 'centre') {
-            $this->_text_h_align = 2;
-        }
-        if ($location == 'center') {
-            $this->_text_h_align = 2;
-        }
-        if ($location == 'right') {
-            $this->_text_h_align = 3;
-        }
-        if ($location == 'fill') {
-            $this->_text_h_align = 4;
-        }
-        if ($location == 'justify') {
-            $this->_text_h_align = 5;
-        }
-        if ($location == 'merge') {
-            $this->_text_h_align = 6;
-        }
-        if ($location == 'equal_space') { // For T.K.
-            $this->_text_h_align = 7;
-        }
-    }
-
-    /**
-    * Set cell vertical alignment.
-    *
-    * @access public
-    * @param string $location alignment for the cell ('top', 'vleft', 'vright', etc...).
-    */
-    function setVAlign($location)
-    {
-        if (preg_match("/\d/",$location)) {
-            return;                      // Ignore numbers
-        }
-    
-        $location = strtolower($location);
-        if ($location == 'top') {
-            $this->_text_v_align = 0;
-        }
-        if ($location == 'vcentre') {
-            $this->_text_v_align = 1;
-        }
-        if ($location == 'vcenter') {
-            $this->_text_v_align = 1;
-        }
-        if ($location == 'bottom') {
-            $this->_text_v_align = 2;
-        }
-        if ($location == 'vjustify') {
-            $this->_text_v_align = 3;
-        }
-        if ($location == 'vequal_space') { // For T.K.
-            $this->_text_v_align = 4;
-        }
-    }
-
-    /**
-    * This is an alias for the unintuitive setAlign('merge')
-    *
-    * @access public
-    */
-    function setMerge()
-    {
-        $this->setAlign('merge');
-    }
-
-    /**
-    * Sets the boldness of the text.
-    * Bold has a range 100..1000.
-    * 0 (400) is normal. 1 (700) is bold.
-    *
-    * @access public
-    * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
-                             1 maps to 700 (bold text). Valid range is: 100-1000.
-                             It's Optional, default is 1 (bold).
-    */
-    function setBold($weight = 1)
-    {
-        if ($weight == 1) {
-            $weight = 0x2BC;  // Bold text
-        }
-        if ($weight == 0) {
-            $weight = 0x190;  // Normal text
-        }
-        if ($weight <  0x064) {
-            $weight = 0x190;  // Lower bound
-        }
-        if ($weight >  0x3E8) {
-            $weight = 0x190;  // Upper bound
-        }
-        $this->_bold = $weight;
-    }
-
-
-    /************************************
-    * FUNCTIONS FOR SETTING CELLS BORDERS
-    */
-
-    /**
-    * Sets the width for the bottom border of the cell
-    *
-    * @access public
-    * @param integer $style style of the cell border. 1 => thin, 2 => thick.
-    */
-    function setBottom($style)
-    {
-        $this->_bottom = $style;
-    }
-
-    /**
-    * Sets the width for the top border of the cell
-    *
-    * @access public
-    * @param integer $style style of the cell top border. 1 => thin, 2 => thick.
-    */
-    function setTop($style)
-    {
-        $this->_top = $style;
-    }
-
-    /**
-    * Sets the width for the left border of the cell
-    *
-    * @access public
-    * @param integer $style style of the cell left border. 1 => thin, 2 => thick.
-    */
-    function setLeft($style)
-    {
-        $this->_left = $style;
-    }
-
-    /**
-    * Sets the width for the right border of the cell
-    *
-    * @access public
-    * @param integer $style style of the cell right border. 1 => thin, 2 => thick.
-    */
-    function setRight($style)
-    {
-        $this->_right = $style;
-    }
-
-
-    /**
-    * Set cells borders to the same style
-    *
-    * @access public
-    * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
-    */
-    function setBorder($style)
-    {
-        $this->setBottom($style);
-        $this->setTop($style);
-        $this->setLeft($style);
-        $this->setRight($style);
-    }
-
-
-    /*******************************************
-    * FUNCTIONS FOR SETTING CELLS BORDERS COLORS
-    */
-
-    /**
-    * Sets all the cell's borders to the same color
-    *
-    * @access public
-    * @param mixed $color The color we are setting. Either a string (like 'blue'),
-    *                     or an integer (range is [8...63]).
-    */
-    function setBorderColor($color)
-    {
-        $this->setBottomColor($color);
-        $this->setTopColor($color);
-        $this->setLeftColor($color);
-        $this->setRightColor($color);
-    }
-
-    /**
-    * Sets the cell's bottom border color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setBottomColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_bottom_color = $value;
-    }
-
-    /**
-    * Sets the cell's top border color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setTopColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_top_color = $value;
-    }
-
-    /**
-    * Sets the cell's left border color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setLeftColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_left_color = $value;
-    }
-
-    /**
-    * Sets the cell's right border color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setRightColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_right_color = $value;
-    }
-
-
-    /**
-    * Sets the cell's foreground color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setFgColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_fg_color = $value;
-        if ($this->_pattern == 0) { // force color to be seen
-            $this->_pattern = 1;
-        }
-    }
-
-    /**
-    * Sets the cell's background color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setBgColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_bg_color = $value;
-        if ($this->_pattern == 0) { // force color to be seen
-            $this->_pattern = 1;
-        }
-    }
-
-    /**
-    * Sets the cell's color
-    *
-    * @access public
-    * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]).
-    */
-    function setColor($color)
-    {
-        $value = $this->_getColor($color);
-        $this->_color = $value;
-    }
-
-    /**
-    * Sets the fill pattern attribute of a cell
-    *
-    * @access public
-    * @param integer $arg Optional. Defaults to 1. Meaningful values are: 0-18,
-    *                     0 meaning no background.
-    */
-    function setPattern($arg = 1)
-    {
-        $this->_pattern = $arg;
-    }
-
-    /**
-    * Sets the underline of the text
-    *
-    * @access public
-    * @param integer $underline The value for underline. Possible values are:
-    *                          1 => underline, 2 => double underline.
-    */
-    function setUnderline($underline)
-    {
-        $this->_underline = $underline;
-    }
-
-    /**
-    * Sets the font style as italic
-    *
-    * @access public
-    */
-    function setItalic()
-    {
-        $this->_italic = 1;
-    }
-
-    /**
-    * Sets the font size
-    *
-    * @access public
-    * @param integer $size The font size (in pixels I think).
-    */
-    function setSize($size)
-    {
-        $this->_size = $size;
-    }
-
-    /**
-    * Sets text wrapping
-    *
-    * @access public
-    */
-    function setTextWrap()
-    {
-        $this->_text_wrap = 1;
-    }
-
-    /**
-    * Sets the orientation of the text
-    *
-    * @access public
-    * @param integer $angle The rotation angle for the text (clockwise). Possible
-                            values are: 0, 90, 270 and -1 for stacking top-to-bottom.
-    */
-    function setTextRotation($angle)
-    {
-        switch ($angle)
-        {
-            case 0:
-                $this->_rotation = 0;
-                break;
-            case 90:
-                $this->_rotation = 3;
-                break;
-            case 270:
-                $this->_rotation = 2;
-                break;
-            case -1:
-                $this->_rotation = 1;
-                break;
-            default :
-                return $this->raiseError("Invalid value for angle.".
-                                  " Possible values are: 0, 90, 270 and -1 ".
-                                  "for stacking top-to-bottom.");
-                $this->_rotation = 0;
-                break;
-        }
-    }
-
-    /**
-    * Sets the numeric format.
-    * It can be date, time, currency, etc...
-    *
-    * @access public
-    * @param integer $num_format The numeric format.
-    */
-    function setNumFormat($num_format)
-    {
-        $this->_num_format = $num_format;
-    }
-
-    /**
-    * Sets font as strikeout.
-    *
-    * @access public
-    */
-    function setStrikeOut()
-    {
-        $this->_font_strikeout = 1;
-    }
-
-    /**
-    * Sets outlining for a font.
-    *
-    * @access public
-    */
-    function setOutLine()
-    {
-        $this->_font_outline = 1;
-    }
-
-    /**
-    * Sets font as shadow.
-    *
-    * @access public
-    */
-    function setShadow()
-    {
-        $this->_font_shadow = 1;
-    }
-
-    /**
-    * Sets the script type of the text
-    *
-    * @access public
-    * @param integer $script The value for script type. Possible values are:
-    *                        1 => superscript, 2 => subscript.
-    */
-    function setScript($script)
-    {
-        $this->_font_script = $script;
-    }
-
-     /**
-     * Locks a cell.
-     *
-     * @access public
-     */
-     function setLocked()
-     {
-         $this->_locked = 1;
-     }
-
-    /**
-    * Unlocks a cell. Useful for unprotecting particular cells of a protected sheet.
-    *
-    * @access public
-    */
-    function setUnLocked()
-    {
-        $this->_locked = 0;
-    }
-
-    /**
-    * Sets the font family name.
-    *
-    * @access public
-    * @param string $fontfamily The font family name. Possible values are:
-    *                           'Times New Roman', 'Arial', 'Courier'.
-    */
-    function setFontFamily($font_family)
-    {
-        $this->_font_name = $font_family;
-    }
-}
-?>
diff --git a/lib/pear/Spreadsheet/Excel/Writer/Parser.php b/lib/pear/Spreadsheet/Excel/Writer/Parser.php
deleted file mode 100644 (file)
index c52cb48..0000000
+++ /dev/null
@@ -1,1689 +0,0 @@
-<?php
-/**
-*  Class for parsing Excel formulas
-*
-*  License Information:
-*
-*    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
-*    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
-*
-*    This library is free software; you can redistribute it and/or
-*    modify it under the terms of the GNU Lesser General Public
-*    License as published by the Free Software Foundation; either
-*    version 2.1 of the License, or (at your option) any later version.
-*
-*    This library is distributed in the hope that it will be useful,
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-*    Lesser General Public License for more details.
-*
-*    You should have received a copy of the GNU Lesser General Public
-*    License along with this library; if not, write to the Free Software
-*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_ADD token identifier for character "+"
-*/
-define('SPREADSHEET_EXCEL_WRITER_ADD', "+");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_SUB token identifier for character "-"
-*/
-define('SPREADSHEET_EXCEL_WRITER_SUB', "-");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_MUL token identifier for character "*"
-*/
-define('SPREADSHEET_EXCEL_WRITER_MUL', "*");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_DIV token identifier for character "/"
-*/
-define('SPREADSHEET_EXCEL_WRITER_DIV', "/");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_OPEN token identifier for character "("
-*/
-define('SPREADSHEET_EXCEL_WRITER_OPEN', "(");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_CLOSE token identifier for character ")"
-*/
-define('SPREADSHEET_EXCEL_WRITER_CLOSE', ")");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_COMA token identifier for character ","
-*/
-define('SPREADSHEET_EXCEL_WRITER_COMA', ",");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_SEMICOLON token identifier for character ";"
-*/
-define('SPREADSHEET_EXCEL_WRITER_SEMICOLON', ";");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_GT token identifier for character ">"
-*/
-define('SPREADSHEET_EXCEL_WRITER_GT', ">");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<"
-*/
-define('SPREADSHEET_EXCEL_WRITER_LT', "<");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<="
-*/
-define('SPREADSHEET_EXCEL_WRITER_LE', "<=");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">="
-*/
-define('SPREADSHEET_EXCEL_WRITER_GE', ">=");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "="
-*/
-define('SPREADSHEET_EXCEL_WRITER_EQ', "=");
-
-/**
-* @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>"
-*/
-define('SPREADSHEET_EXCEL_WRITER_NE', "<>");
-
-
-require_once 'PEAR.php';
-
-/**
-* Class for parsing Excel formulas
-*
-* @author   Xavier Noguer <xnoguer@rezebra.com>
-* @category FileFormats
-* @package  Spreadsheet_Excel_Writer
-*/
-
-class Spreadsheet_Excel_Writer_Parser extends PEAR
-{
-    /**
-    * The index of the character we are currently looking at
-    * @var integer
-    */
-    var $_current_char;
-
-    /**
-    * The token we are working on.
-    * @var string
-    */
-    var $_current_token;
-
-    /**
-    * The formula to parse
-    * @var string
-    */
-    var $_formula;
-
-    /**
-    * The character ahead of the current char
-    * @var string
-    */
-    var $_lookahead;
-
-    /**
-    * The parse tree to be generated
-    * @var string
-    */
-    var $_parse_tree;
-
-    /**
-    * The byte order. 1 => big endian, 0 => little endian.
-    * @var integer
-    */
-    var $_byte_order;
-
-    /**
-    * Array of external sheets
-    * @var array
-    */
-    var $_ext_sheets;
-
-    /**
-    * Array of sheet references in the form of REF structures
-    * @var array
-    */
-    var $_references;
-
-    /**
-    * The BIFF version for the workbook
-    * @var integer
-    */
-    var $_BIFF_version;
-
-    /**
-    * The class constructor
-    *
-    * @param integer $byte_order The byte order (Little endian or Big endian) of the architecture
-                                 (optional). 1 => big endian, 0 (default) little endian.
-    */
-    function Spreadsheet_Excel_Writer_Parser($byte_order, $biff_version)
-    {
-        $this->_current_char  = 0;
-        $this->_BIFF_version  = $biff_version;
-        $this->_current_token = '';       // The token we are working on.
-        $this->_formula       = '';       // The formula to parse.
-        $this->_lookahead     = '';       // The character ahead of the current char.
-        $this->_parse_tree    = '';       // The parse tree to be generated.
-        $this->_initializeHashes();      // Initialize the hashes: ptg's and function's ptg's
-        $this->_byte_order = $byte_order; // Little Endian or Big Endian
-        $this->_ext_sheets = array();
-        $this->_references = array();
-    }
-
-    /**
-    * Initialize the ptg and function hashes.
-    *
-    * @access private
-    */
-    function _initializeHashes()
-    {
-        // The Excel ptg indices
-        $this->ptg = array(
-            'ptgExp'       => 0x01,
-            'ptgTbl'       => 0x02,
-            'ptgAdd'       => 0x03,
-            'ptgSub'       => 0x04,
-            'ptgMul'       => 0x05,
-            'ptgDiv'       => 0x06,
-            'ptgPower'     => 0x07,
-            'ptgConcat'    => 0x08,
-            'ptgLT'        => 0x09,
-            'ptgLE'        => 0x0A,
-            'ptgEQ'        => 0x0B,
-            'ptgGE'        => 0x0C,
-            'ptgGT'        => 0x0D,
-            'ptgNE'        => 0x0E,
-            'ptgIsect'     => 0x0F,
-            'ptgUnion'     => 0x10,
-            'ptgRange'     => 0x11,
-            'ptgUplus'     => 0x12,
-            'ptgUminus'    => 0x13,
-            'ptgPercent'   => 0x14,
-            'ptgParen'     => 0x15,
-            'ptgMissArg'   => 0x16,
-            'ptgStr'       => 0x17,
-            'ptgAttr'      => 0x19,
-            'ptgSheet'     => 0x1A,
-            'ptgEndSheet'  => 0x1B,
-            'ptgErr'       => 0x1C,
-            'ptgBool'      => 0x1D,
-            'ptgInt'       => 0x1E,
-            'ptgNum'       => 0x1F,
-            'ptgArray'     => 0x20,
-            'ptgFunc'      => 0x21,
-            'ptgFuncVar'   => 0x22,
-            'ptgName'      => 0x23,
-            'ptgRef'       => 0x24,
-            'ptgArea'      => 0x25,
-            'ptgMemArea'   => 0x26,
-            'ptgMemErr'    => 0x27,
-            'ptgMemNoMem'  => 0x28,
-            'ptgMemFunc'   => 0x29,
-            'ptgRefErr'    => 0x2A,
-            'ptgAreaErr'   => 0x2B,
-            'ptgRefN'      => 0x2C,
-            'ptgAreaN'     => 0x2D,
-            'ptgMemAreaN'  => 0x2E,
-            'ptgMemNoMemN' => 0x2F,
-            'ptgNameX'     => 0x39,
-            'ptgRef3d'     => 0x3A,
-            'ptgArea3d'    => 0x3B,
-            'ptgRefErr3d'  => 0x3C,
-            'ptgAreaErr3d' => 0x3D,
-            'ptgArrayV'    => 0x40,
-            'ptgFuncV'     => 0x41,
-            'ptgFuncVarV'  => 0x42,
-            'ptgNameV'     => 0x43,
-            'ptgRefV'      => 0x44,
-            'ptgAreaV'     => 0x45,
-            'ptgMemAreaV'  => 0x46,
-            'ptgMemErrV'   => 0x47,
-            'ptgMemNoMemV' => 0x48,
-            'ptgMemFuncV'  => 0x49,
-            'ptgRefErrV'   => 0x4A,
-            'ptgAreaErrV'  => 0x4B,
-            'ptgRefNV'     => 0x4C,
-            'ptgAreaNV'    => 0x4D,
-            'ptgMemAreaNV' => 0x4E,
-            'ptgMemNoMemN' => 0x4F,
-            'ptgFuncCEV'   => 0x58,
-            'ptgNameXV'    => 0x59,
-            'ptgRef3dV'    => 0x5A,
-            'ptgArea3dV'   => 0x5B,
-            'ptgRefErr3dV' => 0x5C,
-            'ptgAreaErr3d' => 0x5D,
-            'ptgArrayA'    => 0x60,
-            'ptgFuncA'     => 0x61,
-            'ptgFuncVarA'  => 0x62,
-            'ptgNameA'     => 0x63,
-            'ptgRefA'      => 0x64,
-            'ptgAreaA'     => 0x65,
-            'ptgMemAreaA'  => 0x66,
-            'ptgMemErrA'   => 0x67,
-            'ptgMemNoMemA' => 0x68,
-            'ptgMemFuncA'  => 0x69,
-            'ptgRefErrA'   => 0x6A,
-            'ptgAreaErrA'  => 0x6B,
-            'ptgRefNA'     => 0x6C,
-            'ptgAreaNA'    => 0x6D,
-            'ptgMemAreaNA' => 0x6E,
-            'ptgMemNoMemN' => 0x6F,
-            'ptgFuncCEA'   => 0x78,
-            'ptgNameXA'    => 0x79,
-            'ptgRef3dA'    => 0x7A,
-            'ptgArea3dA'   => 0x7B,
-            'ptgRefErr3dA' => 0x7C,
-            'ptgAreaErr3d' => 0x7D
-            );
-
-        // Thanks to Michael Meeks and Gnumeric for the initial arg values.
-        //
-        // The following hash was generated by "function_locale.pl" in the distro.
-        // Refer to function_locale.pl for non-English function names.
-        //
-        // The array elements are as follow:
-        // ptg:   The Excel function ptg code.
-        // args:  The number of arguments that the function takes:
-        //           >=0 is a fixed number of arguments.
-        //           -1  is a variable  number of arguments.
-        // class: The reference, value or array class of the function args.
-        // vol:   The function is volatile.
-        //
-        $this->_functions = array(
-              // function                  ptg  args  class  vol
-              'COUNT'           => array(   0,   -1,    0,    0 ),
-              'IF'              => array(   1,   -1,    1,    0 ),
-              'ISNA'            => array(   2,    1,    1,    0 ),
-              'ISERROR'         => array(   3,    1,    1,    0 ),
-              'SUM'             => array(   4,   -1,    0,    0 ),
-              'AVERAGE'         => array(   5,   -1,    0,    0 ),
-              'MIN'             => array(   6,   -1,    0,    0 ),
-              'MAX'             => array(   7,   -1,    0,    0 ),
-              'ROW'             => array(   8,   -1,    0,    0 ),
-              'COLUMN'          => array(   9,   -1,    0,    0 ),
-              'NA'              => array(  10,    0,    0,    0 ),
-              'NPV'             => array(  11,   -1,    1,    0 ),
-              'STDEV'           => array(  12,   -1,    0,    0 ),
-              'DOLLAR'          => array(  13,   -1,    1,    0 ),
-              'FIXED'           => array(  14,   -1,    1,    0 ),
-              'SIN'             => array(  15,    1,    1,    0 ),
-              'COS'             => array(  16,    1,    1,    0 ),
-              'TAN'             => array(  17,    1,    1,    0 ),
-              'ATAN'            => array(  18,    1,    1,    0 ),
-              'PI'              => array(  19,    0,    1,    0 ),
-              'SQRT'            => array(  20,    1,    1,    0 ),
-              'EXP'             => array(  21,    1,    1,    0 ),
-              'LN'              => array(  22,    1,    1,    0 ),
-              'LOG10'           => array(  23,    1,    1,    0 ),
-              'ABS'             => array(  24,    1,    1,    0 ),
-              'INT'             => array(  25,    1,    1,    0 ),
-              'SIGN'            => array(  26,    1,    1,    0 ),
-              'ROUND'           => array(  27,    2,    1,    0 ),
-              'LOOKUP'          => array(  28,   -1,    0,    0 ),
-              'INDEX'           => array(  29,   -1,    0,    1 ),
-              'REPT'            => array(  30,    2,    1,    0 ),
-              'MID'             => array(  31,    3,    1,    0 ),
-              'LEN'             => array(  32,    1,    1,    0 ),
-              'VALUE'           => array(  33,    1,    1,    0 ),
-              'TRUE'            => array(  34,    0,    1,    0 ),
-              'FALSE'           => array(  35,    0,    1,    0 ),
-              'AND'             => array(  36,   -1,    0,    0 ),
-              'OR'              => array(  37,   -1,    0,    0 ),
-              'NOT'             => array(  38,    1,    1,    0 ),
-              'MOD'             => array(  39,    2,    1,    0 ),
-              'DCOUNT'          => array(  40,    3,    0,    0 ),
-              'DSUM'            => array(  41,    3,    0,    0 ),
-              'DAVERAGE'        => array(  42,    3,    0,    0 ),
-              'DMIN'            => array(  43,    3,    0,    0 ),
-              'DMAX'            => array(  44,    3,    0,    0 ),
-              'DSTDEV'          => array(  45,    3,    0,    0 ),
-              'VAR'             => array(  46,   -1,    0,    0 ),
-              'DVAR'            => array(  47,    3,    0,    0 ),
-              'TEXT'            => array(  48,    2,    1,    0 ),
-              'LINEST'          => array(  49,   -1,    0,    0 ),
-              'TREND'           => array(  50,   -1,    0,    0 ),
-              'LOGEST'          => array(  51,   -1,    0,    0 ),
-              'GROWTH'          => array(  52,   -1,    0,    0 ),
-              'PV'              => array(  56,   -1,    1,    0 ),
-              'FV'              => array(  57,   -1,    1,    0 ),
-              'NPER'            => array(  58,   -1,    1,    0 ),
-              'PMT'             => array(  59,   -1,    1,    0 ),
-              'RATE'            => array(  60,   -1,    1,    0 ),
-              'MIRR'            => array(  61,    3,    0,    0 ),
-              'IRR'             => array(  62,   -1,    0,    0 ),
-              'RAND'            => array(  63,    0,    1,    1 ),
-              'MATCH'           => array(  64,   -1,    0,    0 ),
-              'DATE'            => array(  65,    3,    1,    0 ),
-              'TIME'            => array(  66,    3,    1,    0 ),
-              'DAY'             => array(  67,    1,    1,    0 ),
-              'MONTH'           => array(  68,    1,    1,    0 ),
-              'YEAR'            => array(  69,    1,    1,    0 ),
-              'WEEKDAY'         => array(  70,   -1,    1,    0 ),
-              'HOUR'            => array(  71,    1,    1,    0 ),
-              'MINUTE'          => array(  72,    1,    1,    0 ),
-              'SECOND'          => array(  73,    1,    1,    0 ),
-              'NOW'             => array(  74,    0,    1,    1 ),
-              'AREAS'           => array(  75,    1,    0,    1 ),
-              'ROWS'            => array(  76,    1,    0,    1 ),
-              'COLUMNS'         => array(  77,    1,    0,    1 ),
-              'OFFSET'          => array(  78,   -1,    0,    1 ),
-              'SEARCH'          => array(  82,   -1,    1,    0 ),
-              'TRANSPOSE'       => array(  83,    1,    1,    0 ),
-              'TYPE'            => array(  86,    1,    1,    0 ),
-              'ATAN2'           => array(  97,    2,    1,    0 ),
-              'ASIN'            => array(  98,    1,    1,    0 ),
-              'ACOS'            => array(  99,    1,    1,    0 ),
-              'CHOOSE'          => array( 100,   -1,    1,    0 ),
-              'HLOOKUP'         => array( 101,   -1,    0,    0 ),
-              'VLOOKUP'         => array( 102,   -1,    0,    0 ),
-              'ISREF'           => array( 105,    1,    0,    0 ),
-              'LOG'             => array( 109,   -1,    1,    0 ),
-              'CHAR'            => array( 111,    1,    1,    0 ),
-              'LOWER'           => array( 112,    1,    1,    0 ),
-              'UPPER'           => array( 113,    1,    1,    0 ),
-              'PROPER'          => array( 114,    1,    1,    0 ),
-              'LEFT'            => array( 115,   -1,    1,    0 ),
-              'RIGHT'           => array( 116,   -1,    1,    0 ),
-              'EXACT'           => array( 117,    2,    1,    0 ),
-              'TRIM'            => array( 118,    1,    1,    0 ),
-              'REPLACE'         => array( 119,    4,    1,    0 ),
-              'SUBSTITUTE'      => array( 120,   -1,    1,    0 ),
-              'CODE'            => array( 121,    1,    1,    0 ),
-              'FIND'            => array( 124,   -1,    1,    0 ),
-              'CELL'            => array( 125,   -1,    0,    1 ),
-              'ISERR'           => array( 126,    1,    1,    0 ),
-              'ISTEXT'          => array( 127,    1,    1,    0 ),
-              'ISNUMBER'        => array( 128,    1,    1,    0 ),
-              'ISBLANK'         => array( 129,    1,    1,    0 ),
-              'T'               => array( 130,    1,    0,    0 ),
-              'N'               => array( 131,    1,    0,    0 ),
-              'DATEVALUE'       => array( 140,    1,    1,    0 ),
-              'TIMEVALUE'       => array( 141,    1,    1,    0 ),
-              'SLN'             => array( 142,    3,    1,    0 ),
-              'SYD'             => array( 143,    4,    1,    0 ),
-              'DDB'             => array( 144,   -1,    1,    0 ),
-              'INDIRECT'        => array( 148,   -1,    1,    1 ),
-              'CALL'            => array( 150,   -1,    1,    0 ),
-              'CLEAN'           => array( 162,    1,    1,    0 ),
-              'MDETERM'         => array( 163,    1,    2,    0 ),
-              'MINVERSE'        => array( 164,    1,    2,    0 ),
-              'MMULT'           => array( 165,    2,    2,    0 ),
-              'IPMT'            => array( 167,   -1,    1,    0 ),
-              'PPMT'            => array( 168,   -1,    1,    0 ),
-              'COUNTA'          => array( 169,   -1,    0,    0 ),
-              'PRODUCT'         => array( 183,   -1,    0,    0 ),
-              'FACT'            => array( 184,    1,    1,    0 ),
-              'DPRODUCT'        => array( 189,    3,    0,    0 ),
-              'ISNONTEXT'       => array( 190,    1,    1,    0 ),
-              'STDEVP'          => array( 193,   -1,    0,    0 ),
-              'VARP'            => array( 194,   -1,    0,    0 ),
-              'DSTDEVP'         => array( 195,    3,    0,    0 ),
-              'DVARP'           => array( 196,    3,    0,    0 ),
-              'TRUNC'           => array( 197,   -1,    1,    0 ),
-              'ISLOGICAL'       => array( 198,    1,    1,    0 ),
-              'DCOUNTA'         => array( 199,    3,    0,    0 ),
-              'ROUNDUP'         => array( 212,    2,    1,    0 ),
-              'ROUNDDOWN'       => array( 213,    2,    1,    0 ),
-              'RANK'            => array( 216,   -1,    0,    0 ),
-              'ADDRESS'         => array( 219,   -1,    1,    0 ),
-              'DAYS360'         => array( 220,   -1,    1,    0 ),
-              'TODAY'           => array( 221,    0,    1,    1 ),
-              'VDB'             => array( 222,   -1,    1,    0 ),
-              'MEDIAN'          => array( 227,   -1,    0,    0 ),
-              'SUMPRODUCT'      => array( 228,   -1,    2,    0 ),
-              'SINH'            => array( 229,    1,    1,    0 ),
-              'COSH'            => array( 230,    1,    1,    0 ),
-              'TANH'            => array( 231,    1,    1,    0 ),
-              'ASINH'           => array( 232,    1,    1,    0 ),
-              'ACOSH'           => array( 233,    1,    1,    0 ),
-              'ATANH'           => array( 234,    1,    1,    0 ),
-              'DGET'            => array( 235,    3,    0,    0 ),
-              'INFO'            => array( 244,    1,    1,    1 ),
-              'DB'              => array( 247,   -1,    1,    0 ),
-              'FREQUENCY'       => array( 252,    2,    0,    0 ),
-              'ERROR.TYPE'      => array( 261,    1,    1,    0 ),
-              'REGISTER.ID'     => array( 267,   -1,    1,    0 ),
-              'AVEDEV'          => array( 269,   -1,    0,    0 ),
-              'BETADIST'        => array( 270,   -1,    1,    0 ),
-              'GAMMALN'         => array( 271,    1,    1,    0 ),
-              'BETAINV'         => array( 272,   -1,    1,    0 ),
-              'BINOMDIST'       => array( 273,    4,    1,    0 ),
-              'CHIDIST'         => array( 274,    2,    1,    0 ),
-              'CHIINV'          => array( 275,    2,    1,    0 ),
-              'COMBIN'          => array( 276,    2,    1,    0 ),
-              'CONFIDENCE'      => array( 277,    3,    1,    0 ),
-              'CRITBINOM'       => array( 278,    3,    1,    0 ),
-              'EVEN'            => array( 279,    1,    1,    0 ),
-              'EXPONDIST'       => array( 280,    3,    1,    0 ),
-              'FDIST'           => array( 281,    3,    1,    0 ),
-              'FINV'            => array( 282,    3,    1,    0 ),
-              'FISHER'          => array( 283,    1,    1,    0 ),
-              'FISHERINV'       => array( 284,    1,    1,    0 ),
-              'FLOOR'           => array( 285,    2,    1,    0 ),
-              'GAMMADIST'       => array( 286,    4,    1,    0 ),
-              'GAMMAINV'        => array( 287,    3,    1,    0 ),
-              'CEILING'         => array( 288,    2,    1,    0 ),
-              'HYPGEOMDIST'     => array( 289,    4,    1,    0 ),
-              'LOGNORMDIST'     => array( 290,    3,    1,    0 ),
-              'LOGINV'          => array( 291,    3,    1,    0 ),
-              'NEGBINOMDIST'    => array( 292,    3,    1,    0 ),
-              'NORMDIST'        => array( 293,    4,    1,    0 ),
-              'NORMSDIST'       => array( 294,    1,    1,    0 ),
-              'NORMINV'         => array( 295,    3,    1,    0 ),
-              'NORMSINV'        => array( 296,    1,    1,    0 ),
-              'STANDARDIZE'     => array( 297,    3,    1,    0 ),
-              'ODD'             => array( 298,    1,    1,    0 ),
-              'PERMUT'          => array( 299,    2,    1,    0 ),
-              'POISSON'         => array( 300,    3,    1,    0 ),
-              'TDIST'           => array( 301,    3,    1,    0 ),
-              'WEIBULL'         => array( 302,    4,    1,    0 ),
-              'SUMXMY2'         => array( 303,    2,    2,    0 ),
-              'SUMX2MY2'        => array( 304,    2,    2,    0 ),
-              'SUMX2PY2'        => array( 305,    2,    2,    0 ),
-              'CHITEST'         => array( 306,    2,    2,    0 ),
-              'CORREL'          => array( 307,    2,    2,    0 ),
-              'COVAR'           => array( 308,    2,    2,    0 ),
-              'FORECAST'        => array( 309,    3,    2,    0 ),
-              'FTEST'           => array( 310,    2,    2,    0 ),
-              'INTERCEPT'       => array( 311,    2,    2,    0 ),
-              'PEARSON'         => array( 312,    2,    2,    0 ),
-              'RSQ'             => array( 313,    2,    2,    0 ),
-              'STEYX'           => array( 314,    2,    2,    0 ),
-              'SLOPE'           => array( 315,    2,    2,    0 ),
-              'TTEST'           => array( 316,    4,    2,    0 ),
-              'PROB'            => array( 317,   -1,    2,    0 ),
-              'DEVSQ'           => array( 318,   -1,    0,    0 ),
-              'GEOMEAN'         => array( 319,   -1,    0,    0 ),
-              'HARMEAN'         => array( 320,   -1,    0,    0 ),
-              'SUMSQ'           => array( 321,   -1,    0,    0 ),
-              'KURT'            => array( 322,   -1,    0,    0 ),
-              'SKEW'            => array( 323,   -1,    0,    0 ),
-              'ZTEST'           => array( 324,   -1,    0,    0 ),
-              'LARGE'           => array( 325,    2,    0,    0 ),
-              'SMALL'           => array( 326,    2,    0,    0 ),
-              'QUARTILE'        => array( 327,    2,    0,    0 ),
-              'PERCENTILE'      => array( 328,    2,    0,    0 ),
-              'PERCENTRANK'     => array( 329,   -1,    0,    0 ),
-              'MODE'            => array( 330,   -1,    2,    0 ),
-              'TRIMMEAN'        => array( 331,    2,    0,    0 ),
-              'TINV'            => array( 332,    2,    1,    0 ),
-              'CONCATENATE'     => array( 336,   -1,    1,    0 ),
-              'POWER'           => array( 337,    2,    1,    0 ),
-              'RADIANS'         => array( 342,    1,    1,    0 ),
-              'DEGREES'         => array( 343,    1,    1,    0 ),
-              'SUBTOTAL'        => array( 344,   -1,    0,    0 ),
-              'SUMIF'           => array( 345,   -1,    0,    0 ),
-              'COUNTIF'         => array( 346,    2,    0,    0 ),
-              'COUNTBLANK'      => array( 347,    1,    0,    0 ),
-              'ROMAN'           => array( 354,   -1,    1,    0 )
-              );
-    }
-
-    /**
-    * Convert a token to the proper ptg value.
-    *
-    * @access private
-    * @param mixed $token The token to convert.
-    * @return mixed the converted token on success. PEAR_Error if the token
-    *               is not recognized
-    */
-    function _convert($token)
-    {
-        if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) {
-            return $this->_convertString($token);
-
-        } elseif (is_numeric($token)) {
-            return $this->_convertNumber($token);
-
-        // match references like A1 or $A$1
-        } elseif (preg_match('/^\$?([A-Ia-i]?[A-Za-z])\$?(\d+)$/',$token)) {
-            return $this->_convertRef2d($token);
-
-        // match external references like Sheet1!A1 or Sheet1:Sheet2!A1
-        } elseif (preg_match("/^\w+(\:\w+)?\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) {
-            return $this->_convertRef3d($token);
-
-        // match external references like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1
-        } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\![A-Ia-i]?[A-Za-z](\d+)$/u",$token)) {
-            return $this->_convertRef3d($token);
-
-        // match ranges like A1:B2
-        } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\:(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) {
-            return $this->_convertRange2d($token);
-
-        // match ranges like A1..B2
-        } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) {
-            return $this->_convertRange2d($token);
-
-        // match external ranges like Sheet1!A1 or Sheet1:Sheet2!A1:B2
-        } elseif (preg_match("/^\w+(\:\w+)?\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) {
-            return $this->_convertRange3d($token);
-
-        // match external ranges like 'Sheet1'!A1 or 'Sheet1:Sheet2'!A1:B2
-        } elseif (preg_match("/^'[\w -]+(\:[\w -]+)?'\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/u",$token)) {
-            return $this->_convertRange3d($token);
-
-        // operators (including parentheses)
-        } elseif (isset($this->ptg[$token])) {
-            return pack("C", $this->ptg[$token]);
-
-        // commented so argument number can be processed correctly. See toReversePolish().
-        /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token))
-        {
-            return($this->_convertFunction($token,$this->_func_args));
-        }*/
-
-        // if it's an argument, ignore the token (the argument remains)
-        } elseif ($token == 'arg') {
-            return '';
-        }
-        // TODO: use real error codes
-        return $this->raiseError("Unknown token $token");
-    }
-
-    /**
-    * Convert a number token to ptgInt or ptgNum
-    *
-    * @access private
-    * @param mixed $num an integer or double for conversion to its ptg value
-    */
-    function _convertNumber($num)
-    {
-        // Integer in the range 0..2**16-1
-        if ((preg_match("/^\d+$/", $num)) and ($num <= 65535)) {
-            return pack("Cv", $this->ptg['ptgInt'], $num);
-        } else { // A float
-            if ($this->_byte_order) { // if it's Big Endian
-                $num = strrev($num);
-            }
-            return pack("Cd", $this->ptg['ptgNum'], $num);
-        }
-    }
-
-    /**
-    * Convert a string token to ptgStr
-    *
-    * @access private
-    * @param string $string A string for conversion to its ptg value.
-    * @return mixed the converted token on success. PEAR_Error if the string
-    *               is longer than 255 characters.
-    */
-    function _convertString($string)
-    {
-        // chop away beggining and ending quotes
-        $string = substr($string, 1, strlen($string) - 2);
-        if (strlen($string) > 255) {
-            return $this->raiseError("String is too long");
-        }
-
-        if ($this->_BIFF_version == 0x0500) {
-            return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string;
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $encoding = 0;   // TODO: Unicode support
-            return pack("CCC", $this->ptg['ptgStr'], strlen($string), $encoding).$string;
-        }
-    }
-
-    /**
-    * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of
-    * args that it takes.
-    *
-    * @access private
-    * @param string  $token    The name of the function for convertion to ptg value.
-    * @param integer $num_args The number of arguments the function receives.
-    * @return string The packed ptg for the function
-    */
-    function _convertFunction($token, $num_args)
-    {
-        $args     = $this->_functions[$token][1];
-        $volatile = $this->_functions[$token][3];
-
-        // Fixed number of args eg. TIME($i,$j,$k).
-        if ($args >= 0) {
-            return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]);
-        }
-        // Variable number of args eg. SUM($i,$j,$k, ..).
-        if ($args == -1) {
-            return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]);
-        }
-    }
-
-    /**
-    * Convert an Excel range such as A1:D4 to a ptgRefV.
-    *
-    * @access private
-    * @param string $range An Excel range in the A1:A2 or A1..A2 format.
-    */
-    function _convertRange2d($range)
-    {
-        $class = 2; // as far as I know, this is magick.
-
-        // Split the range into 2 cell refs
-        if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
-            list($cell1, $cell2) = explode(':', $range);
-        } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/", $range)) {
-            list($cell1, $cell2) = explode('..', $range);
-
-        } else {
-            // TODO: use real error codes
-            return $this->raiseError("Unknown range separator", 0, PEAR_ERROR_DIE);
-        }
-
-        // Convert the cell references
-        $cell_array1 = $this->_cellToPackedRowcol($cell1);
-        if (PEAR::isError($cell_array1)) {
-            return $cell_array1;
-        }
-        list($row1, $col1) = $cell_array1;
-        $cell_array2 = $this->_cellToPackedRowcol($cell2);
-        if (PEAR::isError($cell_array2)) {
-            return $cell_array2;
-        }
-        list($row2, $col2) = $cell_array2;
-
-        // The ptg value depends on the class of the ptg.
-        if ($class == 0) {
-            $ptgArea = pack("C", $this->ptg['ptgArea']);
-        } elseif ($class == 1) {
-            $ptgArea = pack("C", $this->ptg['ptgAreaV']);
-        } elseif ($class == 2) {
-            $ptgArea = pack("C", $this->ptg['ptgAreaA']);
-        } else {
-            // TODO: use real error codes
-            return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
-        }
-        return $ptgArea . $row1 . $row2 . $col1. $col2;
-    }
-
-    /**
-    * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to
-    * a ptgArea3d.
-    *
-    * @access private
-    * @param string $token An Excel range in the Sheet1!A1:A2 format.
-    * @return mixed The packed ptgArea3d token on success, PEAR_Error on failure.
-    */
-    function _convertRange3d($token)
-    {
-        $class = 2; // as far as I know, this is magick.
-
-        // Split the ref at the ! symbol
-        list($ext_ref, $range) = explode('!', $token);
-
-        // Convert the external reference part (different for BIFF8)
-        if ($this->_BIFF_version == 0x0500) {
-            $ext_ref = $this->_packExtRef($ext_ref);
-            if (PEAR::isError($ext_ref)) {
-                return $ext_ref;
-            }
-        } elseif ($this->_BIFF_version == 0x0600) {
-             $ext_ref = $this->_getRefIndex($ext_ref);
-             if (PEAR::isError($ext_ref)) {
-                 return $ext_ref;
-             }
-        }
-
-        // Split the range into 2 cell refs
-        list($cell1, $cell2) = explode(':', $range);
-
-        // Convert the cell references
-        if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) {
-            $cell_array1 = $this->_cellToPackedRowcol($cell1);
-            if (PEAR::isError($cell_array1)) {
-                return $cell_array1;
-            }
-            list($row1, $col1) = $cell_array1;
-            $cell_array2 = $this->_cellToPackedRowcol($cell2);
-            if (PEAR::isError($cell_array2)) {
-                return $cell_array2;
-            }
-            list($row2, $col2) = $cell_array2;
-        } else { // It's a rows range (like 26:27)
-             $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2);
-             if (PEAR::isError($cells_array)) {
-                 return $cells_array;
-             }
-             list($row1, $col1, $row2, $col2) = $cells_array;
-        }
-
-        // The ptg value depends on the class of the ptg.
-        if ($class == 0) {
-            $ptgArea = pack("C", $this->ptg['ptgArea3d']);
-        } elseif ($class == 1) {
-            $ptgArea = pack("C", $this->ptg['ptgArea3dV']);
-        } elseif ($class == 2) {
-            $ptgArea = pack("C", $this->ptg['ptgArea3dA']);
-        } else {
-            return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
-        }
-
-        return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2;
-    }
-
-    /**
-    * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV.
-    *
-    * @access private
-    * @param string $cell An Excel cell reference
-    * @return string The cell in packed() format with the corresponding ptg
-    */
-    function _convertRef2d($cell)
-    {
-        $class = 2; // as far as I know, this is magick.
-
-        // Convert the cell reference
-        $cell_array = $this->_cellToPackedRowcol($cell);
-        if (PEAR::isError($cell_array)) {
-            return $cell_array;
-        }
-        list($row, $col) = $cell_array;
-
-        // The ptg value depends on the class of the ptg.
-        if ($class == 0) {
-            $ptgRef = pack("C", $this->ptg['ptgRef']);
-        } elseif ($class == 1) {
-            $ptgRef = pack("C", $this->ptg['ptgRefV']);
-        } elseif ($class == 2) {
-            $ptgRef = pack("C", $this->ptg['ptgRefA']);
-        } else {
-            // TODO: use real error codes
-            return $this->raiseError("Unknown class $class");
-        }
-        return $ptgRef.$row.$col;
-    }
-
-    /**
-    * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a
-    * ptgRef3d.
-    *
-    * @access private
-    * @param string $cell An Excel cell reference
-    * @return mixed The packed ptgRef3d token on success, PEAR_Error on failure.
-    */
-    function _convertRef3d($cell)
-    {
-        $class = 2; // as far as I know, this is magick.
-
-        // Split the ref at the ! symbol
-        list($ext_ref, $cell) = explode('!', $cell);
-
-        // Convert the external reference part (different for BIFF8)
-        if ($this->_BIFF_version == 0x0500) {
-            $ext_ref = $this->_packExtRef($ext_ref);
-            if (PEAR::isError($ext_ref)) {
-                return $ext_ref;
-            }
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $ext_ref = $this->_getRefIndex($ext_ref);
-            if (PEAR::isError($ext_ref)) {
-                return $ext_ref;
-            }
-        }
-
-        // Convert the cell reference part
-        list($row, $col) = $this->_cellToPackedRowcol($cell);
-
-        // The ptg value depends on the class of the ptg.
-        if ($class == 0) {
-            $ptgRef = pack("C", $this->ptg['ptgRef3d']);
-        } elseif ($class == 1) {
-            $ptgRef = pack("C", $this->ptg['ptgRef3dV']);
-        } elseif ($class == 2) {
-            $ptgRef = pack("C", $this->ptg['ptgRef3dA']);
-        } else {
-            return $this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
-        }
-
-        return $ptgRef . $ext_ref. $row . $col;
-    }
-
-    /**
-    * Convert the sheet name part of an external reference, for example "Sheet1" or
-    * "Sheet1:Sheet2", to a packed structure.
-    *
-    * @access private
-    * @param string $ext_ref The name of the external reference
-    * @return string The reference index in packed() format
-    */
-    function _packExtRef($ext_ref)
-    {
-        $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading  ' if any.
-        $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
-
-        // Check if there is a sheet range eg., Sheet1:Sheet2.
-        if (preg_match("/:/", $ext_ref)) {
-            list($sheet_name1, $sheet_name2) = explode(':', $ext_ref);
-
-            $sheet1 = $this->_getSheetIndex($sheet_name1);
-            if ($sheet1 == -1) {
-                return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
-            }
-            $sheet2 = $this->_getSheetIndex($sheet_name2);
-            if ($sheet2 == -1) {
-                return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
-            }
-
-            // Reverse max and min sheet numbers if necessary
-            if ($sheet1 > $sheet2) {
-                list($sheet1, $sheet2) = array($sheet2, $sheet1);
-            }
-        } else { // Single sheet name only.
-            $sheet1 = $this->_getSheetIndex($ext_ref);
-            if ($sheet1 == -1) {
-                return $this->raiseError("Unknown sheet name $ext_ref in formula");
-            }
-            $sheet2 = $sheet1;
-        }
-
-        // References are stored relative to 0xFFFF.
-        $offset = -1 - $sheet1;
-
-        return pack('vdvv', $offset, 0x00, $sheet1, $sheet2);
-    }
-
-    /**
-    * Look up the REF index that corresponds to an external sheet name
-    * (or range). If it doesn't exist yet add it to the workbook's references
-    * array. It assumes all sheet names given must exist.
-    *
-    * @access private
-    * @param string $ext_ref The name of the external reference
-    * @return mixed The reference index in packed() format on success,
-    *               PEAR_Error on failure
-    */
-    function _getRefIndex($ext_ref)
-    {
-        $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading  ' if any.
-        $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
-
-        // Check if there is a sheet range eg., Sheet1:Sheet2.
-        if (preg_match("/:/", $ext_ref)) {
-            list($sheet_name1, $sheet_name2) = explode(':', $ext_ref);
-
-            $sheet1 = $this->_getSheetIndex($sheet_name1);
-            if ($sheet1 == -1) {
-                return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
-            }
-            $sheet2 = $this->_getSheetIndex($sheet_name2);
-            if ($sheet2 == -1) {
-                return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
-            }
-
-            // Reverse max and min sheet numbers if necessary
-            if ($sheet1 > $sheet2) {
-                list($sheet1, $sheet2) = array($sheet2, $sheet1);
-            }
-        } else { // Single sheet name only.
-            $sheet1 = $this->_getSheetIndex($ext_ref);
-            if ($sheet1 == -1) {
-                return $this->raiseError("Unknown sheet name $ext_ref in formula");
-            }
-            $sheet2 = $sheet1;
-        }
-
-        // assume all references belong to this document
-        $supbook_index = 0x00;
-        $ref = pack('vvv', $supbook_index, $sheet1, $sheet2);
-        $total_references = count($this->_references);
-        $index = -1;
-        for ($i = 0; $i < $total_references; $i++) {
-            if ($ref == $this->_references[$i]) {
-                $index = $i;
-                break;
-            }
-        }
-        // if REF was not found add it to references array
-        if ($index == -1) {
-            $this->_references[$total_references] = $ref;
-            $index = $total_references;
-        }
-
-        return pack('v', $index);
-    }
-
-    /**
-    * Look up the index that corresponds to an external sheet name. The hash of
-    * sheet names is updated by the addworksheet() method of the
-    * Spreadsheet_Excel_Writer_Workbook class.
-    *
-    * @access private
-    * @return integer The sheet index, -1 if the sheet was not found
-    */
-    function _getSheetIndex($sheet_name)
-    {
-        if (!isset($this->_ext_sheets[$sheet_name])) {
-            return -1;
-        } else {
-            return $this->_ext_sheets[$sheet_name];
-        }
-    }
-
-    /**
-    * This method is used to update the array of sheet names. It is
-    * called by the addWorksheet() method of the
-    * Spreadsheet_Excel_Writer_Workbook class.
-    *
-    * @access public
-    * @see Spreadsheet_Excel_Writer_Workbook::addWorksheet()
-    * @param string  $name  The name of the worksheet being added
-    * @param integer $index The index of the worksheet being added
-    */
-    function setExtSheet($name, $index)
-    {
-        $this->_ext_sheets[$name] = $index;
-    }
-
-    /**
-    * pack() row and column into the required 3 or 4 byte format.
-    *
-    * @access private
-    * @param string $cell The Excel cell reference to be packed
-    * @return array Array containing the row and column in packed() format
-    */
-    function _cellToPackedRowcol($cell)
-    {
-        $cell = strtoupper($cell);
-        list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell);
-        if ($col >= 256) {
-            return $this->raiseError("Column in: $cell greater than 255");
-        }
-        // FIXME: change for BIFF8
-        if ($row >= 16384) {
-            return $this->raiseError("Row in: $cell greater than 16384 ");
-        }
-
-        // Set the high bits to indicate if row or col are relative.
-        if ($this->_BIFF_version == 0x0500) {
-            $row    |= $col_rel << 14;
-            $row    |= $row_rel << 15;
-            $col     = pack('C', $col);
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $col    |= $col_rel << 14;
-            $col    |= $row_rel << 15;
-            $col     = pack('v', $col);
-        }
-        $row     = pack('v', $row);
-
-        return array($row, $col);
-    }
-
-    /**
-    * pack() row range into the required 3 or 4 byte format.
-    * Just using maximum col/rows, which is probably not the correct solution
-    *
-    * @access private
-    * @param string $range The Excel range to be packed
-    * @return array Array containing (row1,col1,row2,col2) in packed() format
-    */
-    function _rangeToPackedRange($range)
-    {
-        preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match);
-        // return absolute rows if there is a $ in the ref
-        $row1_rel = empty($match[1]) ? 1 : 0;
-        $row1     = $match[2];
-        $row2_rel = empty($match[3]) ? 1 : 0;
-        $row2     = $match[4];
-        // Convert 1-index to zero-index
-        $row1--;
-        $row2--;
-        // Trick poor inocent Excel
-        $col1 = 0;
-        $col2 = 16383; // FIXME: maximum possible value for Excel 5 (change this!!!)
-
-        // FIXME: this changes for BIFF8
-        if (($row1 >= 16384) or ($row2 >= 16384)) {
-            return $this->raiseError("Row in: $range greater than 16384 ");
-        }
-
-        // Set the high bits to indicate if rows are relative.
-        if ($this->_BIFF_version == 0x0500) {
-            $row1    |= $row1_rel << 14; // FIXME: probably a bug
-            $row2    |= $row2_rel << 15;
-            $col1     = pack('C', $col1);
-            $col2     = pack('C', $col2);
-        } elseif ($this->_BIFF_version == 0x0600) {
-            $col1    |= $row1_rel << 15;
-            $col2    |= $row2_rel << 15;
-            $col1     = pack('v', $col1);
-            $col2     = pack('v', $col2);
-        }
-        $row1     = pack('v', $row1);
-        $row2     = pack('v', $row2);
-
-        return array($row1, $col1, $row2, $col2);
-    }
-
-    /**
-    * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero
-    * indexed row and column number. Also returns two (0,1) values to indicate
-    * whether the row or column are relative references.
-    *
-    * @access private
-    * @param string $cell The Excel cell reference in A1 format.
-    * @return array
-    */
-    function _cellToRowcol($cell)
-    {
-        preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match);
-        // return absolute column if there is a $ in the ref
-        $col_rel = empty($match[1]) ? 1 : 0;
-        $col_ref = $match[2];
-        $row_rel = empty($match[3]) ? 1 : 0;
-        $row     = $match[4];
-
-        // Convert base26 column string to a number.
-        $expn   = strlen($col_ref) - 1;
-        $col    = 0;
-        $col_ref_length = strlen($col_ref);
-        for ($i = 0; $i < $col_ref_length; $i++) {
-            $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn);
-            $expn--;
-        }
-
-        // Convert 1-index to zero-index
-        $row--;
-        $col--;
-
-        return array($row, $col, $row_rel, $col_rel);
-    }
-
-    /**
-    * Advance to the next valid token.
-    *
-    * @access private
-    */
-    function _advance()
-    {
-        $i = $this->_current_char;
-        $formula_length = strlen($this->_formula);
-        // eat up white spaces
-        if ($i < $formula_length) {
-            while ($this->_formula{$i} == " ") {
-                $i++;
-            }
-
-            if ($i < ($formula_length - 1)) {
-                $this->_lookahead = $this->_formula{$i+1};
-            }
-            $token = '';
-        }
-
-        while ($i < $formula_length) {
-            $token .= $this->_formula{$i};
-            if ($i < ($formula_length - 1)) {
-                $this->_lookahead = $this->_formula{$i+1};
-            } else {
-                $this->_lookahead = '';
-            }
-
-            if ($this->_match($token) != '') {
-                //if ($i < strlen($this->_formula) - 1) {
-                //    $this->_lookahead = $this->_formula{$i+1};
-                //}
-                $this->_current_char = $i + 1;
-                $this->_current_token = $token;
-                return 1;
-            }
-
-            if ($i < ($formula_length - 2)) {
-                $this->_lookahead = $this->_formula{$i+2};
-            } else { // if we run out of characters _lookahead becomes empty
-                $this->_lookahead = '';
-            }
-            $i++;
-        }
-        //die("Lexical error ".$this->_current_char);
-    }
-
-    /**
-    * Checks if it's a valid token.
-    *
-    * @access private
-    * @param mixed $token The token to check.
-    * @return mixed       The checked token or false on failure
-    */
-    function _match($token)
-    {
-        switch($token) {
-            case SPREADSHEET_EXCEL_WRITER_ADD:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_SUB:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_MUL:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_DIV:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_OPEN:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_CLOSE:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_COMA:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_SEMICOLON:
-                return $token;
-                break;
-            case SPREADSHEET_EXCEL_WRITER_GT:
-                if ($this->_lookahead == '=') { // it's a GE token
-                    break;
-                }
-                return $token;
-                break;
-   &n