Browse Source

Upgrade phpexcel lib to 1.7.8

Laurent Destailleur 11 years ago
parent
commit
789427b75d
100 changed files with 19298 additions and 11119 deletions
  1. 1 1
      COPYRIGHT
  2. 1 0
      ChangeLog
  3. 1 1
      htdocs/core/modules/export/export_excel.modules.php
  4. 1 1
      htdocs/core/modules/export/export_excel2007.modules.php
  5. 50 23
      htdocs/includes/phpexcel/PHPExcel.php
  6. 39 14
      htdocs/includes/phpexcel/PHPExcel/Autoloader.php
  7. 280 218
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/APC.php
  8. 252 172
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/CacheBase.php
  9. 205 157
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/DiscISAM.php
  10. 38 30
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/ICache.php
  11. 138 0
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Igbinary.php
  12. 298 236
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Memcache.php
  13. 109 98
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Memory.php
  14. 123 107
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/MemoryGZip.php
  15. 123 107
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/MemorySerialized.php
  16. 192 157
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/PHPTemp.php
  17. 270 0
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/SQLite.php
  18. 277 0
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/SQLite3.php
  19. 280 230
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Wincache.php
  20. 238 130
      htdocs/includes/phpexcel/PHPExcel/CachedObjectStorageFactory.php
  21. 213 185
      htdocs/includes/phpexcel/PHPExcel/Calculation.php
  22. 359 18
      htdocs/includes/phpexcel/PHPExcel/Calculation/Database.php
  23. 364 95
      htdocs/includes/phpexcel/PHPExcel/Calculation/DateTime.php
  24. 454 154
      htdocs/includes/phpexcel/PHPExcel/Calculation/Engineering.php
  25. 5 5
      htdocs/includes/phpexcel/PHPExcel/Calculation/Exception.php
  26. 4 4
      htdocs/includes/phpexcel/PHPExcel/Calculation/ExceptionHandler.php
  27. 554 152
      htdocs/includes/phpexcel/PHPExcel/Calculation/Financial.php
  28. 4 4
      htdocs/includes/phpexcel/PHPExcel/Calculation/FormulaParser.php
  29. 4 4
      htdocs/includes/phpexcel/PHPExcel/Calculation/FormulaToken.php
  30. 6 6
      htdocs/includes/phpexcel/PHPExcel/Calculation/Function.php
  31. 156 146
      htdocs/includes/phpexcel/PHPExcel/Calculation/Functions.php
  32. 74 76
      htdocs/includes/phpexcel/PHPExcel/Calculation/Logical.php
  33. 129 67
      htdocs/includes/phpexcel/PHPExcel/Calculation/LookupRef.php
  34. 325 200
      htdocs/includes/phpexcel/PHPExcel/Calculation/MathTrig.php
  35. 280 279
      htdocs/includes/phpexcel/PHPExcel/Calculation/Statistical.php
  36. 96 86
      htdocs/includes/phpexcel/PHPExcel/Calculation/TextData.php
  37. 73 0
      htdocs/includes/phpexcel/PHPExcel/Calculation/Token/Stack.php
  38. 315 218
      htdocs/includes/phpexcel/PHPExcel/Cell.php
  39. 64 14
      htdocs/includes/phpexcel/PHPExcel/Cell/AdvancedValueBinder.php
  40. 5 5
      htdocs/includes/phpexcel/PHPExcel/Cell/DataType.php
  41. 27 27
      htdocs/includes/phpexcel/PHPExcel/Cell/DataValidation.php
  42. 6 6
      htdocs/includes/phpexcel/PHPExcel/Cell/DefaultValueBinder.php
  43. 14 14
      htdocs/includes/phpexcel/PHPExcel/Cell/Hyperlink.php
  44. 4 4
      htdocs/includes/phpexcel/PHPExcel/Cell/IValueBinder.php
  45. 527 0
      htdocs/includes/phpexcel/PHPExcel/Chart.php
  46. 354 0
      htdocs/includes/phpexcel/PHPExcel/Chart/DataSeries.php
  47. 321 0
      htdocs/includes/phpexcel/PHPExcel/Chart/DataSeriesValues.php
  48. 52 0
      htdocs/includes/phpexcel/PHPExcel/Chart/Exception.php
  49. 417 0
      htdocs/includes/phpexcel/PHPExcel/Chart/Layout.php
  50. 171 0
      htdocs/includes/phpexcel/PHPExcel/Chart/Legend.php
  51. 125 0
      htdocs/includes/phpexcel/PHPExcel/Chart/PlotArea.php
  52. 17 0
      htdocs/includes/phpexcel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt
  53. 839 0
      htdocs/includes/phpexcel/PHPExcel/Chart/Renderer/jpgraph.php
  54. 89 0
      htdocs/includes/phpexcel/PHPExcel/Chart/Title.php
  55. 4 4
      htdocs/includes/phpexcel/PHPExcel/Comment.php
  56. 23 23
      htdocs/includes/phpexcel/PHPExcel/DocumentProperties.php
  57. 4 4
      htdocs/includes/phpexcel/PHPExcel/DocumentSecurity.php
  58. 52 0
      htdocs/includes/phpexcel/PHPExcel/Exception.php
  59. 5 5
      htdocs/includes/phpexcel/PHPExcel/HashTable.php
  60. 6 6
      htdocs/includes/phpexcel/PHPExcel/IComparable.php
  61. 96 82
      htdocs/includes/phpexcel/PHPExcel/IOFactory.php
  62. 10 10
      htdocs/includes/phpexcel/PHPExcel/NamedRange.php
  63. 199 105
      htdocs/includes/phpexcel/PHPExcel/Reader/CSV.php
  64. 4 4
      htdocs/includes/phpexcel/PHPExcel/Reader/DefaultReadFilter.php
  65. 156 37
      htdocs/includes/phpexcel/PHPExcel/Reader/Excel2003XML.php
  66. 432 108
      htdocs/includes/phpexcel/PHPExcel/Reader/Excel2007.php
  67. 513 0
      htdocs/includes/phpexcel/PHPExcel/Reader/Excel2007/Chart.php
  68. 4 4
      htdocs/includes/phpexcel/PHPExcel/Reader/Excel2007/Theme.php
  69. 6890 6667
      htdocs/includes/phpexcel/PHPExcel/Reader/Excel5.php
  70. 4 4
      htdocs/includes/phpexcel/PHPExcel/Reader/Excel5/Escher.php
  71. 125 57
      htdocs/includes/phpexcel/PHPExcel/Reader/Gnumeric.php
  72. 499 0
      htdocs/includes/phpexcel/PHPExcel/Reader/HTML.php
  73. 7 7
      htdocs/includes/phpexcel/PHPExcel/Reader/IReadFilter.php
  74. 9 9
      htdocs/includes/phpexcel/PHPExcel/Reader/IReader.php
  75. 224 73
      htdocs/includes/phpexcel/PHPExcel/Reader/OOCalc.php
  76. 103 20
      htdocs/includes/phpexcel/PHPExcel/Reader/SYLK.php
  77. 63 10
      htdocs/includes/phpexcel/PHPExcel/ReferenceHelper.php
  78. 5 5
      htdocs/includes/phpexcel/PHPExcel/RichText.php
  79. 3 3
      htdocs/includes/phpexcel/PHPExcel/RichText/ITextElement.php
  80. 3 3
      htdocs/includes/phpexcel/PHPExcel/RichText/Run.php
  81. 3 3
      htdocs/includes/phpexcel/PHPExcel/RichText/TextElement.php
  82. 255 16
      htdocs/includes/phpexcel/PHPExcel/Settings.php
  83. 49 43
      htdocs/includes/phpexcel/PHPExcel/Shared/CodePage.php
  84. 73 32
      htdocs/includes/phpexcel/PHPExcel/Shared/Date.php
  85. 21 21
      htdocs/includes/phpexcel/PHPExcel/Shared/Drawing.php
  86. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher.php
  87. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DgContainer.php
  88. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php
  89. 31 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php
  90. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer.php
  91. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php
  92. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php
  93. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php
  94. 4 4
      htdocs/includes/phpexcel/PHPExcel/Shared/Excel5.php
  95. 8 8
      htdocs/includes/phpexcel/PHPExcel/Shared/File.php
  96. 20 8
      htdocs/includes/phpexcel/PHPExcel/Shared/Font.php
  97. 0 6
      htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/docs.php
  98. 0 65
      htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/download.php
  99. 0 166
      htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/example.php
  100. 0 14
      htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/includes/credits.php

+ 1 - 1
COPYRIGHT

@@ -19,7 +19,7 @@ FPDF_TPL              1.2           Apache Software License 2.0 Yes
 GeoIP                 1.4           LGPL-2.1+                   Yes             Sample code to make geoip convert (not into deb package)
 NuSoap                0.9.5         LGPL 2.1+                   Yes             Library to develop SOAP Web services (not into rpm and deb package)
 odtPHP                1.0.1         GPL-2+  b                   Yes             Library to build/edit ODT files
-PHPExcel              1.7.6         LGPL-2.1+                   Yes             Read/Write XLS files, read ODS files
+PHPExcel              1.7.8         LGPL-2.1+                   Yes             Read/Write XLS files, read ODS files
 PHPPrintIPP           1.3           GPL-2+                      Yes             Library to send print IPP requests
 TCPDF                 6.0.021       LGPL-3+                     Yes             PDF generation
 

+ 1 - 0
ChangeLog

@@ -49,6 +49,7 @@ For users:
 - New: [ task #1204 ] add a External reference to contract
 - New: [ task #1218 ] Can drag and drop an event from calendar to change its day.
 - New: Optimize size of image static resources.
+- Upgrade phpexcel lib to 1.7.8
 - Fix: [ bug #1487 ] PAYMENT_DELETE trigger does not intercept trigger action
 - Fix: [ bug #1470, #1472, #1473] User trigger problem
 - Fix: [ bug #1489, #1491 ] Intervention trigger problem

+ 1 - 1
htdocs/core/modules/export/export_excel.modules.php

@@ -66,7 +66,7 @@ class ExportExcel extends ModeleExports
 
 		// If driver use an external library, put its name here
 		$this->label_lib='PhpExcel';
-		$this->version_lib='1.7.2';
+		$this->version_lib='1.7.8';
 
 		$this->disabled = (in_array(constant('PHPEXCEL_PATH'),array('disabled','disabled/'))?1:0);	// A condition to disable module (used for native debian packages)
 

+ 1 - 1
htdocs/core/modules/export/export_excel2007.modules.php

@@ -66,7 +66,7 @@ class ExportExcel2007 extends ExportExcel
 
 		// If driver use an external library, put its name here
 		$this->label_lib='PhpExcel';
-		$this->version_lib='1.7.2';
+		$this->version_lib='1.7.8';
 
 		$this->disabled = (in_array(constant('PHPEXCEL_PATH'),array('disabled','disabled/'))?1:0);	// A condition to disable module (used for native debian packages)
 

+ 50 - 23
htdocs/includes/phpexcel/PHPExcel.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -38,7 +38,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel
 {
@@ -127,6 +127,11 @@ class PHPExcel
 	}
 
 
+	/**
+	 * Disconnect all worksheets from this PHPExcel workbook object,
+	 *    typically so that the PHPExcel object can be unset
+	 *
+	 */
 	public function disconnectWorksheets() {
 		foreach($this->_workSheetCollection as $k => &$worksheet) {
 			$worksheet->disconnectCells();
@@ -189,15 +194,28 @@ class PHPExcel
     /**
      * Create sheet and add it to this workbook
      *
+	 * @param int|null $iSheetIndex Index where sheet should go (0,1,..., or null for last)
      * @return PHPExcel_Worksheet
+     * @throws Exception
      */
-    public function createSheet($iSheetIndex = null)
+    public function createSheet($iSheetIndex = NULL)
     {
         $newSheet = new PHPExcel_Worksheet($this);
         $this->addSheet($newSheet, $iSheetIndex);
         return $newSheet;
     }
 
+    /**
+     * Chech if a sheet with a specified name already exists
+     *
+     * @param string $pSheetName  Name of the worksheet to check
+     * @return boolean
+     */
+    public function sheetNameExists($pSheetName)
+    {
+		return ($this->getSheetByName($pSheetName) !== NULL);
+    }
+
     /**
      * Add sheet
      *
@@ -206,14 +224,18 @@ class PHPExcel
      * @return PHPExcel_Worksheet
      * @throws Exception
      */
-    public function addSheet(PHPExcel_Worksheet $pSheet = null, $iSheetIndex = null)
+    public function addSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = NULL)
     {
-        if(is_null($iSheetIndex))
-        {
+		if ($this->sheetNameExists($pSheet->getTitle())) {
+			throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename this worksheet first.");
+		}
+
+        if($iSheetIndex === NULL) {
+            if ($this->_activeSheetIndex < 0) {
+            	$this->_activeSheetIndex = 0;
+            }
             $this->_workSheetCollection[] = $pSheet;
-        }
-        else
-        {
+        } else {
             // Insert the sheet at the requested index
             array_splice(
                 $this->_workSheetCollection,
@@ -226,7 +248,6 @@ class PHPExcel
 			if ($this->_activeSheetIndex >= $iSheetIndex) {
 				++$this->_activeSheetIndex;
 			}
-
         }
 		return $pSheet;
     }
@@ -244,6 +265,12 @@ class PHPExcel
 		} else {
 			array_splice($this->_workSheetCollection, $pIndex, 1);
 		}
+		// Adjust active sheet index if necessary
+		if (($this->_activeSheetIndex >= $pIndex) &&
+			($pIndex > count($this->_workSheetCollection) - 1)) {
+			--$this->_activeSheetIndex;
+		}
+
 	}
 
 	/**
@@ -379,7 +406,7 @@ class PHPExcel
 	public function setActiveSheetIndexByName($pValue = '')
 	{
 		if (($worksheet = $this->getSheetByName($pValue)) instanceof PHPExcel_Worksheet) {
-			$this->setActiveSheetIndex($worksheet->getParent()->getIndex($worksheet));
+			$this->setActiveSheetIndex($this->getIndex($worksheet));
 			return $worksheet;
 		}
 
@@ -396,7 +423,7 @@ class PHPExcel
 		$returnValue = array();
 		$worksheetCount = $this->getSheetCount();
 		for ($i = 0; $i < $worksheetCount; ++$i) {
-			array_push($returnValue, $this->getSheet($i)->getTitle());
+			$returnValue[] = $this->getSheet($i)->getTitle();
 		}
 
 		return $returnValue;
@@ -411,7 +438,7 @@ class PHPExcel
 	 * @return PHPExcel_Worksheet
 	 */
 	public function addExternalSheet(PHPExcel_Worksheet $pSheet, $iSheetIndex = null) {
-		if (!is_null($this->getSheetByName($pSheet->getTitle()))) {
+		if ($this->sheetNameExists($pSheet->getTitle())) {
 			throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
 		}
 
@@ -471,14 +498,14 @@ class PHPExcel
 	public function getNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null) {
 		$returnValue = null;
 
-		if ($namedRange != '' && !is_null($namedRange)) {
+		if ($namedRange != '' && ($namedRange !== NULL)) {
 			// first look for global defined name
 			if (isset($this->_namedRanges[$namedRange])) {
 				$returnValue = $this->_namedRanges[$namedRange];
 			}
 
 			// then look for local defined name (has priority over global defined name if both names exist)
-			if (!is_null($pSheet) && isset($this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
+			if (($pSheet !== NULL) && isset($this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange])) {
 				$returnValue = $this->_namedRanges[$pSheet->getTitle() . '!' . $namedRange];
 			}
 		}
@@ -489,12 +516,12 @@ class PHPExcel
 	/**
 	 * Remove named range
 	 *
-	 * @param string $namedRange
-	 * @param PHPExcel_Worksheet|null $pSheet. Scope. Use null for global scope.
+	 * @param  string  $namedRange
+	 * @param  PHPExcel_Worksheet|null  $pSheet  Scope: use null for global scope.
 	 * @return PHPExcel
 	 */
 	public function removeNamedRange($namedRange, PHPExcel_Worksheet $pSheet = null) {
-		if (is_null($pSheet)) {
+		if ($pSheet === NULL) {
 			if (isset($this->_namedRanges[$namedRange])) {
 				unset($this->_namedRanges[$namedRange]);
 			}
@@ -556,7 +583,7 @@ class PHPExcel
 	/**
 	 * Get cellXf by index
 	 *
-	 * @param int $index
+	 * @param int $pIndex
 	 * @return PHPExcel_Style
 	 */
 	public function getCellXfByIndex($pIndex = 0)
@@ -597,7 +624,7 @@ class PHPExcel
 	/**
 	 * Add a cellXf to the workbook
 	 *
-	 * @param PHPExcel_Style
+	 * @param PHPExcel_Style $style
 	 */
 	public function addCellXf(PHPExcel_Style $style)
 	{
@@ -761,7 +788,7 @@ class PHPExcel
 		}
 
 		// make sure there is always at least one cellXf (there should be)
-		if (count($this->_cellXfCollection) == 0) {
+		if (empty($this->_cellXfCollection)) {
 			$this->_cellXfCollection[] = new PHPExcel_Style();
 		}
 

+ 39 - 14
htdocs/includes/phpexcel/PHPExcel/Autoloader.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,41 +20,66 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ * @version    1.7.8, 2012-10-12
  */
 
 PHPExcel_Autoloader::Register();
+//	As we always try to run the autoloader before anything else, we can use it to do a few
+//		simple checks and initialisations
 PHPExcel_Shared_ZipStreamWrapper::register();
 // check mbstring.func_overload
 if (ini_get('mbstring.func_overload') & 2) {
-	throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).');
+    throw new Exception('Multibyte function overloading in PHP must be disabled for string functions (2).');
 }
 PHPExcel_Shared_String::buildCharacterSets();
 
 
+/**
+ * PHPExcel_Autoloader
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
 class PHPExcel_Autoloader
 {
+	/**
+	 * Register the Autoloader with SPL
+	 *
+	 */
 	public static function Register() {
+		if (function_exists('__autoload')) {
+			//	Register any existing autoloader function with SPL, so we don't get any clashes
+			spl_autoload_register('__autoload');
+		}
+		//	Register ourselves with SPL
 		return spl_autoload_register(array('PHPExcel_Autoloader', 'Load'));
 	}	//	function Register()
 
 
-	public static function Load($pObjectName){
-		if ((class_exists($pObjectName)) || (strpos($pObjectName, 'PHPExcel') === False)) {
-			return false;
+	/**
+	 * Autoload a class identified by name
+	 *
+	 * @param	string	$pClassName		Name of the object to load
+	 */
+	public static function Load($pClassName){
+		if ((class_exists($pClassName,FALSE)) || (strpos($pClassName, 'PHPExcel') !== 0)) {
+			//	Either already loaded, or not a PHPExcel class request
+			return FALSE;
 		}
 
-		$pObjectFilePath =	PHPEXCEL_ROOT.
-							str_replace('_',DIRECTORY_SEPARATOR,$pObjectName).
-							'.php';
+		$pClassFilePath = PHPEXCEL_ROOT .
+						  str_replace('_',DIRECTORY_SEPARATOR,$pClassName) .
+						  '.php';
 
-		if ((file_exists($pObjectFilePath) === false) || (is_readable($pObjectFilePath) === false)) {
-			return false;
+		if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
+			//	Can't load
+			return FALSE;
 		}
 
-		require($pObjectFilePath);
+		require($pClassFilePath);
 	}	//	function Load()
 
 }

+ 280 - 218
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/APC.php

@@ -1,218 +1,280 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_APC
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private $_cachePrefix = null;
-
-	private $_cacheTime = 600;
-
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		if (!apc_store($this->_cachePrefix.$this->_currentObjectID.'.cache',serialize($this->_currentObject),$this->_cacheTime)) {
-			$this->__destruct();
-			throw new Exception('Failed to store cell '.$cellID.' in APC');
-		}
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-		$this->_cellCache[$pCoord] = true;
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-	/**
-	 *	Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
-	 *
-	 *	@param	string		$pCoord		Coordinate address of the cell to check
-	 *	@return	void
-	 *	@return	boolean
-	 */
-	public function isDataSet($pCoord) {
-		//	Check if the requested entry is the current object, or exists in the cache
-		if (parent::isDataSet($pCoord)) {
-			if ($this->_currentObjectID == $pCoord) {
-				return true;
-			}
-			//	Check if the requested entry still exists in apc
-			$success = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
-			if ($success === false) {
-				//	Entry no longer exists in APC, so clear it from the cache array
-				parent::deleteCacheData($pCoord);
-				throw new Exception('Cell entry '.$cellID.' no longer exists in APC');
-			}
-			return true;
-		}
-		return false;
-	}	//	function isDataSet()
-
-
-    /**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		if (parent::isDataSet($pCoord)) {
-			$obj = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
-			if ($obj === false) {
-				//	Entry no longer exists in APC, so clear it from the cache array
-				parent::deleteCacheData($pCoord);
-				throw new Exception('Cell entry '.$cellID.' no longer exists in APC');
-			}
-		} else {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = unserialize($obj);
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-    /**
-     *	Delete a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to delete
-     *	@throws	Exception
-     */
-	public function deleteCacheData($pCoord) {
-		//	Delete the entry from APC
-		apc_delete($this->_cachePrefix.$pCoord.'.cache');
-
-		//	Delete the entry from our cell address array
-		parent::deleteCacheData($pCoord);
-	}	//	function deleteCacheData()
-
-
-	/**
-	 *	Clone the cell collection
-	 *
-	 *	@return	void
-	 */
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		parent::copyCellCollection($parent);
-		//	Get a new id for the new file name
-		$baseUnique = $this->_getUniqueID();
-		$newCachePrefix = substr(md5($baseUnique),0,8).'.';
-		$cacheList = $this->getCellList();
-		foreach($cacheList as $cellID) {
-			if ($cellID != $this->_currentObjectID) {
-				$obj = apc_fetch($this->_cachePrefix.$cellID.'.cache');
-				if ($obj === false) {
-					//	Entry no longer exists in APC, so clear it from the cache array
-					parent::deleteCacheData($cellID);
-					throw new Exception('Cell entry '.$cellID.' no longer exists in APC');
-				}
-				if (!apc_store($newCachePrefix.$cellID.'.cache',$obj,$this->_cacheTime)) {
-					$this->__destruct();
-					throw new Exception('Failed to store cell '.$cellID.' in APC');
-				}
-			}
-		}
-		$this->_cachePrefix = $newCachePrefix;
-	}	//	function copyCellCollection()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-
-		//	Flush the APC cache
-		$this->__destruct();
-
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-	}	//	function unsetWorksheetCells()
-
-
-	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
-		$cacheTime	= (isset($arguments['cacheTime']))	? $arguments['cacheTime']	: 600;
-
-		if (is_null($this->_cachePrefix)) {
-			$baseUnique = $this->_getUniqueID();
-			$this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
-			$this->_cacheTime = $cacheTime;
-
-			parent::__construct($parent);
-		}
-	}	//	function __construct()
-
-
-	public function __destruct() {
-		$cacheList = $this->getCellList();
-		foreach($cacheList as $cellID) {
-			apc_delete($this->_cachePrefix.$cellID.'.cache');
-		}
-	}	//	function __destruct()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_APC
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Prefix used to uniquely identify cache data for this worksheet
+	 *
+	 * @access	private
+	 * @var string
+	 */
+	private $_cachePrefix = null;
+
+	/**
+	 * Cache timeout
+	 *
+	 * @access	private
+	 * @var integer
+	 */
+	private $_cacheTime = 600;
+
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @access	private
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			if (!apc_store($this->_cachePrefix.$this->_currentObjectID.'.cache',serialize($this->_currentObject),$this->_cacheTime)) {
+				$this->__destruct();
+				throw new Exception('Failed to store cell '.$this->_currentObjectID.' in APC');
+			}
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+	 * @access	public
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+		$this->_cellCache[$pCoord] = true;
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+	/**
+	 * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+	 *
+	 * @access	public
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	void
+	 * @return	boolean
+	 */
+	public function isDataSet($pCoord) {
+		//	Check if the requested entry is the current object, or exists in the cache
+		if (parent::isDataSet($pCoord)) {
+			if ($this->_currentObjectID == $pCoord) {
+				return true;
+			}
+			//	Check if the requested entry still exists in apc
+			$success = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
+			if ($success === false) {
+				//	Entry no longer exists in APC, so clear it from the cache array
+				parent::deleteCacheData($pCoord);
+				throw new Exception('Cell entry '.$pCoord.' no longer exists in APC');
+			}
+			return true;
+		}
+		return false;
+	}	//	function isDataSet()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+	 * @access	public
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (parent::isDataSet($pCoord)) {
+			$obj = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
+			if ($obj === false) {
+				//	Entry no longer exists in APC, so clear it from the cache array
+				parent::deleteCacheData($pCoord);
+				throw new Exception('Cell entry '.$pCoord.' no longer exists in APC');
+			}
+		} else {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = unserialize($obj);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+	 * @access	public
+     * @param	string			$pCoord		Coordinate address of the cell to delete
+     * @throws	Exception
+     */
+	public function deleteCacheData($pCoord) {
+		//	Delete the entry from APC
+		apc_delete($this->_cachePrefix.$pCoord.'.cache');
+
+		//	Delete the entry from our cell address array
+		parent::deleteCacheData($pCoord);
+	}	//	function deleteCacheData()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @access	public
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		parent::copyCellCollection($parent);
+		//	Get a new id for the new file name
+		$baseUnique = $this->_getUniqueID();
+		$newCachePrefix = substr(md5($baseUnique),0,8).'.';
+		$cacheList = $this->getCellList();
+		foreach($cacheList as $cellID) {
+			if ($cellID != $this->_currentObjectID) {
+				$obj = apc_fetch($this->_cachePrefix.$cellID.'.cache');
+				if ($obj === false) {
+					//	Entry no longer exists in APC, so clear it from the cache array
+					parent::deleteCacheData($cellID);
+					throw new Exception('Cell entry '.$cellID.' no longer exists in APC');
+				}
+				if (!apc_store($newCachePrefix.$cellID.'.cache',$obj,$this->_cacheTime)) {
+					$this->__destruct();
+					throw new Exception('Failed to store cell '.$cellID.' in APC');
+				}
+			}
+		}
+		$this->_cachePrefix = $newCachePrefix;
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if ($this->_currentObject !== NULL) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+
+		//	Flush the APC cache
+		$this->__destruct();
+
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 * @param	array of mixed		$arguments	Additional initialisation arguments
+	 */
+	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
+		$cacheTime	= (isset($arguments['cacheTime']))	? $arguments['cacheTime']	: 600;
+
+		if ($this->_cachePrefix === NULL) {
+			$baseUnique = $this->_getUniqueID();
+			$this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
+			$this->_cacheTime = $cacheTime;
+
+			parent::__construct($parent);
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		$cacheList = $this->getCellList();
+		foreach($cacheList as $cellID) {
+			apc_delete($this->_cachePrefix.$cellID.'.cache');
+		}
+	}	//	function __destruct()
+
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		if (!function_exists('apc_store')) {
+			return false;
+		}
+		if (apc_sma_info() === false) {
+			return false;
+		}
+
+		return true;
+	}
+
+}

+ 252 - 172
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/CacheBase.php

@@ -1,172 +1,252 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_CacheBase
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_CacheBase {
-
-	/**
-	 *	Parent worksheet
-	 *
-	 *	@var PHPExcel_Worksheet
-	 */
-	protected $_parent;
-
-	/**
-	 *	The currently active Cell
-	 *
-	 *	@var PHPExcel_Cell
-	 */
-	protected $_currentObject = null;
-
-	/**
-	 *	Coordinate address of the currently active Cell
-	 *
-	 *	@var string
-	 */
-	protected $_currentObjectID = null;
-
-
-	/**
-	 *	An array of cells or cell pointers for the worksheet cells held in this cache,
-	 *		and indexed by their coordinate address within the worksheet
-	 *
-	 *	@var array of mixed
-	 */
-	protected $_cellCache = array();
-
-
-	public function __construct(PHPExcel_Worksheet $parent) {
-		//	Set our parent worksheet.
-		//	This is maintained within the cache controller to facilitate re-attaching it to PHPExcel_Cell objects when
-		//		they are woken from a serialized state
-		$this->_parent = $parent;
-	}	//	function __construct()
-
-
-	/**
-	 *	Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
-	 *
-	 *	@param	string		$pCoord		Coordinate address of the cell to check
-	 *	@return	void
-	 *	@return	boolean
-	 */
-	public function isDataSet($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return true;
-		}
-		//	Check if the requested entry exists in the cache
-		return isset($this->_cellCache[$pCoord]);
-	}	//	function isDataSet()
-
-
-    /**
-     *	Add or Update a cell in cache
-     *
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function updateCacheData(PHPExcel_Cell $cell) {
-		return $this->addCacheData($cell->getCoordinate(),$cell);
-	}	//	function updateCacheData()
-
-
-    /**
-     *	Delete a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to delete
-     *	@throws	Exception
-     */
-	public function deleteCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			$this->_currentObject->detach();
-			$this->_currentObjectID = $this->_currentObject = null;
-		}
-
-		if (is_object($this->_cellCache[$pCoord])) {
-			$this->_cellCache[$pCoord]->detach();
-			unset($this->_cellCache[$pCoord]);
-		}
-	}	//	function deleteCacheData()
-
-
-	/**
-	 *	Get a list of all cell addresses currently held in cache
-	 *
-	 *	@return	array of string
-	 */
-	public function getCellList() {
-		return array_keys($this->_cellCache);
-	}	//	function getCellList()
-
-
-	/**
-	 *	Sort the list of all cell addresses currently held in cache by row and column
-	 *
-	 *	@return	void
-	 */
-	public function getSortedCellList() {
-		$sortKeys = array();
-		foreach (array_keys($this->_cellCache) as $coord) {
-			list($column,$row) = sscanf($coord,'%[A-Z]%d');
-			$sortKeys[sprintf('%09d%3s',$row,$column)] = $coord;
-		}
-		ksort($sortKeys);
-
-		return array_values($sortKeys);
-	}	//	function sortCellList()
-
-
-	protected function _getUniqueID() {
-		if (function_exists('posix_getpid')) {
-			$baseUnique = posix_getpid();
-		} else {
-			$baseUnique = mt_rand();
-		}
-		return uniqid($baseUnique,true);
-	}
-
-	/**
-	 *	Clone the cell collection
-	 *
-	 *	@return	void
-	 */
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		$this->_parent = $parent;
-		if ((!is_null($this->_currentObject)) && (is_object($this->_currentObject))) {
-			$this->_currentObject->attach($parent);
-		}
-	}	//	function copyCellCollection()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_CacheBase
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+abstract class PHPExcel_CachedObjectStorage_CacheBase {
+
+	/**
+	 * Parent worksheet
+	 *
+	 * @var PHPExcel_Worksheet
+	 */
+	protected $_parent;
+
+	/**
+	 * The currently active Cell
+	 *
+	 * @var PHPExcel_Cell
+	 */
+	protected $_currentObject = null;
+
+	/**
+	 * Coordinate address of the currently active Cell
+	 *
+	 * @var string
+	 */
+	protected $_currentObjectID = null;
+
+
+	/**
+	 * Flag indicating whether the currently active Cell requires saving
+	 *
+	 * @var boolean
+	 */
+	protected $_currentCellIsDirty = true;
+
+	/**
+	 * An array of cells or cell pointers for the worksheet cells held in this cache,
+	 *		and indexed by their coordinate address within the worksheet
+	 *
+	 * @var array of mixed
+	 */
+	protected $_cellCache = array();
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 */
+	public function __construct(PHPExcel_Worksheet $parent) {
+		//	Set our parent worksheet.
+		//	This is maintained within the cache controller to facilitate re-attaching it to PHPExcel_Cell objects when
+		//		they are woken from a serialized state
+		$this->_parent = $parent;
+	}	//	function __construct()
+
+
+	/**
+	 * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+	 *
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	boolean
+	 */
+	public function isDataSet($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return true;
+		}
+		//	Check if the requested entry exists in the cache
+		return isset($this->_cellCache[$pCoord]);
+	}	//	function isDataSet()
+
+
+    /**
+     * Add or Update a cell in cache
+     *
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function updateCacheData(PHPExcel_Cell $cell) {
+		return $this->addCacheData($cell->getCoordinate(),$cell);
+	}	//	function updateCacheData()
+
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to delete
+     * @throws	Exception
+     */
+	public function deleteCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			$this->_currentObject->detach();
+			$this->_currentObjectID = $this->_currentObject = null;
+		}
+
+		if (is_object($this->_cellCache[$pCoord])) {
+			$this->_cellCache[$pCoord]->detach();
+			unset($this->_cellCache[$pCoord]);
+		}
+		$this->_currentCellIsDirty = false;
+	}	//	function deleteCacheData()
+
+
+	/**
+	 * Get a list of all cell addresses currently held in cache
+	 *
+	 * @return	array of string
+	 */
+	public function getCellList() {
+		return array_keys($this->_cellCache);
+	}	//	function getCellList()
+
+
+	/**
+	 * Sort the list of all cell addresses currently held in cache by row and column
+	 *
+	 * @return	void
+	 */
+	public function getSortedCellList() {
+		$sortKeys = array();
+		foreach ($this->getCellList() as $coord) {
+			list($column,$row) = sscanf($coord,'%[A-Z]%d');
+			$sortKeys[sprintf('%09d%3s',$row,$column)] = $coord;
+		}
+		ksort($sortKeys);
+
+		return array_values($sortKeys);
+	}	//	function sortCellList()
+
+
+
+	/**
+	 * Get highest worksheet column and highest row that have cell records
+	 *
+	 * @return array Highest column name and highest row number
+	 */
+	public function getHighestRowAndColumn()
+	{
+		// Lookup highest column and highest row
+		$col = array('A' => '1A');
+		$row = array(1);
+		foreach ($this->getCellList() as $coord) {
+			list($c,$r) = sscanf($coord,'%[A-Z]%d');
+			$row[$r] = $r;
+			$col[$c] = strlen($c).$c;
+		}
+		if (!empty($row)) {
+			// Determine highest column and row
+			$highestRow = max($row);
+			$highestColumn = substr(max($col),1);
+		}
+
+		return array( 'row'	   => $highestRow,
+					  'column' => $highestColumn
+					);
+	}
+
+
+	/**
+	 * Get highest worksheet column
+	 *
+	 * @return string Highest column name
+	 */
+	public function getHighestColumn()
+	{
+		$colRow = $this->getHighestRowAndColumn();
+		return $colRow['column'];
+	}
+
+	/**
+	 * Get highest worksheet row
+	 *
+	 * @return int Highest row number
+	 */
+	public function getHighestRow()
+	{
+		$colRow = $this->getHighestRowAndColumn();
+		return $colRow['row'];
+	}
+
+
+	/**
+	 * Generate a unique ID for cache referencing
+	 *
+	 * @return string Unique Reference
+	 */
+	protected function _getUniqueID() {
+		if (function_exists('posix_getpid')) {
+			$baseUnique = posix_getpid();
+		} else {
+			$baseUnique = mt_rand();
+		}
+		return uniqid($baseUnique,true);
+	}
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		$this->_parent = $parent;
+		if (($this->_currentObject !== NULL) && (is_object($this->_currentObject))) {
+			$this->_currentObject->attach($parent);
+		}
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		return true;
+	}
+
+}

+ 205 - 157
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/DiscISAM.php

@@ -1,157 +1,205 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_DiscISAM
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private $_fileName = null;
-	private $_fileHandle = null;
-
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		fseek($this->_fileHandle,0,SEEK_END);
-		$offset = ftell($this->_fileHandle);
-		fwrite($this->_fileHandle, serialize($this->_currentObject));
-		$this->_cellCache[$this->_currentObjectID]	= array('ptr' => $offset,
-															'sz'  => ftell($this->_fileHandle) - $offset
-														   );
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-    /**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		if (!isset($this->_cellCache[$pCoord])) {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']);
-		$this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz']));
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-	/**
-	 *	Clone the cell collection
-	 *
-	 *	@return	void
-	 */
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		parent::copyCellCollection($parent);
-		//	Get a new id for the new file name
-		$baseUnique = $this->_getUniqueID();
-		$newFileName = PHPExcel_Shared_File::sys_get_temp_dir().'/PHPExcel.'.$baseUnique.'.cache';
-		//	Copy the existing cell cache file
-		copy ($this->_fileName,$newFileName);
-		$this->_fileName = $newFileName;
-		//	Open the copied cell cache file
-		$this->_fileHandle = fopen($this->_fileName,'a+');
-	}	//	function copyCellCollection()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-
-		//	Close down the temporary cache file
-		$this->__destruct();
-	}	//	function unsetWorksheetCells()
-
-
-	public function __construct(PHPExcel_Worksheet $parent) {
-		parent::__construct($parent);
-		if (is_null($this->_fileHandle)) {
-			$baseUnique = $this->_getUniqueID();
-			$this->_fileName = PHPExcel_Shared_File::sys_get_temp_dir().'/PHPExcel.'.$baseUnique.'.cache';
-			$this->_fileHandle = fopen($this->_fileName,'a+');
-		}
-	}	//	function __construct()
-
-
-	public function __destruct() {
-		if (!is_null($this->_fileHandle)) {
-			fclose($this->_fileHandle);
-			unlink($this->_fileName);
-		}
-		$this->_fileHandle = null;
-	}	//	function __destruct()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_DiscISAM
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Name of the file for this cache
+	 *
+	 * @var string
+	 */
+	private $_fileName = null;
+
+	/**
+	 * File handle for this cache file
+	 *
+	 * @var resource
+	 */
+	private $_fileHandle = null;
+
+	/**
+	 * Directory/Folder where the cache file is located
+	 *
+	 * @var string
+	 */
+	private $_cacheDirectory = NULL;
+
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			fseek($this->_fileHandle,0,SEEK_END);
+			$offset = ftell($this->_fileHandle);
+			fwrite($this->_fileHandle, serialize($this->_currentObject));
+			$this->_cellCache[$this->_currentObjectID]	= array('ptr' => $offset,
+																'sz'  => ftell($this->_fileHandle) - $offset
+															   );
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (!isset($this->_cellCache[$pCoord])) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']);
+		$this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz']));
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		parent::copyCellCollection($parent);
+		//	Get a new id for the new file name
+		$baseUnique = $this->_getUniqueID();
+		$newFileName = $this->_cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
+		//	Copy the existing cell cache file
+		copy ($this->_fileName,$newFileName);
+		$this->_fileName = $newFileName;
+		//	Open the copied cell cache file
+		$this->_fileHandle = fopen($this->_fileName,'a+');
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+
+		//	Close down the temporary cache file
+		$this->__destruct();
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 * @param	array of mixed		$arguments	Additional initialisation arguments
+	 */
+	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
+		$this->_cacheDirectory	= ((isset($arguments['dir'])) && ($arguments['dir'] !== NULL))
+									? $arguments['dir']
+									: PHPExcel_Shared_File::sys_get_temp_dir();
+
+		parent::__construct($parent);
+		if (is_null($this->_fileHandle)) {
+			$baseUnique = $this->_getUniqueID();
+			$this->_fileName = $this->_cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache';
+			$this->_fileHandle = fopen($this->_fileName,'a+');
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		if (!is_null($this->_fileHandle)) {
+			fclose($this->_fileHandle);
+			unlink($this->_fileName);
+		}
+		$this->_fileHandle = null;
+	}	//	function __destruct()
+
+}

+ 38 - 30
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/ICache.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,74 +31,82 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 interface PHPExcel_CachedObjectStorage_ICache
 {
     /**
-     *	Add or Update a cell in cache identified by coordinate address
+     * Add or Update a cell in cache identified by coordinate address
      *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
      */
 	public function addCacheData($pCoord, PHPExcel_Cell $cell);
 
     /**
-     *	Add or Update a cell in cache
+     * Add or Update a cell in cache
      *
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
      */
 	public function updateCacheData(PHPExcel_Cell $cell);
 
     /**
-     *	Fetch a cell from cache identified by coordinate address
+     * Fetch a cell from cache identified by coordinate address
      *
-     *	@param	string			$pCoord		Coordinate address of the cell to retrieve
-     *	@return PHPExcel_Cell 	Cell that was found, or null if not found
-     *	@throws	Exception
+     * @param	string			$pCoord		Coordinate address of the cell to retrieve
+     * @return PHPExcel_Cell 	Cell that was found, or null if not found
+     * @throws	Exception
      */
 	public function getCacheData($pCoord);
 
     /**
-     *	Delete a cell in cache identified by coordinate address
+     * Delete a cell in cache identified by coordinate address
      *
-     *	@param	string			$pCoord		Coordinate address of the cell to delete
-     *	@throws	Exception
+     * @param	string			$pCoord		Coordinate address of the cell to delete
+     * @throws	Exception
      */
 	public function deleteCacheData($pCoord);
 
 	/**
-	 *	Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+	 * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
 	 *
-	 *	@param	string		$pCoord		Coordinate address of the cell to check
-	 *	@return	void
-	 *	@return	boolean
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	boolean
 	 */
 	public function isDataSet($pCoord);
 
 	/**
-	 *	Get a list of all cell addresses currently held in cache
+	 * Get a list of all cell addresses currently held in cache
 	 *
-	 *	@return	array of string
+	 * @return	array of string
 	 */
 	public function getCellList();
 
 	/**
-	 *	Get the list of all cell addresses currently held in cache sorted by column and row
+	 * Get the list of all cell addresses currently held in cache sorted by column and row
 	 *
-	 *	@return	void
+	 * @return	void
 	 */
 	public function getSortedCellList();
 
 	/**
-	 *	Clone the cell collection
+	 * Clone the cell collection
 	 *
-	 *	@return	void
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
 	 */
 	public function copyCellCollection(PHPExcel_Worksheet $parent);
 
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable();
+
 }

+ 138 - 0
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Igbinary.php

@@ -0,0 +1,138 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_Igbinary
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_Igbinary extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			$this->_cellCache[$this->_currentObjectID] = igbinary_serialize($this->_currentObject);
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (!isset($this->_cellCache[$pCoord])) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = igbinary_unserialize($this->_cellCache[$pCoord]);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		if (!function_exists('igbinary_serialize')) {
+			return false;
+		}
+
+		return true;
+	}
+
+}

+ 298 - 236
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Memcache.php

@@ -1,236 +1,298 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_Memcache
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private $_cachePrefix = null;
-
-	private $_cacheTime = 600;
-
-	private $_memcache = null;
-
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		$obj = serialize($this->_currentObject);
-		if (!$this->_memcache->replace($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
-			if (!$this->_memcache->add($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
-				$this->__destruct();
-				throw new Exception('Failed to store cell '.$cellID.' in MemCache');
-			}
-		}
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-		$this->_cellCache[$pCoord] = true;
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-	/**
-	 *	Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
-	 *
-	 *	@param	string		$pCoord		Coordinate address of the cell to check
-	 *	@return	void
-	 *	@return	boolean
-	 */
-	public function isDataSet($pCoord) {
-		//	Check if the requested entry is the current object, or exists in the cache
-		if (parent::isDataSet($pCoord)) {
-			if ($this->_currentObjectID == $pCoord) {
-				return true;
-			}
-			//	Check if the requested entry still exists in Memcache
-			$success = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
-			if ($success === false) {
-				//	Entry no longer exists in Memcache, so clear it from the cache array
-				parent::deleteCacheData($pCoord);
-				throw new Exception('Cell entry '.$cellID.' no longer exists in MemCache');
-			}
-			return true;
-		}
-		return false;
-	}	//	function isDataSet()
-
-
-	/**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		if (parent::isDataSet($pCoord)) {
-			$obj = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
-			if ($obj === false) {
-				//	Entry no longer exists in Memcache, so clear it from the cache array
-				parent::deleteCacheData($pCoord);
-				throw new Exception('Cell entry '.$cellID.' no longer exists in MemCache');
-			}
-		} else {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = unserialize($obj);
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-    /**
-     *	Delete a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to delete
-     *	@throws	Exception
-     */
-	public function deleteCacheData($pCoord) {
-		//	Delete the entry from Memcache
-		$this->_memcache->delete($this->_cachePrefix.$pCoord.'.cache');
-
-		//	Delete the entry from our cell address array
-		parent::deleteCacheData($pCoord);
-	}	//	function deleteCacheData()
-
-
-	/**
-	 *	Clone the cell collection
-	 *
-	 *	@return	void
-	 */
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		parent::copyCellCollection($parent);
-		//	Get a new id for the new file name
-		$baseUnique = $this->_getUniqueID();
-		$newCachePrefix = substr(md5($baseUnique),0,8).'.';
-		$cacheList = $this->getCellList();
-		foreach($cacheList as $cellID) {
-			if ($cellID != $this->_currentObjectID) {
-				$obj = $this->_memcache->get($this->_cachePrefix.$cellID.'.cache');
-				if ($obj === false) {
-					//	Entry no longer exists in Memcache, so clear it from the cache array
-					parent::deleteCacheData($cellID);
-					throw new Exception('Cell entry '.$cellID.' no longer exists in MemCache');
-				}
-				if (!$this->_memcache->add($newCachePrefix.$cellID.'.cache',$obj,NULL,$this->_cacheTime)) {
-					$this->__destruct();
-					throw new Exception('Failed to store cell '.$cellID.' in MemCache');
-				}
-			}
-		}
-		$this->_cachePrefix = $newCachePrefix;
-	}	//	function copyCellCollection()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-
-		//	Flush the Memcache cache
-		$this->__destruct();
-
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-	}	//	function unsetWorksheetCells()
-
-
-	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
-		$memcacheServer	= (isset($arguments['memcacheServer']))	? $arguments['memcacheServer']	: 'localhost';
-		$memcachePort	= (isset($arguments['memcachePort']))	? $arguments['memcachePort']	: 11211;
-		$cacheTime		= (isset($arguments['cacheTime']))		? $arguments['cacheTime']		: 600;
-
-		if (is_null($this->_cachePrefix)) {
-			$baseUnique = $this->_getUniqueID();
-			$this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
-
-			//	Set a new Memcache object and connect to the Memcache server
-			$this->_memcache = new Memcache();
-			if (!$this->_memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) {
-				throw new Exception('Could not connect to MemCache server at '.$memcacheServer.':'.$memcachePort);
-			}
-			$this->_cacheTime = $cacheTime;
-
-			parent::__construct($parent);
-		}
-	}	//	function __construct()
-
-
-	public function failureCallback($host, $port) {
-		throw new Exception('memcache '.$host.':'.$port.' failed');
-	}
-
-
-	public function __destruct() {
-		$cacheList = $this->getCellList();
-		foreach($cacheList as $cellID) {
-			$this->_memcache->delete($this->_cachePrefix.$cellID.'.cache');
-		}
-	}	//	function __destruct()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_Memcache
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Prefix used to uniquely identify cache data for this worksheet
+	 *
+	 * @var string
+	 */
+	private $_cachePrefix = null;
+
+	/**
+	 * Cache timeout
+	 *
+	 * @var integer
+	 */
+	private $_cacheTime = 600;
+
+	/**
+	 * Memcache interface
+	 *
+	 * @var resource
+	 */
+	private $_memcache = null;
+
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			$obj = serialize($this->_currentObject);
+			if (!$this->_memcache->replace($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
+				if (!$this->_memcache->add($this->_cachePrefix.$this->_currentObjectID.'.cache',$obj,NULL,$this->_cacheTime)) {
+					$this->__destruct();
+					throw new Exception('Failed to store cell '.$this->_currentObjectID.' in MemCache');
+				}
+			}
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+		$this->_cellCache[$pCoord] = true;
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+	/**
+	 * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+	 *
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	void
+	 * @return	boolean
+	 */
+	public function isDataSet($pCoord) {
+		//	Check if the requested entry is the current object, or exists in the cache
+		if (parent::isDataSet($pCoord)) {
+			if ($this->_currentObjectID == $pCoord) {
+				return true;
+			}
+			//	Check if the requested entry still exists in Memcache
+			$success = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
+			if ($success === false) {
+				//	Entry no longer exists in Memcache, so clear it from the cache array
+				parent::deleteCacheData($pCoord);
+				throw new Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
+			}
+			return true;
+		}
+		return false;
+	}	//	function isDataSet()
+
+
+	/**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (parent::isDataSet($pCoord)) {
+			$obj = $this->_memcache->get($this->_cachePrefix.$pCoord.'.cache');
+			if ($obj === false) {
+				//	Entry no longer exists in Memcache, so clear it from the cache array
+				parent::deleteCacheData($pCoord);
+				throw new Exception('Cell entry '.$pCoord.' no longer exists in MemCache');
+			}
+		} else {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = unserialize($obj);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to delete
+     * @throws	Exception
+     */
+	public function deleteCacheData($pCoord) {
+		//	Delete the entry from Memcache
+		$this->_memcache->delete($this->_cachePrefix.$pCoord.'.cache');
+
+		//	Delete the entry from our cell address array
+		parent::deleteCacheData($pCoord);
+	}	//	function deleteCacheData()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		parent::copyCellCollection($parent);
+		//	Get a new id for the new file name
+		$baseUnique = $this->_getUniqueID();
+		$newCachePrefix = substr(md5($baseUnique),0,8).'.';
+		$cacheList = $this->getCellList();
+		foreach($cacheList as $cellID) {
+			if ($cellID != $this->_currentObjectID) {
+				$obj = $this->_memcache->get($this->_cachePrefix.$cellID.'.cache');
+				if ($obj === false) {
+					//	Entry no longer exists in Memcache, so clear it from the cache array
+					parent::deleteCacheData($cellID);
+					throw new Exception('Cell entry '.$cellID.' no longer exists in MemCache');
+				}
+				if (!$this->_memcache->add($newCachePrefix.$cellID.'.cache',$obj,NULL,$this->_cacheTime)) {
+					$this->__destruct();
+					throw new Exception('Failed to store cell '.$cellID.' in MemCache');
+				}
+			}
+		}
+		$this->_cachePrefix = $newCachePrefix;
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+
+		//	Flush the Memcache cache
+		$this->__destruct();
+
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 * @param	array of mixed		$arguments	Additional initialisation arguments
+	 */
+	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
+		$memcacheServer	= (isset($arguments['memcacheServer']))	? $arguments['memcacheServer']	: 'localhost';
+		$memcachePort	= (isset($arguments['memcachePort']))	? $arguments['memcachePort']	: 11211;
+		$cacheTime		= (isset($arguments['cacheTime']))		? $arguments['cacheTime']		: 600;
+
+		if (is_null($this->_cachePrefix)) {
+			$baseUnique = $this->_getUniqueID();
+			$this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
+
+			//	Set a new Memcache object and connect to the Memcache server
+			$this->_memcache = new Memcache();
+			if (!$this->_memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) {
+				throw new Exception('Could not connect to MemCache server at '.$memcacheServer.':'.$memcachePort);
+			}
+			$this->_cacheTime = $cacheTime;
+
+			parent::__construct($parent);
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Memcache error handler
+	 *
+	 * @param	string	$host		Memcache server
+	 * @param	integer	$port		Memcache port
+     * @throws	Exception
+	 */
+	public function failureCallback($host, $port) {
+		throw new Exception('memcache '.$host.':'.$port.' failed');
+	}
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		$cacheList = $this->getCellList();
+		foreach($cacheList as $cellID) {
+			$this->_memcache->delete($this->_cachePrefix.$cellID.'.cache');
+		}
+	}	//	function __destruct()
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		if (!function_exists('memcache_add')) {
+			return false;
+		}
+
+		return true;
+	}
+
+}

+ 109 - 98
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Memory.php

@@ -1,98 +1,109 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_Memory
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		$this->_cellCache[$pCoord] = $cell;
-		return $cell;
-	}	//	function addCacheData()
-
-
-    /**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		//	Check if the entry that has been requested actually exists
-		if (!isset($this->_cellCache[$pCoord])) {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Return requested entry
-		return $this->_cellCache[$pCoord];
-	}	//	function getCacheData()
-
-
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		parent::copyCellCollection($parent);
-
-		$newCollection = array();
-		foreach($this->_cellCache as $k => &$cell) {
-			$newCollection[$k] = clone $cell;
-			$newCollection[$k]->attach($parent);
-		}
-
-		$this->_cellCache = $newCollection;
-	}
-
-
-	public function unsetWorksheetCells() {
-		//	Because cells are all stored as intact objects in memory, we need to detach each one from the parent
-		foreach($this->_cellCache as $k => &$cell) {
-			$cell->detach();
-			$this->_cellCache[$k] = null;
-		}
-		unset($cell);
-
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-	}	//	function unsetWorksheetCells()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_Memory
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		$this->_cellCache[$pCoord] = $cell;
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		//	Check if the entry that has been requested actually exists
+		if (!isset($this->_cellCache[$pCoord])) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Return requested entry
+		return $this->_cellCache[$pCoord];
+	}	//	function getCacheData()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		parent::copyCellCollection($parent);
+
+		$newCollection = array();
+		foreach($this->_cellCache as $k => &$cell) {
+			$newCollection[$k] = clone $cell;
+			$newCollection[$k]->attach($parent);
+		}
+
+		$this->_cellCache = $newCollection;
+	}
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		//	Because cells are all stored as intact objects in memory, we need to detach each one from the parent
+		foreach($this->_cellCache as $k => &$cell) {
+			$cell->detach();
+			$this->_cellCache[$k] = null;
+		}
+		unset($cell);
+
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+}

+ 123 - 107
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/MemoryGZip.php

@@ -1,107 +1,123 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_MemoryGZip
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		$this->_cellCache[$this->_currentObjectID] = gzdeflate(serialize($this->_currentObject));
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-    /**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		if (!isset($this->_cellCache[$pCoord])) {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = unserialize(gzinflate($this->_cellCache[$pCoord]));
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-	}	//	function unsetWorksheetCells()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_MemoryGZip
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			$this->_cellCache[$this->_currentObjectID] = gzdeflate(serialize($this->_currentObject));
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (!isset($this->_cellCache[$pCoord])) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = unserialize(gzinflate($this->_cellCache[$pCoord]));
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+}

+ 123 - 107
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/MemorySerialized.php

@@ -1,107 +1,123 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_MemorySerialized
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		$this->_cellCache[$this->_currentObjectID] = serialize($this->_currentObject);
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-    /**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		if (!isset($this->_cellCache[$pCoord])) {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = unserialize($this->_cellCache[$pCoord]);
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-	}	//	function unsetWorksheetCells()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_MemorySerialized
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			$this->_cellCache[$this->_currentObjectID] = serialize($this->_currentObject);
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (!isset($this->_cellCache[$pCoord])) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = unserialize($this->_cellCache[$pCoord]);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+}

+ 192 - 157
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/PHPTemp.php

@@ -1,157 +1,192 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_PHPTemp
- *
- * @category   PHPExcel
- * @package    PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private $_fileHandle = null;
-
-
-	private $_memoryCacheSize = null;
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		fseek($this->_fileHandle,0,SEEK_END);
-		$offset = ftell($this->_fileHandle);
-		fwrite($this->_fileHandle, serialize($this->_currentObject));
-		$this->_cellCache[$this->_currentObjectID]	= array('ptr' => $offset,
-															'sz'  => ftell($this->_fileHandle) - $offset
-														   );
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-    /**
-     *	Add or Update a cell in cache identified by coordinate address
-     *
-     *	@param	string			$pCoord		Coordinate address of the cell to update
-     *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-     *	@throws	Exception
-     */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-    /**
-     * Get cell at a specific coordinate
-     *
-     * @param 	string 			$pCoord		Coordinate of the cell
-     * @throws 	Exception
-     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
-     */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		if (!isset($this->_cellCache[$pCoord])) {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']);
-		$this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz']));
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-	/**
-	 *	Clone the cell collection
-	 *
-	 *	@return	void
-	 */
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		parent::copyCellCollection($parent);
-		//	Open a new stream for the cell cache data
-		$newFileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
-		//	Copy the existing cell cache data to the new stream
-		fseek($this->_fileHandle,0);
-		while (!feof($this->_fileHandle)) {
-			fwrite($newFileHandle,fread($this->_fileHandle, 1024));
-		}
-		$this->_fileHandle = $newFileHandle;
-	}	//	function copyCellCollection()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-
-		//	Close down the php://temp file
-		$this->__destruct();
-	}	//	function unsetWorksheetCells()
-
-
-	public function __construct(PHPExcel_Worksheet $parent, $memoryCacheSize = '1MB') {
-		$this->_memoryCacheSize	= (isset($arguments['memoryCacheSize']))	? $arguments['memoryCacheSize']	: '1MB';
-
-		parent::__construct($parent);
-		if (is_null($this->_fileHandle)) {
-			$this->_fileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
-		}
-	}	//	function __construct()
-
-
-	public function __destruct() {
-		if (!is_null($this->_fileHandle)) {
-			fclose($this->_fileHandle);
-		}
-		$this->_fileHandle = null;
-	}	//	function __destruct()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_PHPTemp
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Name of the file for this cache
+	 *
+	 * @var string
+	 */
+	private $_fileHandle = null;
+
+	/**
+	 * Memory limit to use before reverting to file cache
+	 *
+	 * @var integer
+	 */
+	private $_memoryCacheSize = null;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			fseek($this->_fileHandle,0,SEEK_END);
+			$offset = ftell($this->_fileHandle);
+			fwrite($this->_fileHandle, serialize($this->_currentObject));
+			$this->_cellCache[$this->_currentObjectID]	= array('ptr' => $offset,
+																'sz'  => ftell($this->_fileHandle) - $offset
+															   );
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		if (!isset($this->_cellCache[$pCoord])) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		fseek($this->_fileHandle,$this->_cellCache[$pCoord]['ptr']);
+		$this->_currentObject = unserialize(fread($this->_fileHandle,$this->_cellCache[$pCoord]['sz']));
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		parent::copyCellCollection($parent);
+		//	Open a new stream for the cell cache data
+		$newFileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
+		//	Copy the existing cell cache data to the new stream
+		fseek($this->_fileHandle,0);
+		while (!feof($this->_fileHandle)) {
+			fwrite($newFileHandle,fread($this->_fileHandle, 1024));
+		}
+		$this->_fileHandle = $newFileHandle;
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+
+		//	Close down the php://temp file
+		$this->__destruct();
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 * @param	array of mixed		$arguments	Additional initialisation arguments
+	 */
+	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
+		$this->_memoryCacheSize	= (isset($arguments['memoryCacheSize']))	? $arguments['memoryCacheSize']	: '1MB';
+
+		parent::__construct($parent);
+		if (is_null($this->_fileHandle)) {
+			$this->_fileHandle = fopen('php://temp/maxmemory:'.$this->_memoryCacheSize,'a+');
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		if (!is_null($this->_fileHandle)) {
+			fclose($this->_fileHandle);
+		}
+		$this->_fileHandle = null;
+	}	//	function __destruct()
+
+}

+ 270 - 0
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/SQLite.php

@@ -0,0 +1,270 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_SQLite
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Database table name
+	 *
+	 * @var string
+	 */
+	private $_TableName = null;
+
+	/**
+	 * Database handle
+	 *
+	 * @var resource
+	 */
+	private $_DBHandle = null;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			if (!$this->_DBHandle->queryExec("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES('".$this->_currentObjectID."','".sqlite_escape_string(serialize($this->_currentObject))."')"))
+				throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		$query = "SELECT value FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
+		$cellResultSet = $this->_DBHandle->query($query,SQLITE_ASSOC);
+		if ($cellResultSet === false) {
+			throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+		} elseif ($cellResultSet->numRows() == 0) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+
+		$cellResult = $cellResultSet->fetchSingle();
+		$this->_currentObject = unserialize($cellResult);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Is a value set for an indexed cell?
+	 *
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	boolean
+	 */
+	public function isDataSet($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return true;
+		}
+
+		//	Check if the requested entry exists in the cache
+		$query = "SELECT id FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
+		$cellResultSet = $this->_DBHandle->query($query,SQLITE_ASSOC);
+		if ($cellResultSet === false) {
+			throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+		} elseif ($cellResultSet->numRows() == 0) {
+			//	Return null if requested entry doesn't exist in cache
+			return false;
+		}
+		return true;
+	}	//	function isDataSet()
+
+
+    /**
+     * Delete a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to delete
+     * @throws	Exception
+     */
+	public function deleteCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			$this->_currentObject->detach();
+			$this->_currentObjectID = $this->_currentObject = null;
+		}
+
+		//	Check if the requested entry exists in the cache
+		$query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
+		if (!$this->_DBHandle->queryExec($query))
+			throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+
+		$this->_currentCellIsDirty = false;
+	}	//	function deleteCacheData()
+
+
+	/**
+	 * Get a list of all cell addresses currently held in cache
+	 *
+	 * @return	array of string
+	 */
+	public function getCellList() {
+		$query = "SELECT id FROM kvp_".$this->_TableName;
+		$cellIdsResult = $this->_DBHandle->unbufferedQuery($query,SQLITE_ASSOC);
+		if ($cellIdsResult === false)
+			throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+
+		$cellKeys = array();
+		foreach($cellIdsResult as $row) {
+			$cellKeys[] = $row['id'];
+		}
+
+		return $cellKeys;
+	}	//	function getCellList()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		//	Get a new id for the new table name
+		$tableName = str_replace('.','_',$this->_getUniqueID());
+		if (!$this->_DBHandle->queryExec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
+													AS SELECT * FROM kvp_'.$this->_TableName))
+			throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+
+		//	Copy the existing cell cache file
+		$this->_TableName = $tableName;
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+
+		//	Close down the temporary cache file
+		$this->__destruct();
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 */
+	public function __construct(PHPExcel_Worksheet $parent) {
+		parent::__construct($parent);
+		if (is_null($this->_DBHandle)) {
+			$this->_TableName = str_replace('.','_',$this->_getUniqueID());
+			$_DBName = ':memory:';
+
+			$this->_DBHandle = new SQLiteDatabase($_DBName);
+			if ($this->_DBHandle === false)
+				throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+			if (!$this->_DBHandle->queryExec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)'))
+				throw new Exception(sqlite_error_string($this->_DBHandle->lastError()));
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		$this->_DBHandle = null;
+	}	//	function __destruct()
+
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		if (!function_exists('sqlite_open')) {
+			return false;
+		}
+
+		return true;
+	}
+
+}

+ 277 - 0
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/SQLite3.php

@@ -0,0 +1,277 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_SQLite3
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Database table name
+	 *
+	 * @var string
+	 */
+	private $_TableName = null;
+
+	/**
+	 * Database handle
+	 *
+	 * @var resource
+	 */
+	private $_DBHandle = null;
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			$query = $this->_DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->_TableName." VALUES(:id,:data)");
+			$query->bindValue('id',$this->_currentObjectID,SQLITE3_TEXT);
+			$query->bindValue('data',serialize($this->_currentObject),SQLITE3_BLOB);
+			$result = $query->execute();
+			if ($result === false)
+				throw new Exception($this->_DBHandle->lastErrorMsg());
+			$this->_currentCellIsDirty = false;
+		}
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+    /**
+     * Add or Update a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to update
+     * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+     * @throws	Exception
+     */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+    /**
+     * Get cell at a specific coordinate
+     *
+     * @param 	string 			$pCoord		Coordinate of the cell
+     * @throws 	Exception
+     * @return 	PHPExcel_Cell 	Cell that was found, or null if not found
+     */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		$query = "SELECT value FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
+		$cellResult = $this->_DBHandle->querySingle($query);
+		if ($cellResult === false) {
+			throw new Exception($this->_DBHandle->lastErrorMsg());
+		} elseif (is_null($cellResult)) {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+
+		$this->_currentObject = unserialize($cellResult);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 *	Is a value set for an indexed cell?
+	 *
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	boolean
+	 */
+	public function isDataSet($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return true;
+		}
+
+		//	Check if the requested entry exists in the cache
+		$query = "SELECT id FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
+		$cellResult = $this->_DBHandle->querySingle($query);
+		if ($cellResult === false) {
+			throw new Exception($this->_DBHandle->lastErrorMsg());
+		} elseif (is_null($cellResult)) {
+			//	Return null if requested entry doesn't exist in cache
+			return false;
+		}
+		return true;
+	}	//	function isDataSet()
+
+
+    /**
+     *	Delete a cell in cache identified by coordinate address
+     *
+     * @param	string			$pCoord		Coordinate address of the cell to delete
+     * @throws	Exception
+     */
+	public function deleteCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			$this->_currentObject->detach();
+			$this->_currentObjectID = $this->_currentObject = null;
+		}
+
+		//	Check if the requested entry exists in the cache
+		$query = "DELETE FROM kvp_".$this->_TableName." WHERE id='".$pCoord."'";
+		$result = $this->_DBHandle->exec($query);
+		if ($result === false)
+			throw new Exception($this->_DBHandle->lastErrorMsg());
+
+		$this->_currentCellIsDirty = false;
+	}	//	function deleteCacheData()
+
+
+	/**
+	 * Get a list of all cell addresses currently held in cache
+	 *
+	 * @return	array of string
+	 */
+	public function getCellList() {
+		$query = "SELECT id FROM kvp_".$this->_TableName;
+		$cellIdsResult = $this->_DBHandle->query($query);
+		if ($cellIdsResult === false)
+			throw new Exception($this->_DBHandle->lastErrorMsg());
+
+		$cellKeys = array();
+		while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) {
+			$cellKeys[] = $row['id'];
+		}
+
+		return $cellKeys;
+	}	//	function getCellList()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		//	Get a new id for the new table name
+		$tableName = str_replace('.','_',$this->_getUniqueID());
+		if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)
+		                                       AS SELECT * FROM kvp_'.$this->_TableName))
+			throw new Exception($this->_DBHandle->lastErrorMsg());
+
+		//	Copy the existing cell cache file
+		$this->_TableName = $tableName;
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+
+		//	Close down the temporary cache file
+		$this->__destruct();
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 */
+	public function __construct(PHPExcel_Worksheet $parent) {
+		parent::__construct($parent);
+		if (is_null($this->_DBHandle)) {
+			$this->_TableName = str_replace('.','_',$this->_getUniqueID());
+			$_DBName = ':memory:';
+
+			$this->_DBHandle = new SQLite3($_DBName);
+			if ($this->_DBHandle === false)
+				throw new Exception($this->_DBHandle->lastErrorMsg());
+			if (!$this->_DBHandle->exec('CREATE TABLE kvp_'.$this->_TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)'))
+				throw new Exception($this->_DBHandle->lastErrorMsg());
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		if (!is_null($this->_DBHandle)) {
+			$this->_DBHandle->close();
+		}
+		$this->_DBHandle = null;
+	}	//	function __destruct()
+
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		if (!class_exists('SQLite3',FALSE)) {
+			return false;
+		}
+
+		return true;
+	}
+
+}

+ 280 - 230
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorage/Wincache.php

@@ -1,230 +1,280 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package	PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version	1.7.6, 2011-02-27
- */
-
-
-/**
- * PHPExcel_CachedObjectStorage_Wincache
- *
- * @category   PHPExcel
- * @package	PHPExcel_CachedObjectStorage
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
-
-	private $_cachePrefix = null;
-
-	private $_cacheTime = 600;
-
-
-	private function _storeData() {
-		$this->_currentObject->detach();
-
-		$obj = serialize($this->_currentObject);
-		if (wincache_ucache_exists($this->_cachePrefix.$this->_currentObjectID.'.cache')) {
-			if (!wincache_ucache_set($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
-				$this->__destruct();
-				throw new Exception('Failed to store cell '.$cellID.' in WinCache');
-			}
-		} else {
-			if (!wincache_ucache_add($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
-				$this->__destruct();
-				throw new Exception('Failed to store cell '.$cellID.' in WinCache');
-			}
-		}
-
-		$this->_currentObjectID = $this->_currentObject = null;
-	}	//	function _storeData()
-
-
-	/**
-	 *	Add or Update a cell in cache identified by coordinate address
-	 *
-	 *	@param	string			$pCoord		Coordinate address of the cell to update
-	 *	@param	PHPExcel_Cell	$cell		Cell to update
-	 *	@return	void
-	 *	@throws	Exception
-	 */
-	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
-		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
-			$this->_storeData();
-		}
-		$this->_cellCache[$pCoord] = true;
-
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = $cell;
-
-		return $cell;
-	}	//	function addCacheData()
-
-
-	/**
-	 *	Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
-	 *
-	 *	@param	string		$pCoord		Coordinate address of the cell to check
-	 *	@return	void
-	 *	@return	boolean
-	 */
-	public function isDataSet($pCoord) {
-		//	Check if the requested entry is the current object, or exists in the cache
-		if (parent::isDataSet($pCoord)) {
-			if ($this->_currentObjectID == $pCoord) {
-				return true;
-			}
-			//	Check if the requested entry still exists in cache
-			$success = wincache_ucache_exists($this->_cachePrefix.$pCoord.'.cache');
-			if ($success === false) {
-				//	Entry no longer exists in Wincache, so clear it from the cache array
-				parent::deleteCacheData($pCoord);
-				throw new Exception('Cell entry '.$cellID.' no longer exists in WinCache');
-			}
-			return true;
-		}
-		return false;
-	}	//	function isDataSet()
-
-
-	/**
-	 * Get cell at a specific coordinate
-	 *
-	 * @param	string			$pCoord		Coordinate of the cell
-	 * @throws	Exception
-	 * @return	PHPExcel_Cell	Cell that was found, or null if not found
-	 */
-	public function getCacheData($pCoord) {
-		if ($pCoord === $this->_currentObjectID) {
-			return $this->_currentObject;
-		}
-		$this->_storeData();
-
-		//	Check if the entry that has been requested actually exists
-		$obj = null;
-		if (parent::isDataSet($pCoord)) {
-			$success = false;
-			$obj = wincache_ucache_get($this->_cachePrefix.$pCoord.'.cache', $success);
-			if ($success === false) {
-				//	Entry no longer exists in WinCache, so clear it from the cache array
-				parent::deleteCacheData($pCoord);
-				throw new Exception('Cell entry '.$cellID.' no longer exists in WinCache');
-			}
-		} else {
-			//	Return null if requested entry doesn't exist in cache
-			return null;
-		}
-
-		//	Set current entry to the requested entry
-		$this->_currentObjectID = $pCoord;
-		$this->_currentObject = unserialize($obj);
-		//	Re-attach the parent worksheet
-		$this->_currentObject->attach($this->_parent);
-
-		//	Return requested entry
-		return $this->_currentObject;
-	}	//	function getCacheData()
-
-
-	/**
-	 *	Delete a cell in cache identified by coordinate address
-	 *
-	 *	@param	string			$pCoord		Coordinate address of the cell to delete
-	 *	@throws	Exception
-	 */
-	public function deleteCacheData($pCoord) {
-		//	Delete the entry from Wincache
-		wincache_ucache_delete($this->_cachePrefix.$pCoord.'.cache');
-
-		//	Delete the entry from our cell address array
-		parent::deleteCacheData($pCoord);
-	}	//	function deleteCacheData()
-
-
-	/**
-	 *	Clone the cell collection
-	 *
-	 *	@return	void
-	 */
-	public function copyCellCollection(PHPExcel_Worksheet $parent) {
-		parent::copyCellCollection($parent);
-		//	Get a new id for the new file name
-		$baseUnique = $this->_getUniqueID();
-		$newCachePrefix = substr(md5($baseUnique),0,8).'.';
-		$cacheList = $this->getCellList();
-		foreach($cacheList as $cellID) {
-			if ($cellID != $this->_currentObjectID) {
-				$success = false;
-				$obj = wincache_ucache_get($this->_cachePrefix.$cellID.'.cache', $success);
-				if ($success === false) {
-					//	Entry no longer exists in WinCache, so clear it from the cache array
-					parent::deleteCacheData($cellID);
-					throw new Exception('Cell entry '.$cellID.' no longer exists in Wincache');
-				}
-				if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->_cacheTime)) {
-					$this->__destruct();
-					throw new Exception('Failed to store cell '.$cellID.' in Wincache');
-				}
-			}
-		}
-		$this->_cachePrefix = $newCachePrefix;
-	}	//	function copyCellCollection()
-
-
-	public function unsetWorksheetCells() {
-		if(!is_null($this->_currentObject)) {
-			$this->_currentObject->detach();
-			$this->_currentObject = $this->_currentObjectID = null;
-		}
-
-		//	Flush the WinCache cache
-		$this->__destruct();
-
-		$this->_cellCache = array();
-
-		//	detach ourself from the worksheet, so that it can then delete this object successfully
-		$this->_parent = null;
-	}	//	function unsetWorksheetCells()
-
-
-	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
-		$cacheTime	= (isset($arguments['cacheTime']))	? $arguments['cacheTime']	: 600;
-
-		if (is_null($this->_cachePrefix)) {
-			$baseUnique = $this->_getUniqueID();
-			$this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
-			$this->_cacheTime = $cacheTime;
-
-			parent::__construct($parent);
-		}
-	}	//	function __construct()
-
-
-	public function __destruct() {
-		$cacheList = $this->getCellList();
-		foreach($cacheList as $cellID) {
-			wincache_ucache_delete($this->_cachePrefix.$cellID.'.cache');
-		}
-	}	//	function __destruct()
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package	PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorage_Wincache
+ *
+ * @category   PHPExcel
+ * @package	PHPExcel_CachedObjectStorage
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
+
+	/**
+	 * Prefix used to uniquely identify cache data for this worksheet
+	 *
+	 * @var string
+	 */
+	private $_cachePrefix = null;
+
+	/**
+	 * Cache timeout
+	 *
+	 * @var integer
+	 */
+	private $_cacheTime = 600;
+
+
+    /**
+     * Store cell data in cache for the current cell object if it's "dirty",
+     *     and the 'nullify' the current cell object
+     *
+	 * @return	void
+     * @throws	Exception
+     */
+	private function _storeData() {
+		if ($this->_currentCellIsDirty) {
+			$this->_currentObject->detach();
+
+			$obj = serialize($this->_currentObject);
+			if (wincache_ucache_exists($this->_cachePrefix.$this->_currentObjectID.'.cache')) {
+				if (!wincache_ucache_set($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
+					$this->__destruct();
+					throw new Exception('Failed to store cell '.$this->_currentObjectID.' in WinCache');
+				}
+			} else {
+				if (!wincache_ucache_add($this->_cachePrefix.$this->_currentObjectID.'.cache', $obj, $this->_cacheTime)) {
+					$this->__destruct();
+					throw new Exception('Failed to store cell '.$this->_currentObjectID.' in WinCache');
+				}
+			}
+			$this->_currentCellIsDirty = false;
+		}
+
+		$this->_currentObjectID = $this->_currentObject = null;
+	}	//	function _storeData()
+
+
+	/**
+	 * Add or Update a cell in cache identified by coordinate address
+	 *
+	 * @param	string			$pCoord		Coordinate address of the cell to update
+	 * @param	PHPExcel_Cell	$cell		Cell to update
+	 * @return	void
+	 * @throws	Exception
+	 */
+	public function addCacheData($pCoord, PHPExcel_Cell $cell) {
+		if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
+			$this->_storeData();
+		}
+		$this->_cellCache[$pCoord] = true;
+
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = $cell;
+		$this->_currentCellIsDirty = true;
+
+		return $cell;
+	}	//	function addCacheData()
+
+
+	/**
+	 * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
+	 *
+	 * @param	string		$pCoord		Coordinate address of the cell to check
+	 * @return	boolean
+	 */
+	public function isDataSet($pCoord) {
+		//	Check if the requested entry is the current object, or exists in the cache
+		if (parent::isDataSet($pCoord)) {
+			if ($this->_currentObjectID == $pCoord) {
+				return true;
+			}
+			//	Check if the requested entry still exists in cache
+			$success = wincache_ucache_exists($this->_cachePrefix.$pCoord.'.cache');
+			if ($success === false) {
+				//	Entry no longer exists in Wincache, so clear it from the cache array
+				parent::deleteCacheData($pCoord);
+				throw new Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
+			}
+			return true;
+		}
+		return false;
+	}	//	function isDataSet()
+
+
+	/**
+	 * Get cell at a specific coordinate
+	 *
+	 * @param	string			$pCoord		Coordinate of the cell
+	 * @throws	Exception
+	 * @return	PHPExcel_Cell	Cell that was found, or null if not found
+	 */
+	public function getCacheData($pCoord) {
+		if ($pCoord === $this->_currentObjectID) {
+			return $this->_currentObject;
+		}
+		$this->_storeData();
+
+		//	Check if the entry that has been requested actually exists
+		$obj = null;
+		if (parent::isDataSet($pCoord)) {
+			$success = false;
+			$obj = wincache_ucache_get($this->_cachePrefix.$pCoord.'.cache', $success);
+			if ($success === false) {
+				//	Entry no longer exists in WinCache, so clear it from the cache array
+				parent::deleteCacheData($pCoord);
+				throw new Exception('Cell entry '.$pCoord.' no longer exists in WinCache');
+			}
+		} else {
+			//	Return null if requested entry doesn't exist in cache
+			return null;
+		}
+
+		//	Set current entry to the requested entry
+		$this->_currentObjectID = $pCoord;
+		$this->_currentObject = unserialize($obj);
+		//	Re-attach the parent worksheet
+		$this->_currentObject->attach($this->_parent);
+
+		//	Return requested entry
+		return $this->_currentObject;
+	}	//	function getCacheData()
+
+
+	/**
+	 * Delete a cell in cache identified by coordinate address
+	 *
+	 * @param	string			$pCoord		Coordinate address of the cell to delete
+	 * @throws	Exception
+	 */
+	public function deleteCacheData($pCoord) {
+		//	Delete the entry from Wincache
+		wincache_ucache_delete($this->_cachePrefix.$pCoord.'.cache');
+
+		//	Delete the entry from our cell address array
+		parent::deleteCacheData($pCoord);
+	}	//	function deleteCacheData()
+
+
+	/**
+	 * Clone the cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The new worksheet
+	 * @return	void
+	 */
+	public function copyCellCollection(PHPExcel_Worksheet $parent) {
+		parent::copyCellCollection($parent);
+		//	Get a new id for the new file name
+		$baseUnique = $this->_getUniqueID();
+		$newCachePrefix = substr(md5($baseUnique),0,8).'.';
+		$cacheList = $this->getCellList();
+		foreach($cacheList as $cellID) {
+			if ($cellID != $this->_currentObjectID) {
+				$success = false;
+				$obj = wincache_ucache_get($this->_cachePrefix.$cellID.'.cache', $success);
+				if ($success === false) {
+					//	Entry no longer exists in WinCache, so clear it from the cache array
+					parent::deleteCacheData($cellID);
+					throw new Exception('Cell entry '.$cellID.' no longer exists in Wincache');
+				}
+				if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->_cacheTime)) {
+					$this->__destruct();
+					throw new Exception('Failed to store cell '.$cellID.' in Wincache');
+				}
+			}
+		}
+		$this->_cachePrefix = $newCachePrefix;
+	}	//	function copyCellCollection()
+
+
+	/**
+	 * Clear the cell collection and disconnect from our parent
+	 *
+	 * @return	void
+	 */
+	public function unsetWorksheetCells() {
+		if(!is_null($this->_currentObject)) {
+			$this->_currentObject->detach();
+			$this->_currentObject = $this->_currentObjectID = null;
+		}
+
+		//	Flush the WinCache cache
+		$this->__destruct();
+
+		$this->_cellCache = array();
+
+		//	detach ourself from the worksheet, so that it can then delete this object successfully
+		$this->_parent = null;
+	}	//	function unsetWorksheetCells()
+
+
+	/**
+	 * Initialise this new cell collection
+	 *
+	 * @param	PHPExcel_Worksheet	$parent		The worksheet for this cell collection
+	 * @param	array of mixed		$arguments	Additional initialisation arguments
+	 */
+	public function __construct(PHPExcel_Worksheet $parent, $arguments) {
+		$cacheTime	= (isset($arguments['cacheTime']))	? $arguments['cacheTime']	: 600;
+
+		if (is_null($this->_cachePrefix)) {
+			$baseUnique = $this->_getUniqueID();
+			$this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
+			$this->_cacheTime = $cacheTime;
+
+			parent::__construct($parent);
+		}
+	}	//	function __construct()
+
+
+	/**
+	 * Destroy this cell collection
+	 */
+	public function __destruct() {
+		$cacheList = $this->getCellList();
+		foreach($cacheList as $cellID) {
+			wincache_ucache_delete($this->_cachePrefix.$cellID.'.cache');
+		}
+	}	//	function __destruct()
+
+
+	/**
+	 * Identify whether the caching method is currently available
+	 * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
+	 *
+	 * @return	boolean
+	 */
+	public static function cacheMethodIsAvailable() {
+		if (!function_exists('wincache_ucache_add')) {
+			return false;
+		}
+
+		return true;
+	}
+
+}

+ 238 - 130
htdocs/includes/phpexcel/PHPExcel/CachedObjectStorageFactory.php

@@ -1,131 +1,239 @@
-<?php
-
-class PHPExcel_CachedObjectStorageFactory {
-	const cache_in_memory				= 'Memory';
-	const cache_in_memory_gzip			= 'MemoryGZip';
-	const cache_in_memory_serialized	= 'MemorySerialized';
-	const cache_to_discISAM				= 'DiscISAM';
-	const cache_to_apc					= 'APC';
-	const cache_to_memcache				= 'Memcache';
-	const cache_to_phpTemp				= 'PHPTemp';
-	const cache_to_wincache				= 'Wincache';
-
-
-	private static $_cacheStorageMethod = null;
-
-	private static $_cacheStorageClass = null;
-
-
-	private static $_storageMethods = array(
-		self::cache_in_memory,
-		self::cache_in_memory_gzip,
-		self::cache_in_memory_serialized,
-		self::cache_to_phpTemp,
-		self::cache_to_discISAM,
-		self::cache_to_apc,
-		self::cache_to_memcache,
-		self::cache_to_wincache,
-	);
-
-
-	private static $_storageMethodDefaultParameters = array(
-		self::cache_in_memory				=> array(
-													),
-		self::cache_in_memory_gzip			=> array(
-													),
-		self::cache_in_memory_serialized	=> array(
-													),
-		self::cache_to_phpTemp				=> array( 'memoryCacheSize'	=> '1MB'
-													),
-		self::cache_to_discISAM				=> array(
-													),
-		self::cache_to_apc					=> array( 'cacheTime'		=> 600
-													),
-		self::cache_to_memcache				=> array( 'memcacheServer'	=> 'localhost',
-													  'memcachePort'	=> 11211,
-													  'cacheTime'		=> 600
-													),
-		self::cache_to_wincache				=> array( 'cacheTime'		=> 600
-													)
-	);
-
-
-	private static $_storageMethodParameters = array();
-
-
-	public static function getCacheStorageMethod() {
-		if (!is_null(self::$_cacheStorageMethod)) {
-			return self::$_cacheStorageMethod;
-		}
-		return null;
-	}	//	function getCacheStorageMethod()
-
-
-	public static function getCacheStorageClass() {
-		if (!is_null(self::$_cacheStorageClass)) {
-			return self::$_cacheStorageClass;
-		}
-		return null;
-	}	//	function getCacheStorageClass()
-
-
-	public static function getCacheStorageMethods() {
-		return self::$_storageMethods;
-	}	//	function getCacheStorageMethods()
-
-
-	public static function initialize($method = self::cache_in_memory, $arguments = array()) {
-		if (!in_array($method,self::$_storageMethods)) {
-			return false;
-		}
-
-		switch($method) {
-			case self::cache_to_apc	:
-				if (!function_exists('apc_store')) {
-					return false;
-				}
-				if (apc_sma_info() === false) {
-					return false;
-				}
-				break;
-			case self::cache_to_memcache :
-				if (!function_exists('memcache_add')) {
-					return false;
-				}
-				break;
-			case self::cache_to_wincache :
-				if (!function_exists('wincache_ucache_add')) {
-					return false;
-				}
-				break;
-		}
-
-		self::$_storageMethodParameters[$method] = self::$_storageMethodDefaultParameters[$method];
-		foreach($arguments as $k => $v) {
-			if (isset(self::$_storageMethodParameters[$method][$k])) {
-				self::$_storageMethodParameters[$method][$k] = $v;
-			}
-		}
-
-		if (is_null(self::$_cacheStorageMethod)) {
-			self::$_cacheStorageClass = 'PHPExcel_CachedObjectStorage_'.$method;
-			self::$_cacheStorageMethod = $method;
-		}
-		return true;
-	}	//	function initialize()
-
-
-	public static function getInstance(PHPExcel_Worksheet $parent) {
-		if (is_null(self::$_cacheStorageMethod)) {
-			self::initialize();
-		}
-
-		$instance = new self::$_cacheStorageClass($parent,self::$_storageMethodParameters[self::$_cacheStorageMethod]);
-		if (!is_null($instance)) {
-			return $instance;
-		}
-
-		return false;
-	}	//	function getInstance()
-
+<?php
+
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_CachedObjectStorageFactory
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_CachedObjectStorage
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_CachedObjectStorageFactory
+{
+	const cache_in_memory				= 'Memory';
+	const cache_in_memory_gzip			= 'MemoryGZip';
+	const cache_in_memory_serialized	= 'MemorySerialized';
+	const cache_igbinary				= 'Igbinary';
+	const cache_to_discISAM				= 'DiscISAM';
+	const cache_to_apc					= 'APC';
+	const cache_to_memcache				= 'Memcache';
+	const cache_to_phpTemp				= 'PHPTemp';
+	const cache_to_wincache				= 'Wincache';
+	const cache_to_sqlite				= 'SQLite';
+	const cache_to_sqlite3				= 'SQLite3';
+
+
+	/**
+	 * Name of the method used for cell cacheing
+	 *
+	 * @var string
+	 */
+	private static $_cacheStorageMethod = NULL;
+
+	/**
+	 * Name of the class used for cell cacheing
+	 *
+	 * @var string
+	 */
+	private static $_cacheStorageClass = NULL;
+
+
+	/**
+	 * List of all possible cache storage methods
+	 *
+	 * @var string[]
+	 */
+	private static $_storageMethods = array(
+		self::cache_in_memory,
+		self::cache_in_memory_gzip,
+		self::cache_in_memory_serialized,
+		self::cache_igbinary,
+		self::cache_to_phpTemp,
+		self::cache_to_discISAM,
+		self::cache_to_apc,
+		self::cache_to_memcache,
+		self::cache_to_wincache,
+		self::cache_to_sqlite,
+		self::cache_to_sqlite3,
+	);
+
+
+	/**
+	 * Default arguments for each cache storage method
+	 *
+	 * @var array of mixed array
+	 */
+	private static $_storageMethodDefaultParameters = array(
+		self::cache_in_memory				=> array(
+													),
+		self::cache_in_memory_gzip			=> array(
+													),
+		self::cache_in_memory_serialized	=> array(
+													),
+		self::cache_igbinary				=> array(
+													),
+		self::cache_to_phpTemp				=> array( 'memoryCacheSize'	=> '1MB'
+													),
+		self::cache_to_discISAM				=> array( 'dir'				=> NULL
+													),
+		self::cache_to_apc					=> array( 'cacheTime'		=> 600
+													),
+		self::cache_to_memcache				=> array( 'memcacheServer'	=> 'localhost',
+													  'memcachePort'	=> 11211,
+													  'cacheTime'		=> 600
+													),
+		self::cache_to_wincache				=> array( 'cacheTime'		=> 600
+													),
+		self::cache_to_sqlite				=> array(
+													),
+		self::cache_to_sqlite3				=> array(
+													),
+	);
+
+
+	/**
+	 * Arguments for the active cache storage method
+	 *
+	 * @var array of mixed array
+	 */
+	private static $_storageMethodParameters = array();
+
+
+	/**
+	 * Return the current cache storage method
+	 *
+	 * @return string|NULL
+	 **/
+	public static function getCacheStorageMethod()
+	{
+		return self::$_cacheStorageMethod;
+	}	//	function getCacheStorageMethod()
+
+
+	/**
+	 * Return the current cache storage class
+	 *
+	 * @return PHPExcel_CachedObjectStorage_ICache|NULL
+	 **/
+	public static function getCacheStorageClass()
+	{
+		return self::$_cacheStorageClass;
+	}	//	function getCacheStorageClass()
+
+
+	/**
+	 * Return the list of all possible cache storage methods
+	 *
+	 * @return string[]
+	 **/
+	public static function getAllCacheStorageMethods()
+	{
+		return self::$_storageMethods;
+	}	//	function getCacheStorageMethods()
+
+
+	/**
+	 * Return the list of all available cache storage methods
+	 *
+	 * @return string[]
+	 **/
+	public static function getCacheStorageMethods()
+	{
+		$activeMethods = array();
+		foreach(self::$_storageMethods as $storageMethod) {
+			$cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $storageMethod;
+			if (call_user_func(array($cacheStorageClass, 'cacheMethodIsAvailable'))) {
+				$activeMethods[] = $storageMethod;
+			}
+		}
+		return $activeMethods;
+	}	//	function getCacheStorageMethods()
+
+
+	/**
+	 * Identify the cache storage method to use
+	 *
+	 * @param	string			$method		Name of the method to use for cell cacheing
+	 * @param	array of mixed	$arguments	Additional arguments to pass to the cell caching class
+	 *										when instantiating
+	 * @return boolean
+	 **/
+	public static function initialize($method = self::cache_in_memory, $arguments = array())
+	{
+		if (!in_array($method,self::$_storageMethods)) {
+			return FALSE;
+		}
+
+		$cacheStorageClass = 'PHPExcel_CachedObjectStorage_'.$method;
+		if (!call_user_func(array( $cacheStorageClass,
+								   'cacheMethodIsAvailable'))) {
+			return FALSE;
+		}
+
+		self::$_storageMethodParameters[$method] = self::$_storageMethodDefaultParameters[$method];
+		foreach($arguments as $k => $v) {
+			if (isset(self::$_storageMethodParameters[$method][$k])) {
+				self::$_storageMethodParameters[$method][$k] = $v;
+			}
+		}
+
+		if (self::$_cacheStorageMethod === NULL) {
+			self::$_cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $method;
+			self::$_cacheStorageMethod = $method;
+		}
+		return TRUE;
+	}	//	function initialize()
+
+
+	/**
+	 * Initialise the cache storage
+	 *
+	 * @param	PHPExcel_Worksheet 	$parent		Enable cell caching for this worksheet
+	 * @return	PHPExcel_CachedObjectStorage_ICache
+	 **/
+	public static function getInstance(PHPExcel_Worksheet $parent)
+	{
+		$cacheMethodIsAvailable = TRUE;
+		if (self::$_cacheStorageMethod === NULL) {
+			$cacheMethodIsAvailable = self::initialize();
+		}
+
+		if ($cacheMethodIsAvailable) {
+			$instance = new self::$_cacheStorageClass( $parent,
+													   self::$_storageMethodParameters[self::$_cacheStorageMethod]
+													 );
+			if ($instance !== NULL) {
+				return $instance;
+			}
+		}
+
+		return FALSE;
+	}	//	function getInstance()
+
 }

File diff suppressed because it is too large
+ 213 - 185
htdocs/includes/phpexcel/PHPExcel/Calculation.php


+ 359 - 18
htdocs/includes/phpexcel/PHPExcel/Calculation/Database.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -41,11 +41,29 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_Database {
 
 
+	/**
+	 * __fieldExtract
+	 *
+	 * Extracts the column ID to use for the data field.
+	 *
+	 * @access	private
+	 * @param	mixed[]		$database		The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	mixed		$field			Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @return	string|NULL
+	 *
+	 */
 	private static function __fieldExtract($database,$field) {
 		$field = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($field));
 		$fieldNames = array_map('strtoupper',array_shift($database));
@@ -55,9 +73,28 @@ class PHPExcel_Calculation_Database {
 			return $keys[$field-1];
 		}
 		$key = array_search($field,$fieldNames);
-		return ($key) ? $key : null;
+		return ($key) ? $key : NULL;
 	}
 
+	/**
+	 * __filter
+	 *
+	 * Parses the selection criteria, extracts the database rows that match those criteria, and
+	 * returns that subset of rows.
+	 *
+	 * @access	private
+	 * @param	mixed[]		$database		The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	mixed[]		$criteria		The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	array of mixed
+	 *
+	 */
 	private static function __filter($database,$criteria) {
 		$fieldNames = array_shift($database);
 		$criteriaNames = array_shift($criteria);
@@ -82,6 +119,7 @@ class PHPExcel_Calculation_Database {
 				$testConditionsCount++;
 			}
 		}
+
 		if ($testConditionsCount > 1) {
 			$testConditionSet = 'AND('.implode(',',$testConditions).')';
 		} elseif($testConditionsCount == 1) {
@@ -113,7 +151,30 @@ class PHPExcel_Calculation_Database {
 
 
 	/**
-	 *	DAVERAGE
+	 * DAVERAGE
+	 *
+	 * Averages the values in a column of a list or database that match conditions you specify.
+	 *
+	 * Excel Function:
+	 *		DAVERAGE(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DAVERAGE($database,$field,$criteria) {
@@ -121,7 +182,6 @@ class PHPExcel_Calculation_Database {
 		if (is_null($field)) {
 			return NULL;
 		}
-
 		//	reduce the database to a set of rows that match all the criteria
 		$database = self::__filter($database,$criteria);
 		//	extract an array of values for the requested column
@@ -134,8 +194,39 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::AVERAGE($colData);
 	}	//	function DAVERAGE()
 
+
 	/**
-	 *	DCOUNT
+	 * DCOUNT
+	 *
+	 * Counts the cells that contain numbers in a column of a list or database that match conditions
+	 * that you specify.
+	 *
+	 * Excel Function:
+	 *		DCOUNT(database,[field],criteria)
+	 *
+	 * Excel Function:
+	 *		DAVERAGE(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	integer
+	 *
+	 * @TODO	The field argument is optional. If field is omitted, DCOUNT counts all records in the
+	 *			database that match the criteria.
 	 *
 	 */
 	public static function DCOUNT($database,$field,$criteria) {
@@ -156,8 +247,35 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::COUNT($colData);
 	}	//	function DCOUNT()
 
+
 	/**
-	 *	DCOUNTA
+	 * DCOUNTA
+	 *
+	 * Counts the nonblank cells in a column of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DCOUNTA(database,[field],criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	integer
+	 *
+	 * @TODO	The field argument is optional. If field is omitted, DCOUNTA counts all records in the
+	 *			database that match the criteria.
 	 *
 	 */
 	public static function DCOUNTA($database,$field,$criteria) {
@@ -178,8 +296,33 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::COUNTA($colData);
 	}	//	function DCOUNTA()
 
+
 	/**
-	 *	DGET
+	 * DGET
+	 *
+	 * Extracts a single value from a column of a list or database that matches conditions that you
+	 * specify.
+	 *
+	 * Excel Function:
+	 *		DGET(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	mixed
 	 *
 	 */
 	public static function DGET($database,$field,$criteria) {
@@ -204,8 +347,33 @@ class PHPExcel_Calculation_Database {
 		return $colData[0];
 	}	//	function DGET()
 
+
 	/**
-	 *	DMAX
+	 * DMAX
+	 *
+	 * Returns the largest number in a column of a list or database that matches conditions you that
+	 * specify.
+	 *
+	 * Excel Function:
+	 *		DMAX(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DMAX($database,$field,$criteria) {
@@ -226,8 +394,33 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::MAX($colData);
 	}	//	function DMAX()
 
+
 	/**
-	 *	DMIN
+	 * DMIN
+	 *
+	 * Returns the smallest number in a column of a list or database that matches conditions you that
+	 * specify.
+	 *
+	 * Excel Function:
+	 *		DMIN(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DMIN($database,$field,$criteria) {
@@ -248,8 +441,32 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::MIN($colData);
 	}	//	function DMIN()
 
+
 	/**
-	 *	DPRODUCT
+	 * DPRODUCT
+	 *
+	 * Multiplies the values in a column of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DPRODUCT(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DPRODUCT($database,$field,$criteria) {
@@ -270,8 +487,33 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_MathTrig::PRODUCT($colData);
 	}	//	function DPRODUCT()
 
+
 	/**
-	 *	DSTDEV
+	 * DSTDEV
+	 *
+	 * Estimates the standard deviation of a population based on a sample by using the numbers in a
+	 * column of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DSTDEV(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DSTDEV($database,$field,$criteria) {
@@ -292,8 +534,33 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::STDEV($colData);
 	}	//	function DSTDEV()
 
+
 	/**
-	 *	DSTDEVP
+	 * DSTDEVP
+	 *
+	 * Calculates the standard deviation of a population based on the entire population by using the
+	 * numbers in a column of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DSTDEVP(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DSTDEVP($database,$field,$criteria) {
@@ -314,8 +581,32 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::STDEVP($colData);
 	}	//	function DSTDEVP()
 
+
 	/**
-	 *	DSUM
+	 * DSUM
+	 *
+	 * Adds the numbers in a column of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DSUM(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DSUM($database,$field,$criteria) {
@@ -336,8 +627,33 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_MathTrig::SUM($colData);
 	}	//	function DSUM()
 
+
 	/**
-	 *	DVAR
+	 * DVAR
+	 *
+	 * Estimates the variance of a population based on a sample by using the numbers in a column
+	 * of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DVAR(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DVAR($database,$field,$criteria) {
@@ -358,8 +674,33 @@ class PHPExcel_Calculation_Database {
 		return PHPExcel_Calculation_Statistical::VARFunc($colData);
 	}	//	function DVAR()
 
+
 	/**
-	 *	DVARP
+	 * DVARP
+	 *
+	 * Calculates the variance of a population based on the entire population by using the numbers
+	 * in a column of a list or database that match conditions that you specify.
+	 *
+	 * Excel Function:
+	 *		DVARP(database,field,criteria)
+	 *
+	 * @access	public
+	 * @category Database Functions
+	 * @param	mixed[]			$database	The range of cells that makes up the list or database.
+	 *										A database is a list of related data in which rows of related
+	 *										information are records, and columns of data are fields. The
+	 *										first row of the list contains labels for each column.
+	 * @param	string|integer	$field		Indicates which column is used in the function. Enter the
+	 *										column label enclosed between double quotation marks, such as
+	 *										"Age" or "Yield," or a number (without quotation marks) that
+	 *										represents the position of the column within the list: 1 for
+	 *										the first column, 2 for the second column, and so on.
+	 * @param	mixed[]			$criteria	The range of cells that contains the conditions you specify.
+	 *										You can use any range for the criteria argument, as long as it
+	 *										includes at least one column label and at least one cell below
+	 *										the column label in which you specify a condition for the
+	 *										column.
+	 * @return	float
 	 *
 	 */
 	public static function DVARP($database,$field,$criteria) {

+ 364 - 95
htdocs/includes/phpexcel/PHPExcel/Calculation/DateTime.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -41,10 +41,16 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_DateTime {
 
+	/**
+	 * Identify if a year is a leap year or not
+	 *
+	 * @param	integer	$year	The year to test
+	 * @return	boolean			TRUE if the year is a leap year, otherwise FALSE
+	 */
 	public static function _isLeapYear($year) {
 		return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
 	}	//	function _isLeapYear()
@@ -82,7 +88,8 @@ class PHPExcel_Calculation_DateTime {
 	 */
 	public static function _getDateValue($dateValue) {
 		if (!is_numeric($dateValue)) {
-			if ((is_string($dateValue)) && (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
+			if ((is_string($dateValue)) &&
+				(PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
 				return PHPExcel_Calculation_Functions::VALUE();
 			}
 			if ((is_object($dateValue)) && ($dateValue instanceof PHPExcel_Shared_Date::$dateTimeObjectType)) {
@@ -142,6 +149,19 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DATETIMENOW
 	 *
+	 * Returns the current date and time.
+	 * The NOW function is useful when you need to display the current date and time on a worksheet or
+	 * calculate a value based on the current date and time, and have that value updated each time you
+	 * open the worksheet.
+	 *
+	 * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+	 * and time format of your regional settings. PHPExcel does not change cell formatting in this way.
+	 *
+	 * Excel Function:
+	 *		NOW()
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
 	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 	 *						depending on the value of the ReturnDateType flag
 	 */
@@ -169,6 +189,19 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DATENOW
 	 *
+	 * Returns the current date.
+	 * The NOW function is useful when you need to display the current date and time on a worksheet or
+	 * calculate a value based on the current date and time, and have that value updated each time you
+	 * open the worksheet.
+	 *
+	 * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+	 * and time format of your regional settings. PHPExcel does not change cell formatting in this way.
+	 *
+	 * Excel Function:
+	 *		TODAY()
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
 	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 	 *						depending on the value of the ReturnDateType flag
 	 */
@@ -182,7 +215,7 @@ class PHPExcel_Calculation_DateTime {
 					$retValue = (float) $excelDateTime;
 					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
-					$retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime) - 3600;
+					$retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime);
 					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 					$retValue = PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
@@ -197,16 +230,65 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DATE
 	 *
-	 * @param	long	$year
-	 * @param	long	$month
-	 * @param	long	$day
+	 * The DATE function returns a value that represents a particular date.
+	 *
+	 * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+	 * format of your regional settings. PHPExcel does not change cell formatting in this way.
+	 *
+	 * Excel Function:
+	 *		DATE(year,month,day)
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	integer		$year	The value of the year argument can include one to four digits.
+	 *								Excel interprets the year argument according to the configured
+	 *								date system: 1900 or 1904.
+	 *								If year is between 0 (zero) and 1899 (inclusive), Excel adds that
+	 *								value to 1900 to calculate the year. For example, DATE(108,1,2)
+	 *								returns January 2, 2008 (1900+108).
+	 *								If year is between 1900 and 9999 (inclusive), Excel uses that
+	 *								value as the year. For example, DATE(2008,1,2) returns January 2,
+	 *								2008.
+	 *								If year is less than 0 or is 10000 or greater, Excel returns the
+	 *								#NUM! error value.
+	 * @param	integer		$month	A positive or negative integer representing the month of the year
+	 *								from 1 to 12 (January to December).
+	 *								If month is greater than 12, month adds that number of months to
+	 *								the first month in the year specified. For example, DATE(2008,14,2)
+	 *								returns the serial number representing February 2, 2009.
+	 *								If month is less than 1, month subtracts the magnitude of that
+	 *								number of months, plus 1, from the first month in the year
+	 *								specified. For example, DATE(2008,-3,2) returns the serial number
+	 *								representing September 2, 2007.
+	 * @param	integer		$day	A positive or negative integer representing the day of the month
+	 *								from 1 to 31.
+	 *								If day is greater than the number of days in the month specified,
+	 *								day adds that number of days to the first day in the month. For
+	 *								example, DATE(2008,1,35) returns the serial number representing
+	 *								February 4, 2008.
+	 *								If day is less than 1, day subtracts the magnitude that number of
+	 *								days, plus one, from the first day of the month specified. For
+	 *								example, DATE(2008,1,-15) returns the serial number representing
+	 *								December 16, 2007.
 	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 	 *						depending on the value of the ReturnDateType flag
 	 */
 	public static function DATE($year = 0, $month = 1, $day = 1) {
-		$year	= (integer) PHPExcel_Calculation_Functions::flattenSingleValue($year);
-		$month	= (integer) PHPExcel_Calculation_Functions::flattenSingleValue($month);
-		$day	= (integer) PHPExcel_Calculation_Functions::flattenSingleValue($day);
+		$year	= PHPExcel_Calculation_Functions::flattenSingleValue($year);
+		$month	= PHPExcel_Calculation_Functions::flattenSingleValue($month);
+		$day	= PHPExcel_Calculation_Functions::flattenSingleValue($day);
+
+		$year	= ($year !== NULL)	? PHPExcel_Shared_String::testStringAsNumeric($year) : 0;
+		$month	= ($month !== NULL)	? PHPExcel_Shared_String::testStringAsNumeric($month) : 0;
+		$day	= ($day !== NULL)	? PHPExcel_Shared_String::testStringAsNumeric($day) : 0;
+		if ((!is_numeric($year)) ||
+			(!is_numeric($month)) ||
+			(!is_numeric($day))) {
+			return PHPExcel_Calculation_Functions::VALUE();
+		}
+		$year	= (integer) $year;
+		$month	= (integer) $month;
+		$day	= (integer) $day;
 
 		$baseYear = PHPExcel_Shared_Date::getExcelCalendar();
 		// Validate parameters
@@ -242,13 +324,10 @@ class PHPExcel_Calculation_DateTime {
 		switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 			case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
 					return (float) $excelDateValue;
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
 					return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 					return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
-					break;
 		}
 	}	//	function DATE()
 
@@ -256,9 +335,27 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * TIME
 	 *
-	 * @param	long	$hour
-	 * @param	long	$minute
-	 * @param	long	$second
+	 * The TIME function returns a value that represents a particular time.
+	 *
+	 * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
+	 * format of your regional settings. PHPExcel does not change cell formatting in this way.
+	 *
+	 * Excel Function:
+	 *		TIME(hour,minute,second)
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	integer		$hour		A number from 0 (zero) to 32767 representing the hour.
+	 *									Any value greater than 23 will be divided by 24 and the remainder
+	 *									will be treated as the hour value. For example, TIME(27,0,0) =
+	 *									TIME(3,0,0) = .125 or 3:00 AM.
+	 * @param	integer		$minute		A number from 0 to 32767 representing the minute.
+	 *									Any value greater than 59 will be converted to hours and minutes.
+	 *									For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
+	 * @param	integer		$second		A number from 0 to 32767 representing the second.
+	 *									Any value greater than 59 will be converted to hours, minutes,
+	 *									and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
+	 *									or 12:33:20 AM
 	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 	 *						depending on the value of the ReturnDateType flag
 	 */
@@ -310,10 +407,8 @@ class PHPExcel_Calculation_DateTime {
 						$date = 1;
 					}
 					return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
-					return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour-1, $minute, $second));	// -2147468400; //	-2147472000 + 3600
-					break;
+					return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour, $minute, $second));	// -2147468400; //	-2147472000 + 3600
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 					$dayAdjust = 0;
 					if ($hour < 0) {
@@ -329,7 +424,6 @@ class PHPExcel_Calculation_DateTime {
 						$phpDateObject->modify($dayAdjust.' days');
 					}
 					return $phpDateObject;
-					break;
 		}
 	}	//	function TIME()
 
@@ -337,7 +431,26 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DATEVALUE
 	 *
-	 * @param	string	$dateValue
+	 * Returns a value that represents a particular date.
+	 * Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
+	 * value.
+	 *
+	 * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
+	 * format of your regional settings. PHPExcel does not change cell formatting in this way.
+	 *
+	 * Excel Function:
+	 *		DATEVALUE(dateValue)
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	string	$dateValue		Text that represents a date in a Microsoft Excel date format.
+	 *									For example, "1/30/2008" or "30-Jan-2008" are text strings within
+	 *									quotation marks that represent dates. Using the default date
+	 *									system in Excel for Windows, date_text must represent a date from
+	 *									January 1, 1900, to December 31, 9999. Using the default date
+	 *									system in Excel for the Macintosh, date_text must represent a date
+	 *									from January 1, 1904, to December 31, 9999. DATEVALUE returns the
+	 *									#VALUE! error value if date_text is out of this range.
 	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 	 *						depending on the value of the ReturnDateType flag
 	 */
@@ -402,6 +515,8 @@ class PHPExcel_Calculation_DateTime {
 		if (($PHPDateArray !== False) && ($PHPDateArray['error_count'] == 0)) {
 			// Execute function
 			if ($PHPDateArray['year'] == '')	{ $PHPDateArray['year'] = strftime('%Y'); }
+			if ($PHPDateArray['year'] < 1900)
+				return PHPExcel_Calculation_Functions::VALUE();
 			if ($PHPDateArray['month'] == '')	{ $PHPDateArray['month'] = strftime('%m'); }
 			if ($PHPDateArray['day'] == '')		{ $PHPDateArray['day'] = strftime('%d'); }
 			$excelDateValue = floor(PHPExcel_Shared_Date::FormattedPHPToExcel($PHPDateArray['year'],$PHPDateArray['month'],$PHPDateArray['day'],$PHPDateArray['hour'],$PHPDateArray['minute'],$PHPDateArray['second']));
@@ -409,13 +524,10 @@ class PHPExcel_Calculation_DateTime {
 			switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 				case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
 						return (float) $excelDateValue;
-						break;
 				case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
 						return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
-						break;
 				case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 						return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
-						break;
 			}
 		}
 		return PHPExcel_Calculation_Functions::VALUE();
@@ -425,7 +537,22 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * TIMEVALUE
 	 *
-	 * @param	string	$timeValue
+	 * Returns a value that represents a particular time.
+	 * Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
+	 * value.
+	 *
+	 * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
+	 * format of your regional settings. PHPExcel does not change cell formatting in this way.
+	 *
+	 * Excel Function:
+	 *		TIMEVALUE(timeValue)
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	string	$timeValue		A text string that represents a time in any one of the Microsoft
+	 *									Excel time formats; for example, "6:45 PM" and "18:45" text strings
+	 *									within quotation marks that represent time.
+	 *									Date information in time_text is ignored.
 	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 	 *						depending on the value of the ReturnDateType flag
 	 */
@@ -444,13 +571,10 @@ class PHPExcel_Calculation_DateTime {
 			switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 				case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
 						return (float) $excelDateValue;
-						break;
 				case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
 						return (integer) $phpDateValue = PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+25569) - 3600;;
-						break;
 				case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 						return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
-						break;
 			}
 		}
 		return PHPExcel_Calculation_Functions::VALUE();
@@ -460,10 +584,12 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DATEDIF
 	 *
-	 * @param	long	$startDate		Excel date serial value or a standard date string
-	 * @param	long	$endDate		Excel date serial value or a standard date string
+	 * @param	mixed	$startDate		Excel date serial value, PHP date/time stamp, PHP DateTime object
+	 *									or a standard date string
+	 * @param	mixed	$endDate		Excel date serial value, PHP date/time stamp, PHP DateTime object
+	 *									or a standard date string
 	 * @param	string	$unit
-	 * @return	long	Interval between the dates
+	 * @return	integer	Interval between the dates
 	 */
 	public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D') {
 		$startDate	= PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
@@ -547,6 +673,8 @@ class PHPExcel_Calculation_DateTime {
 					if ($retVal < 0) { $retVal += 365; }
 				}
 				break;
+			default:
+				$retVal = PHPExcel_Calculation_Functions::NaN();
 		}
 		return $retVal;
 	}	//	function DATEDIF()
@@ -555,10 +683,31 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DAYS360
 	 *
-	 * @param	long	$startDate		Excel date serial value or a standard date string
-	 * @param	long	$endDate		Excel date serial value or a standard date string
-	 * @param	boolean	$method			US or European Method
-	 * @return	long	PHP date/time serial
+	 * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
+	 * which is used in some accounting calculations. Use this function to help compute payments if
+	 * your accounting system is based on twelve 30-day months.
+	 *
+	 * Excel Function:
+	 *		DAYS360(startDate,endDate[,method])
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	mixed		$startDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *										PHP DateTime object, or a standard date string
+	 * @param	mixed		$endDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *										PHP DateTime object, or a standard date string
+	 * @param	boolean		$method			US or European Method
+	 *										FALSE or omitted: U.S. (NASD) method. If the starting date is
+	 *										the last day of a month, it becomes equal to the 30th of the
+	 *										same month. If the ending date is the last day of a month and
+	 *										the starting date is earlier than the 30th of a month, the
+	 *										ending date becomes equal to the 1st of the next month;
+	 *										otherwise the ending date becomes equal to the 30th of the
+	 *										same month.
+	 *										TRUE: European method. Starting dates and ending dates that
+	 *										occur on the 31st of a month become equal to the 30th of the
+	 *										same month.
+	 * @return	integer		Number of days between start date and end date
 	 */
 	public static function DAYS360($startDate = 0, $endDate = 0, $method = false) {
 		$startDate	= PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
@@ -587,21 +736,29 @@ class PHPExcel_Calculation_DateTime {
 
 
 	/**
-	 *	YEARFRAC
+	 * YEARFRAC
+	 *
+	 * Calculates the fraction of the year represented by the number of whole days between two dates
+	 * (the start_date and the end_date).
+	 * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
+	 * obligations to assign to a specific term.
 	 *
-	 *	Calculates the fraction of the year represented by the number of whole days between two dates (the start_date and the
-	 *	end_date). Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or obligations
-	 *	to assign to a specific term.
+	 * Excel Function:
+	 *		YEARFRAC(startDate,endDate[,method])
 	 *
-	 *	@param	mixed	$startDate		Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
-	 *	@param	mixed	$endDate		Excel date serial value (float), PHP date timestamp (integer) or date object, or a standard date string
-	 *	@param	integer	$method			Method used for the calculation
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	mixed	$startDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
+	 * @param	mixed	$endDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
+	 * @param	integer	$method			Method used for the calculation
 	 *										0 or omitted	US (NASD) 30/360
 	 *										1				Actual/actual
 	 *										2				Actual/360
 	 *										3				Actual/365
 	 *										4				European 30/360
-	 *	@return	float	fraction of the year
+	 * @return	float	fraction of the year
 	 */
 	public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0) {
 		$startDate	= PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
@@ -619,7 +776,6 @@ class PHPExcel_Calculation_DateTime {
 			switch($method) {
 				case 0	:
 					return self::DAYS360($startDate,$endDate) / 360;
-					break;
 				case 1	:
 					$days = self::DATEDIF($startDate,$endDate);
 					$startYear = self::YEAR($startDate);
@@ -664,16 +820,12 @@ class PHPExcel_Calculation_DateTime {
 						$leapDays /= $years;
 					}
 					return $days / (365 + $leapDays);
-					break;
 				case 2	:
 					return self::DATEDIF($startDate,$endDate) / 360;
-					break;
 				case 3	:
 					return self::DATEDIF($startDate,$endDate) / 365;
-					break;
 				case 4	:
 					return self::DAYS360($startDate,$endDate,True) / 360;
-					break;
 			}
 		}
 		return PHPExcel_Calculation_Functions::VALUE();
@@ -683,10 +835,25 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * NETWORKDAYS
 	 *
-	 * @param	mixed				Start date
-	 * @param	mixed				End date
-	 * @param	array of mixed		Optional Date Series
-	 * @return	long	Interval between the dates
+	 * Returns the number of whole working days between start_date and end_date. Working days
+	 * exclude weekends and any dates identified in holidays.
+	 * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
+	 * worked during a specific term.
+	 *
+	 * Excel Function:
+	 *		NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	mixed			$startDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *											PHP DateTime object, or a standard date string
+	 * @param	mixed			$endDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *											PHP DateTime object, or a standard date string
+	 * @param	mixed			$holidays,...	Optional series of Excel date serial value (float), PHP date
+	 *											timestamp (integer), PHP DateTime object, or a standard date
+	 *											strings that will be excluded from the working calendar, such
+	 *											as state and federal holidays and floating holidays.
+	 * @return	integer			Interval between the dates
 	 */
 	public static function NETWORKDAYS($startDate,$endDate) {
 		//	Retrieve the mandatory start and end date that are referenced in the function definition
@@ -748,15 +915,32 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * WORKDAY
 	 *
-	 * @param	mixed				Start date
-	 * @param	mixed				number of days for adjustment
-	 * @param	array of mixed		Optional Date Series
-	 * @return	long	Interval between the dates
+	 * Returns the date that is the indicated number of working days before or after a date (the
+	 * starting date). Working days exclude weekends and any dates identified as holidays.
+	 * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
+	 * delivery times, or the number of days of work performed.
+	 *
+	 * Excel Function:
+	 *		WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
+	 *
+	 * @access	public
+	 * @category Date/Time Functions
+	 * @param	mixed		$startDate		Excel date serial value (float), PHP date timestamp (integer),
+	 *										PHP DateTime object, or a standard date string
+	 * @param	integer		$endDays		The number of nonweekend and nonholiday days before or after
+	 *										startDate. A positive value for days yields a future date; a
+	 *										negative value yields a past date.
+	 * @param	mixed		$holidays,...	Optional series of Excel date serial value (float), PHP date
+	 *										timestamp (integer), PHP DateTime object, or a standard date
+	 *										strings that will be excluded from the working calendar, such
+	 *										as state and federal holidays and floating holidays.
+	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+	 *						depending on the value of the ReturnDateType flag
 	 */
 	public static function WORKDAY($startDate,$endDays) {
 		//	Retrieve the mandatory start date and days that are referenced in the function definition
 		$startDate	= PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
-		$endDays	= (int) PHPExcel_Calculation_Functions::flattenSingleValue($endDays);
+		$endDays	= PHPExcel_Calculation_Functions::flattenSingleValue($endDays);
 		//	Flush the mandatory start date and days that are referenced in the function definition, and get the optional days
 		$dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 		array_shift($dateArgs);
@@ -766,6 +950,7 @@ class PHPExcel_Calculation_DateTime {
 			return PHPExcel_Calculation_Functions::VALUE();
 		}
 		$startDate = (float) floor($startDate);
+		$endDays = (int) floor($endDays);
 		//	If endDays is 0, we always return startDate
 		if ($endDays == 0) { return $startDate; }
 
@@ -789,10 +974,10 @@ class PHPExcel_Calculation_DateTime {
 		}
 
 		//	Test any extra holiday parameters
-		if (count($dateArgs) > 0) {
+		if (!empty($dateArgs)) {
 			$holidayCountedArray = $holidayDates = array();
 			foreach ($dateArgs as $holidayDate) {
-				if ((!is_null($holidayDate)) && (trim($holidayDate) > '')) {
+				if (($holidayDate !== NULL) && (trim($holidayDate) > '')) {
 					if (is_string($holidayDate = self::_getDateValue($holidayDate))) {
 						return PHPExcel_Calculation_Functions::VALUE();
 					}
@@ -834,13 +1019,10 @@ class PHPExcel_Calculation_DateTime {
 		switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 			case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
 					return (float) $endDate;
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
 					return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 					return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
-					break;
 		}
 	}	//	function WORKDAY()
 
@@ -848,8 +1030,15 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DAYOFMONTH
 	 *
-	 * @param	long	$dateValue		Excel date serial value or a standard date string
-	 * @return	int		Day
+	 * Returns the day of the month, for a specified date. The day is given as an integer
+	 * ranging from 1 to 31.
+	 *
+	 * Excel Function:
+	 *		DAY(dateValue)
+	 *
+	 * @param	mixed	$dateValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
+	 * @return	int		Day of the month
 	 */
 	public static function DAYOFMONTH($dateValue = 1) {
 		$dateValue	= PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
@@ -872,12 +1061,30 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * DAYOFWEEK
 	 *
-	 * @param	long	$dateValue		Excel date serial value or a standard date string
-	 * @return	int		Day
+	 * Returns the day of the week for a specified date. The day is given as an integer
+	 * ranging from 0 to 7 (dependent on the requested style).
+	 *
+	 * Excel Function:
+	 *		WEEKDAY(dateValue[,style])
+	 *
+	 * @param	mixed	$dateValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
+	 * @param	int		$style			A number that determines the type of return value
+	 *										1 or omitted	Numbers 1 (Sunday) through 7 (Saturday).
+	 *										2				Numbers 1 (Monday) through 7 (Sunday).
+	 *										3				Numbers 0 (Monday) through 6 (Sunday).
+	 * @return	int		Day of the week value
 	 */
 	public static function DAYOFWEEK($dateValue = 1, $style = 1) {
 		$dateValue	= PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
-		$style		= floor(PHPExcel_Calculation_Functions::flattenSingleValue($style));
+		$style		= PHPExcel_Calculation_Functions::flattenSingleValue($style);
+
+		if (!is_numeric($style)) {
+			return PHPExcel_Calculation_Functions::VALUE();
+		} elseif (($style < 1) || ($style > 3)) {
+			return PHPExcel_Calculation_Functions::NaN();
+		}
+		$style = floor($style);
 
 		if (is_string($dateValue = self::_getDateValue($dateValue))) {
 			return PHPExcel_Calculation_Functions::VALUE();
@@ -899,7 +1106,6 @@ class PHPExcel_Calculation_DateTime {
 					$firstDay = 0;
 					--$DoW;
 					break;
-			default:
 		}
 		if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL) {
 			//	Test for Excel's 1900 leap year, and introduce the error as required
@@ -918,19 +1124,33 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * WEEKOFYEAR
 	 *
-	 * @param	long	$dateValue		Excel date serial value or a standard date string
+	 * Returns the week of the year for a specified date.
+	 * The WEEKNUM function considers the week containing January 1 to be the first week of the year.
+	 * However, there is a European standard that defines the first week as the one with the majority
+	 * of days (four or more) falling in the new year. This means that for years in which there are
+	 * three days or less in the first week of January, the WEEKNUM function returns week numbers
+	 * that are incorrect according to the European standard.
+	 *
+	 * Excel Function:
+	 *		WEEKNUM(dateValue[,style])
+	 *
+	 * @param	mixed	$dateValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
 	 * @param	boolean	$method			Week begins on Sunday or Monday
+	 *										1 or omitted	Week begins on Sunday.
+	 *										2				Week begins on Monday.
 	 * @return	int		Week Number
 	 */
 	public static function WEEKOFYEAR($dateValue = 1, $method = 1) {
 		$dateValue	= PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
-		$method		= floor(PHPExcel_Calculation_Functions::flattenSingleValue($method));
+		$method		= PHPExcel_Calculation_Functions::flattenSingleValue($method);
 
 		if (!is_numeric($method)) {
 			return PHPExcel_Calculation_Functions::VALUE();
 		} elseif (($method < 1) || ($method > 2)) {
 			return PHPExcel_Calculation_Functions::NaN();
 		}
+		$method = floor($method);
 
 		if (is_string($dateValue = self::_getDateValue($dateValue))) {
 			return PHPExcel_Calculation_Functions::VALUE();
@@ -955,8 +1175,15 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * MONTHOFYEAR
 	 *
-	 * @param	long	$dateValue		Excel date serial value or a standard date string
-	 * @return	int		Month
+	 * Returns the month of a date represented by a serial number.
+	 * The month is given as an integer, ranging from 1 (January) to 12 (December).
+	 *
+	 * Excel Function:
+	 *		MONTH(dateValue)
+	 *
+	 * @param	mixed	$dateValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
+	 * @return	int		Month of the year
 	 */
 	public static function MONTHOFYEAR($dateValue = 1) {
 		$dateValue	= PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
@@ -977,7 +1204,14 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * YEAR
 	 *
-	 * @param	long	$dateValue		Excel date serial value or a standard date string
+	 * Returns the year corresponding to a date.
+	 * The year is returned as an integer in the range 1900-9999.
+	 *
+	 * Excel Function:
+	 *		YEAR(dateValue)
+	 *
+	 * @param	mixed	$dateValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard date string
 	 * @return	int		Year
 	 */
 	public static function YEAR($dateValue = 1) {
@@ -999,7 +1233,14 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * HOUROFDAY
 	 *
-	 * @param	mixed	$timeValue		Excel time serial value or a standard time string
+	 * Returns the hour of a time value.
+	 * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
+	 *
+	 * Excel Function:
+	 *		HOUR(timeValue)
+	 *
+	 * @param	mixed	$timeValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard time string
 	 * @return	int		Hour
 	 */
 	public static function HOUROFDAY($timeValue = 0) {
@@ -1032,7 +1273,14 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * MINUTEOFHOUR
 	 *
-	 * @param	long	$timeValue		Excel time serial value or a standard time string
+	 * Returns the minutes of a time value.
+	 * The minute is given as an integer, ranging from 0 to 59.
+	 *
+	 * Excel Function:
+	 *		MINUTE(timeValue)
+	 *
+	 * @param	mixed	$timeValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard time string
 	 * @return	int		Minute
 	 */
 	public static function MINUTEOFHOUR($timeValue = 0) {
@@ -1065,7 +1313,14 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * SECONDOFMINUTE
 	 *
-	 * @param	long	$timeValue		Excel time serial value or a standard time string
+	 * Returns the seconds of a time value.
+	 * The second is given as an integer in the range 0 (zero) to 59.
+	 *
+	 * Excel Function:
+	 *		SECOND(timeValue)
+	 *
+	 * @param	mixed	$timeValue		Excel date serial value (float), PHP date timestamp (integer),
+	 *									PHP DateTime object, or a standard time string
 	 * @return	int		Second
 	 */
 	public static function SECONDOFMINUTE($timeValue = 0) {
@@ -1098,20 +1353,30 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * EDATE
 	 *
-	 * Returns the serial number that represents the date that is the indicated number of months before or after a specified date
-	 * (the start_date). Use EDATE to calculate maturity dates or due dates that fall on the same day of the month as the date of issue.
+	 * Returns the serial number that represents the date that is the indicated number of months
+	 * before or after a specified date (the start_date).
+	 * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
+	 * as the date of issue.
+	 *
+	 * Excel Function:
+	 *		EDATE(dateValue,adjustmentMonths)
 	 *
-	 * @param	long	$dateValue				Excel date serial value or a standard date string
-	 * @param	int		$adjustmentMonths		Number of months to adjust by
-	 * @return	long	Excel date serial value
+	 * @param	mixed	$dateValue			Excel date serial value (float), PHP date timestamp (integer),
+	 *										PHP DateTime object, or a standard date string
+	 * @param	int		$adjustmentMonths	The number of months before or after start_date.
+	 *										A positive value for months yields a future date;
+	 *										a negative value yields a past date.
+	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+	 *						depending on the value of the ReturnDateType flag
 	 */
 	public static function EDATE($dateValue = 1, $adjustmentMonths = 0) {
 		$dateValue			= PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
-		$adjustmentMonths	= floor(PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths));
+		$adjustmentMonths	= PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
 
 		if (!is_numeric($adjustmentMonths)) {
 			return PHPExcel_Calculation_Functions::VALUE();
 		}
+		$adjustmentMonths = floor($adjustmentMonths);
 
 		if (is_string($dateValue = self::_getDateValue($dateValue))) {
 			return PHPExcel_Calculation_Functions::VALUE();
@@ -1123,13 +1388,10 @@ class PHPExcel_Calculation_DateTime {
 		switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 			case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
 					return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
 					return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 					return $PHPDateObject;
-					break;
 		}
 	}	//	function EDATE()
 
@@ -1137,20 +1399,29 @@ class PHPExcel_Calculation_DateTime {
 	/**
 	 * EOMONTH
 	 *
-	 * Returns the serial number for the last day of the month that is the indicated number of months before or after start_date.
+	 * Returns the date value for the last day of the month that is the indicated number of months
+	 * before or after start_date.
 	 * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
 	 *
-	 * @param	long	$dateValue			Excel date serial value or a standard date string
-	 * @param	int		$adjustmentMonths	Number of months to adjust by
-	 * @return	long	Excel date serial value
+	 * Excel Function:
+	 *		EOMONTH(dateValue,adjustmentMonths)
+	 *
+	 * @param	mixed	$dateValue			Excel date serial value (float), PHP date timestamp (integer),
+	 *										PHP DateTime object, or a standard date string
+	 * @param	int		$adjustmentMonths	The number of months before or after start_date.
+	 *										A positive value for months yields a future date;
+	 *										a negative value yields a past date.
+	 * @return	mixed	Excel date/time serial value, PHP date/time serial value or PHP date/time object,
+	 *						depending on the value of the ReturnDateType flag
 	 */
 	public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0) {
 		$dateValue			= PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
-		$adjustmentMonths	= floor(PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths));
+		$adjustmentMonths	= PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
 
 		if (!is_numeric($adjustmentMonths)) {
 			return PHPExcel_Calculation_Functions::VALUE();
 		}
+		$adjustmentMonths = floor($adjustmentMonths);
 
 		if (is_string($dateValue = self::_getDateValue($dateValue))) {
 			return PHPExcel_Calculation_Functions::VALUE();
@@ -1165,14 +1436,12 @@ class PHPExcel_Calculation_DateTime {
 		switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 			case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
 					return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
 					return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
-					break;
 			case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
 					return $PHPDateObject;
-					break;
 		}
 	}	//	function EOMONTH()
 
 }	//	class PHPExcel_Calculation_DateTime
+

File diff suppressed because it is too large
+ 454 - 154
htdocs/includes/phpexcel/PHPExcel/Calculation/Engineering.php


+ 5 - 5
htdocs/includes/phpexcel/PHPExcel/Calculation/Exception.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version	1.7.6, 2011-02-27
+ * @version	1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_Exception extends Exception {
 	/**
@@ -48,5 +48,5 @@ class PHPExcel_Calculation_Exception extends Exception {
 		$e->line = $line;
 		$e->file = $file;
 		throw $e;
-	}	
+	}
 }

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Calculation/ExceptionHandler.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version	1.7.6, 2011-02-27
+ * @version	1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_ExceptionHandler {
 	/**

File diff suppressed because it is too large
+ 554 - 152
htdocs/includes/phpexcel/PHPExcel/Calculation/Financial.php


+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Calculation/FormulaParser.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -54,7 +54,7 @@ PARTLY BASED ON:
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_FormulaParser {
 	/* Character constants */

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Calculation/FormulaToken.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -55,7 +55,7 @@ PARTLY BASED ON:
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_FormulaToken {
 	/* Token types */

+ 6 - 6
htdocs/includes/phpexcel/PHPExcel/Calculation/Function.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Calculation
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_Function {
 	/* Function categories */
@@ -76,9 +76,9 @@ class PHPExcel_Calculation_Function {
      * @param 	string		$pPHPExcelName	PHPExcel function mapping
      * @throws 	Exception
      */
-    public function __construct($pCategory = null, $pExcelName = null, $pPHPExcelName = null)
+    public function __construct($pCategory = NULL, $pExcelName = NULL, $pPHPExcelName = NULL)
     {
-    	if (!is_null($pCategory) && !is_null($pExcelName) && !is_null($pPHPExcelName)) {
+    	if (($pCategory !== NULL) && ($pExcelName !== NULL) && ($pPHPExcelName !== NULL)) {
     		// Initialise values
     		$this->_category 		= $pCategory;
     		$this->_excelName 		= $pExcelName;

+ 156 - 146
htdocs/includes/phpexcel/PHPExcel/Calculation/Functions.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -54,7 +54,7 @@ define('PRECISION', 8.88E-016);
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_Functions {
 
@@ -69,26 +69,26 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Compatibility mode to use for error checking and responses
+	 * Compatibility mode to use for error checking and responses
 	 *
-	 *	@access	private
-	 *	@var string
+	 * @access	private
+	 * @var string
 	 */
 	protected static $compatibilityMode	= self::COMPATIBILITY_EXCEL;
 
 	/**
-	 *	Data Type to use when returning date values
+	 * Data Type to use when returning date values
 	 *
-	 *	@access	private
-	 *	@var string
+	 * @access	private
+	 * @var string
 	 */
 	protected static $ReturnDateType	= self::RETURNDATE_EXCEL;
 
 	/**
-	 *	List of error codes
+	 * List of error codes
 	 *
-	 *	@access	private
-	 *	@var array
+	 * @access	private
+	 * @var array
 	 */
 	protected static $_errorCodes	= array( 'null'				=> '#NULL!',
 											 'divisionbyzero'	=> '#DIV/0!',
@@ -102,16 +102,16 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Set the Compatibility Mode
+	 * Set the Compatibility Mode
 	 *
-	 *	@access	public
-	 *	@category Function Configuration
-	 *	@param	 string		$compatibilityMode		Compatibility Mode
+	 * @access	public
+	 * @category Function Configuration
+	 * @param	 string		$compatibilityMode		Compatibility Mode
 	 *												Permitted values are:
 	 *													PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL			'Excel'
 	 *													PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC		'Gnumeric'
 	 *													PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE	'OpenOfficeCalc'
-	 *	@return	 boolean	(Success or Failure)
+	 * @return	 boolean	(Success or Failure)
 	 */
 	public static function setCompatibilityMode($compatibilityMode) {
 		if (($compatibilityMode == self::COMPATIBILITY_EXCEL) ||
@@ -125,11 +125,11 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Return the current Compatibility Mode
+	 * Return the current Compatibility Mode
 	 *
-	 *	@access	public
-	 *	@category Function Configuration
-	 *	@return	 string		Compatibility Mode
+	 * @access	public
+	 * @category Function Configuration
+	 * @return	 string		Compatibility Mode
 	 *							Possible Return values are:
 	 *								PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL			'Excel'
 	 *								PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC		'Gnumeric'
@@ -141,16 +141,16 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
+	 * Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
 	 *
-	 *	@access	public
-	 *	@category Function Configuration
-	 *	@param	 string	$returnDateType			Return Date Format
+	 * @access	public
+	 * @category Function Configuration
+	 * @param	 string	$returnDateType			Return Date Format
 	 *												Permitted values are:
 	 *													PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC		'P'
 	 *													PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT		'O'
 	 *													PHPExcel_Calculation_Functions::RETURNDATE_EXCEL			'E'
-	 *	@return	 boolean							Success or failure
+	 * @return	 boolean							Success or failure
 	 */
 	public static function setReturnDateType($returnDateType) {
 		if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) ||
@@ -164,11 +164,11 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
+	 * Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object)
 	 *
-	 *	@access	public
-	 *	@category Function Configuration
-	 *	@return	 string		Return Date Format
+	 * @access	public
+	 * @category Function Configuration
+	 * @return	 string		Return Date Format
 	 *							Possible Return values are:
 	 *								PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC		'P'
 	 *								PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT		'O'
@@ -180,11 +180,11 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	DUMMY
+	 * DUMMY
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#Not Yet Implemented
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#Not Yet Implemented
 	 */
 	public static function DUMMY() {
 		return '#Not Yet Implemented';
@@ -192,11 +192,11 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	DIV0
+	 * DIV0
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#Not Yet Implemented
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#Not Yet Implemented
 	 */
 	public static function DIV0() {
 		return self::$_errorCodes['divisionbyzero'];
@@ -204,17 +204,17 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	NA
+	 * NA
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=NA()
 	 *
-	 *	Returns the error value #N/A
+	 * Returns the error value #N/A
 	 *		#N/A is the error value that means "no value is available."
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@return	string	#N/A!
+	 * @access	public
+	 * @category Logical Functions
+	 * @return	string	#N/A!
 	 */
 	public static function NA() {
 		return self::$_errorCodes['na'];
@@ -222,13 +222,13 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	NaN
+	 * NaN
 	 *
-	 *	Returns the error value #NUM!
+	 * Returns the error value #NUM!
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#NUM!
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#NUM!
 	 */
 	public static function NaN() {
 		return self::$_errorCodes['num'];
@@ -236,13 +236,13 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	NAME
+	 * NAME
 	 *
-	 *	Returns the error value #NAME?
+	 * Returns the error value #NAME?
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#NAME?
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#NAME?
 	 */
 	public static function NAME() {
 		return self::$_errorCodes['name'];
@@ -250,13 +250,13 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	REF
+	 * REF
 	 *
-	 *	Returns the error value #REF!
+	 * Returns the error value #REF!
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#REF!
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#REF!
 	 */
 	public static function REF() {
 		return self::$_errorCodes['reference'];
@@ -264,13 +264,13 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	NULL
+	 * NULL
 	 *
-	 *	Returns the error value #NULL!
+	 * Returns the error value #NULL!
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#REF!
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#REF!
 	 */
 	public static function NULL() {
 		return self::$_errorCodes['null'];
@@ -278,13 +278,13 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	VALUE
+	 * VALUE
 	 *
-	 *	Returns the error value #VALUE!
+	 * Returns the error value #VALUE!
 	 *
-	 *	@access	public
-	 *	@category Error Returns
-	 *	@return	string	#VALUE!
+	 * @access	public
+	 * @category Error Returns
+	 * @return	string	#VALUE!
 	 */
 	public static function VALUE() {
 		return self::$_errorCodes['value'];
@@ -321,32 +321,32 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	ERROR_TYPE
+	 * ERROR_TYPE
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
 	public static function ERROR_TYPE($value = '') {
 		$value	= self::flattenSingleValue($value);
 
 		$i = 1;
 		foreach(self::$_errorCodes as $errorCode) {
-			if ($value == $errorCode) {
+			if ($value === $errorCode) {
 				return $i;
 			}
 			++$i;
 		}
-		return self::$_errorCodes['na'];
+		return self::NA();
 	}	//	function ERROR_TYPE()
 
 
 	/**
-	 *	IS_BLANK
+	 * IS_BLANK
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
-	public static function IS_BLANK($value=null) {
+	public static function IS_BLANK($value = NULL) {
 		if (!is_null($value)) {
 			$value	= self::flattenSingleValue($value);
 		}
@@ -356,10 +356,10 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	IS_ERR
+	 * IS_ERR
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
 	public static function IS_ERR($value = '') {
 		$value		= self::flattenSingleValue($value);
@@ -369,70 +369,74 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	IS_ERROR
+	 * IS_ERROR
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
 	public static function IS_ERROR($value = '') {
 		$value		= self::flattenSingleValue($value);
 
+		if (!is_string($value))
+			return false;
 		return in_array($value, array_values(self::$_errorCodes));
 	}	//	function IS_ERROR()
 
 
 	/**
-	 *	IS_NA
+	 * IS_NA
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
 	public static function IS_NA($value = '') {
 		$value		= self::flattenSingleValue($value);
 
-		return ($value === self::$_errorCodes['na']);
+		return ($value === self::NA());
 	}	//	function IS_NA()
 
 
 	/**
-	 *	IS_EVEN
+	 * IS_EVEN
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
-	public static function IS_EVEN($value = 0) {
-		$value		= self::flattenSingleValue($value);
+	public static function IS_EVEN($value = NULL) {
+		$value = self::flattenSingleValue($value);
 
-		if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
-			return self::$_errorCodes['value'];
-		}
+		if ($value === NULL)
+			return self::NAME();
+		if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value))))
+			return self::VALUE();
 		return ($value % 2 == 0);
 	}	//	function IS_EVEN()
 
 
 	/**
-	 *	IS_ODD
+	 * IS_ODD
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
-	public static function IS_ODD($value = null) {
-		$value	= self::flattenSingleValue($value);
+	public static function IS_ODD($value = NULL) {
+		$value = self::flattenSingleValue($value);
 
-		if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) {
-			return self::$_errorCodes['value'];
-		}
+		if ($value === NULL)
+			return self::NAME();
+		if ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value))))
+			return self::VALUE();
 		return (abs($value) % 2 == 1);
 	}	//	function IS_ODD()
 
 
 	/**
-	 *	IS_NUMBER
+	 * IS_NUMBER
 	 *
-	 *	@param	mixed	$value		Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value		Value to check
+	 * @return	boolean
 	 */
-	public static function IS_NUMBER($value = 0) {
+	public static function IS_NUMBER($value = NULL) {
 		$value		= self::flattenSingleValue($value);
 
 		if (is_string($value)) {
@@ -443,12 +447,12 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	IS_LOGICAL
+	 * IS_LOGICAL
 	 *
-	 *	@param	mixed	$value		Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value		Value to check
+	 * @return	boolean
 	 */
-	public static function IS_LOGICAL($value = true) {
+	public static function IS_LOGICAL($value = NULL) {
 		$value		= self::flattenSingleValue($value);
 
 		return is_bool($value);
@@ -456,46 +460,46 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	IS_TEXT
+	 * IS_TEXT
 	 *
-	 *	@param	mixed	$value		Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value		Value to check
+	 * @return	boolean
 	 */
-	public static function IS_TEXT($value = '') {
+	public static function IS_TEXT($value = NULL) {
 		$value		= self::flattenSingleValue($value);
 
-		return is_string($value);
+		return (is_string($value) && !self::IS_ERROR($value));
 	}	//	function IS_TEXT()
 
 
 	/**
-	 *	IS_NONTEXT
+	 * IS_NONTEXT
 	 *
-	 *	@param	mixed	$value		Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value		Value to check
+	 * @return	boolean
 	 */
-	public static function IS_NONTEXT($value = '') {
+	public static function IS_NONTEXT($value = NULL) {
 		return !self::IS_TEXT($value);
 	}	//	function IS_NONTEXT()
 
 
 	/**
-	 *	VERSION
+	 * VERSION
 	 *
-	 *	@return	string	Version information
+	 * @return	string	Version information
 	 */
 	public static function VERSION() {
-		return 'PHPExcel 1.7.6, 2011-02-27';
+		return 'PHPExcel 1.7.8, 2012-10-12';
 	}	//	function VERSION()
 
 
 	/**
-	 *	N
+	 * N
 	 *
-	 *	Returns a value converted to a number
+	 * Returns a value converted to a number
 	 *
-	 *	@param	value		The value you want converted
-	 *	@return	number		N converts values listed in the following table
+	 * @param	value		The value you want converted
+	 * @return	number		N converts values listed in the following table
 	 *		If value is or refers to N returns
 	 *		A number			That number
 	 *		A date				The serial number of that date
@@ -504,7 +508,7 @@ class PHPExcel_Calculation_Functions {
 	 *		An error value		The error value
 	 *		Anything else		0
 	 */
-	public static function N($value) {
+	public static function N($value = NULL) {
 		while (is_array($value)) {
 			$value = array_shift($value);
 		}
@@ -530,12 +534,12 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	TYPE
+	 * TYPE
 	 *
-	 *	Returns a number that identifies the type of a value
+	 * Returns a number that identifies the type of a value
 	 *
-	 *	@param	value		The value you want tested
-	 *	@return	number		N converts values listed in the following table
+	 * @param	value		The value you want tested
+	 * @return	number		N converts values listed in the following table
 	 *		If value is or refers to N returns
 	 *		A number			1
 	 *		Text				2
@@ -543,7 +547,7 @@ class PHPExcel_Calculation_Functions {
 	 *		An error value		16
 	 *		Array or Matrix		64
 	 */
-	public static function TYPE($value) {
+	public static function TYPE($value = NULL) {
 		$value	= self::flattenArrayIndexed($value);
 		if (is_array($value) && (count($value) > 1)) {
 			$a = array_keys($value);
@@ -555,13 +559,13 @@ class PHPExcel_Calculation_Functions {
 			} elseif (self::isMatrixValue($a)) {
 				return 64;
 			}
-		} elseif(count($value) == 0) {
+		} elseif(empty($value)) {
 			//	Empty Cell
 			return 1;
 		}
 		$value	= self::flattenSingleValue($value);
 
-		if ((is_float($value)) || (is_int($value))) {
+		if (($value === NULL) || (is_float($value)) || (is_int($value))) {
 				return 1;
 		} elseif(is_bool($value)) {
 				return 4;
@@ -580,10 +584,10 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Convert a multi-dimensional array to a simple 1-dimensional array
+	 * Convert a multi-dimensional array to a simple 1-dimensional array
 	 *
-	 *	@param	array	$array	Array to be flattened
-	 *	@return	array	Flattened array
+	 * @param	array	$array	Array to be flattened
+	 * @return	array	Flattened array
 	 */
 	public static function flattenArray($array) {
 		if (!is_array($array)) {
@@ -612,10 +616,10 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
+	 * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing
 	 *
-	 *	@param	array	$array	Array to be flattened
-	 *	@return	array	Flattened array
+	 * @param	array	$array	Array to be flattened
+	 * @return	array	Flattened array
 	 */
 	public static function flattenArrayIndexed($array) {
 		if (!is_array($array)) {
@@ -644,10 +648,10 @@ class PHPExcel_Calculation_Functions {
 
 
 	/**
-	 *	Convert an array to a single scalar value by extracting the first element
+	 * Convert an array to a single scalar value by extracting the first element
 	 *
-	 *	@param	mixed		$value		Array or scalar value
-	 *	@return	mixed
+	 * @param	mixed		$value		Array or scalar value
+	 * @return	mixed
 	 */
 	public static function flattenSingleValue($value = '') {
 		while (is_array($value)) {
@@ -746,6 +750,12 @@ if (!function_exists('money_format')) {
 		}
 		$space = $locale["{$letter}_sep_by_space"] ? ' ' : '';
 
+		if (!isset($locale['mon_decimal_point']) || empty($locale['mon_decimal_point'])) {
+			$locale['mon_decimal_point'] = (!isset($locale['decimal_point']) || empty($locale['decimal_point'])) ?
+											$locale['decimal_point'] :
+											'.';
+		}
+
 		$number = number_format($number, $right, $locale['mon_decimal_point'], $flags['nogroup'] ? '' : $locale['mon_thousands_sep'] );
 		$number = explode($locale['mon_decimal_point'], $number);
 

+ 74 - 76
htdocs/includes/phpexcel/PHPExcel/Calculation/Logical.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -41,50 +41,50 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_Logical {
 
 	/**
-	 *	TRUE
+	 * TRUE
 	 *
-	 *	Returns the boolean TRUE.
+	 * Returns the boolean TRUE.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=TRUE()
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@return	boolean		True
+	 * @access	public
+	 * @category Logical Functions
+	 * @return	boolean		True
 	 */
 	public static function TRUE() {
-		return true;
+		return TRUE;
 	}	//	function TRUE()
 
 
 	/**
-	 *	FALSE
+	 * FALSE
 	 *
-	 *	Returns the boolean FALSE.
+	 * Returns the boolean FALSE.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=FALSE()
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@return	boolean		False
+	 * @access	public
+	 * @category Logical Functions
+	 * @return	boolean		False
 	 */
 	public static function FALSE() {
-		return false;
+		return FALSE;
 	}	//	function FALSE()
 
 
 	/**
-	 *	LOGICAL_AND
+	 * LOGICAL_AND
 	 *
-	 *	Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
+	 * Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=AND(logical1[,logical2[, ...]])
 	 *
 	 *		The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
@@ -95,19 +95,19 @@ class PHPExcel_Calculation_Logical {
 	 *		If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
 	 *			the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@return	boolean		The logical AND of the arguments.
+	 * @access	public
+	 * @category Logical Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @return	boolean		The logical AND of the arguments.
 	 */
 	public static function LOGICAL_AND() {
 		// Return value
-		$returnValue = True;
+		$returnValue = TRUE;
 
 		// Loop through the arguments
 		$aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
-		$argCount = 0;
-		foreach ($aArgs as $arg) {
+		$argCount = -1;
+		foreach ($aArgs as $argCount => $arg) {
 			// Is it a boolean value?
 			if (is_bool($arg)) {
 				$returnValue = $returnValue && $arg;
@@ -116,19 +116,18 @@ class PHPExcel_Calculation_Logical {
 			} elseif (is_string($arg)) {
 				$arg = strtoupper($arg);
 				if (($arg == 'TRUE') || ($arg == PHPExcel_Calculation::getTRUE())) {
-					$arg = true;
+					$arg = TRUE;
 				} elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) {
-					$arg = false;
+					$arg = FALSE;
 				} else {
 					return PHPExcel_Calculation_Functions::VALUE();
 				}
 				$returnValue = $returnValue && ($arg != 0);
 			}
-			++$argCount;
 		}
 
 		// Return
-		if ($argCount == 0) {
+		if ($argCount < 0) {
 			return PHPExcel_Calculation_Functions::VALUE();
 		}
 		return $returnValue;
@@ -136,11 +135,11 @@ class PHPExcel_Calculation_Logical {
 
 
 	/**
-	 *	LOGICAL_OR
+	 * LOGICAL_OR
 	 *
-	 *	Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
+	 * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=OR(logical1[,logical2[, ...]])
 	 *
 	 *		The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays
@@ -151,19 +150,19 @@ class PHPExcel_Calculation_Logical {
 	 *		If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
 	 *			the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@return	boolean		The logical OR of the arguments.
+	 * @access	public
+	 * @category Logical Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @return	boolean		The logical OR of the arguments.
 	 */
 	public static function LOGICAL_OR() {
 		// Return value
-		$returnValue = False;
+		$returnValue = FALSE;
 
 		// Loop through the arguments
 		$aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
-		$argCount = 0;
-		foreach ($aArgs as $arg) {
+		$argCount = -1;
+		foreach ($aArgs as $argCount => $arg) {
 			// Is it a boolean value?
 			if (is_bool($arg)) {
 				$returnValue = $returnValue || $arg;
@@ -172,19 +171,18 @@ class PHPExcel_Calculation_Logical {
 			} elseif (is_string($arg)) {
 				$arg = strtoupper($arg);
 				if (($arg == 'TRUE') || ($arg == PHPExcel_Calculation::getTRUE())) {
-					$arg = true;
+					$arg = TRUE;
 				} elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) {
-					$arg = false;
+					$arg = FALSE;
 				} else {
 					return PHPExcel_Calculation_Functions::VALUE();
 				}
 				$returnValue = $returnValue || ($arg != 0);
 			}
-			++$argCount;
 		}
 
 		// Return
-		if ($argCount == 0) {
+		if ($argCount < 0) {
 			return PHPExcel_Calculation_Functions::VALUE();
 		}
 		return $returnValue;
@@ -192,11 +190,11 @@ class PHPExcel_Calculation_Logical {
 
 
 	/**
-	 *	NOT
+	 * NOT
 	 *
-	 *	Returns the boolean inverse of the argument.
+	 * Returns the boolean inverse of the argument.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=NOT(logical)
 	 *
 	 *		The argument must evaluate to a logical value such as TRUE or FALSE
@@ -206,19 +204,19 @@ class PHPExcel_Calculation_Logical {
 	 *		If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds
 	 *			the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@param	mixed		$logical	A value or expression that can be evaluated to TRUE or FALSE
-	 *	@return	boolean		The boolean inverse of the argument.
+	 * @access	public
+	 * @category Logical Functions
+	 * @param	mixed		$logical	A value or expression that can be evaluated to TRUE or FALSE
+	 * @return	boolean		The boolean inverse of the argument.
 	 */
-	public static function NOT($logical) {
+	public static function NOT($logical=FALSE) {
 		$logical = PHPExcel_Calculation_Functions::flattenSingleValue($logical);
 		if (is_string($logical)) {
 			$logical = strtoupper($logical);
 			if (($logical == 'TRUE') || ($logical == PHPExcel_Calculation::getTRUE())) {
-				return false;
+				return FALSE;
 			} elseif (($logical == 'FALSE') || ($logical == PHPExcel_Calculation::getFALSE())) {
-				return true;
+				return TRUE;
 			} else {
 				return PHPExcel_Calculation_Functions::VALUE();
 			}
@@ -228,11 +226,11 @@ class PHPExcel_Calculation_Logical {
 	}	//	function NOT()
 
 	/**
-	 *	STATEMENT_IF
+	 * STATEMENT_IF
 	 *
-	 *	Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
+	 * Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=IF(condition[,returnIfTrue[,returnIfFalse]])
 	 *
 	 *		Condition is any value or expression that can be evaluated to TRUE or FALSE.
@@ -252,33 +250,33 @@ class PHPExcel_Calculation_Logical {
 	 *			If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned.
 	 *			ReturnIfFalse can be another formula.
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@param	mixed	$condition		Condition to evaluate
-	 *	@param	mixed	$returnIfTrue	Value to return when condition is true
-	 *	@param	mixed	$returnIfFalse	Optional value to return when condition is false
-	 *	@return	mixed	The value of returnIfTrue or returnIfFalse determined by condition
+	 * @access	public
+	 * @category Logical Functions
+	 * @param	mixed	$condition		Condition to evaluate
+	 * @param	mixed	$returnIfTrue	Value to return when condition is true
+	 * @param	mixed	$returnIfFalse	Optional value to return when condition is false
+	 * @return	mixed	The value of returnIfTrue or returnIfFalse determined by condition
 	 */
-	public static function STATEMENT_IF($condition = true, $returnIfTrue = 0, $returnIfFalse = False) {
-		$condition		= (is_null($condition))		? True :	(boolean) PHPExcel_Calculation_Functions::flattenSingleValue($condition);
+	public static function STATEMENT_IF($condition = TRUE, $returnIfTrue = 0, $returnIfFalse = FALSE) {
+		$condition		= (is_null($condition))		? TRUE :	(boolean) PHPExcel_Calculation_Functions::flattenSingleValue($condition);
 		$returnIfTrue	= (is_null($returnIfTrue))	? 0 :		PHPExcel_Calculation_Functions::flattenSingleValue($returnIfTrue);
-		$returnIfFalse	= (is_null($returnIfFalse))	? False :	PHPExcel_Calculation_Functions::flattenSingleValue($returnIfFalse);
+		$returnIfFalse	= (is_null($returnIfFalse))	? FALSE :	PHPExcel_Calculation_Functions::flattenSingleValue($returnIfFalse);
 
-		return ($condition ? $returnIfTrue : $returnIfFalse);
+		return ($condition) ? $returnIfTrue : $returnIfFalse;
 	}	//	function STATEMENT_IF()
 
 
 	/**
-	 *	IFERROR
+	 * IFERROR
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=IFERROR(testValue,errorpart)
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@param	mixed	$testValue	Value to check, is also the value returned when no error
-	 *	@param	mixed	$errorpart	Value to return when testValue is an error condition
-	 *	@return	mixed	The value of errorpart or testValue determined by error condition
+	 * @access	public
+	 * @category Logical Functions
+	 * @param	mixed	$testValue	Value to check, is also the value returned when no error
+	 * @param	mixed	$errorpart	Value to return when testValue is an error condition
+	 * @return	mixed	The value of errorpart or testValue determined by error condition
 	 */
 	public static function IFERROR($testValue = '', $errorpart = '') {
 		$testValue	= (is_null($testValue))	? '' :	PHPExcel_Calculation_Functions::flattenSingleValue($testValue);

+ 129 - 67
htdocs/includes/phpexcel/PHPExcel/Calculation/LookupRef.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -41,28 +41,31 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	CELL_ADDRESS
+	 * CELL_ADDRESS
 	 *
-	 *	Creates a cell address as text, given specified row and column numbers.
+	 * Creates a cell address as text, given specified row and column numbers.
 	 *
-	 *	@param	row				Row number to use in the cell reference
-	 *	@param	column			Column number to use in the cell reference
-	 *	@param	relativity		Flag indicating the type of reference to return
+	 * Excel Function:
+	 *		=ADDRESS(row, column, [relativity], [referenceStyle], [sheetText])
+	 *
+	 * @param	row				Row number to use in the cell reference
+	 * @param	column			Column number to use in the cell reference
+	 * @param	relativity		Flag indicating the type of reference to return
 	 *								1 or omitted	Absolute
 	 *								2				Absolute row; relative column
 	 *								3				Relative row; absolute column
 	 *								4				Relative
-	 *	@param	referenceStyle	A logical value that specifies the A1 or R1C1 reference style.
+	 * @param	referenceStyle	A logical value that specifies the A1 or R1C1 reference style.
 	 *								TRUE or omitted		CELL_ADDRESS returns an A1-style reference
 	 *								FALSE				CELL_ADDRESS returns an R1C1-style reference
-	 *	@param	sheetText		Optional Name of worksheet to use
-	 *	@return	string
+	 * @param	sheetText		Optional Name of worksheet to use
+	 * @return	string
 	 */
 	public static function CELL_ADDRESS($row, $column, $relativity=1, $referenceStyle=True, $sheetText='') {
 		$row		= PHPExcel_Calculation_Functions::flattenSingleValue($row);
@@ -93,15 +96,18 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	COLUMN
+	 * COLUMN
 	 *
-	 *	Returns the column number of the given cell reference
-	 *	If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array.
-	 *	If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
+	 * Returns the column number of the given cell reference
+	 * If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array.
+	 * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
 	 *		reference of the cell in which the COLUMN function appears; otherwise this function returns 0.
 	 *
-	 *	@param	cellAddress		A reference to a range of cells for which you want the column numbers
-	 *	@return	integer or array of integer
+	 * Excel Function:
+	 *		=COLUMN([cellAddress])
+	 *
+	 * @param	cellAddress		A reference to a range of cells for which you want the column numbers
+	 * @return	integer or array of integer
 	 */
 	public static function COLUMN($cellAddress=Null) {
 		if (is_null($cellAddress) || trim($cellAddress) === '') { return 0; }
@@ -133,12 +139,15 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	COLUMNS
+	 * COLUMNS
 	 *
-	 *	Returns the number of columns in an array or reference.
+	 * Returns the number of columns in an array or reference.
 	 *
-	 *	@param	cellAddress		An array or array formula, or a reference to a range of cells for which you want the number of columns
-	 *	@return	integer
+	 * Excel Function:
+	 *		=COLUMNS(cellAddress)
+	 *
+	 * @param	cellAddress		An array or array formula, or a reference to a range of cells for which you want the number of columns
+	 * @return	integer			The number of columns in cellAddress
 	 */
 	public static function COLUMNS($cellAddress=Null) {
 		if (is_null($cellAddress) || $cellAddress === '') {
@@ -161,15 +170,18 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	ROW
+	 * ROW
 	 *
-	 *	Returns the row number of the given cell reference
-	 *	If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array.
-	 *	If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
+	 * Returns the row number of the given cell reference
+	 * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array.
+	 * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the
 	 *		reference of the cell in which the ROW function appears; otherwise this function returns 0.
 	 *
-	 *	@param	cellAddress		A reference to a range of cells for which you want the row numbers
-	 *	@return	integer or array of integer
+	 * Excel Function:
+	 *		=ROW([cellAddress])
+	 *
+	 * @param	cellAddress		A reference to a range of cells for which you want the row numbers
+	 * @return	integer or array of integer
 	 */
 	public static function ROW($cellAddress=Null) {
 		if (is_null($cellAddress) || trim($cellAddress) === '') { return 0; }
@@ -202,12 +214,15 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	ROWS
+	 * ROWS
 	 *
-	 *	Returns the number of rows in an array or reference.
+	 * Returns the number of rows in an array or reference.
 	 *
-	 *	@param	cellAddress		An array or array formula, or a reference to a range of cells for which you want the number of rows
-	 *	@return	integer
+	 * Excel Function:
+	 *		=ROWS(cellAddress)
+	 *
+	 * @param	cellAddress		An array or array formula, or a reference to a range of cells for which you want the number of rows
+	 * @return	integer			The number of rows in cellAddress
 	 */
 	public static function ROWS($cellAddress=Null) {
 		if (is_null($cellAddress) || $cellAddress === '') {
@@ -229,16 +244,16 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	HYPERLINK
+	 * HYPERLINK
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		=HYPERLINK(linkURL,displayName)
 	 *
-	 *	@access	public
-	 *	@category Logical Functions
-	 *	@param	string	$linkURL		Value to check, is also the value returned when no error
-	 *	@param	string	$displayName	Value to return when testValue is an error condition
-	 *	@return	mixed	The value of errorpart or testValue determined by error condition
+	 * @access	public
+	 * @category Logical Functions
+	 * @param	string	$linkURL		Value to check, is also the value returned when no error
+	 * @param	string	$displayName	Value to return when testValue is an error condition
+	 * @return	mixed	The value of $displayName (or $linkURL if $displayName was blank)
 	 */
 	public static function HYPERLINK($linkURL = '', $displayName = null, PHPExcel_Cell $pCell = null) {
 		$args = func_get_args();
@@ -262,12 +277,21 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	INDIRECT
+	 * INDIRECT
+	 *
+	 * Returns the reference specified by a text string.
+	 * References are immediately evaluated to display their contents.
+	 *
+	 * Excel Function:
+	 *		=INDIRECT(cellAddress)
 	 *
-	 *	Returns the number of rows in an array or reference.
+	 * NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010
+	 *
+	 * @param	cellAddress		An array or array formula, or a reference to a range of cells for which you want the number of rows
+	 * @return	mixed			The cells referenced by cellAddress
+	 *
+	 * @todo	Support for the optional a1 parameter introduced in Excel 2010
 	 *
-	 *	@param	cellAddress		An array or array formula, or a reference to a range of cells for which you want the number of rows
-	 *	@return	integer
 	 */
 	public static function INDIRECT($cellAddress=Null, PHPExcel_Cell $pCell = null) {
 		$cellAddress	= PHPExcel_Calculation_Functions::flattenSingleValue($cellAddress);
@@ -283,7 +307,19 @@ class PHPExcel_Calculation_LookupRef {
 
 		if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress1, $matches)) ||
 			((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress2, $matches)))) {
-			return PHPExcel_Calculation_Functions::REF();
+
+			if (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $cellAddress1, $matches)) {
+				return PHPExcel_Calculation_Functions::REF();
+			}
+
+			if (strpos($cellAddress,'!') !== false) {
+				list($sheetName,$cellAddress) = explode('!',$cellAddress);
+				$pSheet = $pCell->getParent()->getParent()->getSheetByName($sheetName);
+			} else {
+				$pSheet = $pCell->getParent();
+			}
+
+			return PHPExcel_Calculation::getInstance()->extractNamedRange($cellAddress, $pSheet, False);
 		}
 
 		if (strpos($cellAddress,'!') !== false) {
@@ -298,26 +334,29 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	OFFSET
+	 * OFFSET
 	 *
-	 *	Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells.
-	 *	The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and
-	 *	the number of columns to be returned.
+	 * Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells.
+	 * The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and
+	 * the number of columns to be returned.
 	 *
-	 *	@param	cellAddress		The reference from which you want to base the offset. Reference must refer to a cell or
+	 * Excel Function:
+	 *		=OFFSET(cellAddress, rows, cols, [height], [width])
+	 *
+	 * @param	cellAddress		The reference from which you want to base the offset. Reference must refer to a cell or
 	 *								range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value.
-	 *	@param	rows			The number of rows, up or down, that you want the upper-left cell to refer to.
+	 * @param	rows			The number of rows, up or down, that you want the upper-left cell to refer to.
 	 *								Using 5 as the rows argument specifies that the upper-left cell in the reference is
 	 *								five rows below reference. Rows can be positive (which means below the starting reference)
 	 *								or negative (which means above the starting reference).
-	 *	@param	cols			The number of columns, to the left or right, that you want the upper-left cell of the result
+	 * @param	cols			The number of columns, to the left or right, that you want the upper-left cell of the result
 	 *								to refer to. Using 5 as the cols argument specifies that the upper-left cell in the
 	 *								reference is five columns to the right of reference. Cols can be positive (which means
 	 *								to the right of the starting reference) or negative (which means to the left of the
 	 *								starting reference).
-	 *	@param	height			The height, in number of rows, that you want the returned reference to be. Height must be a positive number.
-	 *	@param	width			The width, in number of columns, that you want the returned reference to be. Width must be a positive number.
-	 *	@return	string			A reference to a cell or range of cells
+	 * @param	height			The height, in number of rows, that you want the returned reference to be. Height must be a positive number.
+	 * @param	width			The width, in number of columns, that you want the returned reference to be. Width must be a positive number.
+	 * @return	string			A reference to a cell or range of cells
 	 */
 	public static function OFFSET($cellAddress=Null,$rows=0,$columns=0,$height=null,$width=null) {
 		$rows		= PHPExcel_Calculation_Functions::flattenSingleValue($rows);
@@ -387,6 +426,24 @@ class PHPExcel_Calculation_LookupRef {
 	}	//	function OFFSET()
 
 
+	/**
+	 * CHOOSE
+	 *
+	 * Uses lookup_value to return a value from the list of value arguments.
+	 * Use CHOOSE to select one of up to 254 values based on the lookup_value.
+	 *
+	 * Excel Function:
+	 *		=CHOOSE(index_num, value1, [value2], ...)
+	 *
+	 * @param	index_num		Specifies which value argument is selected.
+	 *							Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number
+	 *								between 1 and 254.
+	 * @param	value1...		Value1 is required, subsequent values are optional.
+	 *							Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on
+	 *								index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or
+	 *								text.
+	 * @return	mixed			The selected value
+	 */
 	public static function CHOOSE() {
 		$chooseArgs = func_get_args();
 		$chosenEntry = PHPExcel_Calculation_Functions::flattenArray(array_shift($chooseArgs));
@@ -414,14 +471,17 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	MATCH
+	 * MATCH
 	 *
-	 *	The MATCH function searches for a specified item in a range of cells
+	 * The MATCH function searches for a specified item in a range of cells
 	 *
-	 *	@param	lookup_value	The value that you want to match in lookup_array
-	 *	@param	lookup_array	The range of cells being searched
-	 *	@param	match_type		The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered.
-	 *	@return	integer			The relative position of the found item
+	 * Excel Function:
+	 *		=MATCH(lookup_value, lookup_array, [match_type])
+	 *
+	 * @param	lookup_value	The value that you want to match in lookup_array
+	 * @param	lookup_array	The range of cells being searched
+	 * @param	match_type		The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered.
+	 * @return	integer			The relative position of the found item
 	 */
 	public static function MATCH($lookup_value, $lookup_array, $match_type=1) {
 		$lookup_array = PHPExcel_Calculation_Functions::flattenArray($lookup_array);
@@ -524,15 +584,17 @@ class PHPExcel_Calculation_LookupRef {
 
 
 	/**
-	 *	INDEX
+	 * INDEX
 	 *
 	 * Uses an index to choose a value from a reference or array
-	 * implemented: Return the value of a specified cell or array of cells	Array form
-	 * not implemented: Return a reference to specified cells	Reference form
 	 *
-	 * @param	range_array	a range of cells or an array constant
-	 * @param	row_num		selects the row in array from which to return a value. If row_num is omitted, column_num is required.
-	 * @param	column_num	selects the column in array from which to return a value. If column_num is omitted, row_num is required.
+	 * Excel Function:
+	 *		=INDEX(range_array, row_num, [column_num])
+	 *
+	 * @param	range_array		A range of cells or an array constant
+	 * @param	row_num			The row in array from which to return a value. If row_num is omitted, column_num is required.
+	 * @param	column_num		The column in array from which to return a value. If column_num is omitted, row_num is required.
+	 * @return	mixed			the value of a specified cell or array of cells
 	 */
 	public static function INDEX($arrayValues,$rowNum = 0,$columnNum = 0) {
 
@@ -635,7 +697,7 @@ class PHPExcel_Calculation_LookupRef {
 		}
 
 		// index_number must be less than or equal to the number of columns in lookup_array
-		if ((!is_array($lookup_array)) || (count($lookup_array) < 1)) {
+		if ((!is_array($lookup_array)) || (empty($lookup_array))) {
 			return PHPExcel_Calculation_Functions::REF();
 		} else {
 			$f = array_keys($lookup_array);

+ 325 - 200
htdocs/includes/phpexcel/PHPExcel/Calculation/MathTrig.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -41,7 +41,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_MathTrig {
 
@@ -61,7 +61,7 @@ class PHPExcel_Calculation_MathTrig {
 				}
 			}
 		}
-		if (count($factorArray) > 0) {
+		if (!empty($factorArray)) {
 			rsort($factorArray);
 			return $factorArray;
 		} else {
@@ -76,61 +76,79 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	ATAN2
+	 * ATAN2
 	 *
-	 *	This function calculates the arc tangent of the two variables x and y. It is similar to
+	 * This function calculates the arc tangent of the two variables x and y. It is similar to
 	 *		calculating the arc tangent of y ÷ x, except that the signs of both arguments are used
 	 *		to determine the quadrant of the result.
-	 *	The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
+	 * The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
 	 *		point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between
 	 *		-pi and pi, excluding -pi.
 	 *
-	 *	Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
+	 * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
 	 *		PHP atan2() function, so we need to reverse them here before calling the PHP atan() function.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		ATAN2(xCoordinate,yCoordinate)
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	float	$xCoordinate		The x-coordinate of the point.
-	 *	@param	float	$yCoordinate		The y-coordinate of the point.
-	 *	@return	float	The inverse tangent of the specified x- and y-coordinates.
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$xCoordinate		The x-coordinate of the point.
+	 * @param	float	$yCoordinate		The y-coordinate of the point.
+	 * @return	float	The inverse tangent of the specified x- and y-coordinates.
 	 */
-	public static function ATAN2($xCoordinate, $yCoordinate) {
-		$xCoordinate	= (float) PHPExcel_Calculation_Functions::flattenSingleValue($xCoordinate);
-		$yCoordinate	= (float) PHPExcel_Calculation_Functions::flattenSingleValue($yCoordinate);
+	public static function ATAN2($xCoordinate = NULL, $yCoordinate = NULL) {
+		$xCoordinate	= PHPExcel_Calculation_Functions::flattenSingleValue($xCoordinate);
+		$yCoordinate	= PHPExcel_Calculation_Functions::flattenSingleValue($yCoordinate);
 
-		if (($xCoordinate == 0) && ($yCoordinate == 0)) {
-			return PHPExcel_Calculation_Functions::DIV0();
-		}
+		$xCoordinate	= ($xCoordinate !== NULL)	? $xCoordinate : 0.0;
+		$yCoordinate	= ($yCoordinate !== NULL)	? $yCoordinate : 0.0;
 
-		return atan2($yCoordinate, $xCoordinate);
-	}	//	function REVERSE_ATAN2()
+		if (((is_numeric($xCoordinate)) || (is_bool($xCoordinate))) &&
+			((is_numeric($yCoordinate)))  || (is_bool($yCoordinate))) {
+			$xCoordinate	= (float) $xCoordinate;
+			$yCoordinate	= (float) $yCoordinate;
+
+			if (($xCoordinate == 0) && ($yCoordinate == 0)) {
+				return PHPExcel_Calculation_Functions::DIV0();
+			}
+
+			return atan2($yCoordinate, $xCoordinate);
+		}
+		return PHPExcel_Calculation_Functions::VALUE();
+	}	//	function ATAN2()
 
 
 	/**
-	 *	CEILING
+	 * CEILING
+	 *
+	 * Returns number rounded up, away from zero, to the nearest multiple of significance.
+	 *		For example, if you want to avoid using pennies in your prices and your product is
+	 *		priced at $4.42, use the formula =CEILING(4.42,0.05) to round prices up to the
+	 *		nearest nickel.
 	 *
-	 *	Returns number rounded up, away from zero, to the nearest multiple of significance.
+	 * Excel Function:
+	 *		CEILING(number[,significance])
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@param	float	$significance	Significance
-	 *	@return	float	Rounded Number
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$number			The number you want to round.
+	 * @param	float	$significance	The multiple to which you want to round.
+	 * @return	float	Rounded Number
 	 */
-	public static function CEILING($number,$significance=null) {
+	public static function CEILING($number, $significance = NULL) {
 		$number			= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 		$significance	= PHPExcel_Calculation_Functions::flattenSingleValue($significance);
 
-		if ((is_null($significance)) && (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
+		if ((is_null($significance)) &&
+			(PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
 			$significance = $number/abs($number);
 		}
 
 		if ((is_numeric($number)) && (is_numeric($significance))) {
-			if (self::SIGN($number) == self::SIGN($significance)) {
-				if ($significance == 0.0) {
-					return 0;
-				}
+			if ($significance == 0.0) {
+				return 0.0;
+			} elseif (self::SIGN($number) == self::SIGN($significance)) {
 				return ceil($number / $significance) * $significance;
 			} else {
 				return PHPExcel_Calculation_Functions::NaN();
@@ -141,16 +159,21 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	COMBIN
+	 * COMBIN
+	 *
+	 * Returns the number of combinations for a given number of items. Use COMBIN to
+	 *		determine the total possible number of groups for a given number of items.
 	 *
-	 *	Returns the number of combinations for a given number of items. Use COMBIN to
-	 *	determine the total possible number of groups for a given number of items.
+	 * Excel Function:
+	 *		COMBIN(numObjs,numInSet)
 	 *
-	 *	@param	int		$numObjs	Number of different objects
-	 *	@param	int		$numInSet	Number of objects in each combination
-	 *	@return	int		Number of combinations
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	int		$numObjs	Number of different objects
+	 * @param	int		$numInSet	Number of objects in each combination
+	 * @return	int		Number of combinations
 	 */
-	public static function COMBIN($numObjs,$numInSet) {
+	public static function COMBIN($numObjs, $numInSet) {
 		$numObjs	= PHPExcel_Calculation_Functions::flattenSingleValue($numObjs);
 		$numInSet	= PHPExcel_Calculation_Functions::flattenSingleValue($numInSet);
 
@@ -167,19 +190,32 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	EVEN
+	 * EVEN
 	 *
-	 *	Returns number rounded up to the nearest even integer.
+	 * Returns number rounded up to the nearest even integer.
+	 * You can use this function for processing items that come in twos. For example,
+	 *		a packing crate accepts rows of one or two items. The crate is full when
+	 *		the number of items, rounded up to the nearest two, matches the crate's
+	 *		capacity.
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@return	int		Rounded Number
+	 * Excel Function:
+	 *		EVEN(number)
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$number			Number to round
+	 * @return	int		Rounded Number
 	 */
 	public static function EVEN($number) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 
 		if (is_null($number)) {
 			return 0;
-		} elseif (is_numeric($number)) {
+		} elseif (is_bool($number)) {
+			$number = (int) $number;
+		}
+
+		if (is_numeric($number)) {
 			$significance = 2 * self::SIGN($number);
 			return (int) self::CEILING($number,$significance);
 		}
@@ -188,12 +224,18 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	FACT
+	 * FACT
 	 *
-	 *	Returns the factorial of a number.
+	 * Returns the factorial of a number.
+	 * The factorial of a number is equal to 1*2*3*...* number.
 	 *
-	 *	@param	float	$factVal	Factorial Value
-	 *	@return	int		Factorial
+	 * Excel Function:
+	 *		FACT(factVal)
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$factVal	Factorial Value
+	 * @return	int		Factorial
 	 */
 	public static function FACT($factVal) {
 		$factVal	= PHPExcel_Calculation_Functions::flattenSingleValue($factVal);
@@ -220,17 +262,23 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	FACTDOUBLE
+	 * FACTDOUBLE
+	 *
+	 * Returns the double factorial of a number.
 	 *
-	 *	Returns the double factorial of a number.
+	 * Excel Function:
+	 *		FACTDOUBLE(factVal)
 	 *
-	 *	@param	float	$factVal	Factorial Value
-	 *	@return	int		Double Factorial
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$factVal	Factorial Value
+	 * @return	int		Double Factorial
 	 */
 	public static function FACTDOUBLE($factVal) {
-		$factLoop	= floor(PHPExcel_Calculation_Functions::flattenSingleValue($factVal));
+		$factLoop	= PHPExcel_Calculation_Functions::flattenSingleValue($factVal);
 
 		if (is_numeric($factLoop)) {
+			$factLoop	= floor($factLoop);
 			if ($factVal < 0) {
 				return PHPExcel_Calculation_Functions::NaN();
 			}
@@ -246,15 +294,20 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	FLOOR
+	 * FLOOR
 	 *
-	 *	Rounds number down, toward zero, to the nearest multiple of significance.
+	 * Rounds number down, toward zero, to the nearest multiple of significance.
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@param	float	$significance	Significance
-	 *	@return	float	Rounded Number
+	 * Excel Function:
+	 *		FLOOR(number[,significance])
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$number			Number to round
+	 * @param	float	$significance	Significance
+	 * @return	float	Rounded Number
 	 */
-	public static function FLOOR($number,$significance=null) {
+	public static function FLOOR($number, $significance = NULL) {
 		$number			= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 		$significance	= PHPExcel_Calculation_Functions::flattenSingleValue($significance);
 
@@ -277,26 +330,41 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	GCD
+	 * GCD
+	 *
+	 * Returns the greatest common divisor of a series of numbers.
+	 * The greatest common divisor is the largest integer that divides both
+	 *		number1 and number2 without a remainder.
 	 *
-	 *	Returns the greatest common divisor of a series of numbers
+	 * Excel Function:
+	 *		GCD(number1[,number2[, ...]])
 	 *
-	 *	@param	$array	Values to calculate the Greatest Common Divisor
-	 *	@return	int		Greatest Common Divisor
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed	$arg,...		Data values
+	 * @return	integer					Greatest Common Divisor
 	 */
 	public static function GCD() {
 		$returnValue = 1;
-		$allPoweredFactors = array();
+		$allValuesFactors = array();
 		// Loop through arguments
 		foreach(PHPExcel_Calculation_Functions::flattenArray(func_get_args()) as $value) {
-			if ($value == 0) {
-				break;
+			if (!is_numeric($value)) {
+				return PHPExcel_Calculation_Functions::VALUE();
+			} elseif ($value == 0) {
+				continue;
+			} elseif($value < 0) {
+				return PHPExcel_Calculation_Functions::NaN();
 			}
 			$myFactors = self::_factors($value);
 			$myCountedFactors = array_count_values($myFactors);
 			$allValuesFactors[] = $myCountedFactors;
 		}
 		$allValuesCount = count($allValuesFactors);
+		if ($allValuesCount == 0) {
+			return 0;
+		}
+
 		$mergedArray = $allValuesFactors[0];
 		for ($i=1;$i < $allValuesCount; ++$i) {
 			$mergedArray = array_intersect_key($mergedArray,$allValuesFactors[$i]);
@@ -338,16 +406,26 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	INT
+	 * INT
 	 *
-	 *	Casts a floating point value to an integer
+	 * Casts a floating point value to an integer
 	 *
-	 *	@param	float	$number			Number to cast to an integer
-	 *	@return	integer	Integer value
+	 * Excel Function:
+	 *		INT(number)
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$number			Number to cast to an integer
+	 * @return	integer	Integer value
 	 */
 	public static function INT($number) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 
+		if (is_null($number)) {
+			return 0;
+		} elseif (is_bool($number)) {
+			return (int) $number;
+		}
 		if (is_numeric($number)) {
 			return (int) floor($number);
 		}
@@ -356,12 +434,20 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	LCM
+	 * LCM
 	 *
-	 *	Returns the lowest common multiplier of a series of numbers
+	 * Returns the lowest common multiplier of a series of numbers
+	 * The least common multiple is the smallest positive integer that is a multiple
+	 * of all integer arguments number1, number2, and so on. Use LCM to add fractions
+	 * with different denominators.
 	 *
-	 *	@param	$array	Values to calculate the Lowest Common Multiplier
-	 *	@return	int		Lowest Common Multiplier
+	 * Excel Function:
+	 *		LCM(number1[,number2[, ...]])
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed	$arg,...		Data values
+	 * @return	int		Lowest Common Multiplier
 	 */
 	public static function LCM() {
 		$returnValue = 1;
@@ -400,23 +486,27 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	LOG_BASE
+	 * LOG_BASE
 	 *
-	 *	Returns the logarithm of a number to a specified base. The default base is 10.
+	 * Returns the logarithm of a number to a specified base. The default base is 10.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		LOG(number[,base])
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	float	$value		The positive real number for which you want the logarithm
-	 *	@param	float	$base		The base of the logarithm. If base is omitted, it is assumed to be 10.
-	 *	@return	float
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	float	$value		The positive real number for which you want the logarithm
+	 * @param	float	$base		The base of the logarithm. If base is omitted, it is assumed to be 10.
+	 * @return	float
 	 */
-	public static function LOG_BASE($number, $base=10) {
+	public static function LOG_BASE($number = NULL, $base = 10) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 		$base	= (is_null($base))	? 10 :	(float) PHPExcel_Calculation_Functions::flattenSingleValue($base);
 
+		if ((!is_numeric($base)) || (!is_numeric($number)))
+			return PHPExcel_Calculation_Functions::VALUE();
+		if (($base <= 0) || ($number <= 0))
+			return PHPExcel_Calculation_Functions::NaN();
 		return log($number, $base);
 	}	//	function LOG_BASE()
 
@@ -424,6 +514,13 @@ class PHPExcel_Calculation_MathTrig {
 	/**
 	 * MDETERM
 	 *
+	 * Returns the matrix determinant of an array.
+	 *
+	 * Excel Function:
+	 *		MDETERM(array)
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
 	 * @param	array	$matrixValues	A matrix of values
 	 * @return	float
 	 */
@@ -433,6 +530,7 @@ class PHPExcel_Calculation_MathTrig {
 
 		$row = $maxColumn = 0;
 		foreach($matrixValues as $matrixRow) {
+			if (!is_array($matrixRow)) { $matrixRow = array($matrixRow); }
 			$column = 0;
 			foreach($matrixRow as $matrixCell) {
 				if ((is_string($matrixCell)) || ($matrixCell === null)) {
@@ -458,6 +556,13 @@ class PHPExcel_Calculation_MathTrig {
 	/**
 	 * MINVERSE
 	 *
+	 * Returns the inverse matrix for the matrix stored in an array.
+	 *
+	 * Excel Function:
+	 *		MINVERSE(array)
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
 	 * @param	array	$matrixValues	A matrix of values
 	 * @return	array
 	 */
@@ -467,6 +572,7 @@ class PHPExcel_Calculation_MathTrig {
 
 		$row = $maxColumn = 0;
 		foreach($matrixValues as $matrixRow) {
+			if (!is_array($matrixRow)) { $matrixRow = array($matrixRow); }
 			$column = 0;
 			foreach($matrixRow as $matrixCell) {
 				if ((is_string($matrixCell)) || ($matrixCell === null)) {
@@ -503,6 +609,7 @@ class PHPExcel_Calculation_MathTrig {
 
 		$rowA = 0;
 		foreach($matrixData1 as $matrixRow) {
+			if (!is_array($matrixRow)) { $matrixRow = array($matrixRow); }
 			$columnA = 0;
 			foreach($matrixRow as $matrixCell) {
 				if ((is_string($matrixCell)) || ($matrixCell === null)) {
@@ -517,6 +624,7 @@ class PHPExcel_Calculation_MathTrig {
 			$matrixA = new PHPExcel_Shared_JAMA_Matrix($matrixAData);
 			$rowB = 0;
 			foreach($matrixData2 as $matrixRow) {
+				if (!is_array($matrixRow)) { $matrixRow = array($matrixRow); }
 				$columnB = 0;
 				foreach($matrixRow as $matrixCell) {
 					if ((is_string($matrixCell)) || ($matrixCell === null)) {
@@ -564,13 +672,13 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	MROUND
+	 * MROUND
 	 *
-	 *	Rounds a number to the nearest multiple of a specified value
+	 * Rounds a number to the nearest multiple of a specified value
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@param	int		$multiple		Multiple to which you want to round $number
-	 *	@return	float	Rounded Number
+	 * @param	float	$number			Number to round
+	 * @param	int		$multiple		Multiple to which you want to round $number
+	 * @return	float	Rounded Number
 	 */
 	public static function MROUND($number,$multiple) {
 		$number		= PHPExcel_Calculation_Functions::flattenSingleValue($number);
@@ -591,12 +699,12 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	MULTINOMIAL
+	 * MULTINOMIAL
 	 *
-	 *	Returns the ratio of the factorial of a sum of values to the product of factorials.
+	 * Returns the ratio of the factorial of a sum of values to the product of factorials.
 	 *
-	 *	@param	array of mixed		Data Series
-	 *	@return	float
+	 * @param	array of mixed		Data Series
+	 * @return	float
 	 */
 	public static function MULTINOMIAL() {
 		$summer = 0;
@@ -625,19 +733,23 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	ODD
+	 * ODD
 	 *
-	 *	Returns number rounded up to the nearest odd integer.
+	 * Returns number rounded up to the nearest odd integer.
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@return	int		Rounded Number
+	 * @param	float	$number			Number to round
+	 * @return	int		Rounded Number
 	 */
 	public static function ODD($number) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 
 		if (is_null($number)) {
 			return 1;
-		} elseif (is_numeric($number)) {
+		} elseif (is_bool($number)) {
+			$number = (int) $number;
+		}
+
+		if (is_numeric($number)) {
 			$significance = self::SIGN($number);
 			if ($significance == 0) {
 				return 1;
@@ -655,40 +767,43 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	POWER
+	 * POWER
 	 *
-	 *	Computes x raised to the power y.
+	 * Computes x raised to the power y.
 	 *
-	 *	@param	float		$x
-	 *	@param	float		$y
-	 *	@return	float
+	 * @param	float		$x
+	 * @param	float		$y
+	 * @return	float
 	 */
 	public static function POWER($x = 0, $y = 2) {
 		$x	= PHPExcel_Calculation_Functions::flattenSingleValue($x);
 		$y	= PHPExcel_Calculation_Functions::flattenSingleValue($y);
 
 		// Validate parameters
-		if ($x == 0 && $y <= 0) {
+		if ($x == 0.0 && $y == 0.0) {
+			return PHPExcel_Calculation_Functions::NaN();
+		} elseif ($x == 0.0 && $y < 0.0) {
 			return PHPExcel_Calculation_Functions::DIV0();
 		}
 
 		// Return
-		return pow($x, $y);
+		$result = pow($x, $y);
+		return (!is_nan($result) && !is_infinite($result)) ? $result : PHPExcel_Calculation_Functions::NaN();
 	}	//	function POWER()
 
 
 	/**
-	 *	PRODUCT
+	 * PRODUCT
 	 *
-	 *	PRODUCT returns the product of all the values and cells referenced in the argument list.
+	 * PRODUCT returns the product of all the values and cells referenced in the argument list.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		PRODUCT(value1[,value2[, ...]])
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@return	float
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @return	float
 	 */
 	public static function PRODUCT() {
 		// Return value
@@ -715,18 +830,18 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	QUOTIENT
+	 * QUOTIENT
 	 *
-	 *	QUOTIENT function returns the integer portion of a division. Numerator is the divided number
+	 * QUOTIENT function returns the integer portion of a division. Numerator is the divided number
 	 *		and denominator is the divisor.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		QUOTIENT(value1[,value2[, ...]])
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@return	float
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @return	float
 	 */
 	public static function QUOTIENT() {
 		// Return value
@@ -773,11 +888,12 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	public static function ROMAN($aValue, $style=0) {
-		$aValue	= (integer) PHPExcel_Calculation_Functions::flattenSingleValue($aValue);
+		$aValue	= PHPExcel_Calculation_Functions::flattenSingleValue($aValue);
 		$style	= (is_null($style))	? 0 :	(integer) PHPExcel_Calculation_Functions::flattenSingleValue($style);
 		if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) {
 			return PHPExcel_Calculation_Functions::VALUE();
 		}
+		$aValue = (integer) $aValue;
 		if ($aValue == 0) {
 			return '';
 		}
@@ -801,20 +917,20 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	ROUNDUP
+	 * ROUNDUP
 	 *
-	 *	Rounds a number up to a specified number of decimal places
+	 * Rounds a number up to a specified number of decimal places
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@param	int		$digits			Number of digits to which you want to round $number
-	 *	@return	float	Rounded Number
+	 * @param	float	$number			Number to round
+	 * @param	int		$digits			Number of digits to which you want to round $number
+	 * @return	float	Rounded Number
 	 */
 	public static function ROUNDUP($number,$digits) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 		$digits	= PHPExcel_Calculation_Functions::flattenSingleValue($digits);
 
 		if ((is_numeric($number)) && (is_numeric($digits))) {
-			$significance = pow(10,$digits);
+			$significance = pow(10,(int) $digits);
 			if ($number < 0.0) {
 				return floor($number * $significance) / $significance;
 			} else {
@@ -826,20 +942,20 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	ROUNDDOWN
+	 * ROUNDDOWN
 	 *
-	 *	Rounds a number down to a specified number of decimal places
+	 * Rounds a number down to a specified number of decimal places
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@param	int		$digits			Number of digits to which you want to round $number
-	 *	@return	float	Rounded Number
+	 * @param	float	$number			Number to round
+	 * @param	int		$digits			Number of digits to which you want to round $number
+	 * @return	float	Rounded Number
 	 */
 	public static function ROUNDDOWN($number,$digits) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 		$digits	= PHPExcel_Calculation_Functions::flattenSingleValue($digits);
 
 		if ((is_numeric($number)) && (is_numeric($digits))) {
-			$significance = pow(10,$digits);
+			$significance = pow(10,(int) $digits);
 			if ($number < 0.0) {
 				return ceil($number * $significance) / $significance;
 			} else {
@@ -851,15 +967,15 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SERIESSUM
+	 * SERIESSUM
 	 *
-	 *	Returns the sum of a power series
+	 * Returns the sum of a power series
 	 *
-	 *	@param	float			$x	Input value to the power series
-	 *	@param	float			$n	Initial power to which you want to raise $x
-	 *	@param	float			$m	Step by which to increase $n for each term in the series
-	 *	@param	array of mixed		Data Series
-	 *	@return	float
+	 * @param	float			$x	Input value to the power series
+	 * @param	float			$n	Initial power to which you want to raise $x
+	 * @param	float			$m	Step by which to increase $n for each term in the series
+	 * @param	array of mixed		Data Series
+	 * @return	float
 	 */
 	public static function SERIESSUM() {
 		// Return value
@@ -891,17 +1007,19 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SIGN
+	 * SIGN
 	 *
-	 *	Determines the sign of a number. Returns 1 if the number is positive, zero (0)
-	 *	if the number is 0, and -1 if the number is negative.
+	 * Determines the sign of a number. Returns 1 if the number is positive, zero (0)
+	 *		if the number is 0, and -1 if the number is negative.
 	 *
-	 *	@param	float	$number			Number to round
-	 *	@return	int		sign value
+	 * @param	float	$number			Number to round
+	 * @return	int		sign value
 	 */
 	public static function SIGN($number) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
 
+		if (is_bool($number))
+			return (int) $number;
 		if (is_numeric($number)) {
 			if ($number == 0.0) {
 				return 0;
@@ -913,12 +1031,12 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SQRTPI
+	 * SQRTPI
 	 *
-	 *	Returns the square root of (number * pi).
+	 * Returns the square root of (number * pi).
 	 *
-	 *	@param	float	$number		Number
-	 *	@return	float	Square Root of Number * Pi
+	 * @param	float	$number		Number
+	 * @return	float	Square Root of Number * Pi
 	 */
 	public static function SQRTPI($number) {
 		$number	= PHPExcel_Calculation_Functions::flattenSingleValue($number);
@@ -934,14 +1052,14 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SUBTOTAL
+	 * SUBTOTAL
 	 *
-	 *	Returns a subtotal in a list or database.
+	 * Returns a subtotal in a list or database.
 	 *
-	 *	@param	int		the number 1 to 11 that specifies which function to
+	 * @param	int		the number 1 to 11 that specifies which function to
 	 *					use in calculating subtotals within a list.
-	 *	@param	array of mixed		Data Series
-	 *	@return	float
+	 * @param	array of mixed		Data Series
+	 * @return	float
 	 */
 	public static function SUBTOTAL() {
 		$aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
@@ -991,17 +1109,17 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SUM
+	 * SUM
 	 *
-	 *	SUM computes the sum of all the values and cells referenced in the argument list.
+	 * SUM computes the sum of all the values and cells referenced in the argument list.
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		SUM(value1[,value2[, ...]])
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@return	float
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @return	float
 	 */
 	public static function SUM() {
 		// Return value
@@ -1021,18 +1139,18 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SUMIF
+	 * SUMIF
 	 *
-	 *	Counts the number of cells that contain numbers within the list of arguments
+	 * Counts the number of cells that contain numbers within the list of arguments
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		SUMIF(value1[,value2[, ...]],condition)
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@param	string		$condition		The criteria that defines which cells will be summed.
-	 *	@return	float
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @param	string		$condition		The criteria that defines which cells will be summed.
+	 * @return	float
 	 */
 	public static function SUMIF($aArgs,$condition,$sumArgs = array()) {
 		// Return value
@@ -1040,7 +1158,7 @@ class PHPExcel_Calculation_MathTrig {
 
 		$aArgs = PHPExcel_Calculation_Functions::flattenArray($aArgs);
 		$sumArgs = PHPExcel_Calculation_Functions::flattenArray($sumArgs);
-		if (count($sumArgs) == 0) {
+		if (empty($sumArgs)) {
 			$sumArgs = $aArgs;
 		}
 		$condition = PHPExcel_Calculation_Functions::_ifCondition($condition);
@@ -1062,7 +1180,12 @@ class PHPExcel_Calculation_MathTrig {
 	/**
 	 * SUMPRODUCT
 	 *
-	 * @param	mixed	$value	Value to check
+	 * Excel Function:
+	 *		SUMPRODUCT(value1[,value2[, ...]])
+	 *
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed		$arg,...		Data values
 	 * @return	float
 	 */
 	public static function SUMPRODUCT() {
@@ -1071,6 +1194,12 @@ class PHPExcel_Calculation_MathTrig {
 		$wrkArray = PHPExcel_Calculation_Functions::flattenArray(array_shift($arrayList));
 		$wrkCellCount = count($wrkArray);
 
+		for ($i=0; $i< $wrkCellCount; ++$i) {
+			if ((!is_numeric($wrkArray[$i])) || (is_string($wrkArray[$i]))) {
+				$wrkArray[$i] = 0;
+			}
+		}
+
 		foreach($arrayList as $matrixData) {
 			$array2 = PHPExcel_Calculation_Functions::flattenArray($matrixData);
 			$count = count($array2);
@@ -1079,10 +1208,10 @@ class PHPExcel_Calculation_MathTrig {
 			}
 
 			foreach ($array2 as $i => $val) {
-				if (((is_numeric($wrkArray[$i])) && (!is_string($wrkArray[$i]))) &&
-					((is_numeric($val)) && (!is_string($val)))) {
-					$wrkArray[$i] *= $val;
+				if ((!is_numeric($val)) || (is_string($val))) {
+					$val = 0;
 				}
+				$wrkArray[$i] *= $val;
 			}
 		}
 
@@ -1091,17 +1220,17 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	SUMSQ
+	 * SUMSQ
 	 *
-	 *	SUMSQ returns the sum of the squares of the arguments
+	 * SUMSQ returns the sum of the squares of the arguments
 	 *
-	 *	Excel Function:
+	 * Excel Function:
 	 *		SUMSQ(value1[,value2[, ...]])
 	 *
-	 *	@access	public
-	 *	@category Mathematical and Trigonometric Functions
-	 *	@param	mixed		$arg,...		Data values
-	 *	@return	float
+	 * @access	public
+	 * @category Mathematical and Trigonometric Functions
+	 * @param	mixed		$arg,...		Data values
+	 * @return	float
 	 */
 	public static function SUMSQ() {
 		// Return value
@@ -1208,34 +1337,30 @@ class PHPExcel_Calculation_MathTrig {
 
 
 	/**
-	 *	TRUNC
+	 * TRUNC
 	 *
-	 *	Truncates value to the number of fractional digits by number_digits.
+	 * Truncates value to the number of fractional digits by number_digits.
 	 *
-	 *	@param	float		$value
-	 *	@param	int			$number_digits
-	 *	@return	float		Truncated value
+	 * @param	float		$value
+	 * @param	int			$digits
+	 * @return	float		Truncated value
 	 */
-	public static function TRUNC($value = 0, $number_digits = 0) {
-		$value			= PHPExcel_Calculation_Functions::flattenSingleValue($value);
-		$number_digits	= PHPExcel_Calculation_Functions::flattenSingleValue($number_digits);
+	public static function TRUNC($value = 0, $digits = 0) {
+		$value	= PHPExcel_Calculation_Functions::flattenSingleValue($value);
+		$digits	= PHPExcel_Calculation_Functions::flattenSingleValue($digits);
 
 		// Validate parameters
-		if ($number_digits < 0) {
+		if ((!is_numeric($value)) || (!is_numeric($digits)))
 			return PHPExcel_Calculation_Functions::VALUE();
-		}
+		$digits	= floor($digits);
 
 		// Truncate
-		if ($number_digits > 0) {
-			$value = $value * pow(10, $number_digits);
-		}
-		$value = intval($value);
-		if ($number_digits > 0) {
-			$value = $value / pow(10, $number_digits);
-		}
+		$adjust = pow(10, $digits);
 
-		// Return
-		return $value;
+		if (($digits > 0) && (rtrim(intval((abs($value) - abs(intval($value))) * $adjust),'0') < $adjust/10))
+			return $value;
+
+		return (intval($value * $adjust)) / $adjust;
 	}	//	function TRUNC()
 
 }	//	class PHPExcel_Calculation_MathTrig

File diff suppressed because it is too large
+ 280 - 279
htdocs/includes/phpexcel/PHPExcel/Calculation/Statistical.php


+ 96 - 86
htdocs/includes/phpexcel/PHPExcel/Calculation/TextData.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version		1.7.6, 2011-02-27
+ * @version		1.7.8, 2012-10-12
  */
 
 
@@ -41,7 +41,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category	PHPExcel
  * @package		PHPExcel_Calculation
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Calculation_TextData {
 
@@ -87,16 +87,16 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	TRIMNONPRINTABLE
+	 * TRIMNONPRINTABLE
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	string
+	 * @param	mixed	$value	Value to check
+	 * @return	string
 	 */
 	public static function TRIMNONPRINTABLE($stringValue = '') {
 		$stringValue	= PHPExcel_Calculation_Functions::flattenSingleValue($stringValue);
 
 		if (is_bool($stringValue)) {
-			$stringValue = ($stringValue) ? 'TRUE' : 'FALSE';
+			return ($stringValue) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (self::$_invalidChars == Null) {
@@ -106,23 +106,27 @@ class PHPExcel_Calculation_TextData {
 		if (is_string($stringValue) || is_numeric($stringValue)) {
 			return str_replace(self::$_invalidChars,'',trim($stringValue,"\x00..\x1F"));
 		}
-		return Null;
+		return NULL;
 	}	//	function TRIMNONPRINTABLE()
 
 
 	/**
-	 *	TRIMSPACES
+	 * TRIMSPACES
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	string
+	 * @param	mixed	$value	Value to check
+	 * @return	string
 	 */
 	public static function TRIMSPACES($stringValue = '') {
 		$stringValue	= PHPExcel_Calculation_Functions::flattenSingleValue($stringValue);
 
+		if (is_bool($stringValue)) {
+			return ($stringValue) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
+		}
+
 		if (is_string($stringValue) || is_numeric($stringValue)) {
-			return trim(preg_replace('/  +/',' ',$stringValue));
+			return trim(preg_replace('/ +/',' ',trim($stringValue,' ')));
 		}
-		return Null;
+		return NULL;
 	}	//	function TRIMSPACES()
 
 
@@ -133,16 +137,14 @@ class PHPExcel_Calculation_TextData {
 	 * @return	int
 	 */
 	public static function ASCIICODE($characters) {
+		if (($characters === NULL) || ($characters === ''))
+			return PHPExcel_Calculation_Functions::VALUE();
 		$characters	= PHPExcel_Calculation_Functions::flattenSingleValue($characters);
 		if (is_bool($characters)) {
 			if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
 				$characters = (int) $characters;
 			} else {
-				if ($characters) {
-					$characters = 'True';
-				} else {
-					$characters = 'False';
-				}
+				$characters = ($characters) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 			}
 		}
 
@@ -173,11 +175,7 @@ class PHPExcel_Calculation_TextData {
 				if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
 					$arg = (int) $arg;
 				} else {
-					if ($arg) {
-						$arg = 'TRUE';
-					} else {
-						$arg = 'FALSE';
-					}
+					$arg = ($arg) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 				}
 			}
 			$returnValue .= $arg;
@@ -189,16 +187,16 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	DOLLAR
+	 * DOLLAR
 	 *
-	 *	This function converts a number to text using currency format, with the decimals rounded to the specified place.
-	 *	The format used is $#,##0.00_);($#,##0.00)..
+	 * This function converts a number to text using currency format, with the decimals rounded to the specified place.
+	 * The format used is $#,##0.00_);($#,##0.00)..
 	 *
-	 *	@param	float	$value			The value to format
-	 *	@param	int		$decimals		The number of digits to display to the right of the decimal point.
+	 * @param	float	$value			The value to format
+	 * @param	int		$decimals		The number of digits to display to the right of the decimal point.
 	 *									If decimals is negative, number is rounded to the left of the decimal point.
 	 *									If you omit decimals, it is assumed to be 2
-	 *	@return	string
+	 * @return	string
 	 */
 	public static function DOLLAR($value = 0, $decimals = 2) {
 		$value		= PHPExcel_Calculation_Functions::flattenSingleValue($value);
@@ -238,12 +236,15 @@ class PHPExcel_Calculation_TextData {
 
 		if (!is_bool($needle)) {
 			if (is_bool($haystack)) {
-				$haystack = ($haystack) ? 'TRUE' : 'FALSE';
+				$haystack = ($haystack) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 			}
 
-			if (($offset > 0) && (strlen($haystack) > $offset)) {
+			if (($offset > 0) && (PHPExcel_Shared_String::CountCharacters($haystack) > $offset)) {
+				if (PHPExcel_Shared_String::CountCharacters($needle) == 0) {
+					return $offset;
+				}
 				if (function_exists('mb_strpos')) {
-					$pos = mb_strpos($haystack, $needle, --$offset,'UTF-8');
+					$pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8');
 				} else {
 					$pos = strpos($haystack, $needle, --$offset);
 				}
@@ -271,10 +272,13 @@ class PHPExcel_Calculation_TextData {
 
 		if (!is_bool($needle)) {
 			if (is_bool($haystack)) {
-				$haystack = ($haystack) ? 'TRUE' : 'FALSE';
+				$haystack = ($haystack) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 			}
 
-			if (($offset > 0) && (strlen($haystack) > $offset)) {
+			if (($offset > 0) && (PHPExcel_Shared_String::CountCharacters($haystack) > $offset)) {
+				if (PHPExcel_Shared_String::CountCharacters($needle) == 0) {
+					return $offset;
+				}
 				if (function_exists('mb_stripos')) {
 					$pos = mb_stripos($haystack, $needle, --$offset,'UTF-8');
 				} else {
@@ -290,15 +294,21 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	FIXEDFORMAT
+	 * FIXEDFORMAT
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
-	public static function FIXEDFORMAT($value,$decimals=2,$no_commas=false) {
+	public static function FIXEDFORMAT($value, $decimals = 2, $no_commas = FALSE) {
 		$value		= PHPExcel_Calculation_Functions::flattenSingleValue($value);
 		$decimals	= PHPExcel_Calculation_Functions::flattenSingleValue($decimals);
-		$no_commas		= PHPExcel_Calculation_Functions::flattenSingleValue($no_commas);
+		$no_commas	= PHPExcel_Calculation_Functions::flattenSingleValue($no_commas);
+
+		// Validate parameters
+		if (!is_numeric($value) || !is_numeric($decimals)) {
+			return PHPExcel_Calculation_Functions::NaN();
+		}
+		$decimals = floor($decimals);
 
 		$valueResult = round($value,$decimals);
 		if ($decimals < 0) { $decimals = 0; }
@@ -326,7 +336,7 @@ class PHPExcel_Calculation_TextData {
 		}
 
 		if (is_bool($value)) {
-			$value = ($value) ? 'TRUE' : 'FALSE';
+			$value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (function_exists('mb_substr')) {
@@ -338,12 +348,12 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	MID
+	 * MID
 	 *
-	 *	@param	string	$value	Value
-	 *	@param	int		$start	Start character
-	 *	@param	int		$chars	Number of characters
-	 *	@return	string
+	 * @param	string	$value	Value
+	 * @param	int		$start	Start character
+	 * @param	int		$chars	Number of characters
+	 * @return	string
 	 */
 	public static function MID($value = '', $start = 1, $chars = null) {
 		$value		= PHPExcel_Calculation_Functions::flattenSingleValue($value);
@@ -355,7 +365,7 @@ class PHPExcel_Calculation_TextData {
 		}
 
 		if (is_bool($value)) {
-			$value = ($value) ? 'TRUE' : 'FALSE';
+			$value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (function_exists('mb_substr')) {
@@ -367,11 +377,11 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	RIGHT
+	 * RIGHT
 	 *
-	 *	@param	string	$value	Value
-	 *	@param	int		$chars	Number of characters
-	 *	@return	string
+	 * @param	string	$value	Value
+	 * @param	int		$chars	Number of characters
+	 * @return	string
 	 */
 	public static function RIGHT($value = '', $chars = 1) {
 		$value		= PHPExcel_Calculation_Functions::flattenSingleValue($value);
@@ -382,7 +392,7 @@ class PHPExcel_Calculation_TextData {
 		}
 
 		if (is_bool($value)) {
-			$value = ($value) ? 'TRUE' : 'FALSE';
+			$value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if ((function_exists('mb_substr')) && (function_exists('mb_strlen'))) {
@@ -404,7 +414,7 @@ class PHPExcel_Calculation_TextData {
 		$value		= PHPExcel_Calculation_Functions::flattenSingleValue($value);
 
 		if (is_bool($value)) {
-			$value = ($value) ? 'TRUE' : 'FALSE';
+			$value = ($value) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (function_exists('mb_strlen')) {
@@ -416,18 +426,18 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	LOWERCASE
+	 * LOWERCASE
 	 *
-	 *	Converts a string value to upper case.
+	 * Converts a string value to upper case.
 	 *
-	 *	@param	string		$mixedCaseString
-	 *	@return	string
+	 * @param	string		$mixedCaseString
+	 * @return	string
 	 */
 	public static function LOWERCASE($mixedCaseString) {
 		$mixedCaseString	= PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString);
 
 		if (is_bool($mixedCaseString)) {
-			$mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE';
+			$mixedCaseString = ($mixedCaseString) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (function_exists('mb_convert_case')) {
@@ -439,18 +449,18 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	UPPERCASE
+	 * UPPERCASE
 	 *
-	 *	Converts a string value to upper case.
+	 * Converts a string value to upper case.
 	 *
-	 *	@param	string		$mixedCaseString
-	 *	@return	string
+	 * @param	string		$mixedCaseString
+	 * @return	string
 	 */
 	public static function UPPERCASE($mixedCaseString) {
 		$mixedCaseString	= PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString);
 
 		if (is_bool($mixedCaseString)) {
-			$mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE';
+			$mixedCaseString = ($mixedCaseString) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (function_exists('mb_convert_case')) {
@@ -462,18 +472,18 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	PROPERCASE
+	 * PROPERCASE
 	 *
-	 *	Converts a string value to upper case.
+	 * Converts a string value to upper case.
 	 *
-	 *	@param	string		$mixedCaseString
-	 *	@return	string
+	 * @param	string		$mixedCaseString
+	 * @return	string
 	 */
 	public static function PROPERCASE($mixedCaseString) {
 		$mixedCaseString	= PHPExcel_Calculation_Functions::flattenSingleValue($mixedCaseString);
 
 		if (is_bool($mixedCaseString)) {
-			$mixedCaseString = ($mixedCaseString) ? 'TRUE' : 'FALSE';
+			$mixedCaseString = ($mixedCaseString) ? PHPExcel_Calculation::getTRUE() : PHPExcel_Calculation::getFALSE();
 		}
 
 		if (function_exists('mb_convert_case')) {
@@ -485,12 +495,12 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	REPLACE
+	 * REPLACE
 	 *
-	 *	@param	string	$value	Value
-	 *	@param	int		$start	Start character
-	 *	@param	int		$chars	Number of characters
-	 *	@return	string
+	 * @param	string	$value	Value
+	 * @param	int		$start	Start character
+	 * @param	int		$chars	Number of characters
+	 * @return	string
 	 */
 	public static function REPLACE($oldText = '', $start = 1, $chars = null, $newText) {
 		$oldText	= PHPExcel_Calculation_Functions::flattenSingleValue($oldText);
@@ -506,13 +516,13 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	SUBSTITUTE
+	 * SUBSTITUTE
 	 *
-	 *	@param	string	$text		Value
-	 *	@param	string	$fromText	From Value
-	 *	@param	string	$toText		To Value
-	 *	@param	integer	$instance	Instance Number
-	 *	@return	string
+	 * @param	string	$text		Value
+	 * @param	string	$fromText	From Value
+	 * @param	string	$toText		To Value
+	 * @param	integer	$instance	Instance Number
+	 * @return	string
 	 */
 	public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0) {
 		$text		= PHPExcel_Calculation_Functions::flattenSingleValue($text);
@@ -548,15 +558,15 @@ class PHPExcel_Calculation_TextData {
 			}
 		}
 
-		return $left.$newText.$right;
+		return $text;
 	}	//	function SUBSTITUTE()
 
 
 	/**
-	 *	RETURNSTRING
+	 * RETURNSTRING
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
 	public static function RETURNSTRING($testValue = '') {
 		$testValue	= PHPExcel_Calculation_Functions::flattenSingleValue($testValue);
@@ -569,10 +579,10 @@ class PHPExcel_Calculation_TextData {
 
 
 	/**
-	 *	TEXTFORMAT
+	 * TEXTFORMAT
 	 *
-	 *	@param	mixed	$value	Value to check
-	 *	@return	boolean
+	 * @param	mixed	$value	Value to check
+	 * @return	boolean
 	 */
 	public static function TEXTFORMAT($value,$format) {
 		$value	= PHPExcel_Calculation_Functions::flattenSingleValue($value);

+ 73 - 0
htdocs/includes/phpexcel/PHPExcel/Calculation/Token/Stack.php

@@ -0,0 +1,73 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Calculation
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
+ */
+
+
+class PHPExcel_Calculation_Token_Stack {
+
+	private $_stack = array();
+	private $_count = 0;
+
+
+	public function count() {
+		return $this->_count;
+	}	//	function count()
+
+
+	public function push($type,$value,$reference=null) {
+		$this->_stack[$this->_count++] = array('type'		=> $type,
+											   'value'		=> $value,
+											   'reference'	=> $reference
+											  );
+		if ($type == 'Function') {
+			$localeFunction = PHPExcel_Calculation::_localeFunc($value);
+			if ($localeFunction != $value) {
+				$this->_stack[($this->_count - 1)]['localeValue'] = $localeFunction;
+			}
+		}
+	}	//	function push()
+
+
+	public function pop() {
+		if ($this->_count > 0) {
+			return $this->_stack[--$this->_count];
+		}
+		return null;
+	}	//	function pop()
+
+
+	public function last($n=1) {
+		if ($this->_count-$n < 0) {
+			return null;
+		}
+		return $this->_stack[$this->_count-$n];
+	}	//	function last()
+
+
+	function __construct() {
+	}
+
+}	//	class PHPExcel_Calculation_Token_Stack

File diff suppressed because it is too large
+ 315 - 218
htdocs/includes/phpexcel/PHPExcel/Cell.php


+ 64 - 14
htdocs/includes/phpexcel/PHPExcel/Cell/AdvancedValueBinder.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -41,7 +41,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
 {
@@ -66,10 +66,10 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder
 		if ($dataType === PHPExcel_Cell_DataType::TYPE_STRING && !$value instanceof PHPExcel_RichText) {
 			//	Test for booleans using locale-setting
 			if ($value == PHPExcel_Calculation::getTRUE()) {
-				$cell->setValueExplicit( True, PHPExcel_Cell_DataType::TYPE_BOOL);
+				$cell->setValueExplicit( TRUE, PHPExcel_Cell_DataType::TYPE_BOOL);
 				return true;
 			} elseif($value == PHPExcel_Calculation::getFALSE()) {
-				$cell->setValueExplicit( False, PHPExcel_Cell_DataType::TYPE_BOOL);
+				$cell->setValueExplicit( FALSE, PHPExcel_Cell_DataType::TYPE_BOOL);
 				return true;
 			}
 
@@ -79,34 +79,82 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder
 				return true;
 			}
 
+			// Check for fraction
+			if (preg_match('/^([+-]?) *([0-9]*)\s?\/\s*([0-9]*)$/', $value, $matches)) {
+				// Convert value to number
+				$value = $matches[2] / $matches[3];
+				if ($matches[1] == '-') $value = 0 - $value;
+				$cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+				// Set style
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode( '??/??' );
+				return true;
+			} elseif (preg_match('/^([+-]?)([0-9]*) +([0-9]*)\s?\/\s*([0-9]*)$/', $value, $matches)) {
+				// Convert value to number
+				$value = $matches[2] + ($matches[3] / $matches[4]);
+				if ($matches[1] == '-') $value = 0 - $value;
+				$cell->setValueExplicit( (float) $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+				// Set style
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode( '# ??/??' );
+				return true;
+			}
+
 			// Check for percentage
 			if (preg_match('/^\-?[0-9]*\.?[0-9]*\s?\%$/', $value)) {
 				// Convert value to number
-				$cell->setValueExplicit( (float)str_replace('%', '', $value) / 100, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+				$value = (float) str_replace('%', '', $value) / 100;
+				$cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
 				// Set style
-				$cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE );
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00 );
+				return true;
+			}
+
+			// Check for currency
+			$currencyCode = PHPExcel_Shared_String::getCurrencyCode();
+			if (preg_match('/^'.preg_quote($currencyCode).' *(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/', $value)) {
+				// Convert value to number
+				$value = (float) trim(str_replace(array($currencyCode,','), '', $value));
+				$cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+				// Set style
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode(
+						str_replace('$', $currencyCode, PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE )
+					);
+				return true;
+			} elseif (preg_match('/^\$ *(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?$/', $value)) {
+				// Convert value to number
+				$value = (float) trim(str_replace(array('$',','), '', $value));
+				$cell->setValueExplicit( $value, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+				// Set style
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE );
 				return true;
 			}
 
 			// Check for time without seconds e.g. '9:45', '09:45'
 			if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) {
+				// Convert value to number
 				list($h, $m) = explode(':', $value);
 				$days = $h / 24 + $m / 1440;
-				// Convert value to number
 				$cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
 				// Set style
-				$cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3 );
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3 );
 				return true;
 			}
 
 			// Check for time with seconds '9:45:59', '09:45:59'
 			if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) {
+				// Convert value to number
 				list($h, $m, $s) = explode(':', $value);
 				$days = $h / 24 + $m / 1440 + $s / 86400;
 				// Convert value to number
 				$cell->setValueExplicit($days, PHPExcel_Cell_DataType::TYPE_NUMERIC);
 				// Set style
-				$cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4 );
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode( PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4 );
 				return true;
 			}
 
@@ -120,16 +168,18 @@ class PHPExcel_Cell_AdvancedValueBinder extends PHPExcel_Cell_DefaultValueBinder
 				} else {
 					$formatCode = 'yyyy-mm-dd';
 				}
-				$cell->getParent()->getStyle( $cell->getCoordinate() )->getNumberFormat()->setFormatCode($formatCode);
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getNumberFormat()->setFormatCode($formatCode);
 				return true;
 			}
 
 			// Check for newline character "\n"
-			if (strpos($value, "\n") !== false) {
+			if (strpos($value, "\n") !== FALSE) {
 				$value = PHPExcel_Shared_String::SanitizeUTF8($value);
 				$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
 				// Set style
-				$cell->getParent()->getStyle( $cell->getCoordinate() )->getAlignment()->setWrapText(true);
+				$cell->getParent()->getStyle( $cell->getCoordinate() )
+					->getAlignment()->setWrapText(TRUE);
 				return true;
 			}
 		}

+ 5 - 5
htdocs/includes/phpexcel/PHPExcel/Cell/DataType.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Cell_DataType
 {
@@ -41,7 +41,7 @@ class PHPExcel_Cell_DataType
 	const TYPE_FORMULA		= 'f';
 	const TYPE_NUMERIC		= 'n';
 	const TYPE_BOOL			= 'b';
-    const TYPE_NULL			= 's';
+    const TYPE_NULL			= 'null';
     const TYPE_INLINE		= 'inlineStr';
 	const TYPE_ERROR		= 'e';
 

+ 27 - 27
htdocs/includes/phpexcel/PHPExcel/Cell/DataValidation.php

@@ -2,27 +2,27 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Cell_DataValidation
 {
@@ -44,12 +44,12 @@ class PHPExcel_Cell_DataValidation
 	const TYPE_TEXTLENGTH	= 'textLength';
 	const TYPE_TIME			= 'time';
 	const TYPE_WHOLE		= 'whole';
-	
+
 	/* Data validation error styles */
 	const STYLE_STOP		= 'stop';
 	const STYLE_WARNING		= 'warning';
 	const STYLE_INFORMATION	= 'information';
-	
+
 	/* Data validation operators */
 	const OPERATOR_BETWEEN				= 'between';
 	const OPERATOR_EQUAL				= 'equal';
@@ -59,98 +59,98 @@ class PHPExcel_Cell_DataValidation
 	const OPERATOR_LESSTHANOREQUAL		= 'lessThanOrEqual';
 	const OPERATOR_NOTBETWEEN			= 'notBetween';
 	const OPERATOR_NOTEQUAL				= 'notEqual';
-    
+
     /**
      * Formula 1
      *
      * @var string
      */
     private $_formula1;
-    
+
     /**
      * Formula 2
      *
      * @var string
      */
     private $_formula2;
-    
+
     /**
      * Type
      *
      * @var string
      */
     private $_type = PHPExcel_Cell_DataValidation::TYPE_NONE;
-    
+
     /**
      * Error style
      *
      * @var string
      */
     private $_errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;
-    
+
     /**
      * Operator
      *
      * @var string
      */
     private $_operator;
-    
+
     /**
      * Allow Blank
      *
      * @var boolean
      */
     private $_allowBlank;
-    
+
     /**
      * Show DropDown
      *
      * @var boolean
      */
     private $_showDropDown;
-    
+
     /**
      * Show InputMessage
      *
      * @var boolean
      */
     private $_showInputMessage;
-    
+
     /**
      * Show ErrorMessage
      *
      * @var boolean
      */
     private $_showErrorMessage;
-    
+
     /**
      * Error title
      *
      * @var string
      */
     private $_errorTitle;
-    
+
     /**
      * Error
      *
      * @var string
      */
     private $_error;
-    
+
     /**
      * Prompt title
      *
      * @var string
      */
     private $_promptTitle;
-    
+
     /**
      * Prompt
      *
      * @var string
      */
     private $_prompt;
-    
+
     /**
      * Create a new PHPExcel_Cell_DataValidation
      *
@@ -173,7 +173,7 @@ class PHPExcel_Cell_DataValidation
 		$this->_promptTitle 		= '';
 		$this->_prompt 				= '';
     }
-	
+
 	/**
 	 * Get Formula 1
 	 *
@@ -213,7 +213,7 @@ class PHPExcel_Cell_DataValidation
 		$this->_formula2 = $value;
 		return $this;
 	}
-	
+
 	/**
 	 * Get Type
 	 *
@@ -433,12 +433,12 @@ class PHPExcel_Cell_DataValidation
 		$this->_prompt = $value;
 		return $this;
 	}
-	
+
 	/**
 	 * Get hash code
 	 *
 	 * @return string	Hash code
-	 */	
+	 */
 	public function getHashCode() {
     	return md5(
     		  $this->_formula1
@@ -457,7 +457,7 @@ class PHPExcel_Cell_DataValidation
     		. __CLASS__
     	);
     }
-    
+
 	/**
 	 * Implement PHP __clone to create a deep clone, not just a shallow copy.
 	 */

+ 6 - 6
htdocs/includes/phpexcel/PHPExcel/Cell/DefaultValueBinder.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -41,7 +41,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
 {
@@ -60,7 +60,7 @@ class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
 		}
 
 		// Set value explicit
-		$cell->setValueExplicit( $value, PHPExcel_Cell_DataType::dataTypeForValue($value) );
+		$cell->setValueExplicit( $value, self::dataTypeForValue($value) );
 
 		// Done!
 		return true;
@@ -81,7 +81,7 @@ class PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
 			return PHPExcel_Cell_DataType::TYPE_STRING;
 
 		} elseif ($pValue instanceof PHPExcel_RichText) {
-			return PHPExcel_Cell_DataType::TYPE_STRING;
+			return PHPExcel_Cell_DataType::TYPE_INLINE;
 
 		} elseif ($pValue{0} === '=' && strlen($pValue) > 1) {
 			return PHPExcel_Cell_DataType::TYPE_FORMULA;

+ 14 - 14
htdocs/includes/phpexcel/PHPExcel/Cell/Hyperlink.php

@@ -2,27 +2,27 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Cell_Hyperlink
 {
@@ -41,14 +41,14 @@ class PHPExcel_Cell_Hyperlink
 	 * @var string
 	 */
 	private $_url;
-	
+
 	/**
 	 * Tooltip to display on the hyperlink
 	 *
 	 * @var string
 	 */
-	private $_tooltip;	
-	
+	private $_tooltip;
+
     /**
      * Create a new PHPExcel_Cell_Hyperlink
      *
@@ -62,7 +62,7 @@ class PHPExcel_Cell_Hyperlink
 		$this->_url 		= $pUrl;
 		$this->_tooltip 	= $pTooltip;
     }
-	
+
 	/**
 	 * Get URL
 	 *
@@ -82,7 +82,7 @@ class PHPExcel_Cell_Hyperlink
 		$this->_url = $value;
 		return $this;
 	}
-	
+
 	/**
 	 * Get tooltip
 	 *
@@ -102,7 +102,7 @@ class PHPExcel_Cell_Hyperlink
 		$this->_tooltip = $value;
 		return $this;
 	}
-	
+
 	/**
 	 * Is this hyperlink internal? (to another sheet)
 	 *
@@ -111,12 +111,12 @@ class PHPExcel_Cell_Hyperlink
 	public function isInternal() {
 		return strpos($this->_url, 'sheet://') !== false;
 	}
-	
+
 	/**
 	 * Get hash code
 	 *
 	 * @return string	Hash code
-	 */	
+	 */
 	public function getHashCode() {
     	return md5(
     		  $this->_url

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Cell/IValueBinder.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Cell
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 interface PHPExcel_Cell_IValueBinder
 {

+ 527 - 0
htdocs/includes/phpexcel/PHPExcel/Chart.php

@@ -0,0 +1,527 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart
+{
+	/**
+	 * Chart Name
+	 *
+	 * @var string
+	 */
+	private $_name = '';
+
+	/**
+	 * Worksheet
+	 *
+	 * @var PHPExcel_Worksheet
+	 */
+	private $_worksheet = null;
+
+	/**
+	 * Chart Title
+	 *
+	 * @var PHPExcel_Chart_Title
+	 */
+	private $_title = null;
+
+	/**
+	 * Chart Legend
+	 *
+	 * @var PHPExcel_Chart_Legend
+	 */
+	private $_legend = null;
+
+	/**
+	 * X-Axis Label
+	 *
+	 * @var PHPExcel_Chart_Title
+	 */
+	private $_xAxisLabel = null;
+
+	/**
+	 * Y-Axis Label
+	 *
+	 * @var PHPExcel_Chart_Title
+	 */
+	private $_yAxisLabel = null;
+
+	/**
+	 * Chart Plot Area
+	 *
+	 * @var PHPExcel_Chart_PlotArea
+	 */
+	private $_plotArea = null;
+
+	/**
+	 * Plot Visible Only
+	 *
+	 * @var boolean
+	 */
+	private $_plotVisibleOnly = true;
+
+	/**
+	 * Display Blanks as
+	 *
+	 * @var string
+	 */
+	private $_displayBlanksAs = '0';
+
+
+	/**
+	 * Top-Left Cell Position
+	 *
+	 * @var string
+	 */
+	private $_topLeftCellRef = 'A1';
+
+
+	/**
+	 * Top-Left X-Offset
+	 *
+	 * @var integer
+	 */
+	private $_topLeftXOffset = 0;
+
+
+	/**
+	 * Top-Left Y-Offset
+	 *
+	 * @var integer
+	 */
+	private $_topLeftYOffset = 0;
+
+
+	/**
+	 * Bottom-Right Cell Position
+	 *
+	 * @var string
+	 */
+	private $_bottomRightCellRef = 'A1';
+
+
+	/**
+	 * Bottom-Right X-Offset
+	 *
+	 * @var integer
+	 */
+	private $_bottomRightXOffset = 10;
+
+
+	/**
+	 * Bottom-Right Y-Offset
+	 *
+	 * @var integer
+	 */
+	private $_bottomRightYOffset = 10;
+
+
+	/**
+	 * Create a new PHPExcel_Chart
+	 */
+	public function __construct($name, PHPExcel_Chart_Title $title = null, PHPExcel_Chart_Legend $legend = null, PHPExcel_Chart_PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = '0', PHPExcel_Chart_Title $xAxisLabel = null, PHPExcel_Chart_Title $yAxisLabel = null)
+	{
+		$this->_name = $name;
+		$this->_title = $title;
+		$this->_legend = $legend;
+		$this->_xAxisLabel = $xAxisLabel;
+		$this->_yAxisLabel = $yAxisLabel;
+		$this->_plotArea = $plotArea;
+		$this->_plotVisibleOnly = $plotVisibleOnly;
+		$this->_displayBlanksAs = $displayBlanksAs;
+	}
+
+	/**
+	 * Get Name
+	 *
+	 * @return string
+	 */
+	public function getName() {
+		return $this->_name;
+	}
+
+	/**
+	 * Get Worksheet
+	 *
+	 * @return PHPExcel_Worksheet
+	 */
+	public function getWorksheet() {
+		return $this->_worksheet;
+	}
+
+	/**
+	 * Set Worksheet
+	 *
+	 * @param	PHPExcel_Worksheet	$pValue
+	 * @throws	Exception
+	 * @return PHPExcel_Chart
+	 */
+	public function setWorksheet(PHPExcel_Worksheet $pValue = null) {
+		$this->_worksheet = $pValue;
+
+		return $this;
+	}
+
+	/**
+	 * Get Title
+	 *
+	 * @return PHPExcel_Chart_Title
+	 */
+	public function getTitle() {
+		return $this->_title;
+	}
+
+	/**
+	 * Set Title
+	 *
+	 * @param	PHPExcel_Chart_Title $title
+	 * @return	PHPExcel_Chart
+	 */
+	public function setTitle(PHPExcel_Chart_Title $title) {
+		$this->_title = $title;
+
+		return $this;
+	}
+
+	/**
+	 * Get Legend
+	 *
+	 * @return PHPExcel_Chart_Legend
+	 */
+	public function getLegend() {
+		return $this->_legend;
+	}
+
+	/**
+	 * Set Legend
+	 *
+	 * @param	PHPExcel_Chart_Legend $legend
+	 * @return	PHPExcel_Chart
+	 */
+	public function setLegend(PHPExcel_Chart_Legend $legend) {
+		$this->_legend = $legend;
+
+		return $this;
+	}
+
+	/**
+	 * Get X-Axis Label
+	 *
+	 * @return PHPExcel_Chart_Title
+	 */
+	public function getXAxisLabel() {
+		return $this->_xAxisLabel;
+	}
+
+	/**
+	 * Set X-Axis Label
+	 *
+	 * @param	PHPExcel_Chart_Title $label
+	 * @return	PHPExcel_Chart
+	 */
+	public function setXAxisLabel(PHPExcel_Chart_Title $label) {
+		$this->_xAxisLabel = $label;
+
+		return $this;
+	}
+
+	/**
+	 * Get Y-Axis Label
+	 *
+	 * @return PHPExcel_Chart_Title
+	 */
+	public function getYAxisLabel() {
+		return $this->_yAxisLabel;
+	}
+
+	/**
+	 * Set Y-Axis Label
+	 *
+	 * @param	PHPExcel_Chart_Title $label
+	 * @return	PHPExcel_Chart
+	 */
+	public function setYAxisLabel(PHPExcel_Chart_Title $label) {
+		$this->_yAxisLabel = $label;
+
+		return $this;
+	}
+
+	/**
+	 * Get Plot Area
+	 *
+	 * @return PHPExcel_Chart_PlotArea
+	 */
+	public function getPlotArea() {
+		return $this->_plotArea;
+	}
+
+	/**
+	 * Get Plot Visible Only
+	 *
+	 * @return boolean
+	 */
+	public function getPlotVisibleOnly() {
+		return $this->_plotVisibleOnly;
+	}
+
+	/**
+	 * Set Plot Visible Only
+	 *
+	 * @param boolean $plotVisibleOnly
+	 * @return PHPExcel_Chart
+	 */
+	public function setPlotVisibleOnly($plotVisibleOnly = true) {
+		$this->_plotVisibleOnly = $plotVisibleOnly;
+
+		return $this;
+	}
+
+	/**
+	 * Get Display Blanks as
+	 *
+	 * @return string
+	 */
+	public function getDisplayBlanksAs() {
+		return $this->_displayBlanksAs;
+	}
+
+	/**
+	 * Set Display Blanks as
+	 *
+	 * @param string $displayBlanksAs
+	 * @return PHPExcel_Chart
+	 */
+	public function setDisplayBlanksAs($displayBlanksAs = '0') {
+		$this->_displayBlanksAs = $displayBlanksAs;
+	}
+
+
+	/**
+	 * Set the Top Left position for the chart
+	 *
+	 * @param	string	$cell
+	 * @param	integer	$xOffset
+	 * @param	integer	$yOffset
+	 * @return PHPExcel_Chart
+	 */
+	public function setTopLeftPosition($cell, $xOffset=null, $yOffset=null) {
+		$this->_topLeftCellRef = $cell;
+		if (!is_null($xOffset))
+			$this->setTopLeftXOffset($xOffset);
+		if (!is_null($yOffset))
+			$this->setTopLeftYOffset($yOffset);
+
+		return $this;
+	}
+
+	/**
+	 * Get the top left position of the chart
+	 *
+	 * @return array	an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+	 */
+	public function getTopLeftPosition() {
+		return array( 'cell'	=> $this->_topLeftCellRef,
+					  'xOffset'	=> $this->_topLeftXOffset,
+					  'yOffset'	=> $this->_topLeftYOffset
+					);
+	}
+
+	/**
+	 * Get the cell address where the top left of the chart is fixed
+	 *
+	 * @return string
+	 */
+	public function getTopLeftCell() {
+		return $this->_topLeftCellRef;
+	}
+
+	/**
+	 * Set the Top Left cell position for the chart
+	 *
+	 * @param	string	$cell
+	 * @return PHPExcel_Chart
+	 */
+	public function setTopLeftCell($cell) {
+		$this->_topLeftCellRef = $cell;
+
+		return $this;
+	}
+
+	public function setTopLeftOffset($xOffset=null,$yOffset=null) {
+		if (!is_null($xOffset))
+			$this->setTopLeftXOffset($xOffset);
+		if (!is_null($yOffset))
+			$this->setTopLeftYOffset($yOffset);
+
+		return $this;
+	}
+
+	public function getTopLeftOffset() {
+		return array( 'X' => $this->_topLeftXOffset,
+					  'Y' => $this->_topLeftYOffset
+					);
+	}
+
+	public function setTopLeftXOffset($xOffset) {
+		$this->_topLeftXOffset = $xOffset;
+
+		return $this;
+	}
+
+	public function getTopLeftXOffset() {
+		return $this->_topLeftXOffset;
+	}
+
+	public function setTopLeftYOffset($yOffset) {
+		$this->_topLeftYOffset = $yOffset;
+
+		return $this;
+	}
+
+	public function getTopLeftYOffset() {
+		return $this->_topLeftYOffset;
+	}
+
+	/**
+	 * Set the Bottom Right position of the chart
+	 *
+	 * @param	string	$cell
+	 * @param	integer	$xOffset
+	 * @param	integer	$yOffset
+	 * @return PHPExcel_Chart
+	 */
+	public function setBottomRightPosition($cell, $xOffset=null, $yOffset=null) {
+		$this->_bottomRightCellRef = $cell;
+		if (!is_null($xOffset))
+			$this->setBottomRightXOffset($xOffset);
+		if (!is_null($yOffset))
+			$this->setBottomRightYOffset($yOffset);
+
+		return $this;
+	}
+
+	/**
+	 * Get the bottom right position of the chart
+	 *
+	 * @return array	an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+	 */
+	public function getBottomRightPosition() {
+		return array( 'cell'	=> $this->_bottomRightCellRef,
+					  'xOffset'	=> $this->_bottomRightXOffset,
+					  'yOffset'	=> $this->_bottomRightYOffset
+					);
+	}
+
+	public function setBottomRightCell($cell) {
+		$this->_bottomRightCellRef = $cell;
+
+		return $this;
+	}
+
+	/**
+	 * Get the cell address where the bottom right of the chart is fixed
+	 *
+	 * @return string
+	 */
+	public function getBottomRightCell() {
+		return $this->_bottomRightCellRef;
+	}
+
+	public function setBottomRightOffset($xOffset=null,$yOffset=null) {
+		if (!is_null($xOffset))
+			$this->setBottomRightXOffset($xOffset);
+		if (!is_null($yOffset))
+			$this->setBottomRightYOffset($yOffset);
+
+		return $this;
+	}
+
+	public function getBottomRightOffset() {
+		return array( 'X' => $this->_bottomRightXOffset,
+					  'Y' => $this->_bottomRightYOffset
+					);
+	}
+
+	public function setBottomRightXOffset($xOffset) {
+		$this->_bottomRightXOffset = $xOffset;
+
+		return $this;
+	}
+
+	public function getBottomRightXOffset() {
+		return $this->_bottomRightXOffset;
+	}
+
+	public function setBottomRightYOffset($yOffset) {
+		$this->_bottomRightYOffset = $yOffset;
+
+		return $this;
+	}
+
+	public function getBottomRightYOffset() {
+		return $this->_bottomRightYOffset;
+	}
+
+
+	public function refresh() {
+		if ($this->_worksheet !== NULL) {
+			$this->_plotArea->refresh($this->_worksheet);
+		}
+	}
+
+	public function render($outputDestination = null) {
+		$libraryName = PHPExcel_Settings::getChartRendererName();
+		if (is_null($libraryName)) {
+			return false;
+		}
+		//	Ensure that data series values are up-to-date before we render
+		$this->refresh();
+
+		$libraryPath = PHPExcel_Settings::getChartRendererPath();
+		$includePath = str_replace('\\','/',get_include_path());
+		$rendererPath = str_replace('\\','/',$libraryPath);
+		if (strpos($rendererPath,$includePath) === false) {
+			set_include_path(get_include_path() . PATH_SEPARATOR . $libraryPath);
+		}
+
+		$rendererName = 'PHPExcel_Chart_Renderer_'.$libraryName;
+		$renderer = new $rendererName($this);
+
+		if ($outputDestination == 'php://output') {
+			$outputDestination = null;
+		}
+		return $renderer->render($outputDestination);
+	}
+
+}

+ 354 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/DataSeries.php

@@ -0,0 +1,354 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_DataSeries
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_DataSeries
+{
+
+	const TYPE_BARCHART			= 'barChart';
+	const TYPE_BARCHART_3D		= 'bar3DChart';
+	const TYPE_LINECHART		= 'lineChart';
+	const TYPE_LINECHART_3D		= 'line3DChart';
+	const TYPE_AREACHART		= 'areaChart';
+	const TYPE_AREACHART_3D		= 'area3DChart';
+	const TYPE_PIECHART			= 'pieChart';
+	const TYPE_PIECHART_3D		= 'pie3DChart';
+	const TYPE_DOUGHTNUTCHART	= 'doughnutChart';
+	const TYPE_DONUTCHART		= self::TYPE_DOUGHTNUTCHART;	//	Synonym
+	const TYPE_SCATTERCHART		= 'scatterChart';
+	const TYPE_SURFACECHART		= 'surfaceChart';
+	const TYPE_SURFACECHART_3D	= 'surface3DChart';
+	const TYPE_RADARCHART		= 'radarChart';
+	const TYPE_BUBBLECHART		= 'bubbleChart';
+	const TYPE_STOCKCHART		= 'stockChart';
+
+	const GROUPING_CLUSTERED			= 'clustered';
+	const GROUPING_STACKED				= 'stacked';
+	const GROUPING_PERCENT_STACKED		= 'percentStacked';
+	const GROUPING_STANDARD				= 'standard';
+
+	const DIRECTION_BAR			= 'bar';
+	const DIRECTION_HORIZONTAL	= self::DIRECTION_BAR;
+	const DIRECTION_COL			= 'col';
+	const DIRECTION_COLUMN		= self::DIRECTION_COL;
+	const DIRECTION_VERTICAL	= self::DIRECTION_COL;
+
+	const STYLE_LINEMARKER		= 'lineMarker';
+	const STYLE_SMOOTHMARKER	= 'smoothMarker';
+	const STYLE_MARKER			= 'marker';
+	const STYLE_FILLED			= 'filled';
+
+
+	/**
+	 * Series Plot Type
+	 *
+	 * @var string
+	 */
+	private $_plotType = null;
+
+	/**
+	 * Plot Grouping Type
+	 *
+	 * @var boolean
+	 */
+	private $_plotGrouping = null;
+
+	/**
+	 * Plot Direction
+	 *
+	 * @var boolean
+	 */
+	private $_plotDirection = null;
+
+	/**
+	 * Plot Style
+	 *
+	 * @var string
+	 */
+	private $_plotStyle = null;
+
+	/**
+	 * Order of plots in Series
+	 *
+	 * @var array of integer
+	 */
+	private $_plotOrder = array();
+
+	/**
+	 * Plot Label
+	 *
+	 * @var array of PHPExcel_Chart_DataSeriesValues
+	 */
+	private $_plotLabel = array();
+
+	/**
+	 * Plot Category
+	 *
+	 * @var array of PHPExcel_Chart_DataSeriesValues
+	 */
+	private $_plotCategory = array();
+
+	/**
+	 * Smooth Line
+	 *
+	 * @var string
+	 */
+	private $_smoothLine = null;
+
+	/**
+	 * Plot Values
+	 *
+	 * @var array of PHPExcel_Chart_DataSeriesValues
+	 */
+	private $_plotValues = array();
+
+	/**
+	 * Create a new PHPExcel_Chart_DataSeries
+	 */
+	public function __construct($plotType = null, $plotGrouping = null, $plotOrder = array(), $plotLabel = array(), $plotCategory = array(), $plotValues = array(), $smoothLine = null, $plotStyle = null)
+	{
+		$this->_plotType = $plotType;
+		$this->_plotGrouping = $plotGrouping;
+		$this->_plotOrder = $plotOrder;
+		$keys = array_keys($plotValues);
+		$this->_plotValues = $plotValues;
+		if ((count($plotLabel) == 0) || (is_null($plotLabel[$keys[0]]))) {
+			$plotLabel[$keys[0]] = new PHPExcel_Chart_DataSeriesValues();
+		}
+
+		$this->_plotLabel = $plotLabel;
+		if ((count($plotCategory) == 0) || (is_null($plotCategory[$keys[0]]))) {
+			$plotCategory[$keys[0]] = new PHPExcel_Chart_DataSeriesValues();
+		}
+		$this->_plotCategory = $plotCategory;
+		$this->_smoothLine = $smoothLine;
+		$this->_plotStyle = $plotStyle;
+	}
+
+	/**
+	 * Get Plot Type
+	 *
+	 * @return string
+	 */
+	public function getPlotType() {
+		return $this->_plotType;
+	}
+
+	/**
+	 * Set Plot Type
+	 *
+	 * @param string $plotType
+	 */
+	public function setPlotType($plotType = '') {
+		$this->_plotType = $plotType;
+	}
+
+	/**
+	 * Get Plot Grouping Type
+	 *
+	 * @return string
+	 */
+	public function getPlotGrouping() {
+		return $this->_plotGrouping;
+	}
+
+	/**
+	 * Set Plot Grouping Type
+	 *
+	 * @param string $groupingType
+	 */
+	public function setPlotGrouping($groupingType = null) {
+		$this->_plotGrouping = $groupingType;
+	}
+
+	/**
+	 * Get Plot Direction
+	 *
+	 * @return string
+	 */
+	public function getPlotDirection() {
+		return $this->_plotDirection;
+	}
+
+	/**
+	 * Set Plot Direction
+	 *
+	 * @param string $plotDirection
+	 */
+	public function setPlotDirection($plotDirection = null) {
+		$this->_plotDirection = $plotDirection;
+	}
+
+	/**
+	 * Get Plot Order
+	 *
+	 * @return string
+	 */
+	public function getPlotOrder() {
+		return $this->_plotOrder;
+	}
+
+	/**
+	 * Get Plot Labels
+	 *
+	 * @return array of PHPExcel_Chart_DataSeriesValues
+	 */
+	public function getPlotLabels() {
+		return $this->_plotLabel;
+	}
+
+	/**
+	 * Get Plot Label by Index
+	 *
+	 * @return PHPExcel_Chart_DataSeriesValues
+	 */
+	public function getPlotLabelByIndex($index) {
+		$keys = array_keys($this->_plotLabel);
+		if (in_array($index,$keys)) {
+			return $this->_plotLabel[$index];
+		} elseif(isset($keys[$index])) {
+			return $this->_plotLabel[$keys[$index]];
+		}
+		return false;
+	}
+
+	/**
+	 * Get Plot Categories
+	 *
+	 * @return array of PHPExcel_Chart_DataSeriesValues
+	 */
+	public function getPlotCategories() {
+		return $this->_plotCategory;
+	}
+
+	/**
+	 * Get Plot Category by Index
+	 *
+	 * @return PHPExcel_Chart_DataSeriesValues
+	 */
+	public function getPlotCategoryByIndex($index) {
+		$keys = array_keys($this->_plotCategory);
+		if (in_array($index,$keys)) {
+			return $this->_plotCategory[$index];
+		} elseif(isset($keys[$index])) {
+			return $this->_plotCategory[$keys[$index]];
+		}
+		return false;
+	}
+
+	/**
+	 * Get Plot Style
+	 *
+	 * @return string
+	 */
+	public function getPlotStyle() {
+		return $this->_plotStyle;
+	}
+
+	/**
+	 * Set Plot Style
+	 *
+	 * @param string $plotStyle
+	 */
+	public function setPlotStyle($plotStyle = null) {
+		$this->_plotStyle = $plotStyle;
+	}
+
+	/**
+	 * Get Plot Values
+	 *
+	 * @return array of PHPExcel_Chart_DataSeriesValues
+	 */
+	public function getPlotValues() {
+		return $this->_plotValues;
+	}
+
+	/**
+	 * Get Plot Values by Index
+	 *
+	 * @return PHPExcel_Chart_DataSeriesValues
+	 */
+	public function getPlotValuesByIndex($index) {
+		$keys = array_keys($this->_plotValues);
+		if (in_array($index,$keys)) {
+			return $this->_plotValues[$index];
+		} elseif(isset($keys[$index])) {
+			return $this->_plotValues[$keys[$index]];
+		}
+		return false;
+	}
+
+	/**
+	 * Get Number of Plot Series
+	 *
+	 * @return integer
+	 */
+	public function getPlotSeriesCount() {
+		return count($this->_plotValues);
+	}
+
+	/**
+	 * Get Smooth Line
+	 *
+	 * @return boolean
+	 */
+	public function getSmoothLine() {
+		return $this->_smoothLine;
+	}
+
+	/**
+	 * Set Smooth Line
+	 *
+	 * @param boolean $smoothLine
+	 */
+	public function setSmoothLine($smoothLine = TRUE) {
+		$this->_smoothLine = $smoothLine;
+	}
+
+	public function refresh(PHPExcel_Worksheet $worksheet) {
+	    foreach($this->_plotValues as $plotValues) {
+			if ($plotValues !== NULL)
+				$plotValues->refresh($worksheet, TRUE);
+		}
+		foreach($this->_plotLabel as $plotValues) {
+			if ($plotValues !== NULL)
+				$plotValues->refresh($worksheet, TRUE);
+		}
+		foreach($this->_plotCategory as $plotValues) {
+			if ($plotValues !== NULL)
+				$plotValues->refresh($worksheet, FALSE);
+		}
+	}
+
+}

+ 321 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/DataSeriesValues.php

@@ -0,0 +1,321 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_DataSeriesValues
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_DataSeriesValues
+{
+
+	const DATASERIES_TYPE_STRING	= 'String';
+	const DATASERIES_TYPE_NUMBER	= 'Number';
+
+	private static $_dataTypeValues = array(
+		self::DATASERIES_TYPE_STRING,
+		self::DATASERIES_TYPE_NUMBER,
+	);
+
+	/**
+	 * Series Data Type
+	 *
+	 * @var	string
+	 */
+	private $_dataType = null;
+
+	/**
+	 * Series Data Source
+	 *
+	 * @var	string
+	 */
+	private $_dataSource = null;
+
+	/**
+	 * Format Code
+	 *
+	 * @var	string
+	 */
+	private $_formatCode = null;
+
+	/**
+	 * Series Point Marker
+	 *
+	 * @var	string
+	 */
+	private $_marker = null;
+
+	/**
+	 * Point Count (The number of datapoints in the dataseries)
+	 *
+	 * @var	integer
+	 */
+	private $_pointCount = 0;
+
+	/**
+	 * Data Values
+	 *
+	 * @var	array of mixed
+	 */
+	private $_dataValues = array();
+
+	/**
+	 * Create a new PHPExcel_Chart_DataSeriesValues object
+	 */
+	public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = array(), $marker = null)
+	{
+		$this->setDataType($dataType);
+		$this->_dataSource = $dataSource;
+		$this->_formatCode = $formatCode;
+		$this->_pointCount = $pointCount;
+		$this->_dataValues = $dataValues;
+		$this->_marker = $marker;
+	}
+
+	/**
+	 * Get Series Data Type
+	 *
+	 * @return	string
+	 */
+	public function getDataType() {
+		return $this->_dataType;
+	}
+
+	/**
+	 * Set Series Data Type
+	 *
+	 * @param	string	$dataType	Datatype of this data series
+	 *								Typical values are:
+	 *									PHPExcel_Chart_DataSeriesValues::DATASERIES_TYPE_STRING
+	 *										Normally used for axis point values
+	 *									PHPExcel_Chart_DataSeriesValues::DATASERIES_TYPE_NUMBER
+	 *										Normally used for chart data values
+	 * @return	PHPExcel_Chart_DataSeriesValues
+	 */
+	public function setDataType($dataType = self::DATASERIES_TYPE_NUMBER) {
+		if (!in_array($dataType, self::$_dataTypeValues)) {
+    		throw new PHPExcel_Chart_Exception('Invalid datatype for chart data series values');
+		}
+		$this->_dataType = $dataType;
+
+		return $this;
+	}
+
+	/**
+	 * Get Series Data Source (formula)
+	 *
+	 * @return	string
+	 */
+	public function getDataSource() {
+		return $this->_dataSource;
+	}
+
+	/**
+	 * Set Series Data Source (formula)
+	 *
+	 * @param	string	$dataSource
+	 * @return	PHPExcel_Chart_DataSeriesValues
+	 */
+	public function setDataSource($dataSource = null, $refreshDataValues = true) {
+		$this->_dataSource = $dataSource;
+
+		if ($refreshDataValues) {
+			//	TO DO
+		}
+
+		return $this;
+	}
+
+	/**
+	 * Get Point Marker
+	 *
+	 * @return string
+	 */
+	public function getPointMarker() {
+		return $this->_marker;
+	}
+
+	/**
+	 * Set Point Marker
+	 *
+	 * @param	string	$marker
+	 * @return	PHPExcel_Chart_DataSeriesValues
+	 */
+	public function setPointMarker($marker = null) {
+		$this->_marker = $marker;
+
+		return $this;
+	}
+
+	/**
+	 * Get Series Format Code
+	 *
+	 * @return	string
+	 */
+	public function getFormatCode() {
+		return $this->_formatCode;
+	}
+
+	/**
+	 * Set Series Format Code
+	 *
+	 * @param	string	$formatCode
+	 * @return	PHPExcel_Chart_DataSeriesValues
+	 */
+	public function setFormatCode($formatCode = null) {
+		$this->_formatCode = $formatCode;
+
+		return $this;
+	}
+
+	/**
+	 * Get Series Point Count
+	 *
+	 * @return	integer
+	 */
+	public function getPointCount() {
+		return $this->_pointCount;
+	}
+
+	/**
+	 * Identify if the Data Series is a multi-level or a simple series
+	 *
+	 * @return	boolean
+	 */
+	public function isMultiLevelSeries() {
+		if (count($this->_dataValues) > 0) {
+			return is_array($this->_dataValues[0]);
+		}
+		return null;
+	}
+
+	/**
+	 * Return the level count of a multi-level Data Series
+	 *
+	 * @return	boolean
+	 */
+	public function multiLevelCount() {
+		$levelCount = 0;
+		foreach($this->_dataValues as $dataValueSet) {
+			$levelCount = max($levelCount,count($dataValueSet));
+		}
+		return $levelCount;
+	}
+
+	/**
+	 * Get Series Data Values
+	 *
+	 * @return	array of mixed
+	 */
+	public function getDataValues() {
+		return $this->_dataValues;
+	}
+
+	/**
+	 * Get the first Series Data value
+	 *
+	 * @return	mixed
+	 */
+	public function getDataValue() {
+		$count = count($this->_dataValues);
+		if ($count == 0) {
+			return null;
+		} elseif ($count == 1) {
+			return $this->_dataValues[0];
+		}
+		return $this->_dataValues;
+	}
+
+	/**
+	 * Set Series Data Values
+	 *
+	 * @param	array	$dataValues
+	 * @param	boolean	$refreshDataSource
+	 *					TRUE - refresh the value of _dataSource based on the values of $dataValues
+	 *					FALSE - don't change the value of _dataSource
+	 * @return	PHPExcel_Chart_DataSeriesValues
+	 */
+	public function setDataValues($dataValues = array(), $refreshDataSource = TRUE) {
+		$this->_dataValues = PHPExcel_Calculation_Functions::flattenArray($dataValues);
+		$this->_pointCount = count($dataValues);
+
+		if ($refreshDataSource) {
+			//	TO DO
+		}
+
+		return $this;
+	}
+
+	private function _stripNulls($var) {
+		return $var !== NULL;
+	}
+
+	public function refresh(PHPExcel_Worksheet $worksheet, $flatten = TRUE) {
+        if ($this->_dataSource !== NULL) {
+        	$calcEngine = PHPExcel_Calculation::getInstance();
+			$newDataValues = PHPExcel_Calculation::_unwrapResult(
+			    $calcEngine->_calculateFormulaValue(
+			        '='.$this->_dataSource,
+			        NULL,
+			        $worksheet->getCell('A1')
+			    )
+			);
+			if ($flatten) {
+				$this->_dataValues = PHPExcel_Calculation_Functions::flattenArray($newDataValues);
+			} else {
+				$cellRange = explode('!',$this->_dataSource);
+				if (count($cellRange) > 1) {
+					list(,$cellRange) = $cellRange;
+				}
+
+				$dimensions = PHPExcel_Cell::rangeDimension(str_replace('$','',$cellRange));
+				if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
+					$this->_dataValues = PHPExcel_Calculation_Functions::flattenArray($newDataValues);
+				} else {
+					$newArray = array_values(array_shift($newDataValues));
+					foreach($newArray as $i => $newDataSet) {
+						$newArray[$i] = array($newDataSet);
+					}
+
+					foreach($newDataValues as $newDataSet) {
+						$i = 0;
+						foreach($newDataSet as $newDataVal) {
+							array_unshift($newArray[$i++],$newDataVal);
+						}
+					}
+					$this->_dataValues = $newArray;
+				}
+			}
+			$this->_pointCount = count($this->_dataValues);
+		}
+
+	}
+
+}

+ 52 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/Exception.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Chart
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_Exception
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Chart
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_Exception extends Exception {
+	/**
+	 * Error handler callback
+	 *
+	 * @param mixed $code
+	 * @param mixed $string
+	 * @param mixed $file
+	 * @param mixed $line
+	 * @param mixed $context
+	 */
+	public static function errorHandlerCallback($code, $string, $file, $line, $context) {
+		$e = new self($string, $code);
+		$e->line = $line;
+		$e->file = $file;
+		throw $e;
+	}
+}

+ 417 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/Layout.php

@@ -0,0 +1,417 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_Layout
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_Layout
+{
+	/**
+	 * layoutTarget
+	 *
+	 * @var string
+	 */
+	private $_layoutTarget = NULL;
+
+	/**
+	 * X Mode
+	 *
+	 * @var string
+	 */
+	private $_xMode		= NULL;
+
+	/**
+	 * Y Mode
+	 *
+	 * @var string
+	 */
+	private $_yMode		= NULL;
+
+	/**
+	 * X-Position
+	 *
+	 * @var float
+	 */
+	private $_xPos		= NULL;
+
+	/**
+	 * Y-Position
+	 *
+	 * @var float
+	 */
+	private $_yPos		= NULL;
+
+	/**
+	 * width
+	 *
+	 * @var float
+	 */
+	private $_width		= NULL;
+
+	/**
+	 * height
+	 *
+	 * @var float
+	 */
+	private $_height	= NULL;
+
+	/**
+	 * show legend key
+	 * Specifies that legend keys should be shown in data labels
+	 *
+	 * @var boolean
+	 */
+	private $_showLegendKey	= NULL;
+
+	/**
+	 * show value
+	 * Specifies that the value should be shown in a data label.
+	 *
+	 * @var boolean
+	 */
+	private $_showVal	= NULL;
+
+	/**
+	 * show category name
+	 * Specifies that the category name should be shown in the data label.
+	 *
+	 * @var boolean
+	 */
+	private $_showCatName	= NULL;
+
+	/**
+	 * show data series name
+	 * Specifies that the series name should be shown in the data label.
+	 *
+	 * @var boolean
+	 */
+	private $_showSerName	= NULL;
+
+	/**
+	 * show percentage
+	 * Specifies that the percentage should be shown in the data label.
+	 *
+	 * @var boolean
+	 */
+	private $_showPercent	= NULL;
+
+	/**
+	 * show bubble size
+	 *
+	 * @var boolean
+	 */
+	private $_showBubbleSize	= NULL;
+
+	/**
+	 * show leader lines
+	 * Specifies that leader lines should be shown for the data label.
+	 *
+	 * @var boolean
+	 */
+	private $_showLeaderLines	= NULL;
+
+
+	/**
+	 * Create a new PHPExcel_Chart_Layout
+	 */
+	public function __construct($layout=array())
+	{
+		if (isset($layout['layoutTarget']))	{ $this->_layoutTarget	= $layout['layoutTarget'];	}
+		if (isset($layout['xMode']))		{ $this->_xMode			= $layout['xMode'];			}
+		if (isset($layout['yMode']))		{ $this->_yMode			= $layout['yMode'];			}
+		if (isset($layout['x']))			{ $this->_xPos			= (float) $layout['x'];		}
+		if (isset($layout['y']))			{ $this->_yPos			= (float) $layout['y'];		}
+		if (isset($layout['w']))			{ $this->_width			= (float) $layout['w'];		}
+		if (isset($layout['h']))			{ $this->_height		= (float) $layout['h'];		}
+	}
+
+	/**
+	 * Get Layout Target
+	 *
+	 * @return string
+	 */
+	public function getLayoutTarget() {
+		return $this->_layoutTarget;
+	}
+
+	/**
+	 * Set Layout Target
+	 *
+	 * @param Layout Target $value
+	 */
+	public function setLayoutTarget($value) {
+		$this->_layoutTarget = $value;
+	}
+
+	/**
+	 * Get X-Mode
+	 *
+	 * @return string
+	 */
+	public function getXMode() {
+		return $this->_xMode;
+	}
+
+	/**
+	 * Set X-Mode
+	 *
+	 * @param X-Mode $value
+	 */
+	public function setXMode($value) {
+		$this->_xMode = $value;
+	}
+
+	/**
+	 * Get Y-Mode
+	 *
+	 * @return string
+	 */
+	public function getYMode() {
+		return $this->_xMode;
+	}
+
+	/**
+	 * Set Y-Mode
+	 *
+	 * @param Y-Mode $value
+	 */
+	public function setYMode($value) {
+		$this->_xMode = $value;
+	}
+
+	/**
+	 * Get X-Position
+	 *
+	 * @return number
+	 */
+	public function getXPosition() {
+		return $this->_xPos;
+	}
+
+	/**
+	 * Set X-Position
+	 *
+	 * @param X-Position $value
+	 */
+	public function setXPosition($value) {
+		$this->_xPos = $value;
+	}
+
+	/**
+	 * Get Y-Position
+	 *
+	 * @return number
+	 */
+	public function getYPosition() {
+		return $this->_yPos;
+	}
+
+	/**
+	 * Set Y-Position
+	 *
+	 * @param Y-Position $value
+	 */
+	public function setYPosition($value) {
+		$this->_yPos = $value;
+	}
+
+	/**
+	 * Get Width
+	 *
+	 * @return number
+	 */
+	public function getWidth() {
+		return $this->_width;
+	}
+
+	/**
+	 * Set Width
+	 *
+	 * @param Width $value
+	 */
+	public function setWidth($value) {
+		$this->_width = $value;
+	}
+
+	/**
+	 * Get Height
+	 *
+	 * @return number
+	 */
+	public function getHeight() {
+		return $this->_height;
+	}
+
+	/**
+	 * Set Height
+	 *
+	 * @param Height $value
+	 */
+	public function setHeight($value) {
+		$this->_height = $value;
+	}
+
+
+	/**
+	 * Get show legend key
+	 *
+	 * @return boolean
+	 */
+	public function getShowLegendKey() {
+		return $this->_showLegendKey;
+	}
+
+	/**
+	 * Set show legend key
+	 * Specifies that legend keys should be shown in data labels.
+	 *
+	 * @param boolean $value		Show legend key
+	 */
+	public function setShowLegendKey($value) {
+		$this->_showLegendKey = $value;
+	}
+
+	/**
+	 * Get show value
+	 *
+	 * @return boolean
+	 */
+	public function getShowVal() {
+		return $this->_showVal;
+	}
+
+	/**
+	 * Set show val
+	 * Specifies that the value should be shown in data labels.
+	 *
+	 * @param boolean $value		Show val
+	 */
+	public function setShowVal($value) {
+		$this->_showVal = $value;
+	}
+
+	/**
+	 * Get show category name
+	 *
+	 * @return boolean
+	 */
+	public function getShowCatName() {
+		return $this->_showCatName;
+	}
+
+	/**
+	 * Set show cat name
+	 * Specifies that the category name should be shown in data labels.
+	 *
+	 * @param boolean $value		Show cat name
+	 */
+	public function setShowCatName($value) {
+		$this->_showCatName = $value;
+	}
+
+	/**
+	 * Get show data series name
+	 *
+	 * @return boolean
+	 */
+	public function getShowSerName() {
+		return $this->_showSerName;
+	}
+
+	/**
+	 * Set show ser name
+	 * Specifies that the series name should be shown in data labels.
+	 *
+	 * @param boolean $value		Show ser name
+	 */
+	public function setShowSerName($value) {
+		$this->_showSerName = $value;
+	}
+
+	/**
+	 * Get show percentage
+	 *
+	 * @return boolean
+	 */
+	public function getShowPercent() {
+		return $this->_showPercent;
+	}
+
+	/**
+	 * Set show percentage
+	 * Specifies that the percentage should be shown in data labels.
+	 *
+	 * @param boolean $value		Show percentage
+	 */
+	public function setShowPercent($value) {
+		$this->_showPercent = $value;
+	}
+
+	/**
+	 * Get show bubble size
+	 *
+	 * @return boolean
+	 */
+	public function getShowBubbleSize() {
+		return $this->_showBubbleSize;
+	}
+
+	/**
+	 * Set show bubble size
+	 * Specifies that the bubble size should be shown in data labels.
+	 *
+	 * @param boolean $value		Show bubble size
+	 */
+	public function setShowBubbleSize($value) {
+		$this->_showBubbleSize = $value;
+	}
+
+	/**
+	 * Get show leader lines
+	 *
+	 * @return boolean
+	 */
+	public function getShowLeaderLines() {
+		return $this->_showLeaderLines;
+	}
+
+	/**
+	 * Set show leader lines
+	 * Specifies that leader lines should be shown in data labels.
+	 *
+	 * @param boolean $value		Show leader lines
+	 */
+	public function setShowLeaderLines($value) {
+		$this->_showLeaderLines = $value;
+	}
+
+}

+ 171 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/Legend.php

@@ -0,0 +1,171 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_Legend
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_Legend
+{
+	/** Legend positions */
+	const xlLegendPositionBottom	= -4107;	//	Below the chart.
+	const xlLegendPositionCorner	= 2;		//	In the upper right-hand corner of the chart border.
+	const xlLegendPositionCustom	= -4161;	//	A custom position.
+	const xlLegendPositionLeft		= -4131;	//	Left of the chart.
+	const xlLegendPositionRight		= -4152;	//	Right of the chart.
+	const xlLegendPositionTop		= -4160;	//	Above the chart.
+
+	const POSITION_RIGHT	= 'r';
+	const POSITION_LEFT		= 'l';
+	const POSITION_BOTTOM	= 'b';
+	const POSITION_TOP		= 't';
+	const POSITION_TOPRIGHT	= 'tr';
+
+	private static $_positionXLref = array( self::xlLegendPositionBottom	=> self::POSITION_BOTTOM,
+											self::xlLegendPositionCorner	=> self::POSITION_TOPRIGHT,
+											self::xlLegendPositionCustom	=> '??',
+											self::xlLegendPositionLeft		=> self::POSITION_LEFT,
+											self::xlLegendPositionRight		=> self::POSITION_RIGHT,
+											self::xlLegendPositionTop		=> self::POSITION_TOP
+										  );
+
+	/**
+	 * Legend position
+	 *
+	 * @var	string
+	 */
+	private $_position = self::POSITION_RIGHT;
+
+	/**
+	 * Allow overlay of other elements?
+	 *
+	 * @var	boolean
+	 */
+	private $_overlay = TRUE;
+
+	/**
+	 * Legend Layout
+	 *
+	 * @var	PHPExcel_Chart_Layout
+	 */
+	private $_layout = NULL;
+
+
+	/**
+	 *	Create a new PHPExcel_Chart_Legend
+	 */
+	public function __construct($position = self::POSITION_RIGHT, PHPExcel_Chart_Layout $layout = NULL, $overlay = FALSE)
+	{
+		$this->setPosition($position);
+		$this->_layout = $layout;
+		$this->setOverlay($overlay);
+	}
+
+	/**
+	 * Get legend position as an excel string value
+	 *
+	 * @return	string
+	 */
+	public function getPosition() {
+		return $this->_position;
+	}
+
+	/**
+	 * Get legend position using an excel string value
+	 *
+	 * @param	string	$position
+	 */
+	public function setPosition($position = self::POSITION_RIGHT) {
+		if (!in_array($position,self::$_positionXLref)) {
+			return false;
+		}
+
+		$this->_position = $position;
+		return true;
+	}
+
+	/**
+	 * Get legend position as an Excel internal numeric value
+	 *
+	 * @return	number
+	 */
+	public function getPositionXL() {
+		return array_search($this->_position,self::$_positionXLref);
+	}
+
+	/**
+	 * Set legend position using an Excel internal numeric value
+	 *
+	 * @param	number	$positionXL
+	 */
+	public function setPositionXL($positionXL = self::xlLegendPositionRight) {
+		if (!array_key_exists($positionXL,self::$_positionXLref)) {
+			return false;
+		}
+
+		$this->_position = self::$_positionXLref[$positionXL];
+		return true;
+	}
+
+	/**
+	 * Get allow overlay of other elements?
+	 *
+	 * @return	boolean
+	 */
+	public function getOverlay() {
+		return $this->_overlay;
+	}
+
+	/**
+	 * Set allow overlay of other elements?
+	 *
+	 * @param	boolean	$overlay
+	 * @return	boolean
+	 */
+	public function setOverlay($overlay = FALSE) {
+		if (!is_bool($overlay)) {
+			return false;
+		}
+
+		$this->_overlay = $overlay;
+		return true;
+	}
+
+	/**
+	 * Get Layout
+	 *
+	 * @return PHPExcel_Chart_Layout
+	 */
+	public function getLayout() {
+		return $this->_layout;
+	}
+
+}

+ 125 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/PlotArea.php

@@ -0,0 +1,125 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_PlotArea
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_PlotArea
+{
+	/**
+	 * PlotArea Layout
+	 *
+	 * @var PHPExcel_Chart_Layout
+	 */
+	private $_layout = null;
+
+	/**
+	 * Plot Series
+	 *
+	 * @var array of PHPExcel_Chart_DataSeries
+	 */
+	private $_plotSeries = array();
+
+	/**
+	 * Create a new PHPExcel_Chart_PlotArea
+	 */
+	public function __construct(PHPExcel_Chart_Layout $layout = null, $plotSeries = array())
+	{
+		$this->_layout = $layout;
+		$this->_plotSeries = $plotSeries;
+	}
+
+	/**
+	 * Get Layout
+	 *
+	 * @return PHPExcel_Chart_Layout
+	 */
+	public function getLayout() {
+		return $this->_layout;
+	}
+
+	/**
+	 * Get Number of Plot Groups
+	 *
+	 * @return array of PHPExcel_Chart_DataSeries
+	 */
+	public function getPlotGroupCount() {
+		return count($this->_plotSeries);
+	}
+
+	/**
+	 * Get Number of Plot Series
+	 *
+	 * @return integer
+	 */
+	public function getPlotSeriesCount() {
+		$seriesCount = 0;
+		foreach($this->_plotSeries as $plot) {
+			$seriesCount += $plot->getPlotSeriesCount();
+		}
+		return $seriesCount;
+	}
+
+	/**
+	 * Get Plot Series
+	 *
+	 * @return array of PHPExcel_Chart_DataSeries
+	 */
+	public function getPlotGroup() {
+		return $this->_plotSeries;
+	}
+
+	/**
+	 * Get Plot Series by Index
+	 *
+	 * @return PHPExcel_Chart_DataSeries
+	 */
+	public function getPlotGroupByIndex($index) {
+		return $this->_plotSeries[$index];
+	}
+
+	/**
+	 * Set Plot Series
+	 *
+	 * @param array of PHPExcel_Chart_DataSeries
+	 */
+	public function setPlotSeries($plotSeries = array()) {
+		$this->_plotSeries = $plotSeries;
+	}
+
+	public function refresh(PHPExcel_Worksheet $worksheet) {
+	    foreach($this->_plotSeries as $plotSeries) {
+			$plotSeries->refresh($worksheet);
+		}
+	}
+
+}

+ 17 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/Renderer/PHP Charting Libraries.txt

@@ -0,0 +1,17 @@
+ChartDirector
+	http://www.advsofteng.com/cdphp.html
+
+GraPHPite
+	http://graphpite.sourceforge.net/
+
+JpGraph
+	http://www.aditus.nu/jpgraph/
+
+LibChart
+	http://naku.dohcrew.com/libchart/pages/introduction/
+
+pChart
+	http://pchart.sourceforge.net/
+
+TeeChart
+	http://www.steema.com/products/teechart/overview.html

+ 839 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/Renderer/jpgraph.php

@@ -0,0 +1,839 @@
+<?php
+
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+
+require_once(PHPExcel_Settings::getChartRendererPath().'/jpgraph.php');
+
+
+/**
+ * PHPExcel_Chart_Renderer_jpgraph
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart_Renderer
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_Renderer_jpgraph
+{
+	private static $_width	= 640;
+
+	private static $_height	= 480;
+
+	private static $_colourSet = array( 'mediumpurple1',	'palegreen3',	'gold1',		'cadetblue1',
+										'darkmagenta',		'coral',		'dodgerblue3',	'eggplant',
+										'mediumblue',		'magenta',		'sandybrown',	'cyan',
+										'firebrick1',		'forestgreen',	'deeppink4',	'darkolivegreen',
+										'goldenrod2'
+									  );
+
+	private static $_markSet = array(	'diamond'	=> MARK_DIAMOND,
+										'square'	=> MARK_SQUARE,
+										'triangle'	=> MARK_UTRIANGLE,
+										'x'			=> MARK_X,
+										'star'		=> MARK_STAR,
+										'dot'		=> MARK_FILLEDCIRCLE,
+										'dash'		=> MARK_DTRIANGLE,
+										'circle'	=> MARK_CIRCLE,
+										'plus'		=> MARK_CROSS
+									);
+
+
+	private $_chart	= null;
+
+	private $_graph	= null;
+
+	private static $_plotColour	= 0;
+
+	private static $_plotMark	= 0;
+
+
+	private function _formatPointMarker($seriesPlot,$markerID) {
+		$plotMarkKeys = array_keys(self::$_markSet);
+		if (is_null($markerID)) {
+			//	Use default plot marker (next marker in the series)
+			self::$_plotMark %= count(self::$_markSet);
+			$seriesPlot->mark->SetType(self::$_markSet[$plotMarkKeys[self::$_plotMark++]]);
+		} elseif ($markerID !== 'none') {
+			//	Use specified plot marker (if it exists)
+			if (isset(self::$_markSet[$markerID])) {
+				$seriesPlot->mark->SetType(self::$_markSet[$markerID]);
+			} else {
+				//	If the specified plot marker doesn't exist, use default plot marker (next marker in the series)
+				self::$_plotMark %= count(self::$_markSet);
+				$seriesPlot->mark->SetType(self::$_markSet[$plotMarkKeys[self::$_plotMark++]]);
+			}
+		} else {
+			//	Hide plot marker
+			$seriesPlot->mark->Hide();
+		}
+		$seriesPlot->mark->SetColor(self::$_colourSet[self::$_plotColour]);
+		$seriesPlot->mark->SetFillColor(self::$_colourSet[self::$_plotColour]);
+		$seriesPlot->SetColor(self::$_colourSet[self::$_plotColour++]);
+
+		return $seriesPlot;
+	}	//	function _formatPointMarker()
+
+
+	private function _formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation = '') {
+		$datasetLabelFormatCode = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode();
+		if (!is_null($datasetLabelFormatCode)) {
+			//	Retrieve any label formatting code
+			$datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
+		}
+
+		$testCurrentIndex = 0;
+		foreach($datasetLabels as $i => $datasetLabel) {
+			array_reverse($datasetLabel);
+
+			if (is_array($datasetLabel)) {
+				if ($rotation == 'bar') {
+					$datasetLabel = array_reverse($datasetLabel);
+					$datasetLabels[$i] = implode(" ",$datasetLabel);
+				} else {
+					$datasetLabels[$i] = implode("\n",$datasetLabel);
+				}
+			} else {
+				//	Format labels according to any formatting code
+				if (!is_null($datasetLabelFormatCode)) {
+					$datasetLabels[$i] = PHPExcel_Style_NumberFormat::toFormattedString($datasetLabel,$datasetLabelFormatCode);
+				}
+			}
+			++$testCurrentIndex;
+		}
+
+		return $datasetLabels;
+	}	//	function _formatDataSetLabels()
+
+
+	private function _percentageSumCalculation($groupID,$seriesCount) {
+		//	Adjust our values to a percentage value across all series in the group
+		for($i = 0; $i < $seriesCount; ++$i) {
+			if ($i == 0) {
+				$sumValues = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+			} else {
+				$nextValues = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+				foreach($nextValues as $k => $value) {
+					if (isset($sumValues[$k])) {
+						$sumValues[$k] += $value;
+					} else {
+						$sumValues[$k] = $value;
+					}
+				}
+			}
+		}
+
+		return $sumValues;
+	}	//	function _percentageSumCalculation()
+
+
+	private function _percentageAdjustValues($dataValues,$sumValues) {
+		foreach($dataValues as $k => $dataValue) {
+			$dataValues[$k] = $dataValue / $sumValues[$k] * 100;
+		}
+
+		return $dataValues;
+	}	//	function _percentageAdjustValues()
+
+
+	private function _getCaption($captionElement) {
+		//	Read any caption
+		$caption = (!is_null($captionElement)) ? $captionElement->getCaption() : NULL;
+		//	Test if we have a title caption to display
+		if (!is_null($caption)) {
+			//	If we do, it could be a plain string or an array
+			if (is_array($caption)) {
+				//	Implode an array to a plain string
+				$caption = implode('',$caption);
+			}
+		}
+		return $caption;
+	}	//	function _getCaption()
+
+
+	private function _renderTitle() {
+		$title = $this->_getCaption($this->_chart->getTitle());
+		if (!is_null($title)) {
+			$this->_graph->title->Set($title);
+		}
+	}	//	function _renderTitle()
+
+
+	private function _renderLegend() {
+		$legend = $this->_chart->getLegend();
+		if (!is_null($legend)) {
+			$legendPosition = $legend->getPosition();
+			$legendOverlay = $legend->getOverlay();
+			switch ($legendPosition) {
+				case 'r'	:
+					$this->_graph->legend->SetPos(0.01,0.5,'right','center');	//	right
+					$this->_graph->legend->SetColumns(1);
+					break;
+				case 'l'	:
+					$this->_graph->legend->SetPos(0.01,0.5,'left','center');	//	left
+					$this->_graph->legend->SetColumns(1);
+					break;
+				case 't'	:
+					$this->_graph->legend->SetPos(0.5,0.01,'center','top');	//	top
+					break;
+				case 'b'	:
+					$this->_graph->legend->SetPos(0.5,0.99,'center','bottom');	//	bottom
+					break;
+				default		:
+					$this->_graph->legend->SetPos(0.01,0.01,'right','top');	//	top-right
+					$this->_graph->legend->SetColumns(1);
+					break;
+			}
+		} else {
+			$this->_graph->legend->Hide();
+		}
+	}	//	function _renderLegend()
+
+
+	private function _renderCartesianPlotArea($type='textlin') {
+		$this->_graph = new Graph(self::$_width,self::$_height);
+		$this->_graph->SetScale($type);
+
+		$this->_renderTitle();
+
+		//	Rotate for bar rather than column chart
+		$rotation = $this->_chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotDirection();
+		$reverse = ($rotation == 'bar') ? true : false;
+
+		$xAxisLabel = $this->_chart->getXAxisLabel();
+		if (!is_null($xAxisLabel)) {
+			$title = $this->_getCaption($xAxisLabel);
+			if (!is_null($title)) {
+				$this->_graph->xaxis->SetTitle($title,'center');
+				$this->_graph->xaxis->title->SetMargin(35);
+				if ($reverse) {
+					$this->_graph->xaxis->title->SetAngle(90);
+					$this->_graph->xaxis->title->SetMargin(90);
+				}
+			}
+		}
+
+		$yAxisLabel = $this->_chart->getYAxisLabel();
+		if (!is_null($yAxisLabel)) {
+			$title = $this->_getCaption($yAxisLabel);
+			if (!is_null($title)) {
+				$this->_graph->yaxis->SetTitle($title,'center');
+				if ($reverse) {
+					$this->_graph->yaxis->title->SetAngle(0);
+					$this->_graph->yaxis->title->SetMargin(-55);
+				}
+			}
+		}
+	}	//	function _renderCartesianPlotArea()
+
+
+	private function _renderPiePlotArea($doughnut = False) {
+		$this->_graph = new PieGraph(self::$_width,self::$_height);
+
+		$this->_renderTitle();
+	}	//	function _renderPiePlotArea()
+
+
+	private function _renderRadarPlotArea() {
+		$this->_graph = new RadarGraph(self::$_width,self::$_height);
+		$this->_graph->SetScale('lin');
+
+		$this->_renderTitle();
+	}	//	function _renderRadarPlotArea()
+
+
+	private function _renderPlotLine($groupID, $filled = false, $combination = false, $dimensions = '2d') {
+		$grouping = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+        $labelCount = count($this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+		if ($labelCount > 0) {
+			$datasetLabels = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+			$datasetLabels = $this->_formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+			$this->_graph->xaxis->SetTickLabels($datasetLabels);
+		}
+
+		$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+		$seriesPlots = array();
+		if ($grouping == 'percentStacked') {
+			$sumValues = $this->_percentageSumCalculation($groupID,$seriesCount);
+		}
+
+		//	Loop through each data series in turn
+		for($i = 0; $i < $seriesCount; ++$i) {
+			$dataValues = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+			$marker = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+			if ($grouping == 'percentStacked') {
+				$dataValues = $this->_percentageAdjustValues($dataValues,$sumValues);
+			}
+
+			//	Fill in any missing values in the $dataValues array
+			$testCurrentIndex = 0;
+			foreach($dataValues as $k => $dataValue) {
+				while($k != $testCurrentIndex) {
+					$dataValues[$testCurrentIndex] = null;
+					++$testCurrentIndex;
+				}
+				++$testCurrentIndex;
+			}
+
+			$seriesPlot = new LinePlot($dataValues);
+			if ($combination) {
+				$seriesPlot->SetBarCenter();
+			}
+
+			if ($filled) {
+				$seriesPlot->SetFilled(true);
+				$seriesPlot->SetColor('black');
+				$seriesPlot->SetFillColor(self::$_colourSet[self::$_plotColour++]);
+			} else {
+				//	Set the appropriate plot marker
+				$this->_formatPointMarker($seriesPlot,$marker);
+			}
+			$dataLabel = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+			$seriesPlot->SetLegend($dataLabel);
+
+			$seriesPlots[] = $seriesPlot;
+		}
+
+		if ($grouping == 'standard') {
+			$groupPlot = $seriesPlots;
+		} else {
+			$groupPlot = new AccLinePlot($seriesPlots);
+		}
+		$this->_graph->Add($groupPlot);
+	}	//	function _renderPlotLine()
+
+
+	private function _renderPlotBar($groupID, $dimensions = '2d') {
+		$rotation = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotDirection();
+		//	Rotate for bar rather than column chart
+		if (($groupID == 0) && ($rotation == 'bar')) {
+			$this->_graph->Set90AndMargin();
+		}
+		$grouping = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+        $labelCount = count($this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+		if ($labelCount > 0) {
+			$datasetLabels = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+			$datasetLabels = $this->_formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation);
+			//	Rotate for bar rather than column chart
+			if ($rotation == 'bar') {
+				$datasetLabels = array_reverse($datasetLabels);
+				$this->_graph->yaxis->SetPos('max');
+				$this->_graph->yaxis->SetLabelAlign('center','top');
+				$this->_graph->yaxis->SetLabelSide(SIDE_RIGHT);
+			}
+			$this->_graph->xaxis->SetTickLabels($datasetLabels);
+		}
+
+
+		$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+		$seriesPlots = array();
+		if ($grouping == 'percentStacked') {
+			$sumValues = $this->_percentageSumCalculation($groupID,$seriesCount);
+		}
+
+		//	Loop through each data series in turn
+		for($j = 0; $j < $seriesCount; ++$j) {
+			$dataValues = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+			if ($grouping == 'percentStacked') {
+				$dataValues = $this->_percentageAdjustValues($dataValues,$sumValues);
+			}
+
+			//	Fill in any missing values in the $dataValues array
+			$testCurrentIndex = 0;
+			foreach($dataValues as $k => $dataValue) {
+				while($k != $testCurrentIndex) {
+					$dataValues[$testCurrentIndex] = null;
+					++$testCurrentIndex;
+				}
+				++$testCurrentIndex;
+			}
+
+			//	Reverse the $dataValues order for bar rather than column chart
+			if ($rotation == 'bar') {
+				$dataValues = array_reverse($dataValues);
+			}
+			$seriesPlot = new BarPlot($dataValues);
+			$seriesPlot->SetColor('black');
+			$seriesPlot->SetFillColor(self::$_colourSet[self::$_plotColour++]);
+			if ($dimensions == '3d') {
+				$seriesPlot->SetShadow();
+			}
+			if (!$this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
+				$dataLabel = '';
+			} else {
+				$dataLabel = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
+			}
+			$seriesPlot->SetLegend($dataLabel);
+
+			$seriesPlots[] = $seriesPlot;
+		}
+		//	Reverse the plot order for bar rather than column chart
+		if (($rotation == 'bar') && (!($grouping == 'percentStacked'))) {
+			$seriesPlots = array_reverse($seriesPlots);
+		}
+
+		if ($grouping == 'clustered') {
+			$groupPlot = new GroupBarPlot($seriesPlots);
+		} elseif ($grouping == 'standard') {
+			$groupPlot = new GroupBarPlot($seriesPlots);
+		} else {
+			$groupPlot = new AccBarPlot($seriesPlots);
+			if ($dimensions == '3d') {
+				$groupPlot->SetShadow();
+			}
+		}
+
+		$this->_graph->Add($groupPlot);
+	}	//	function _renderPlotBar()
+
+
+	private function _renderPlotScatter($groupID,$bubble) {
+		$grouping = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+		$scatterStyle = $bubbleSize = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+		$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+		$seriesPlots = array();
+
+		//	Loop through each data series in turn
+		for($i = 0; $i < $seriesCount; ++$i) {
+			$dataValuesY = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+			$dataValuesX = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+			foreach($dataValuesY as $k => $dataValueY) {
+				$dataValuesY[$k] = $k;
+			}
+
+			$seriesPlot = new ScatterPlot($dataValuesX,$dataValuesY);
+			if ($scatterStyle == 'lineMarker') {
+				$seriesPlot->SetLinkPoints();
+				$seriesPlot->link->SetColor(self::$_colourSet[self::$_plotColour]);
+			} elseif ($scatterStyle == 'smoothMarker') {
+				$spline = new Spline($dataValuesY,$dataValuesX);
+				list($splineDataY,$splineDataX) = $spline->Get(count($dataValuesX) * self::$_width / 20);
+				$lplot = new LinePlot($splineDataX,$splineDataY);
+				$lplot->SetColor(self::$_colourSet[self::$_plotColour]);
+
+				$this->_graph->Add($lplot);
+			}
+
+			if ($bubble) {
+				$this->_formatPointMarker($seriesPlot,'dot');
+				$seriesPlot->mark->SetColor('black');
+				$seriesPlot->mark->SetSize($bubbleSize);
+			} else {
+				$marker = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+				$this->_formatPointMarker($seriesPlot,$marker);
+			}
+			$dataLabel = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+			$seriesPlot->SetLegend($dataLabel);
+
+			$this->_graph->Add($seriesPlot);
+		}
+	}	//	function _renderPlotScatter()
+
+
+	private function _renderPlotRadar($groupID) {
+		$radarStyle = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+		$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+		$seriesPlots = array();
+
+		//	Loop through each data series in turn
+		for($i = 0; $i < $seriesCount; ++$i) {
+			$dataValuesY = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+			$dataValuesX = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+			$marker = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+			$dataValues = array();
+			foreach($dataValuesY as $k => $dataValueY) {
+				$dataValues[$k] = implode(' ',array_reverse($dataValueY));
+			}
+			$tmp = array_shift($dataValues);
+			$dataValues[] = $tmp;
+			$tmp = array_shift($dataValuesX);
+			$dataValuesX[] = $tmp;
+
+			$this->_graph->SetTitles(array_reverse($dataValues));
+
+			$seriesPlot = new RadarPlot(array_reverse($dataValuesX));
+
+			$dataLabel = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+			$seriesPlot->SetColor(self::$_colourSet[self::$_plotColour++]);
+			if ($radarStyle == 'filled') {
+				$seriesPlot->SetFillColor(self::$_colourSet[self::$_plotColour]);
+			}
+			$this->_formatPointMarker($seriesPlot,$marker);
+			$seriesPlot->SetLegend($dataLabel);
+
+			$this->_graph->Add($seriesPlot);
+		}
+	}	//	function _renderPlotRadar()
+
+
+	private function _renderPlotContour($groupID) {
+		$contourStyle = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+		$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+		$seriesPlots = array();
+
+		$dataValues = array();
+		//	Loop through each data series in turn
+		for($i = 0; $i < $seriesCount; ++$i) {
+			$dataValuesY = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+			$dataValuesX = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+			$dataValues[$i] = $dataValuesX;
+		}
+		$seriesPlot = new ContourPlot($dataValues);
+
+		$this->_graph->Add($seriesPlot);
+	}	//	function _renderPlotContour()
+
+
+	private function _renderPlotStock($groupID) {
+		$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+		$plotOrder = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder();
+		$seriesPlots = array();
+
+		$dataValues = array();
+		//	Loop through each data series in turn
+		for($i = 0; $i < $seriesCount; ++$i) {
+			$dataValuesY = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+			$dataValuesX = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+			foreach($dataValuesX as $j => $dataValueX)
+			$dataValues[$j][$plotOrder[$i]] = $dataValueX;
+		}
+
+		$seriesPlot = new StockPlot($dataValues);
+
+		$this->_graph->Add($seriesPlot);
+	}	//	function _renderPlotStock()
+
+
+	private function _renderAreaChart($groupCount, $dimensions = '2d') {
+		require_once('jpgraph_line.php');
+
+		$this->_renderCartesianPlotArea();
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$this->_renderPlotLine($i,True,False,$dimensions);
+		}
+	}	//	function _renderAreaChart()
+
+
+	private function _renderLineChart($groupCount, $dimensions = '2d') {
+		require_once('jpgraph_line.php');
+
+		$this->_renderCartesianPlotArea();
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$this->_renderPlotLine($i,False,False,$dimensions);
+		}
+	}	//	function _renderLineChart()
+
+
+	private function _renderBarChart($groupCount, $dimensions = '2d') {
+		require_once('jpgraph_bar.php');
+
+		$this->_renderCartesianPlotArea();
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$this->_renderPlotBar($i,$dimensions);
+		}
+	}	//	function _renderBarChart()
+
+
+	private function _renderScatterChart($groupCount) {
+		require_once('jpgraph_scatter.php');
+		require_once('jpgraph_regstat.php');
+		require_once('jpgraph_line.php');
+
+		$this->_renderCartesianPlotArea('linlin');
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$this->_renderPlotScatter($i,false);
+		}
+	}	//	function _renderScatterChart()
+
+
+	private function _renderBubbleChart($groupCount) {
+		require_once('jpgraph_scatter.php');
+
+		$this->_renderCartesianPlotArea('linlin');
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$this->_renderPlotScatter($i,true);
+		}
+	}	//	function _renderBubbleChart()
+
+
+	private function _renderPieChart($groupCount, $dimensions = '2d', $doughnut = False, $multiplePlots = False) {
+		require_once('jpgraph_pie.php');
+		if ($dimensions == '3d') {
+			require_once('jpgraph_pie3d.php');
+		}
+
+		$this->_renderPiePlotArea($doughnut);
+
+		$iLimit = ($multiplePlots) ? $groupCount : 1;
+		for($groupID = 0; $groupID < $iLimit; ++$groupID) {
+			$grouping = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+			$exploded = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+			if ($groupID == 0) {
+		        $labelCount = count($this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
+				if ($labelCount > 0) {
+					$datasetLabels = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+					$datasetLabels = $this->_formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+				}
+			}
+
+			$seriesCount = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+			$seriesPlots = array();
+			//	For pie charts, we only display the first series: doughnut charts generally display all series
+			$jLimit = ($multiplePlots) ? $seriesCount : 1;
+			//	Loop through each data series in turn
+			for($j = 0; $j < $jLimit; ++$j) {
+				$dataValues = $this->_chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+
+				//	Fill in any missing values in the $dataValues array
+				$testCurrentIndex = 0;
+				foreach($dataValues as $k => $dataValue) {
+					while($k != $testCurrentIndex) {
+						$dataValues[$testCurrentIndex] = null;
+						++$testCurrentIndex;
+					}
+					++$testCurrentIndex;
+				}
+
+				if ($dimensions == '3d') {
+					$seriesPlot = new PiePlot3D($dataValues);
+				} else {
+					if ($doughnut) {
+						$seriesPlot = new PiePlotC($dataValues);
+					} else {
+						$seriesPlot = new PiePlot($dataValues);
+					}
+				}
+
+				if ($multiplePlots) {
+					$seriesPlot->SetSize(($jLimit-$j) / ($jLimit * 4));
+				}
+
+				if ($doughnut) {
+					$seriesPlot->SetMidColor('white');
+				}
+
+				$seriesPlot->SetColor(self::$_colourSet[self::$_plotColour++]);
+				if (count($datasetLabels) > 0)
+					$seriesPlot->SetLabels(array_fill(0,count($datasetLabels),''));
+				if ($dimensions != '3d') {
+					$seriesPlot->SetGuideLines(false);
+				}
+				if ($j == 0) {
+					if ($exploded) {
+						$seriesPlot->ExplodeAll();
+					}
+					$seriesPlot->SetLegends($datasetLabels);
+				}
+
+				$this->_graph->Add($seriesPlot);
+			}
+		}
+	}	//	function _renderPieChart()
+
+
+	private function _renderRadarChart($groupCount) {
+		require_once('jpgraph_radar.php');
+
+		$this->_renderRadarPlotArea();
+
+		for($groupID = 0; $groupID < $groupCount; ++$groupID) {
+			$this->_renderPlotRadar($groupID);
+		}
+	}	//	function _renderRadarChart()
+
+
+	private function _renderStockChart($groupCount) {
+		require_once('jpgraph_stock.php');
+
+		$this->_renderCartesianPlotArea();
+
+		for($groupID = 0; $groupID < $groupCount; ++$i) {
+			$this->_renderPlotStock($groupID);
+		}
+	}	//	function _renderStockChart()
+
+
+	private function _renderContourChart($groupCount,$dimensions) {
+		require_once('jpgraph_contour.php');
+
+		$this->_renderCartesianPlotArea('intint');
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$this->_renderPlotContour($i);
+		}
+	}	//	function _renderContourChart()
+
+
+	private function _renderCombinationChart($groupCount,$dimensions,$outputDestination) {
+		require_once('jpgraph_line.php');
+		require_once('jpgraph_bar.php');
+		require_once('jpgraph_scatter.php');
+		require_once('jpgraph_regstat.php');
+		require_once('jpgraph_line.php');
+
+		$this->_renderCartesianPlotArea();
+
+		for($i = 0; $i < $groupCount; ++$i) {
+			$dimensions = null;
+			$chartType = $this->_chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+			switch ($chartType) {
+				case 'area3DChart' :
+					$dimensions = '3d';
+				case 'areaChart' :
+					$this->_renderPlotLine($i,True,True,$dimensions);
+					break;
+				case 'bar3DChart' :
+					$dimensions = '3d';
+				case 'barChart' :
+					$this->_renderPlotBar($i,$dimensions);
+					break;
+				case 'line3DChart' :
+					$dimensions = '3d';
+				case 'lineChart' :
+					$this->_renderPlotLine($i,False,True,$dimensions);
+					break;
+				case 'scatterChart' :
+					$this->_renderPlotScatter($i,false);
+					break;
+				case 'bubbleChart' :
+					$this->_renderPlotScatter($i,true);
+					break;
+				default	:
+					$this->_graph = null;
+					return false;
+			}
+		}
+
+		$this->_renderLegend();
+
+		$this->_graph->Stroke($outputDestination);
+		return true;
+	}	//	function _renderCombinationChart()
+
+
+	public function render($outputDestination) {
+        self::$_plotColour = 0;
+
+		$groupCount = $this->_chart->getPlotArea()->getPlotGroupCount();
+
+		$dimensions = null;
+		if ($groupCount == 1) {
+			$chartType = $this->_chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType();
+		} else {
+			$chartTypes = array();
+			for($i = 0; $i < $groupCount; ++$i) {
+				$chartTypes[] = $this->_chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+			}
+			$chartTypes = array_unique($chartTypes);
+			if (count($chartTypes) == 1) {
+				$chartType = array_pop($chartTypes);
+			} elseif (count($chartTypes) == 0) {
+				echo 'Chart is not yet implemented<br />';
+				return false;
+			} else {
+				return $this->_renderCombinationChart($groupCount,$dimensions,$outputDestination);
+			}
+		}
+
+		switch ($chartType) {
+			case 'area3DChart' :
+				$dimensions = '3d';
+			case 'areaChart' :
+				$this->_renderAreaChart($groupCount,$dimensions);
+				break;
+			case 'bar3DChart' :
+				$dimensions = '3d';
+			case 'barChart' :
+				$this->_renderBarChart($groupCount,$dimensions);
+				break;
+			case 'line3DChart' :
+				$dimensions = '3d';
+			case 'lineChart' :
+				$this->_renderLineChart($groupCount,$dimensions);
+				break;
+			case 'pie3DChart' :
+				$dimensions = '3d';
+			case 'pieChart' :
+				$this->_renderPieChart($groupCount,$dimensions,False,False);
+				break;
+			case 'doughnut3DChart' :
+				$dimensions = '3d';
+			case 'doughnutChart' :
+				$this->_renderPieChart($groupCount,$dimensions,True,True);
+				break;
+			case 'scatterChart' :
+				$this->_renderScatterChart($groupCount);
+				break;
+			case 'bubbleChart' :
+				$this->_renderBubbleChart($groupCount);
+				break;
+			case 'radarChart' :
+				$this->_renderRadarChart($groupCount);
+				break;
+			case 'surface3DChart' :
+				$dimensions = '3d';
+			case 'surfaceChart' :
+				$this->_renderContourChart($groupCount,$dimensions);
+				break;
+			case 'stockChart' :
+				$this->_renderStockChart($groupCount,$dimensions);
+				break;
+			default	:
+				echo $chartType.' is not yet implemented<br />';
+				return false;
+		}
+		$this->_renderLegend();
+
+		$this->_graph->Stroke($outputDestination);
+		return true;
+	}	//	function render()
+
+
+	/**
+	 * Create a new PHPExcel_Chart_Renderer_jpgraph
+	 */
+	public function __construct(PHPExcel_Chart $chart)
+	{
+		$this->_graph	= null;
+		$this->_chart	= $chart;
+	}	//	function __construct()
+
+}	//	PHPExcel_Chart_Renderer_jpgraph

+ 89 - 0
htdocs/includes/phpexcel/PHPExcel/Chart/Title.php

@@ -0,0 +1,89 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Chart_Title
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Chart
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Chart_Title
+{
+
+	/**
+	 * Title Caption
+	 *
+	 * @var string
+	 */
+	private $_caption = null;
+
+	/**
+	 * Title Layout
+	 *
+	 * @var PHPExcel_Chart_Layout
+	 */
+	private $_layout = null;
+
+	/**
+	 * Create a new PHPExcel_Chart_Title
+	 */
+	public function __construct($caption = null, PHPExcel_Chart_Layout $layout = null)
+	{
+		$this->_caption = $caption;
+		$this->_layout = $layout;
+	}
+
+	/**
+	 * Get caption
+	 *
+	 * @return string
+	 */
+	public function getCaption() {
+		return $this->_caption;
+	}
+
+	/**
+	 * Set caption
+	 *
+	 * @param string $caption
+	 */
+	public function setCaption($caption = null) {
+		$this->_caption = $caption;
+	}
+
+	/**
+	 * Get Layout
+	 *
+	 * @return PHPExcel_Chart_Layout
+	 */
+	public function getLayout() {
+		return $this->_layout;
+	}
+
+}

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Comment.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Comment implements PHPExcel_IComparable
 {

+ 23 - 23
htdocs/includes/phpexcel/PHPExcel/DocumentProperties.php

@@ -1,28 +1,28 @@
 <?php
 /**
- *	PHPExcel
+ * PHPExcel
  *
- *	Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
- *	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 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.
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
- *	@category	PHPExcel
- *	@package	PHPExcel
- *	@copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- *	@license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- *	@version	1.7.6, 2011-02-27
+ * @category	PHPExcel
+ * @package	PHPExcel
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category	PHPExcel
  * @package		PHPExcel
- * @copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_DocumentProperties
 {
@@ -196,7 +196,7 @@ class PHPExcel_DocumentProperties
 	 * @return	PHPExcel_DocumentProperties
 	 */
 	public function setCreated($pValue = null) {
-		if (is_null($pValue)) {
+		if ($pValue === NULL) {
 			$pValue = time();
 		} elseif (is_string($pValue)) {
 			if (is_numeric($pValue)) {
@@ -226,7 +226,7 @@ class PHPExcel_DocumentProperties
 	 * @return	PHPExcel_DocumentProperties
 	 */
 	public function setModified($pValue = null) {
-		if (is_null($pValue)) {
+		if ($pValue === NULL) {
 			$pValue = time();
 		} elseif (is_string($pValue)) {
 			if (is_numeric($pValue)) {
@@ -439,12 +439,12 @@ class PHPExcel_DocumentProperties
 	 * @return	PHPExcel_DocumentProperties
 	 */
 	public function setCustomProperty($propertyName,$propertyValue='',$propertyType=NULL) {
-		if ((is_null($propertyType)) || (!in_array($propertyType,array(self::PROPERTY_TYPE_INTEGER,
+		if (($propertyType === NULL) || (!in_array($propertyType,array(self::PROPERTY_TYPE_INTEGER,
 																	   self::PROPERTY_TYPE_FLOAT,
 																	   self::PROPERTY_TYPE_STRING,
 																	   self::PROPERTY_TYPE_DATE,
 																	   self::PROPERTY_TYPE_BOOLEAN)))) {
-			if (is_null($propertyValue)) {
+			if ($propertyValue === NULL) {
 				$propertyType = self::PROPERTY_TYPE_STRING;
 			} elseif (is_float($propertyValue)) {
 				$propertyType = self::PROPERTY_TYPE_FLOAT;

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/DocumentSecurity.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_DocumentSecurity
 {

+ 52 - 0
htdocs/includes/phpexcel/PHPExcel/Exception.php

@@ -0,0 +1,52 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version	1.7.8, 2012-10-12
+ */
+
+
+/**
+ * PHPExcel_Exception
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Exception extends Exception {
+	/**
+	 * Error handler callback
+	 *
+	 * @param mixed $code
+	 * @param mixed $string
+	 * @param mixed $file
+	 * @param mixed $line
+	 * @param mixed $context
+	 */
+	public static function errorHandlerCallback($code, $string, $file, $line, $context) {
+		$e = new self($string, $code);
+		$e->line = $line;
+		$e->file = $file;
+		throw $e;
+	}
+}

+ 5 - 5
htdocs/includes/phpexcel/PHPExcel/HashTable.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package	PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version	1.7.6, 2011-02-27
+ * @version	1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package	PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_HashTable
 {
@@ -57,7 +57,7 @@ class PHPExcel_HashTable
 	 */
 	public function __construct($pSource = null)
 	{
-		if (!is_null($pSource)) {
+		if ($pSource !== NULL) {
 			// Create HashTable
 			$this->addFromSource($pSource);
 		}

+ 6 - 6
htdocs/includes/phpexcel/PHPExcel/IComparable.php

@@ -6,21 +6,21 @@
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -29,7 +29,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 interface PHPExcel_IComparable
 {
@@ -37,7 +37,7 @@ interface PHPExcel_IComparable
 	 * Get hash code
 	 *
 	 * @return string	Hash code
-	 */	
+	 */
 	public function getHashCode();
 
 }

+ 96 - 82
htdocs/includes/phpexcel/PHPExcel/IOFactory.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,16 +20,16 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
 /**	PHPExcel root directory */
 if (!defined('PHPEXCEL_ROOT')) {
 	/**
-	 *	@ignore
+	 * @ignore
 	 */
 	define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../');
 	require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
@@ -40,16 +40,16 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_IOFactory
 {
 	/**
-	 *	Search locations
+	 * Search locations
 	 *
-	 *	@var	array
-	 *	@access	private
-	 *	@static
+	 * @var	array
+	 * @access	private
+	 * @static
 	 */
 	private static $_searchLocations = array(
 		array( 'type' => 'IWriter', 'path' => 'PHPExcel/Writer/{0}.php', 'class' => 'PHPExcel_Writer_{0}' ),
@@ -57,11 +57,11 @@ class PHPExcel_IOFactory
 	);
 
 	/**
-	 *	Autoresolve classes
+	 * Autoresolve classes
 	 *
-	 *	@var	array
-	 *	@access	private
-	 *	@static
+	 * @var	array
+	 * @access	private
+	 * @static
 	 */
 	private static $_autoResolveClasses = array(
 		'Excel2007',
@@ -70,6 +70,7 @@ class PHPExcel_IOFactory
 		'OOCalc',
 		'SYLK',
 		'Gnumeric',
+		'HTML',
 		'CSV',
 	);
 
@@ -79,23 +80,23 @@ class PHPExcel_IOFactory
     private function __construct() { }
 
     /**
-     *	Get search locations
+     * Get search locations
      *
-	 *	@static
-	 *	@access	public
-     *	@return	array
+	 * @static
+	 * @access	public
+     * @return	array
      */
 	public static function getSearchLocations() {
 		return self::$_searchLocations;
 	}	//	function getSearchLocations()
 
 	/**
-	 *	Set search locations
+	 * Set search locations
 	 *
-	 *	@static
-	 *	@access	public
-	 *	@param	array $value
-	 *	@throws	Exception
+	 * @static
+	 * @access	public
+	 * @param	array $value
+	 * @throws	Exception
 	 */
 	public static function setSearchLocations($value) {
 		if (is_array($value)) {
@@ -106,27 +107,27 @@ class PHPExcel_IOFactory
 	}	//	function setSearchLocations()
 
 	/**
-	 *	Add search location
+	 * Add search location
 	 *
-	 *	@static
-	 *	@access	public
-	 *	@param	string $type		Example: IWriter
-	 *	@param	string $location	Example: PHPExcel/Writer/{0}.php
-	 *	@param	string $classname 	Example: PHPExcel_Writer_{0}
+	 * @static
+	 * @access	public
+	 * @param	string $type		Example: IWriter
+	 * @param	string $location	Example: PHPExcel/Writer/{0}.php
+	 * @param	string $classname 	Example: PHPExcel_Writer_{0}
 	 */
 	public static function addSearchLocation($type = '', $location = '', $classname = '') {
 		self::$_searchLocations[] = array( 'type' => $type, 'path' => $location, 'class' => $classname );
 	}	//	function addSearchLocation()
 
 	/**
-	 *	Create PHPExcel_Writer_IWriter
+	 * Create PHPExcel_Writer_IWriter
 	 *
-	 *	@static
-	 *	@access	public
-	 *	@param	PHPExcel $phpExcel
-	 *	@param	string  $writerType	Example: Excel2007
-	 *	@return	PHPExcel_Writer_IWriter
-	 *	@throws	Exception
+	 * @static
+	 * @access	public
+	 * @param	PHPExcel $phpExcel
+	 * @param	string  $writerType	Example: Excel2007
+	 * @return	PHPExcel_Writer_IWriter
+	 * @throws	Exception
 	 */
 	public static function createWriter(PHPExcel $phpExcel, $writerType = '') {
 		// Search type
@@ -136,10 +137,9 @@ class PHPExcel_IOFactory
 		foreach (self::$_searchLocations as $searchLocation) {
 			if ($searchLocation['type'] == $searchType) {
 				$className = str_replace('{0}', $writerType, $searchLocation['class']);
-				$classFile = str_replace('{0}', $writerType, $searchLocation['path']);
 
 				$instance = new $className($phpExcel);
-				if (!is_null($instance)) {
+				if ($instance !== NULL) {
 					return $instance;
 				}
 			}
@@ -150,13 +150,13 @@ class PHPExcel_IOFactory
 	}	//	function createWriter()
 
 	/**
-	 *	Create PHPExcel_Reader_IReader
+	 * Create PHPExcel_Reader_IReader
 	 *
-	 *	@static
-	 *	@access	public
-	 *	@param	string $readerType	Example: Excel2007
-	 *	@return	PHPExcel_Reader_IReader
-	 *	@throws	Exception
+	 * @static
+	 * @access	public
+	 * @param	string $readerType	Example: Excel2007
+	 * @return	PHPExcel_Reader_IReader
+	 * @throws	Exception
 	 */
 	public static function createReader($readerType = '') {
 		// Search type
@@ -166,10 +166,9 @@ class PHPExcel_IOFactory
 		foreach (self::$_searchLocations as $searchLocation) {
 			if ($searchLocation['type'] == $searchType) {
 				$className = str_replace('{0}', $readerType, $searchLocation['class']);
-				$classFile = str_replace('{0}', $readerType, $searchLocation['path']);
 
 				$instance = new $className();
-				if (!is_null($instance)) {
+				if ($instance !== NULL) {
 					return $instance;
 				}
 			}
@@ -180,13 +179,13 @@ class PHPExcel_IOFactory
 	}	//	function createReader()
 
 	/**
-	 *	Loads PHPExcel from file using automatic PHPExcel_Reader_IReader resolution
+	 * Loads PHPExcel from file using automatic PHPExcel_Reader_IReader resolution
 	 *
-	 *	@static
-	 *	@access public
-	 *	@param 	string 		$pFileName
-	 *	@return	PHPExcel
-	 *	@throws	Exception
+	 * @static
+	 * @access public
+	 * @param 	string 		$pFileName		The name of the spreadsheet file
+	 * @return	PHPExcel
+	 * @throws	Exception
 	 */
 	public static function load($pFilename) {
 		$reader = self::createReaderForFile($pFilename);
@@ -194,13 +193,13 @@ class PHPExcel_IOFactory
 	}	//	function load()
 
 	/**
-	 *	Identify file type using automatic PHPExcel_Reader_IReader resolution
+	 * Identify file type using automatic PHPExcel_Reader_IReader resolution
 	 *
-	 *	@static
-	 *	@access public
-	 *	@param 	string 		$pFileName
-	 *	@return	string
-	 *	@throws	Exception
+	 * @static
+	 * @access public
+	 * @param 	string 		$pFileName		The name of the spreadsheet file to identify
+	 * @return	string
+	 * @throws	Exception
 	 */
 	public static function identify($pFilename) {
 		$reader = self::createReaderForFile($pFilename);
@@ -211,38 +210,48 @@ class PHPExcel_IOFactory
 	}	//	function identify()
 
 	/**
-	 *	Create PHPExcel_Reader_IReader for file using automatic PHPExcel_Reader_IReader resolution
+	 * Create PHPExcel_Reader_IReader for file using automatic PHPExcel_Reader_IReader resolution
 	 *
-	 *	@static
-	 *	@access	public
-	 *	@param 	string 		$pFileName
-	 *	@return	PHPExcel_Reader_IReader
-	 *	@throws	Exception
+	 * @static
+	 * @access	public
+	 * @param 	string 		$pFileName		The name of the spreadsheet file
+	 * @return	PHPExcel_Reader_IReader
+	 * @throws	Exception
 	 */
 	public static function createReaderForFile($pFilename) {
 
 		// First, lucky guess by inspecting file extension
 		$pathinfo = pathinfo($pFilename);
 
+		$extensionType = NULL;
 		if (isset($pathinfo['extension'])) {
 			switch (strtolower($pathinfo['extension'])) {
-				case 'xlsx':
-					$reader = self::createReader('Excel2007');
+				case 'xlsx':			//	Excel (OfficeOpenXML) Spreadsheet
+				case 'xlsm':			//	Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded)
+				case 'xltx':			//	Excel (OfficeOpenXML) Template
+				case 'xltm':			//	Excel (OfficeOpenXML) Macro Template (macros will be discarded)
+					$extensionType = 'Excel2007';
 					break;
-				case 'xls':
-					$reader = self::createReader('Excel5');
+				case 'xls':				//	Excel (BIFF) Spreadsheet
+				case 'xlt':				//	Excel (BIFF) Template
+					$extensionType = 'Excel5';
 					break;
-				case 'ods':
-					$reader = self::createReader('OOCalc');
+				case 'ods':				//	Open/Libre Offic Calc
+				case 'ots':				//	Open/Libre Offic Calc Template
+					$extensionType = 'OOCalc';
 					break;
 				case 'slk':
-					$reader = self::createReader('SYLK');
+					$extensionType = 'SYLK';
 					break;
-				case 'xml':
-					$reader = self::createReader('Excel2003XML');
+				case 'xml':				//	Excel 2003 SpreadSheetML
+					$extensionType = 'Excel2003XML';
 					break;
 				case 'gnumeric':
-					$reader = self::createReader('Gnumeric');
+					$extensionType = 'Gnumeric';
+					break;
+				case 'htm':
+				case 'html':
+					$extensionType = 'HTML';
 					break;
 				case 'csv':
 					// Do nothing
@@ -253,22 +262,27 @@ class PHPExcel_IOFactory
 					break;
 			}
 
-			// Let's see if we are lucky
-			if (isset($reader) && $reader->canRead($pFilename)) {
-				return $reader;
+			if ($extensionType !== NULL) {
+				$reader = self::createReader($extensionType);
+				// Let's see if we are lucky
+				if (isset($reader) && $reader->canRead($pFilename)) {
+					return $reader;
+				}
 			}
-
 		}
 
 		// If we reach here then "lucky guess" didn't give any result
-
-		// Try loading using self::$_autoResolveClasses
+		// Try walking through all the options in self::$_autoResolveClasses
 		foreach (self::$_autoResolveClasses as $autoResolveClass) {
-			$reader = self::createReader($autoResolveClass);
-			if ($reader->canRead($pFilename)) {
-				return $reader;
+			//	Ignore our original guess, we know that won't work
+			if ($autoResolveClass !== $extensionType) {
+				$reader = self::createReader($autoResolveClass);
+				if ($reader->canRead($pFilename)) {
+					return $reader;
+				}
 			}
 		}
 
+		throw new Exception('Unable to identify a reader for this file');
 	}	//	function createReaderForFile()
 }

+ 10 - 10
htdocs/includes/phpexcel/PHPExcel/NamedRange.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_NamedRange
 {
@@ -82,7 +82,7 @@ class PHPExcel_NamedRange
     public function __construct($pName = null, PHPExcel_Worksheet $pWorksheet, $pRange = 'A1', $pLocalOnly = false, $pScope = null)
     {
     	// Validate data
-    	if (is_null($pName) || is_null($pWorksheet)|| is_null($pRange)) {
+    	if (($pName === NULL) || ($pWorksheet === NULL) || ($pRange === NULL)) {
     		throw new Exception('Parameters can not be null.');
     	}
 
@@ -111,17 +111,17 @@ class PHPExcel_NamedRange
      * @return PHPExcel_NamedRange
      */
     public function setName($value = null) {
-    	if (!is_null($value)) {
+    	if ($value !== NULL) {
     		// Old title
     		$oldTitle = $this->_name;
 
     		// Re-attach
-    		if (!is_null($this->_worksheet)) {
+    		if ($this->_worksheet !== NULL) {
     			$this->_worksheet->getParent()->removeNamedRange($this->_name,$this->_worksheet);
     		}
     		$this->_name = $value;
 
-    		if (!is_null($this->_worksheet)) {
+    		if ($this->_worksheet !== NULL) {
     			$this->_worksheet->getParent()->addNamedRange($this);
     		}
 
@@ -148,7 +148,7 @@ class PHPExcel_NamedRange
      * @return PHPExcel_NamedRange
      */
     public function setWorksheet(PHPExcel_Worksheet $value = null) {
-    	if (!is_null($value)) {
+    	if ($value !== NULL) {
     		$this->_worksheet = $value;
     	}
     	return $this;
@@ -170,7 +170,7 @@ class PHPExcel_NamedRange
      * @return PHPExcel_NamedRange
      */
     public function setRange($value = null) {
-    	if (!is_null($value)) {
+    	if ($value !== NULL) {
     		$this->_range = $value;
     	}
     	return $this;

+ 199 - 105
htdocs/includes/phpexcel/PHPExcel/Reader/CSV.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -40,89 +40,91 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 {
 	/**
-	 *	Input encoding
+	 * Input encoding
 	 *
-	 *	@access	private
-	 *	@var	string
+	 * @access	private
+	 * @var	string
 	 */
 	private $_inputEncoding	= 'UTF-8';
 
 	/**
-	 *	Delimiter
+	 * Delimiter
 	 *
-	 *	@access	private
-	 *	@var string
+	 * @access	private
+	 * @var string
 	 */
 	private $_delimiter		= ',';
 
 	/**
-	 *	Enclosure
+	 * Enclosure
 	 *
-	 *	@access	private
-	 *	@var	string
+	 * @access	private
+	 * @var	string
 	 */
 	private $_enclosure		= '"';
 
 	/**
-	 *	Line ending
+	 * Line ending
 	 *
-	 *	@access	private
-	 *	@var	string
+	 * @access	private
+	 * @var	string
 	 */
 	private $_lineEnding	= PHP_EOL;
 
 	/**
-	 *	Sheet index to read
+	 * Sheet index to read
 	 *
-	 *	@access	private
-	 *	@var	int
+	 * @access	private
+	 * @var	int
 	 */
 	private $_sheetIndex	= 0;
 
 	/**
-	 *	Load rows contiguously
+	 * Load rows contiguously
 	 *
-	 *	@access	private
-	 *	@var	int
+	 * @access	private
+	 * @var	int
 	 */
 	private $_contiguous	= false;
 
 
 	/**
-	 *	Row counter for loading rows contiguously
+	 * Row counter for loading rows contiguously
 	 *
-	 *	@access	private
-	 *	@var	int
+	 * @access	private
+	 * @var	int
 	 */
 	private $_contiguousRow	= -1;
 
 	/**
-	 *	PHPExcel_Reader_IReadFilter instance
+	 * PHPExcel_Reader_IReadFilter instance
 	 *
-	 *	@access	private
-	 *	@var	PHPExcel_Reader_IReadFilter
+	 * @access	private
+	 * @var	PHPExcel_Reader_IReadFilter
 	 */
 	private $_readFilter = null;
 
+
 	/**
-	 *	Create a new PHPExcel_Reader_CSV
+	 * Create a new PHPExcel_Reader_CSV
 	 */
 	public function __construct() {
 		$this->_readFilter		= new PHPExcel_Reader_DefaultReadFilter();
 	}	//	function __construct()
 
+
 	/**
-	 *	Can the current PHPExcel_Reader_IReader read the file?
+	 * Can the current PHPExcel_Reader_IReader read the file?
 	 *
-	 *	@access	public
-	 *	@param 	string 		$pFileName
-	 *	@return boolean
-	 *	@throws Exception
+	 * @access	public
+	 * @param 	string 		$pFileName
+	 * @return boolean
+	 * @throws Exception
 	 */
 	public function canRead($pFilename)
 	{
@@ -134,49 +136,35 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 		return true;
 	}	//	function canRead()
 
-	/**
-	 *	Loads PHPExcel from file
-	 *
-	 *	@access	public
-	 *	@param 	string 		$pFilename
-	 *	@return PHPExcel
-	 *	@throws Exception
-	 */
-	public function load($pFilename)
-	{
-		// Create new PHPExcel
-		$objPHPExcel = new PHPExcel();
-
-		// Load into this instance
-		return $this->loadIntoExisting($pFilename, $objPHPExcel);
-	}	//	function load()
 
 	/**
-	 *	Read filter
+	 * Read filter
 	 *
-	 *	@access	public
-	 *	@return PHPExcel_Reader_IReadFilter
+	 * @access	public
+	 * @return PHPExcel_Reader_IReadFilter
 	 */
 	public function getReadFilter() {
 		return $this->_readFilter;
 	}	//	function getReadFilter()
 
+
 	/**
-	 *	Set read filter
+	 * Set read filter
 	 *
-	 *	@access	public
-	 *	@param	PHPExcel_Reader_IReadFilter $pValue
+	 * @access	public
+	 * @param	PHPExcel_Reader_IReadFilter $pValue
 	 */
 	public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
 		$this->_readFilter = $pValue;
 		return $this;
 	}	//	function setReadFilter()
 
+
 	/**
-	 *	Set input encoding
+	 * Set input encoding
 	 *
-	 *	@access	public
-	 *	@param string $pValue Input encoding
+	 * @access	public
+	 * @param string $pValue Input encoding
 	 */
 	public function setInputEncoding($pValue = 'UTF-8')
 	{
@@ -184,25 +172,116 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 		return $this;
 	}	//	function setInputEncoding()
 
+
 	/**
-	 *	Get input encoding
+	 * Get input encoding
 	 *
-	 *	@access	public
-	 *	@return string
+	 * @access	public
+	 * @return string
 	 */
 	public function getInputEncoding()
 	{
 		return $this->_inputEncoding;
 	}	//	function getInputEncoding()
 
+
 	/**
-	 *	Loads PHPExcel from file into PHPExcel instance
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
 	 *
-	 *	@access	public
-	 *	@param 	string 		$pFilename
-	 *	@param	PHPExcel	$objPHPExcel
-	 *	@return 	PHPExcel
-	 *	@throws 	Exception
+	 * @access	public
+	 * @param 	string 		$pFilename
+	 * @throws	Exception
+	 */
+	public function listWorksheetInfo($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		// Open file
+		$fileHandle = fopen($pFilename, 'r');
+		if ($fileHandle === false) {
+			throw new Exception("Could not open file " . $pFilename . " for reading.");
+		}
+
+		// Skip BOM, if any
+		switch ($this->_inputEncoding) {
+			case 'UTF-8':
+				fgets($fileHandle, 4) == "\xEF\xBB\xBF" ?
+				fseek($fileHandle, 3) : fseek($fileHandle, 0);
+				break;
+			case 'UTF-16LE':
+				fgets($fileHandle, 3) == "\xFF\xFE" ?
+				fseek($fileHandle, 2) : fseek($fileHandle, 0);
+				break;
+			case 'UTF-16BE':
+				fgets($fileHandle, 3) == "\xFE\xFF" ?
+				fseek($fileHandle, 2) : fseek($fileHandle, 0);
+				break;
+			case 'UTF-32LE':
+				fgets($fileHandle, 5) == "\xFF\xFE\x00\x00" ?
+				fseek($fileHandle, 4) : fseek($fileHandle, 0);
+				break;
+			case 'UTF-32BE':
+				fgets($fileHandle, 5) == "\x00\x00\xFE\xFF" ?
+				fseek($fileHandle, 4) : fseek($fileHandle, 0);
+				break;
+			default:
+				break;
+		}
+
+		$escapeEnclosures = array( "\\" . $this->_enclosure, $this->_enclosure . $this->_enclosure );
+
+		$worksheetInfo = array();
+		$worksheetInfo[0]['worksheetName'] = 'Worksheet';
+		$worksheetInfo[0]['lastColumnLetter'] = 'A';
+		$worksheetInfo[0]['lastColumnIndex'] = 0;
+		$worksheetInfo[0]['totalRows'] = 0;
+		$worksheetInfo[0]['totalColumns'] = 0;
+
+		// Loop through each line of the file in turn
+		while (($rowData = fgetcsv($fileHandle, 0, $this->_delimiter, $this->_enclosure)) !== FALSE) {
+			$worksheetInfo[0]['totalRows']++;
+			$worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], count($rowData) - 1);
+		}
+
+		$worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
+		$worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
+
+		// Close file
+		fclose($fileHandle);
+
+		return $worksheetInfo;
+	}
+
+
+	/**
+	 * Loads PHPExcel from file
+	 *
+	 * @access	public
+	 * @param 	string 		$pFilename
+	 * @return PHPExcel
+	 * @throws Exception
+	 */
+	public function load($pFilename)
+	{
+		// Create new PHPExcel
+		$objPHPExcel = new PHPExcel();
+
+		// Load into this instance
+		return $this->loadIntoExisting($pFilename, $objPHPExcel);
+	}	//	function load()
+
+
+	/**
+	 * Loads PHPExcel from file into PHPExcel instance
+	 *
+	 * @access	public
+	 * @param 	string 		$pFilename
+	 * @param	PHPExcel	$objPHPExcel
+	 * @return 	PHPExcel
+	 * @throws 	Exception
 	 */
 	public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
 	{
@@ -215,7 +294,10 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 		while ($objPHPExcel->getSheetCount() <= $this->_sheetIndex) {
 			$objPHPExcel->createSheet();
 		}
-		$objPHPExcel->setActiveSheetIndex( $this->_sheetIndex );
+		$sheet = $objPHPExcel->setActiveSheetIndex( $this->_sheetIndex );
+
+		$lineEnding = ini_get('auto_detect_line_endings');
+		ini_set('auto_detect_line_endings', true);
 
 		// Open file
 		$fileHandle = fopen($pFilename, 'r');
@@ -256,7 +338,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 		// Set our starting row based on whether we're in contiguous mode or not
 		$currentRow = 1;
 		if ($this->_contiguous) {
-			$currentRow = ($this->_contiguousRow == -1) ? $objPHPExcel->getActiveSheet()->getHighestRow(): $this->_contiguousRow;
+			$currentRow = ($this->_contiguousRow == -1) ? $sheet->getHighestRow(): $this->_contiguousRow;
 		}
 
 		// Loop through each line of the file in turn
@@ -273,7 +355,7 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 					}
 
 					// Set cell value
-					$objPHPExcel->getActiveSheet()->getCell($columnLetter . $currentRow)->setValue($rowDatum);
+					$sheet->getCell($columnLetter . $currentRow)->setValue($rowDatum);
 				}
 				++$columnLetter;
 			}
@@ -287,48 +369,54 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 			$this->_contiguousRow = $currentRow;
 		}
 
+		ini_set('auto_detect_line_endings', $lineEnding);
+
 		// Return
 		return $objPHPExcel;
 	}	//	function loadIntoExisting()
 
+
 	/**
-	 *	Get delimiter
+	 * Get delimiter
 	 *
-	 *	@access	public
-	 *	@return string
+	 * @access	public
+	 * @return string
 	 */
 	public function getDelimiter() {
 		return $this->_delimiter;
 	}	//	function getDelimiter()
 
+
 	/**
-	 *	Set delimiter
+	 * Set delimiter
 	 *
-	 *	@access	public
-	 *	@param	string	$pValue		Delimiter, defaults to ,
-	 *	@return	PHPExcel_Reader_CSV
+	 * @access	public
+	 * @param	string	$pValue		Delimiter, defaults to ,
+	 * @return	PHPExcel_Reader_CSV
 	 */
 	public function setDelimiter($pValue = ',') {
 		$this->_delimiter = $pValue;
 		return $this;
 	}	//	function setDelimiter()
 
+
 	/**
-	 *	Get enclosure
+	 * Get enclosure
 	 *
-	 *	@access	public
-	 *	@return string
+	 * @access	public
+	 * @return string
 	 */
 	public function getEnclosure() {
 		return $this->_enclosure;
 	}	//	function getEnclosure()
 
+
 	/**
-	 *	Set enclosure
+	 * Set enclosure
 	 *
-	 *	@access	public
-	 *	@param	string	$pValue		Enclosure, defaults to "
-	 *	@return PHPExcel_Reader_CSV
+	 * @access	public
+	 * @param	string	$pValue		Enclosure, defaults to "
+	 * @return PHPExcel_Reader_CSV
 	 */
 	public function setEnclosure($pValue = '"') {
 		if ($pValue == '') {
@@ -338,55 +426,60 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 		return $this;
 	}	//	function setEnclosure()
 
+
 	/**
-	 *	Get line ending
+	 * Get line ending
 	 *
-	 *	@access	public
-	 *	@return string
+	 * @access	public
+	 * @return string
 	 */
 	public function getLineEnding() {
 		return $this->_lineEnding;
 	}	//	function getLineEnding()
 
+
 	/**
-	 *	Set line ending
+	 * Set line ending
 	 *
-	 *	@access	public
-	 *	@param	string	$pValue		Line ending, defaults to OS line ending (PHP_EOL)
-	 *	@return PHPExcel_Reader_CSV
+	 * @access	public
+	 * @param	string	$pValue		Line ending, defaults to OS line ending (PHP_EOL)
+	 * @return PHPExcel_Reader_CSV
 	 */
 	public function setLineEnding($pValue = PHP_EOL) {
 		$this->_lineEnding = $pValue;
 		return $this;
 	}	//	function setLineEnding()
 
+
 	/**
-	 *	Get sheet index
+	 * Get sheet index
 	 *
-	 *	@access	public
-	 *	@return int
+	 * @access	public
+	 * @return int
 	 */
 	public function getSheetIndex() {
 		return $this->_sheetIndex;
 	}	//	function getSheetIndex()
 
+
 	/**
-	 *	Set sheet index
+	 * Set sheet index
 	 *
-	 *	@access	public
-	 *	@param	int		$pValue		Sheet index
-	 *	@return PHPExcel_Reader_CSV
+	 * @access	public
+	 * @param	int		$pValue		Sheet index
+	 * @return PHPExcel_Reader_CSV
 	 */
 	public function setSheetIndex($pValue = 0) {
 		$this->_sheetIndex = $pValue;
 		return $this;
 	}	//	function setSheetIndex()
 
+
 	/**
-	 *	Set Contiguous
+	 * Set Contiguous
 	 *
-	 *	@access	public
-	 *	@param string $pValue Input encoding
+	 * @access	public
+	 * @param string $pValue Input encoding
 	 */
 	public function setContiguous($contiguous = false)
 	{
@@ -398,11 +491,12 @@ class PHPExcel_Reader_CSV implements PHPExcel_Reader_IReader
 		return $this;
 	}	//	function setInputEncoding()
 
+
 	/**
-	 *	Get Contiguous
+	 * Get Contiguous
 	 *
-	 *	@access	public
-	 *	@return boolean
+	 * @access	public
+	 * @return boolean
 	 */
 	public function getContiguous() {
 		return $this->_contiguous;

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Reader/DefaultReadFilter.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -40,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_DefaultReadFilter implements PHPExcel_Reader_IReadFilter
 {

+ 156 - 37
htdocs/includes/phpexcel/PHPExcel/Reader/Excel2003XML.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -40,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 {
@@ -72,6 +72,21 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 	 */
 	private $_readFilter = null;
 
+	/**
+	 * Character set used in the file
+	 *
+	 * @var string
+	 */
+	private $_charSet = 'UTF-8';
+
+
+	/**
+	 * Create a new PHPExcel_Reader_Excel2003XML
+	 */
+	public function __construct() {
+		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
+	}
+
 
 	/**
 	 * Read data only?
@@ -82,6 +97,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this->_readDataOnly;
 	}
 
+
 	/**
 	 * Set read data only
 	 *
@@ -93,6 +109,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Get which sheets to load
 	 *
@@ -103,6 +120,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this->_loadSheetsOnly;
 	}
 
+
 	/**
 	 * Set which sheets to load
 	 *
@@ -116,6 +134,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Set all sheets to load
 	 *
@@ -127,6 +146,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Read filter
 	 *
@@ -136,6 +156,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this->_readFilter;
 	}
 
+
 	/**
 	 * Set read filter
 	 *
@@ -147,31 +168,26 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
-	/**
-	 * Create a new PHPExcel_Reader_Excel2003XML
-	 */
-	public function __construct() {
-		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
-	}
 
 	/**
 	 * Can the current PHPExcel_Reader_IReader read the file?
 	 *
 	 * @param 	string 		$pFileName
 	 * @return 	boolean
+	 * @throws Exception
 	 */
 	public function canRead($pFilename)
 	{
 
-//	Office					xmlns:o="urn:schemas-microsoft-com:office:office"
-//	Excel					xmlns:x="urn:schemas-microsoft-com:office:excel"
-//	XML Spreadsheet			xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
-//	Spreadsheet component	xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet"
-//	XML schema 				xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
-//	XML data type			xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
-//	MS-persist recordset	xmlns:rs="urn:schemas-microsoft-com:rowset"
-//	Rowset					xmlns:z="#RowsetSchema"
-//
+		//	Office					xmlns:o="urn:schemas-microsoft-com:office:office"
+		//	Excel					xmlns:x="urn:schemas-microsoft-com:office:excel"
+		//	XML Spreadsheet			xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
+		//	Spreadsheet component	xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet"
+		//	XML schema 				xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
+		//	XML data type			xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
+		//	MS-persist recordset	xmlns:rs="urn:schemas-microsoft-com:rowset"
+		//	Rowset					xmlns:z="#RowsetSchema"
+		//
 
 		$signature = array(
 				'<?xml version="1.0"',
@@ -197,9 +213,16 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 			}
 		}
 
+		//	Retrieve charset encoding
+		if(preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/um',$data,$matches)) {
+			$this->_charSet = strtoupper($matches[1]);
+		}
+//		echo 'Character Set is ',$this->_charSet,'<br />';
+
 		return $valid;
 	}
 
+
 	/**
 	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
 	 *
@@ -212,6 +235,9 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		if (!file_exists($pFilename)) {
 			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
 		}
+		if (!$this->canRead($pFilename)) {
+			throw new Exception($pFilename . " is an Invalid Spreadsheet file.");
+		}
 
 		$worksheetNames = array();
 
@@ -221,7 +247,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		$xml_ss = $xml->children($namespaces['ss']);
 		foreach($xml_ss->Worksheet as $worksheet) {
 			$worksheet_ss = $worksheet->attributes($namespaces['ss']);
-			$worksheetNames[] = $worksheet_ss['Name'];
+			$worksheetNames[] = self::_convertStringEncoding((string) $worksheet_ss['Name'],$this->_charSet);
 		}
 
 		return $worksheetNames;
@@ -229,6 +255,77 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 
 
 	/**
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+	 *
+	 * @param   string     $pFilename
+	 * @throws   Exception
+	 */
+	public function listWorksheetInfo($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		$worksheetInfo = array();
+
+		$xml = simplexml_load_file($pFilename);
+		$namespaces = $xml->getNamespaces(true);
+
+		$worksheetID = 1;
+		$xml_ss = $xml->children($namespaces['ss']);
+		foreach($xml_ss->Worksheet as $worksheet) {
+			$worksheet_ss = $worksheet->attributes($namespaces['ss']);
+
+			$tmpInfo = array();
+			$tmpInfo['worksheetName'] = '';
+			$tmpInfo['lastColumnLetter'] = 'A';
+			$tmpInfo['lastColumnIndex'] = 0;
+			$tmpInfo['totalRows'] = 0;
+			$tmpInfo['totalColumns'] = 0;
+
+			if (isset($worksheet_ss['Name'])) {
+				$tmpInfo['worksheetName'] = (string) $worksheet_ss['Name'];
+			} else {
+				$tmpInfo['worksheetName'] = "Worksheet_{$worksheetID}";
+			}
+
+			if (isset($worksheet->Table->Row)) {
+				$rowIndex = 0;
+
+				foreach($worksheet->Table->Row as $rowData) {
+					$columnIndex = 0;
+					$rowHasData = false;
+
+					foreach($rowData->Cell as $cell) {
+						if (isset($cell->Data)) {
+							$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+							$rowHasData = true;
+						}
+
+						++$columnIndex;
+					}
+
+					++$rowIndex;
+
+					if ($rowHasData) {
+						$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+					}
+				}
+			}
+
+			$tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+			$tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+			$worksheetInfo[] = $tmpInfo;
+			++$worksheetID;
+		}
+
+		return $worksheetInfo;
+	}
+
+
+    /**
 	 * Loads PHPExcel from file
 	 *
 	 * @param 	string 		$pFilename
@@ -244,6 +341,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $this->loadIntoExisting($pFilename, $objPHPExcel);
 	}
 
+
 	private static function identifyFixedStyleValue($styleList,&$styleAttributeValue) {
 		$styleAttributeValue = strtolower($styleAttributeValue);
 		foreach($styleList as $style) {
@@ -255,6 +353,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return false;
 	}
 
+
  	/**
  	 * pixel units to excel width units(units of 1/256th of a character width)
  	 * @param pxs
@@ -268,6 +367,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $widthUnits;
 	}
 
+
 	/**
 	 * excel width units(units of 1/256th of a character width) to pixel units
 	 * @param widthUnits
@@ -285,6 +385,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return chr(hexdec($hex[1]));
 	}
 
+
 	/**
 	 * Loads PHPExcel from file into PHPExcel instance
 	 *
@@ -329,6 +430,10 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
 		}
 
+		if (!$this->canRead($pFilename)) {
+			throw new Exception($pFilename . " is an Invalid Spreadsheet file.");
+		}
+
 		$xml = simplexml_load_file($pFilename);
 		$namespaces = $xml->getNamespaces(true);
 
@@ -337,39 +442,39 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 			foreach($xml->DocumentProperties[0] as $propertyName => $propertyValue) {
 				switch ($propertyName) {
 					case 'Title' :
-							$docProps->setTitle($propertyValue);
+							$docProps->setTitle(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Subject' :
-							$docProps->setSubject($propertyValue);
+							$docProps->setSubject(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Author' :
-							$docProps->setCreator($propertyValue);
+							$docProps->setCreator(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Created' :
 							$creationDate = strtotime($propertyValue);
 							$docProps->setCreated($creationDate);
 							break;
 					case 'LastAuthor' :
-							$docProps->setLastModifiedBy($propertyValue);
+							$docProps->setLastModifiedBy(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'LastSaved' :
 							$lastSaveDate = strtotime($propertyValue);
 							$docProps->setModified($lastSaveDate);
 							break;
 					case 'Company' :
-							$docProps->setCompany($propertyValue);
+							$docProps->setCompany(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Category' :
-							$docProps->setCategory($propertyValue);
+							$docProps->setCategory(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Manager' :
-							$docProps->setManager($propertyValue);
+							$docProps->setManager(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Keywords' :
-							$docProps->setKeywords($propertyValue);
+							$docProps->setKeywords(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 					case 'Description' :
-							$docProps->setDescription($propertyValue);
+							$docProps->setDescription(self::_convertStringEncoding($propertyValue,$this->_charSet));
 							break;
 				}
 			}
@@ -462,7 +567,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 												break;
 									}
 								}
-								if (count($thisBorder) > 0) {
+								if (!empty($thisBorder)) {
 									if (($borderPosition == 'left') || ($borderPosition == 'right') || ($borderPosition == 'top') || ($borderPosition == 'bottom')) {
 										$this->_styles[$styleID]['borders'][$borderPosition] = $thisBorder;
 									}
@@ -535,6 +640,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 
 		$worksheetID = 0;
 		$xml_ss = $xml->children($namespaces['ss']);
+
 		foreach($xml_ss->Worksheet as $worksheet) {
 			$worksheet_ss = $worksheet->attributes($namespaces['ss']);
 
@@ -549,8 +655,11 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 			$objPHPExcel->createSheet();
 			$objPHPExcel->setActiveSheetIndex($worksheetID);
 			if (isset($worksheet_ss['Name'])) {
-				$worksheetName = (string) $worksheet_ss['Name'];
-				$objPHPExcel->getActiveSheet()->setTitle($worksheetName);
+				$worksheetName = self::_convertStringEncoding((string) $worksheet_ss['Name'],$this->_charSet);
+				//	Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
+				//		formula cells... during the load, all formulae should be correct, and we're simply bringing
+				//		the worksheet name in line with the formula, not the reverse
+				$objPHPExcel->getActiveSheet()->setTitle($worksheetName,false);
 			}
 
 			$columnID = 'A';
@@ -588,7 +697,7 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 						}
 						$cellRange = $columnID.$rowID;
 
-						if (!is_null($this->getReadFilter())) {
+						if ($this->getReadFilter() !== NULL) {
 							if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
 								continue;
 							}
@@ -630,11 +739,12 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 									const TYPE_FORMULA		= 'f';
 									const TYPE_NUMERIC		= 'n';
 									const TYPE_BOOL			= 'b';
-								    const TYPE_NULL			= 's';
+								    const TYPE_NULL			= 'null';
 								    const TYPE_INLINE		= 'inlineStr';
 									const TYPE_ERROR		= 'e';
 									*/
 									case 'String' :
+											$cellValue = self::_convertStringEncoding($cellValue,$this->_charSet);
 											$type = PHPExcel_Cell_DataType::TYPE_STRING;
 											break;
 									case 'Number' :
@@ -735,14 +845,14 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 							$annotation = strip_tags($node);
 //							echo 'Annotation: ',$annotation,'<br />';
 							$objPHPExcel->getActiveSheet()->getComment( $columnID.$rowID )
-															->setAuthor( $author )
+															->setAuthor(self::_convertStringEncoding($author ,$this->_charSet))
 															->setText($this->_parseRichText($annotation) );
 						}
 
 						if (($cellIsSet) && (isset($cell_ss['StyleID']))) {
 							$style = (string) $cell_ss['StyleID'];
 //							echo 'Cell style for '.$columnID.$rowID.' is '.$style.'<br />';
-							if ((isset($this->_styles[$style])) && (count($this->_styles[$style]) > 0)) {
+							if ((isset($this->_styles[$style])) && (!empty($this->_styles[$style]))) {
 //								echo 'Cell '.$columnID.$rowID.'<br />';
 //								print_r($this->_styles[$style]);
 //								echo '<br />';
@@ -776,10 +886,19 @@ class PHPExcel_Reader_Excel2003XML implements PHPExcel_Reader_IReader
 		return $objPHPExcel;
 	}
 
+
+	private static function _convertStringEncoding($string,$charset) {
+		if ($charset != 'UTF-8') {
+			return PHPExcel_Shared_String::ConvertEncoding($string,'UTF-8',$charset);
+		}
+		return $string;
+	}
+
+
 	private function _parseRichText($is = '') {
 		$value = new PHPExcel_RichText();
 
-		$value->createText($is);
+		$value->createText(self::_convertStringEncoding($is,$this->_charSet));
 
 		return $value;
 	}

+ 432 - 108
htdocs/includes/phpexcel/PHPExcel/Reader/Excel2007.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -36,118 +36,169 @@ if (!defined('PHPEXCEL_ROOT')) {
 }
 
 /**
- *	PHPExcel_Reader_Excel2007
+ * PHPExcel_Reader_Excel2007
  *
- *	@category	PHPExcel
- *	@package	PHPExcel_Reader
- *	@copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @category	PHPExcel
+ * @package	PHPExcel_Reader
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 {
 	/**
-	 *	Read data only?
-	 *	Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
+	 * Read data only?
+	 * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
 	 *		or whether it should read both data and formatting
 	 *
-	 *	@var	boolean
+	 * @var	boolean
 	 */
-	private $_readDataOnly = false;
-
+	private $_readDataOnly = FALSE;
+
+	/**
+	 * Read charts that are defined in the workbook?
+	 * Identifies whether the Reader should read the definitions for any charts that exist in the workbook;
+	 *
+	 * @var	boolean
+	 */
+	private $_includeCharts = FALSE;
+
 	/**
-	 *	Restrict which sheets should be loaded?
-	 *	This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
+	 * Restrict which sheets should be loaded?
+	 * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
 	 *
-	 *	@var array of string
+	 * @var array of string
 	 */
-	private $_loadSheetsOnly = null;
+	private $_loadSheetsOnly = NULL;
 
 	/**
 	 * PHPExcel_Reader_IReadFilter instance
 	 *
 	 * @var PHPExcel_Reader_IReadFilter
 	 */
-	private $_readFilter = null;
+	private $_readFilter = NULL;
 
 	/**
 	 * PHPExcel_ReferenceHelper instance
 	 *
 	 * @var PHPExcel_ReferenceHelper
 	 */
-	private $_referenceHelper = null;
+	private $_referenceHelper = NULL;
 
 	/**
 	 * PHPExcel_Reader_Excel2007_Theme instance
 	 *
 	 * @var PHPExcel_Reader_Excel2007_Theme
 	 */
-	private static $_theme = null;
-
-
+	private static $_theme = NULL;
+
+
+	/**
+	 * Create a new PHPExcel_Reader_Excel2007 instance
+	 */
+	public function __construct() {
+		$this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
+		$this->_referenceHelper = PHPExcel_ReferenceHelper::getInstance();
+	}
+
+
 	/**
-	 *	Read data only?
+	 * Read data only?
 	 *		If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
 	 *		If false (the default) it will read data and formatting.
 	 *
-	 *	@return	boolean
+	 * @return	boolean
 	 */
 	public function getReadDataOnly() {
 		return $this->_readDataOnly;
 	}
 
+
 	/**
-	 *	Set read data only
+	 * Set read data only
 	 *		Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
 	 *		Set to false (the default) to advise the Reader to read both data and formatting for cells.
 	 *
-	 *	@param	boolean	$pValue
+	 * @param	boolean	$pValue
 	 *
-	 *	@return	PHPExcel_Reader_Excel2007
+	 * @return	PHPExcel_Reader_Excel2007
 	 */
-	public function setReadDataOnly($pValue = false) {
+	public function setReadDataOnly($pValue = FALSE) {
 		$this->_readDataOnly = $pValue;
 		return $this;
 	}
-
+
+
+	/**
+	 * Read charts in workbook?
+	 *		If this is true, then the Reader will include any charts that exist in the workbook.
+	 *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+	 *		If false (the default) it will ignore any charts defined in the workbook file.
+	 *
+	 * @return	boolean
+	 */
+	public function getIncludeCharts() {
+		return $this->_includeCharts;
+	}
+
+
+	/**
+	 * Set read charts in workbook
+	 *		Set to true, to advise the Reader to include any charts that exist in the workbook.
+	 *      Note that a ReadDataOnly value of false overrides, and charts won't be read regardless of the IncludeCharts value.
+	 *		Set to false (the default) to discard charts.
+	 *
+	 * @param	boolean	$pValue
+	 *
+	 * @return	PHPExcel_Reader_Excel2007
+	 */
+	public function setIncludeCharts($pValue = FALSE) {
+		$this->_includeCharts = (boolean) $pValue;
+		return $this;
+	}
+
+
 	/**
-	 *	Get which sheets to load
-	 *		Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
-	 *			indicating that all worksheets in the workbook should be loaded.
+	 * Get which sheets to load
+	 * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
+	 *		indicating that all worksheets in the workbook should be loaded.
 	 *
-	 *	@return mixed
+	 * @return mixed
 	 */
 	public function getLoadSheetsOnly()
 	{
 		return $this->_loadSheetsOnly;
 	}
 
+
 	/**
-	 *	Set which sheets to load
+	 * Set which sheets to load
 	 *
-	 *	@param mixed $value
+	 * @param mixed $value
 	 *		This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
 	 *		If NULL, then it tells the Reader to read all worksheets in the workbook
 	 *
-	 *	@return PHPExcel_Reader_Excel2007
+	 * @return PHPExcel_Reader_Excel2007
 	 */
-	public function setLoadSheetsOnly($value = null)
+	public function setLoadSheetsOnly($value = NULL)
 	{
 		$this->_loadSheetsOnly = is_array($value) ?
 			$value : array($value);
 		return $this;
 	}
 
+
 	/**
-	 *	Set all sheets to load
+	 * Set all sheets to load
 	 *		Tells the Reader to load all worksheets from the workbook.
 	 *
-	 *	@return PHPExcel_Reader_Excel2007
+	 * @return PHPExcel_Reader_Excel2007
 	 */
 	public function setLoadAllSheets()
 	{
-		$this->_loadSheetsOnly = null;
+		$this->_loadSheetsOnly = NULL;
 		return $this;
 	}
 
+
 	/**
 	 * Read filter
 	 *
@@ -157,6 +208,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		return $this->_readFilter;
 	}
 
+
 	/**
 	 * Set read filter
 	 *
@@ -168,46 +220,42 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
-	/**
-	 * Create a new PHPExcel_Reader_Excel2007 instance
-	 */
-	public function __construct() {
-		$this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
-		$this->_referenceHelper = PHPExcel_ReferenceHelper::getInstance();
-	}
 
 	/**
 	 * Can the current PHPExcel_Reader_IReader read the file?
 	 *
 	 * @param 	string 		$pFileName
 	 * @return 	boolean
+	 * @throws Exception
 	 */
 	public function canRead($pFilename)
 	{
-		// Check if zip class exists
-		if (!class_exists('ZipArchive')) {
-			return false;
-		}
-
 		// Check if file exists
 		if (!file_exists($pFilename)) {
 			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
 		}
 
+		// Check if zip class exists
+		if (!class_exists('ZipArchive',FALSE)) {
+			throw new Exception("ZipArchive library is not enabled");
+		}
+
 		$xl = false;
 		// Load file
 		$zip = new ZipArchive;
 		if ($zip->open($pFilename) === true) {
 			// check if it is an OOXML archive
 			$rels = simplexml_load_string($this->_getFromZipArchive($zip, "_rels/.rels"));
-			foreach ($rels->Relationship as $rel) {
-				switch ($rel["Type"]) {
-					case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
-						if (basename($rel["Target"]) == 'workbook.xml') {
-							$xl = true;
-						}
-						break;
+			if ($rels !== false) {
+				foreach ($rels->Relationship as $rel) {
+					switch ($rel["Type"]) {
+						case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument":
+							if (basename($rel["Target"]) == 'workbook.xml') {
+								$xl = true;
+							}
+							break;
 
+					}
 				}
 			}
 			$zip->close();
@@ -216,31 +264,110 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		return $xl;
 	}
 
+
+	/**
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+	 *
+	 * @param   string     $pFilename
+	 * @throws   Exception
+	 */
+	public function listWorksheetInfo($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		$worksheetInfo = array();
+
+		$zip = new ZipArchive;
+		$zip->open($pFilename);
+
+		$rels = simplexml_load_string($this->_getFromZipArchive($zip, "_rels/.rels")); //~ http://schemas.openxmlformats.org/package/2006/relationships");
+		foreach ($rels->Relationship as $rel) {
+			if ($rel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument") {
+				$dir = dirname($rel["Target"]);
+				$relsWorkbook = simplexml_load_string($this->_getFromZipArchive($zip, "$dir/_rels/" . basename($rel["Target"]) . ".rels"));  //~ http://schemas.openxmlformats.org/package/2006/relationships");
+				$relsWorkbook->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships");
+
+				$worksheets = array();
+				foreach ($relsWorkbook->Relationship as $ele) {
+					if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet") {
+						$worksheets[(string) $ele["Id"]] = $ele["Target"];
+					}
+				}
+
+				$xmlWorkbook = simplexml_load_string($this->_getFromZipArchive($zip, "{$rel['Target']}"));  //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+				if ($xmlWorkbook->sheets) {
+					$dir = dirname($rel["Target"]);
+					foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
+						$tmpInfo = array();
+						$tmpInfo['worksheetName'] = (string) $eleSheet["name"];
+						$tmpInfo['lastColumnLetter'] = 'A';
+						$tmpInfo['lastColumnIndex'] = 0;
+						$tmpInfo['totalRows'] = 0;
+						$tmpInfo['totalColumns'] = 0;
+
+						$fileWorksheet = $worksheets[(string) self::array_item($eleSheet->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
+						$xmlSheet = simplexml_load_string($this->_getFromZipArchive($zip, "$dir/$fileWorksheet"));  //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
+						if ($xmlSheet && $xmlSheet->sheetData && $xmlSheet->sheetData->row) {
+							foreach ($xmlSheet->sheetData->row as $row) {
+								foreach ($row->c as $c) {
+									$r = (string) $c["r"];
+									$coordinates = PHPExcel_Cell::coordinateFromString($r);
+
+									$rowIndex = $coordinates[1];
+									$columnIndex = PHPExcel_Cell::columnIndexFromString($coordinates[0]) - 1;
+
+									$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+									$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+								}
+							}
+						}
+
+						$tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+						$tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+						$worksheetInfo[] = $tmpInfo;
+					}
+				}
+			}
+		}
+
+		$zip->close();
+
+		return $worksheetInfo;
+	}
+
+
 	private static function _castToBool($c) {
 //		echo 'Initial Cast to Boolean<br />';
-		$value = isset($c->v) ? (string) $c->v : null;
+		$value = isset($c->v) ? (string) $c->v : NULL;
 		if ($value == '0') {
-			return false;
+			return FALSE;
 		} elseif ($value == '1') {
-			return true;
+			return TRUE;
 		} else {
 			return (bool)$c->v;
 		}
 		return $value;
 	}	//	function _castToBool()
 
+
 	private static function _castToError($c) {
 //		echo 'Initial Cast to Error<br />';
-		return isset($c->v) ? (string) $c->v : null;;
+		return isset($c->v) ? (string) $c->v : NULL;
 	}	//	function _castToError()
 
+
 	private static function _castToString($c) {
 //		echo 'Initial Cast to String<br />';
-		return isset($c->v) ? (string) $c->v : null;;
+		return isset($c->v) ? (string) $c->v : NULL;
 	}	//	function _castToString()
 
+
 	private function _castToFormula($c,$r,&$cellDataType,&$value,&$calculatedValue,&$sharedFormulas,$castBaseType) {
-//		echo '<font color="darkgreen">Formula</font><br />';
+//		echo 'Formula<br />';
 //		echo '$c->f is '.$c->f.'<br />';
 		$cellDataType 		= 'f';
 		$value 				= "={$c->f}";
@@ -248,7 +375,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 
 		// Shared formula?
 		if (isset($c->f['t']) && strtolower((string)$c->f['t']) == 'shared') {
-//			echo '<font color="darkgreen">SHARED FORMULA</font><br />';
+//			echo 'SHARED FORMULA<br />';
 			$instance = (string)$c->f['si'];
 
 //			echo 'Instance ID = '.$instance.'<br />';
@@ -257,7 +384,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 //			print_r($sharedFormulas);
 //			echo '</pre>';
 			if (!isset($sharedFormulas[(string)$c->f['si']])) {
-//				echo '<font color="darkgreen">SETTING NEW SHARED FORMULA</font><br />';
+//				echo 'SETTING NEW SHARED FORMULA<br />';
 //				echo 'Master is '.$r.'<br />';
 //				echo 'Formula is '.$value.'<br />';
 				$sharedFormulas[$instance] = array(	'master' => $r,
@@ -267,7 +394,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 //				print_r($sharedFormulas);
 //				echo '</pre>';
 			} else {
-//				echo '<font color="darkgreen">GETTING SHARED FORMULA</font><br />';
+//				echo 'GETTING SHARED FORMULA<br />';
 //				echo 'Master is '.$sharedFormulas[$instance]['master'].'<br />';
 //				echo 'Formula is '.$sharedFormulas[$instance]['formula'].'<br />';
 				$master = PHPExcel_Cell::coordinateFromString($sharedFormulas[$instance]['master']);
@@ -287,6 +414,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		}
 	}
 
+
 	public function _getFromZipArchive(ZipArchive $archive, $fileName = '')
 	{
 		// Root-relative paths
@@ -306,6 +434,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		return $contents;
 	}
 
+
 	/**
 	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
 	 *
@@ -381,7 +510,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 						$xmlThemeName = $xmlTheme->attributes();
 						$xmlTheme = $xmlTheme->children("http://schemas.openxmlformats.org/drawingml/2006/main");
 						$themeName = (string)$xmlThemeName['name'];
-
+
 						$colourScheme = $xmlTheme->themeElements->clrScheme->attributes();
 						$colourSchemeName = (string)$colourScheme['name'];
 						$colourScheme = $xmlTheme->themeElements->clrScheme->children("http://schemas.openxmlformats.org/drawingml/2006/main");
@@ -491,7 +620,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 					if ($xmlStyles && $xmlStyles->numFmts[0]) {
 						$numFmts = $xmlStyles->numFmts[0];
 					}
-					if (isset($numFmts) && !is_null($numFmts)) {
+					if (isset($numFmts) && ($numFmts !== NULL)) {
 						$numFmts->registerXPathNamespace("sml", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
 					}
 					if (!$this->_readDataOnly && $xmlStyles) {
@@ -560,16 +689,16 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 
 					$dxfs = array();
 					if (!$this->_readDataOnly && $xmlStyles) {
+						//	Conditional Styles
 						if ($xmlStyles->dxfs) {
 							foreach ($xmlStyles->dxfs->dxf as $dxf) {
-								$style = new PHPExcel_Style;
+								$style = new PHPExcel_Style(FALSE, TRUE);
 								self::_readStyle($style, $dxf);
 								$dxfs[] = $style;
 							}
 						}
-
-						if ($xmlStyles->cellStyles)
-						{
+						//	Cell Styles
+						if ($xmlStyles->cellStyles) {
 							foreach ($xmlStyles->cellStyles->cellStyle as $cellStyle) {
 								if (intval($cellStyle['builtinId']) == 0) {
 									if (isset($cellStyles[intval($cellStyle['xfId'])])) {
@@ -602,8 +731,10 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 					$countSkippedSheets = 0; // keep track of number of skipped sheets
 					$mapSheetId = array(); // mapping of sheet ids from old to new
 
-					if ($xmlWorkbook->sheets)
-					{
+
+					$charts = $chartDetails = array();
+
+					if ($xmlWorkbook->sheets) {
 						foreach ($xmlWorkbook->sheets->sheet as $eleSheet) {
 							++$oldSheetId;
 
@@ -620,7 +751,11 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 
 							// Load sheet
 							$docSheet = $excel->createSheet();
-							$docSheet->setTitle((string) $eleSheet["name"]);
+							//	Use false for $updateFormulaCellReferences to prevent adjustment of worksheet
+							//		references in formula cells... during the load, all formulae should be correct,
+							//		and we're simply bringing the worksheet name in line with the formula, not the
+							//		reverse
+							$docSheet->setTitle((string) $eleSheet["name"],false);
 							$fileWorksheet = $worksheets[(string) self::array_item($eleSheet->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "id")];
 							$xmlSheet = simplexml_load_string($this->_getFromZipArchive($zip, "$dir/$fileWorksheet"));  //~ http://schemas.openxmlformats.org/spreadsheetml/2006/main");
 
@@ -639,6 +774,10 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 								    $docSheet->getSheetView()->setZoomScaleNormal( intval($xmlSheet->sheetViews->sheetView['zoomScaleNormal']) );
 								}
 
+							    if (isset($xmlSheet->sheetViews->sheetView['view'])) {
+								    $docSheet->getSheetView()->setView((string) $xmlSheet->sheetViews->sheetView['view']);
+								}
+
 								if (isset($xmlSheet->sheetViews->sheetView['showGridLines'])) {
 									$docSheet->setShowGridLines((string)$xmlSheet->sheetViews->sheetView['showGridLines'] ? true : false);
 								}
@@ -716,6 +855,10 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 								if (isset($xmlSheet->sheetFormatPr['defaultColWidth'])) {
 									$docSheet->getDefaultColumnDimension()->setWidth( (float)$xmlSheet->sheetFormatPr['defaultColWidth'] );
 								}
+								if (isset($xmlSheet->sheetFormatPr['zeroHeight']) &&
+									((string)$xmlSheet->sheetFormatPr['zeroHeight'] == '1')) {
+									$docSheet->getDefaultRowDimension()->setzeroHeight(true);
+								}
 							}
 
 							if (isset($xmlSheet->cols) && !$this->_readDataOnly) {
@@ -787,7 +930,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 										$calculatedValue 	= null;
 
 										// Read cell?
-										if (!is_null($this->getReadFilter())) {
+										if ($this->getReadFilter() !== NULL) {
 											$coordinates = PHPExcel_Cell::coordinateFromString($r);
 
 											if (!$this->getReadFilter()->readCell($coordinates[0], $coordinates[1], $docSheet->getTitle())) {
@@ -822,11 +965,11 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 												} else {
 													// Formula
 													$this->_castToFormula($c,$r,$cellDataType,$value,$calculatedValue,$sharedFormulas,'_castToBool');
-													if (isset($c->f['t'])) {
-														$att = array();
-														$att = $c->f;
-														$docSheet->getCell($r)->setFormulaAttributes($att);
-													}
+													if (isset($c->f['t'])) {
+														$att = array();
+														$att = $c->f;
+														$docSheet->getCell($r)->setFormulaAttributes($att);
+													}
 	//												echo '$calculatedValue = '.$calculatedValue.'<br />';
 												}
 												break;
@@ -882,7 +1025,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 										} else {
 											$cell->setValue($value);
 										}
-										if (!is_null($calculatedValue)) {
+										if ($calculatedValue !== NULL) {
 											$cell->setCalculatedValue($calculatedValue);
 										}
 
@@ -943,7 +1086,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 									}
 								}
 							}
-
+
 							$aKeys = array("sheet", "objects", "scenarios", "formatCells", "formatColumns", "formatRows", "insertColumns", "insertRows", "insertHyperlinks", "deleteColumns", "deleteRows", "selectLockedCells", "sort", "autoFilter", "pivotTables", "selectUnlockedCells");
 							if (!$this->_readDataOnly && $xmlSheet && $xmlSheet->sheetProtection) {
 								foreach ($aKeys as $key) {
@@ -962,12 +1105,111 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 							}
 
 							if ($xmlSheet && $xmlSheet->autoFilter && !$this->_readDataOnly) {
-								$docSheet->setAutoFilter((string) $xmlSheet->autoFilter["ref"]);
+								$autoFilter = $docSheet->getAutoFilter();
+								$autoFilter->setRange((string) $xmlSheet->autoFilter["ref"]);
+								foreach ($xmlSheet->autoFilter->filterColumn as $filterColumn) {
+									$column = $autoFilter->getColumnByOffset((integer) $filterColumn["colId"]);
+									//	Check for standard filters
+									if ($filterColumn->filters) {
+										$column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_FILTER);
+										$filters = $filterColumn->filters;
+										if ((isset($filters["blank"])) && ($filters["blank"] == 1)) {
+											$column->createRule()->setRule(
+												NULL,	//	Operator is undefined, but always treated as EQUAL
+												''
+											)
+											->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER);
+										}
+										//	Standard filters are always an OR join, so no join rule needs to be set
+										//	Entries can be either filter elements
+										foreach ($filters->filter as $filterRule) {
+											$column->createRule()->setRule(
+												NULL,	//	Operator is undefined, but always treated as EQUAL
+												(string) $filterRule["val"]
+											)
+											->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_FILTER);
+										}
+										//	Or Date Group elements
+										foreach ($filters->dateGroupItem as $dateGroupItem) {
+											$column->createRule()->setRule(
+												NULL,	//	Operator is undefined, but always treated as EQUAL
+												array(
+													'year' => (string) $dateGroupItem["year"],
+													'month' => (string) $dateGroupItem["month"],
+													'day' => (string) $dateGroupItem["day"],
+													'hour' => (string) $dateGroupItem["hour"],
+													'minute' => (string) $dateGroupItem["minute"],
+													'second' => (string) $dateGroupItem["second"],
+												),
+												(string) $dateGroupItem["dateTimeGrouping"]
+											)
+											->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DATEGROUP);
+										}
+									}
+									//	Check for custom filters
+									if ($filterColumn->customFilters) {
+										$column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_CUSTOMFILTER);
+										$customFilters = $filterColumn->customFilters;
+										//	Custom filters can an AND or an OR join;
+										//		and there should only ever be one or two entries
+										if ((isset($customFilters["and"])) && ($customFilters["and"] == 1)) {
+											$column->setJoin(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_COLUMN_JOIN_AND);
+										}
+										foreach ($customFilters->customFilter as $filterRule) {
+											$column->createRule()->setRule(
+												(string) $filterRule["operator"],
+												(string) $filterRule["val"]
+											)
+											->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_CUSTOMFILTER);
+										}
+									}
+									//	Check for dynamic filters
+									if ($filterColumn->dynamicFilter) {
+										$column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER);
+										//	We should only ever have one dynamic filter
+										foreach ($filterColumn->dynamicFilter as $filterRule) {
+											$column->createRule()->setRule(
+												NULL,	//	Operator is undefined, but always treated as EQUAL
+												(string) $filterRule["val"],
+												(string) $filterRule["type"]
+											)
+											->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER);
+											if (isset($filterRule["val"])) {
+												$column->setAttribute('val',(string) $filterRule["val"]);
+											}
+											if (isset($filterRule["maxVal"])) {
+												$column->setAttribute('maxVal',(string) $filterRule["maxVal"]);
+											}
+										}
+									}
+									//	Check for dynamic filters
+									if ($filterColumn->top10) {
+										$column->setFilterType(PHPExcel_Worksheet_AutoFilter_Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER);
+										//	We should only ever have one top10 filter
+										foreach ($filterColumn->top10 as $filterRule) {
+											$column->createRule()->setRule(
+												(((isset($filterRule["percent"])) && ($filterRule["percent"] == 1))
+													? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT
+													: PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE
+												),
+												(string) $filterRule["val"],
+												(((isset($filterRule["top"])) && ($filterRule["top"] == 1))
+													? PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP
+													: PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM
+												)
+											)
+											->setRuleType(PHPExcel_Worksheet_AutoFilter_Column_Rule::AUTOFILTER_RULETYPE_TOPTENFILTER);
+										}
+									}
+								}
 							}
 
 							if ($xmlSheet && $xmlSheet->mergeCells && $xmlSheet->mergeCells->mergeCell && !$this->_readDataOnly) {
 								foreach ($xmlSheet->mergeCells->mergeCell as $mergeCell) {
-									$docSheet->mergeCells((string) $mergeCell["ref"]);
+									$mergeRef = (string) $mergeCell["ref"];
+									if (strpos($mergeRef,':') !== FALSE) {
+										$docSheet->mergeCells((string) $mergeCell["ref"]);
+									}
 								}
 							}
 
@@ -1051,7 +1293,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 							if ($xmlSheet && $xmlSheet->colBreaks && $xmlSheet->colBreaks->brk && !$this->_readDataOnly) {
 								foreach ($xmlSheet->colBreaks->brk as $brk) {
 									if ($brk["man"]) {
-										$docSheet->setBreak(PHPExcel_Cell::stringFromColumnIndex($brk["id"]) . "1", PHPExcel_Worksheet::BREAK_COLUMN);
+										$docSheet->setBreak(PHPExcel_Cell::stringFromColumnIndex((string) $brk["id"]) . "1", PHPExcel_Worksheet::BREAK_COLUMN);
 									}
 								}
 							}
@@ -1180,7 +1422,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 	    									$row          = null;
 
 	    									$clientData   = $shape->xpath('.//x:ClientData');
-	    									if (is_array($clientData) && count($clientData) > 0) {
+	    									if (is_array($clientData) && !empty($clientData)) {
 	        									$clientData   = $clientData[0];
 
 	        									if ( isset($clientData['ObjectType']) && (string)$clientData['ObjectType'] == 'Note' ) {
@@ -1192,9 +1434,9 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 	        									}
 	    									}
 
-	    									if (!is_null($column) && !is_null($row)) {
+	    									if (($column !== NULL) && ($row !== NULL)) {
 	    									    // Set comment properties
-	    									    $comment = $docSheet->getCommentByColumnAndRow($column, $row + 1);
+	    									    $comment = $docSheet->getCommentByColumnAndRow((string) $column, $row + 1);
 	    									    $comment->getFillColor()->setRGB( $fillColor );
 
 	    									    // Parse style
@@ -1272,7 +1514,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 
 							}
 
-	// TODO: Make sure drawings and graph are loaded differently!
+// TODO: Autoshapes from twoCellAnchors!
 							if ($zip->locateName(dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels")) {
 								$relsWorksheet = simplexml_load_string($this->_getFromZipArchive($zip,  dirname("$dir/$fileWorksheet") . "/_rels/" . basename($fileWorksheet) . ".rels") ); //~ http://schemas.openxmlformats.org/package/2006/relationships");
 								$drawings = array();
@@ -1291,7 +1533,13 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 											foreach ($relsDrawing->Relationship as $ele) {
 												if ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image") {
 													$images[(string) $ele["Id"]] = self::dir_add($fileDrawing, $ele["Target"]);
-												}
+												} elseif ($ele["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart") {
+													if ($this->_includeCharts) {
+														$charts[self::dir_add($fileDrawing, $ele["Target"])] = array('id'		=> (string) $ele["Id"],
+																													 'sheet'	=> $docSheet->getTitle()
+																													);
+													}
+												}
 											}
 										}
 										$xmlDrawing = simplexml_load_string($this->_getFromZipArchive($zip, $fileDrawing))->children("http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing");
@@ -1306,7 +1554,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 													$objDrawing->setName((string) self::array_item($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), "name"));
 													$objDrawing->setDescription((string) self::array_item($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), "descr"));
 													$objDrawing->setPath("zip://$pFilename#" . $images[(string) self::array_item($blip->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "embed")], false);
-													$objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex($oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
+													$objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1));
 													$objDrawing->setOffsetX(PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->colOff));
 													$objDrawing->setOffsetY(PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->rowOff));
 													$objDrawing->setResizeProportional(false);
@@ -1326,6 +1574,13 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 														$shadow->setAlpha(self::array_item($outerShdw->srgbClr->alpha->attributes(), "val") / 1000);
 													}
 													$objDrawing->setWorksheet($docSheet);
+												} else {
+													//	? Can charts be positioned with a oneCellAnchor ?
+													$coordinates	= PHPExcel_Cell::stringFromColumnIndex((string) $oneCellAnchor->from->col) . ($oneCellAnchor->from->row + 1);
+													$offsetX		= PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->colOff);
+													$offsetY		= PHPExcel_Shared_Drawing::EMUToPixels($oneCellAnchor->from->rowOff);
+													$width			= PHPExcel_Shared_Drawing::EMUToPixels(self::array_item($oneCellAnchor->ext->attributes(), "cx"));
+													$height			= PHPExcel_Shared_Drawing::EMUToPixels(self::array_item($oneCellAnchor->ext->attributes(), "cy"));
 												}
 											}
 										}
@@ -1339,7 +1594,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 													$objDrawing->setName((string) self::array_item($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), "name"));
 													$objDrawing->setDescription((string) self::array_item($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), "descr"));
 													$objDrawing->setPath("zip://$pFilename#" . $images[(string) self::array_item($blip->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships"), "embed")], false);
-													$objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex($twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
+													$objDrawing->setCoordinates(PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1));
 													$objDrawing->setOffsetX(PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->colOff));
 													$objDrawing->setOffsetY(PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->rowOff));
 													$objDrawing->setResizeProportional(false);
@@ -1361,7 +1616,27 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 														$shadow->setAlpha(self::array_item($outerShdw->srgbClr->alpha->attributes(), "val") / 1000);
 													}
 													$objDrawing->setWorksheet($docSheet);
-												}
+												} elseif(($this->_includeCharts) && ($twoCellAnchor->graphicFrame)) {
+													$fromCoordinate	= PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->from->col) . ($twoCellAnchor->from->row + 1);
+													$fromOffsetX	= PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->colOff);
+													$fromOffsetY	= PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->from->rowOff);
+													$toCoordinate	= PHPExcel_Cell::stringFromColumnIndex((string) $twoCellAnchor->to->col) . ($twoCellAnchor->to->row + 1);
+													$toOffsetX		= PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->to->colOff);
+													$toOffsetY		= PHPExcel_Shared_Drawing::EMUToPixels($twoCellAnchor->to->rowOff);
+													$graphic		= $twoCellAnchor->graphicFrame->children("http://schemas.openxmlformats.org/drawingml/2006/main")->graphic;
+													$chartRef		= $graphic->graphicData->children("http://schemas.openxmlformats.org/drawingml/2006/chart")->chart;
+													$thisChart		= (string) $chartRef->attributes("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
+
+													$chartDetails[$docSheet->getTitle().'!'.$thisChart] =
+															array(	'fromCoordinate'	=> $fromCoordinate,
+																	'fromOffsetX'		=> $fromOffsetX,
+																	'fromOffsetY'		=> $fromOffsetY,
+																	'toCoordinate'		=> $toCoordinate,
+																	'toOffsetX'			=> $toOffsetX,
+																	'toOffsetY'			=> $toOffsetY,
+																	'worksheetTitle'	=> $docSheet->getTitle()
+																 );
+												}
 											}
 										}
 
@@ -1382,7 +1657,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 									}
 
 									// Valid range?
-									if (stripos((string)$definedName, '#REF!') !== false || $extractedRange == '') {
+									if (stripos((string)$definedName, '#REF!') !== FALSE || $extractedRange == '') {
 										continue;
 									}
 
@@ -1391,8 +1666,10 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 										// Switch on type
 										switch ((string)$definedName['name']) {
 
-											case '_xlnm._FilterDatabase':
-												$docSheet->setAutoFilter($extractedRange);
+											case '_xlnm._FilterDatabase':
+												if ((string)$definedName['hidden'] !== '1') {
+													$docSheet->getAutoFilter()->setRange($extractedRange);
+												}
 												break;
 
 											case '_xlnm.Print_Titles':
@@ -1495,7 +1772,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 										$extractedRange = isset($range[1]) ? $range[1] : $range[0];
 									}
 
-									if (!is_null($locatedSheet)) {
+									if ($locatedSheet !== NULL) {
 										$excel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $locatedSheet, $extractedRange, false) );
 									}
 								}
@@ -1511,8 +1788,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 						if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
 							$excel->setActiveSheetIndex($mapSheetId[$activeTab]);
 						} else {
-							if ($excel->getSheetCount() == 0)
-							{
+							if ($excel->getSheetCount() == 0) {
 								$excel->createSheet();
 							}
 							$excel->setActiveSheetIndex(0);
@@ -1523,18 +1799,56 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 
 		}
 
+
+		if (!$this->_readDataOnly) {
+			$contentTypes = simplexml_load_string($this->_getFromZipArchive($zip, "[Content_Types].xml"));
+			foreach ($contentTypes->Override as $contentType) {
+				switch ($contentType["ContentType"]) {
+					case "application/vnd.openxmlformats-officedocument.drawingml.chart+xml":
+						if ($this->_includeCharts) {
+							$chartEntryRef = ltrim($contentType['PartName'],'/');
+							$chartElements = simplexml_load_string($this->_getFromZipArchive($zip, $chartEntryRef));
+							$objChart = PHPExcel_Reader_Excel2007_Chart::readChart($chartElements,basename($chartEntryRef,'.xml'));
+
+//							echo 'Chart ',$chartEntryRef,'<br />';
+//							var_dump($charts[$chartEntryRef]);
+//
+							if (isset($charts[$chartEntryRef])) {
+								$chartPositionRef = $charts[$chartEntryRef]['sheet'].'!'.$charts[$chartEntryRef]['id'];
+//								echo 'Position Ref ',$chartPositionRef,'<br />';
+								if (isset($chartDetails[$chartPositionRef])) {
+//									var_dump($chartDetails[$chartPositionRef]);
+
+									$excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart);
+									$objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet']));
+									$objChart->setTopLeftPosition( $chartDetails[$chartPositionRef]['fromCoordinate'],
+																   $chartDetails[$chartPositionRef]['fromOffsetX'],
+																   $chartDetails[$chartPositionRef]['fromOffsetY']
+																 );
+									$objChart->setBottomRightPosition( $chartDetails[$chartPositionRef]['toCoordinate'],
+																	   $chartDetails[$chartPositionRef]['toOffsetX'],
+																	   $chartDetails[$chartPositionRef]['toOffsetY']
+																	 );
+								}
+							}
+						}
+				}
+			}
+		}
+
 		$zip->close();
 
 		return $excel;
 	}
+
 
-	private static function _readColor($color, $background=false) {
+	private static function _readColor($color, $background=FALSE) {
 		if (isset($color["rgb"])) {
 			return (string)$color["rgb"];
 		} else if (isset($color["indexed"])) {
-			return PHPExcel_Style_Color::indexedColor($color["indexed"],$background)->getARGB();
+			return PHPExcel_Style_Color::indexedColor($color["indexed"]-7,$background)->getARGB();
 		} else if (isset($color["theme"])) {
-			if (!is_null(self::$_theme)) {
+			if (self::$_theme !== NULL) {
 				$returnColour = self::$_theme->getColourByIndex((int)$color["theme"]);
 				if (isset($color["tint"])) {
 					$tintAdjust = (float) $color["tint"];
@@ -1550,11 +1864,16 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		return 'FF000000';
 	}
 
+
 	private static function _readStyle($docStyle, $style) {
 		// format code
-		if (isset($style->numFmt)) {
-			$docStyle->getNumberFormat()->setFormatCode($style->numFmt);
-		}
+//		if (isset($style->numFmt)) {
+//			if (isset($style->numFmt['formatCode'])) {
+//				$docStyle->getNumberFormat()->setFormatCode((string) $style->numFmt['formatCode']);
+//			} else {
+				$docStyle->getNumberFormat()->setFormatCode($style->numFmt);
+//			}
+//		}
 
 		// font
 		if (isset($style->font)) {
@@ -1592,7 +1911,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		if (isset($style->fill)) {
 			if ($style->fill->gradientFill) {
 				$gradientFill = $style->fill->gradientFill[0];
-				if(!empty($gradientFill["type"])) {
+				if(!empty($gradientFill["type"])) {
 					$docStyle->getFill()->setFillType((string) $gradientFill["type"]);
 				}
 				$docStyle->getFill()->setRotation(floatval($gradientFill["degree"]));
@@ -1676,6 +1995,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 			}
 		}
 	}
+
 
 	private static function _readBorder($docBorder, $eleBorder) {
 		if (isset($eleBorder["style"])) {
@@ -1686,6 +2006,7 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		}
 	}
 
+
 	private function _parseRichText($is = null) {
 		$value = new PHPExcel_RichText();
 
@@ -1748,14 +2069,17 @@ class PHPExcel_Reader_Excel2007 implements PHPExcel_Reader_IReader
 		return $value;
 	}
 
+
 	private static function array_item($array, $key = 0) {
 		return (isset($array[$key]) ? $array[$key] : null);
 	}
 
+
 	private static function dir_add($base, $add) {
 		return preg_replace('~[^/]+/\.\./~', '', dirname($base) . "/$add");
 	}
 
+
 	private static function toCSSArray($style) {
 		$style = str_replace(array("\r","\n"), "", $style);
 

+ 513 - 0
htdocs/includes/phpexcel/PHPExcel/Reader/Excel2007/Chart.php

@@ -0,0 +1,513 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Reader_Excel5
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version		1.7.8, 2012-10-12
+ */
+
+/**
+ * PHPExcel_Reader_Excel2007_Chart
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Reader_Excel2007
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Reader_Excel2007_Chart
+{
+	private static function _getAttribute($component, $name, $format) {
+		$attributes = $component->attributes();
+		if (isset($attributes[$name])) {
+			if ($format == 'string') {
+				return (string) $attributes[$name];
+			} elseif ($format == 'integer') {
+				return (integer) $attributes[$name];
+			} elseif ($format == 'boolean') {
+				return (boolean) ($attributes[$name] == '0') ? false : true;
+			} else {
+				return (float) $attributes[$name];
+			}
+		}
+		return null;
+	}	//	function _getAttribute()
+
+
+	private static function _readColor($color,$background=false) {
+		if (isset($color["rgb"])) {
+			return (string)$color["rgb"];
+		} else if (isset($color["indexed"])) {
+			return PHPExcel_Style_Color::indexedColor($color["indexed"]-7,$background)->getARGB();
+		}
+	}
+
+
+	public static function readChart($chartElements,$chartName) {
+		$namespacesChartMeta = $chartElements->getNamespaces(true);
+		$chartElementsC = $chartElements->children($namespacesChartMeta['c']);
+
+		$XaxisLabel = $YaxisLabel = $legend = $title = NULL;
+		$dispBlanksAs = $plotVisOnly = NULL;
+
+		foreach($chartElementsC as $chartElementKey => $chartElement) {
+			switch ($chartElementKey) {
+				case "chart":
+					foreach($chartElement as $chartDetailsKey => $chartDetails) {
+						$chartDetailsC = $chartDetails->children($namespacesChartMeta['c']);
+						switch ($chartDetailsKey) {
+							case "plotArea":
+									$plotAreaLayout = $XaxisLable = $YaxisLable = null;
+									$plotSeries = $plotAttributes = array();
+									foreach($chartDetails as $chartDetailKey => $chartDetail) {
+										switch ($chartDetailKey) {
+											case "layout":
+												$plotAreaLayout = self::_chartLayoutDetails($chartDetail,$namespacesChartMeta,'plotArea');
+												break;
+											case "catAx":
+												if (isset($chartDetail->title)) {
+													$XaxisLabel = self::_chartTitle($chartDetail->title->children($namespacesChartMeta['c']),$namespacesChartMeta,'cat');
+												}
+												break;
+											case "dateAx":
+												if (isset($chartDetail->title)) {
+													$XaxisLabel = self::_chartTitle($chartDetail->title->children($namespacesChartMeta['c']),$namespacesChartMeta,'cat');
+												}
+												break;
+											case "valAx":
+												if (isset($chartDetail->title)) {
+													$YaxisLabel = self::_chartTitle($chartDetail->title->children($namespacesChartMeta['c']),$namespacesChartMeta,'cat');
+												}
+												break;
+											case "barChart":
+											case "bar3DChart":
+												$barDirection = self::_getAttribute($chartDetail->barDir, 'val', 'string');
+												$plotSer = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotSer->setPlotDirection($barDirection);
+												$plotSeries[] = $plotSer;
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "lineChart":
+											case "line3DChart":
+												$plotSeries[] = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "areaChart":
+											case "area3DChart":
+												$plotSeries[] = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "doughnutChart":
+											case "pieChart":
+											case "pie3DChart":
+												$explosion = isset($chartDetail->ser->explosion);
+												$plotSer = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotSer->setPlotStyle($explosion);
+												$plotSeries[] = $plotSer;
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "scatterChart":
+												$scatterStyle = self::_getAttribute($chartDetail->scatterStyle, 'val', 'string');
+												$plotSer = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotSer->setPlotStyle($scatterStyle);
+												$plotSeries[] = $plotSer;
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "bubbleChart":
+												$bubbleScale = self::_getAttribute($chartDetail->bubbleScale, 'val', 'integer');
+												$plotSer = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotSer->setPlotStyle($bubbleScale);
+												$plotSeries[] = $plotSer;
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "radarChart":
+												$radarStyle = self::_getAttribute($chartDetail->radarStyle, 'val', 'string');
+												$plotSer = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotSer->setPlotStyle($radarStyle);
+												$plotSeries[] = $plotSer;
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "surfaceChart":
+											case "surface3DChart":
+												$wireFrame = self::_getAttribute($chartDetail->wireframe, 'val', 'boolean');
+												$plotSer = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotSer->setPlotStyle($wireFrame);
+												$plotSeries[] = $plotSer;
+												$plotAttributes = self::_readChartAttributes($chartDetail);
+												break;
+											case "stockChart":
+												$plotSeries[] = self::_chartDataSeries($chartDetail,$namespacesChartMeta,$chartDetailKey);
+												$plotAttributes = self::_readChartAttributes($plotAreaLayout);
+												break;
+										}
+									}
+									if ($plotAreaLayout == NULL) {
+										$plotAreaLayout = new PHPExcel_Chart_Layout();
+									}
+									$plotArea = new PHPExcel_Chart_PlotArea($plotAreaLayout,$plotSeries);
+									self::_setChartAttributes($plotAreaLayout,$plotAttributes);
+									break;
+							case "plotVisOnly":
+									$plotVisOnly = self::_getAttribute($chartDetails, 'val', 'string');
+									break;
+							case "dispBlanksAs":
+									$dispBlanksAs = self::_getAttribute($chartDetails, 'val', 'string');
+									break;
+							case "title":
+									$title = self::_chartTitle($chartDetails,$namespacesChartMeta,'title');
+									break;
+							case "legend":
+									$legendPos = 'r';
+									$legendLayout = null;
+									$legendOverlay = false;
+									foreach($chartDetails as $chartDetailKey => $chartDetail) {
+										switch ($chartDetailKey) {
+											case "legendPos":
+												$legendPos = self::_getAttribute($chartDetail, 'val', 'string');
+												break;
+											case "overlay":
+												$legendOverlay = self::_getAttribute($chartDetail, 'val', 'boolean');
+												break;
+											case "layout":
+												$legendLayout = self::_chartLayoutDetails($chartDetail,$namespacesChartMeta,'legend');
+												break;
+										}
+									}
+									$legend = new PHPExcel_Chart_Legend($legendPos, $legendLayout, $legendOverlay);
+									break;
+						}
+					}
+			}
+		}
+		$chart = new PHPExcel_Chart($chartName,$title,$legend,$plotArea,$plotVisOnly,$dispBlanksAs,$XaxisLabel,$YaxisLabel);
+
+		return $chart;
+	}	//	function readChart()
+
+
+	private static function _chartTitle($titleDetails,$namespacesChartMeta,$type) {
+		$caption = array();
+		$titleLayout = null;
+		foreach($titleDetails as $titleDetailKey => $chartDetail) {
+			switch ($titleDetailKey) {
+				case "tx":
+					$titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']);
+					foreach($titleDetails as $titleKey => $titleDetail) {
+						switch ($titleKey) {
+							case "p":
+								$titleDetailPart = $titleDetail->children($namespacesChartMeta['a']);
+								$caption[] = self::_parseRichText($titleDetailPart);
+						}
+					}
+					break;
+				case "layout":
+					$titleLayout = self::_chartLayoutDetails($chartDetail,$namespacesChartMeta);
+					break;
+			}
+		}
+
+		return new PHPExcel_Chart_Title($caption, $titleLayout);
+	}	//	function _chartTitle()
+
+
+	private static function _chartLayoutDetails($chartDetail,$namespacesChartMeta) {
+		if (!isset($chartDetail->manualLayout)) {
+			return null;
+		}
+		$details = $chartDetail->manualLayout->children($namespacesChartMeta['c']);
+		if (is_null($details)) {
+			return null;
+		}
+		$layout = array();
+		foreach($details as $detailKey => $detail) {
+//			echo $detailKey,' => ',self::_getAttribute($detail, 'val', 'string'),PHP_EOL;
+			$layout[$detailKey] = self::_getAttribute($detail, 'val', 'string');
+		}
+		return new PHPExcel_Chart_Layout($layout);
+	}	//	function _chartLayoutDetails()
+
+
+	private static function _chartDataSeries($chartDetail,$namespacesChartMeta,$plotType) {
+		$multiSeriesType = NULL;
+		$smoothLine = false;
+		$seriesLabel = $seriesCategory = $seriesValues = $plotOrder = array();
+
+		$seriesDetailSet = $chartDetail->children($namespacesChartMeta['c']);
+		foreach($seriesDetailSet as $seriesDetailKey => $seriesDetails) {
+			switch ($seriesDetailKey) {
+				case "grouping":
+					$multiSeriesType = self::_getAttribute($chartDetail->grouping, 'val', 'string');
+					break;
+				case "ser":
+					$marker = NULL;
+					foreach($seriesDetails as $seriesKey => $seriesDetail) {
+						switch ($seriesKey) {
+							case "idx":
+								$seriesIndex = self::_getAttribute($seriesDetail, 'val', 'integer');
+								break;
+							case "order":
+								$seriesOrder = self::_getAttribute($seriesDetail, 'val', 'integer');
+								$plotOrder[$seriesIndex] = $seriesOrder;
+								break;
+							case "tx":
+								$seriesLabel[$seriesIndex] = self::_chartDataSeriesValueSet($seriesDetail,$namespacesChartMeta);
+								break;
+							case "marker":
+								$marker = self::_getAttribute($seriesDetail->symbol, 'val', 'string');
+								break;
+							case "smooth":
+								$smoothLine = self::_getAttribute($seriesDetail, 'val', 'boolean');
+								break;
+							case "cat":
+								$seriesCategory[$seriesIndex] = self::_chartDataSeriesValueSet($seriesDetail,$namespacesChartMeta);
+								break;
+							case "val":
+								$seriesValues[$seriesIndex] = self::_chartDataSeriesValueSet($seriesDetail,$namespacesChartMeta,$marker);
+								break;
+							case "xVal":
+								$seriesCategory[$seriesIndex] = self::_chartDataSeriesValueSet($seriesDetail,$namespacesChartMeta,$marker);
+								break;
+							case "yVal":
+								$seriesValues[$seriesIndex] = self::_chartDataSeriesValueSet($seriesDetail,$namespacesChartMeta,$marker);
+								break;
+						}
+					}
+			}
+		}
+		return new PHPExcel_Chart_DataSeries($plotType,$multiSeriesType,$plotOrder,$seriesLabel,$seriesCategory,$seriesValues,$smoothLine);
+	}	//	function _chartDataSeries()
+
+
+	private static function _chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null, $smoothLine = false) {
+		if (isset($seriesDetail->strRef)) {
+			$seriesSource = (string) $seriesDetail->strRef->f;
+			$seriesData = self::_chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']),'s');
+
+			return new PHPExcel_Chart_DataSeriesValues('String',$seriesSource,$seriesData['formatCode'],$seriesData['pointCount'],$seriesData['dataValues'],$marker,$smoothLine);
+		} elseif (isset($seriesDetail->numRef)) {
+			$seriesSource = (string) $seriesDetail->numRef->f;
+			$seriesData = self::_chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c']));
+
+			return new PHPExcel_Chart_DataSeriesValues('Number',$seriesSource,$seriesData['formatCode'],$seriesData['pointCount'],$seriesData['dataValues'],$marker,$smoothLine);
+		} elseif (isset($seriesDetail->multiLvlStrRef)) {
+			$seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
+			$seriesData = self::_chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']),'s');
+			$seriesData['pointCount'] = count($seriesData['dataValues']);
+
+			return new PHPExcel_Chart_DataSeriesValues('String',$seriesSource,$seriesData['formatCode'],$seriesData['pointCount'],$seriesData['dataValues'],$marker,$smoothLine);
+		} elseif (isset($seriesDetail->multiLvlNumRef)) {
+			$seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
+			$seriesData = self::_chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']),'s');
+			$seriesData['pointCount'] = count($seriesData['dataValues']);
+
+			return new PHPExcel_Chart_DataSeriesValues('String',$seriesSource,$seriesData['formatCode'],$seriesData['pointCount'],$seriesData['dataValues'],$marker,$smoothLine);
+		}
+		return null;
+	}	//	function _chartDataSeriesValueSet()
+
+
+	private static function _chartDataSeriesValues($seriesValueSet,$dataType='n') {
+		$seriesVal = array();
+		$formatCode = '';
+		$pointCount = 0;
+
+		foreach($seriesValueSet as $seriesValueIdx => $seriesValue) {
+			switch ($seriesValueIdx) {
+				case 'ptCount':
+					$pointCount = self::_getAttribute($seriesValue, 'val', 'integer');
+					break;
+				case 'formatCode':
+					$formatCode = (string) $seriesValue;
+					break;
+				case 'pt':
+					$pointVal = self::_getAttribute($seriesValue, 'idx', 'integer');
+					if ($dataType == 's') {
+						$seriesVal[$pointVal] = (string) $seriesValue->v;
+					} else {
+						$seriesVal[$pointVal] = (float) $seriesValue->v;
+					}
+					break;
+			}
+		}
+
+		return array( 'formatCode'	=> $formatCode,
+					  'pointCount'	=> $pointCount,
+					  'dataValues'	=> $seriesVal
+					);
+	}	//	function _chartDataSeriesValues()
+
+
+	private static function _chartDataSeriesValuesMultiLevel($seriesValueSet,$dataType='n') {
+		$seriesVal = array();
+		$formatCode = '';
+		$pointCount = 0;
+
+		foreach($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) {
+			foreach($seriesLevel as $seriesValueIdx => $seriesValue) {
+				switch ($seriesValueIdx) {
+					case 'ptCount':
+						$pointCount = self::_getAttribute($seriesValue, 'val', 'integer');
+						break;
+					case 'formatCode':
+						$formatCode = (string) $seriesValue;
+						break;
+					case 'pt':
+						$pointVal = self::_getAttribute($seriesValue, 'idx', 'integer');
+						if ($dataType == 's') {
+							$seriesVal[$pointVal][] = (string) $seriesValue->v;
+						} else {
+							$seriesVal[$pointVal][] = (float) $seriesValue->v;
+						}
+						break;
+				}
+			}
+		}
+
+		return array( 'formatCode'	=> $formatCode,
+					  'pointCount'	=> $pointCount,
+					  'dataValues'	=> $seriesVal
+					);
+	}	//	function _chartDataSeriesValuesMultiLevel()
+
+	private static function _parseRichText($titleDetailPart = null) {
+		$value = new PHPExcel_RichText();
+
+		foreach($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
+			if (isset($titleDetailElement->t)) {
+				$objText = $value->createTextRun( (string) $titleDetailElement->t );
+			}
+			if (isset($titleDetailElement->rPr)) {
+				if (isset($titleDetailElement->rPr->rFont["val"])) {
+					$objText->getFont()->setName((string) $titleDetailElement->rPr->rFont["val"]);
+				}
+
+				$fontSize = (self::_getAttribute($titleDetailElement->rPr, 'sz', 'integer'));
+				if (!is_null($fontSize)) {
+					$objText->getFont()->setSize(floor($fontSize / 100));
+				}
+
+				$fontColor = (self::_getAttribute($titleDetailElement->rPr, 'color', 'string'));
+				if (!is_null($fontColor)) {
+					$objText->getFont()->setColor( new PHPExcel_Style_Color( self::_readColor($fontColor) ) );
+				}
+
+				$bold = self::_getAttribute($titleDetailElement->rPr, 'b', 'boolean');
+				if (!is_null($bold)) {
+					$objText->getFont()->setBold($bold);
+				}
+
+				$italic = self::_getAttribute($titleDetailElement->rPr, 'i', 'boolean');
+				if (!is_null($italic)) {
+					$objText->getFont()->setItalic($italic);
+				}
+
+				$baseline = self::_getAttribute($titleDetailElement->rPr, 'baseline', 'integer');
+				if (!is_null($baseline)) {
+					if ($baseline > 0) {
+						$objText->getFont()->setSuperScript(true);
+					} elseif($baseline < 0) {
+						$objText->getFont()->setSubScript(true);
+					}
+				}
+
+				$underscore = (self::_getAttribute($titleDetailElement->rPr, 'u', 'string'));
+				if (!is_null($underscore)) {
+					if ($underscore == 'sng') {
+						$objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+					} elseif($underscore == 'dbl') {
+						$objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
+					} else {
+						$objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_NONE);
+					}
+				}
+
+				$strikethrough = (self::_getAttribute($titleDetailElement->rPr, 's', 'string'));
+				if (!is_null($strikethrough)) {
+					if ($strikethrough == 'noStrike') {
+						$objText->getFont()->setStrikethrough(false);
+					} else {
+						$objText->getFont()->setStrikethrough(true);
+					}
+				}
+			}
+		}
+
+		return $value;
+	}
+
+	private static function _readChartAttributes($chartDetail) {
+		$plotAttributes = array();
+		if (isset($chartDetail->dLbls)) {
+			if (isset($chartDetail->dLbls->howLegendKey)) {
+				$plotAttributes['showLegendKey'] = self::_getAttribute($chartDetail->dLbls->showLegendKey, 'val', 'string');
+			}
+			if (isset($chartDetail->dLbls->showVal)) {
+				$plotAttributes['showVal'] = self::_getAttribute($chartDetail->dLbls->showVal, 'val', 'string');
+			}
+			if (isset($chartDetail->dLbls->showCatName)) {
+				$plotAttributes['showCatName'] = self::_getAttribute($chartDetail->dLbls->showCatName, 'val', 'string');
+			}
+			if (isset($chartDetail->dLbls->showSerName)) {
+				$plotAttributes['showSerName'] = self::_getAttribute($chartDetail->dLbls->showSerName, 'val', 'string');
+			}
+			if (isset($chartDetail->dLbls->showPercent)) {
+				$plotAttributes['showPercent'] = self::_getAttribute($chartDetail->dLbls->showPercent, 'val', 'string');
+			}
+			if (isset($chartDetail->dLbls->showBubbleSize)) {
+				$plotAttributes['showBubbleSize'] = self::_getAttribute($chartDetail->dLbls->showBubbleSize, 'val', 'string');
+			}
+			if (isset($chartDetail->dLbls->showLeaderLines)) {
+				$plotAttributes['showLeaderLines'] = self::_getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string');
+			}
+		}
+
+		return $plotAttributes;
+	}
+
+	private static function _setChartAttributes($plotArea,$plotAttributes)
+	{
+		foreach($plotAttributes as $plotAttributeKey => $plotAttributeValue) {
+			switch($plotAttributeKey) {
+				case 'showLegendKey' :
+					$plotArea->setShowLegendKey($plotAttributeValue);
+					break;
+				case 'showVal' :
+					$plotArea->setShowVal($plotAttributeValue);
+					break;
+				case 'showCatName' :
+					$plotArea->setShowCatName($plotAttributeValue);
+					break;
+				case 'showSerName' :
+					$plotArea->setShowSerName($plotAttributeValue);
+					break;
+				case 'showPercent' :
+					$plotArea->setShowPercent($plotAttributeValue);
+					break;
+				case 'showBubbleSize' :
+					$plotArea->setShowBubbleSize($plotAttributeValue);
+					break;
+				case 'showLeaderLines' :
+					$plotArea->setShowLeaderLines($plotAttributeValue);
+					break;
+			}
+		}
+	}
+
+}

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Reader/Excel2007/Theme.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader_Excel2007
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader_Excel2007
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_Excel2007_Theme
 {

+ 6890 - 6667
htdocs/includes/phpexcel/PHPExcel/Reader/Excel5.php

@@ -1,6667 +1,6890 @@
-<?php
-/**
- * PHPExcel
- *
- * Copyright (c) 2006 - 2011 PHPExcel
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * @category   PHPExcel
- * @package    PHPExcel_Reader_Excel5
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
- */
-
-// Original file header of ParseXL (used as the base for this class):
-// --------------------------------------------------------------------------------
-// Adapted from Excel_Spreadsheet_Reader developed by users bizon153,
-// trex005, and mmp11 (SourceForge.net)
-// http://sourceforge.net/projects/phpexcelreader/
-// Primary changes made by canyoncasa (dvc) for ParseXL 1.00 ...
-//	 Modelled moreso after Perl Excel Parse/Write modules
-//	 Added Parse_Excel_Spreadsheet object
-//		 Reads a whole worksheet or tab as row,column array or as
-//		 associated hash of indexed rows and named column fields
-//	 Added variables for worksheet (tab) indexes and names
-//	 Added an object call for loading individual woorksheets
-//	 Changed default indexing defaults to 0 based arrays
-//	 Fixed date/time and percent formats
-//	 Includes patches found at SourceForge...
-//		 unicode patch by nobody
-//		 unpack("d") machine depedency patch by matchy
-//		 boundsheet utf16 patch by bjaenichen
-//	 Renamed functions for shorter names
-//	 General code cleanup and rigor, including <80 column width
-//	 Included a testcase Excel file and PHP example calls
-//	 Code works for PHP 5.x
-
-// Primary changes made by canyoncasa (dvc) for ParseXL 1.10 ...
-// http://sourceforge.net/tracker/index.php?func=detail&aid=1466964&group_id=99160&atid=623334
-//	 Decoding of formula conditions, results, and tokens.
-//	 Support for user-defined named cells added as an array "namedcells"
-//		 Patch code for user-defined named cells supports single cells only.
-//		 NOTE: this patch only works for BIFF8 as BIFF5-7 use a different
-//		 external sheet reference structure
-
-
-/** PHPExcel root directory */
-if (!defined('PHPEXCEL_ROOT')) {
-	/**
-	 * @ignore
-	 */
-	define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
-	require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
-}
-
-/**
- *	PHPExcel_Reader_Excel5
- *
- *	This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL}
- *
- *	@category	PHPExcel
- *	@package	PHPExcel_Reader_Excel5
- *	@copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
- */
-class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
-{
-	// ParseXL definitions
-	const XLS_BIFF8						= 0x0600;
-	const XLS_BIFF7						= 0x0500;
-	const XLS_WorkbookGlobals			= 0x0005;
-	const XLS_Worksheet					= 0x0010;
-
-	// record identifiers
-	const XLS_Type_FORMULA				= 0x0006;
-	const XLS_Type_EOF					= 0x000a;
-	const XLS_Type_PROTECT				= 0x0012;
-	const XLS_Type_OBJECTPROTECT		= 0x0063;
-	const XLS_Type_SCENPROTECT			= 0x00dd;
-	const XLS_Type_PASSWORD				= 0x0013;
-	const XLS_Type_HEADER				= 0x0014;
-	const XLS_Type_FOOTER				= 0x0015;
-	const XLS_Type_EXTERNSHEET			= 0x0017;
-	const XLS_Type_DEFINEDNAME			= 0x0018;
-	const XLS_Type_VERTICALPAGEBREAKS	= 0x001a;
-	const XLS_Type_HORIZONTALPAGEBREAKS	= 0x001b;
-	const XLS_Type_NOTE					= 0x001c;
-	const XLS_Type_SELECTION			= 0x001d;
-	const XLS_Type_DATEMODE				= 0x0022;
-	const XLS_Type_EXTERNNAME			= 0x0023;
-	const XLS_Type_LEFTMARGIN			= 0x0026;
-	const XLS_Type_RIGHTMARGIN			= 0x0027;
-	const XLS_Type_TOPMARGIN			= 0x0028;
-	const XLS_Type_BOTTOMMARGIN			= 0x0029;
-	const XLS_Type_PRINTGRIDLINES		= 0x002b;
-	const XLS_Type_FILEPASS				= 0x002f;
-	const XLS_Type_FONT					= 0x0031;
-	const XLS_Type_CONTINUE				= 0x003c;
-	const XLS_Type_PANE					= 0x0041;
-	const XLS_Type_CODEPAGE				= 0x0042;
-	const XLS_Type_DEFCOLWIDTH 			= 0x0055;
-	const XLS_Type_OBJ					= 0x005d;
-	const XLS_Type_COLINFO				= 0x007d;
-	const XLS_Type_IMDATA				= 0x007f;
-	const XLS_Type_SHEETPR				= 0x0081;
-	const XLS_Type_HCENTER				= 0x0083;
-	const XLS_Type_VCENTER				= 0x0084;
-	const XLS_Type_SHEET				= 0x0085;
-	const XLS_Type_PALETTE				= 0x0092;
-	const XLS_Type_SCL					= 0x00a0;
-	const XLS_Type_PAGESETUP			= 0x00a1;
-	const XLS_Type_MULRK				= 0x00bd;
-	const XLS_Type_MULBLANK				= 0x00be;
-	const XLS_Type_DBCELL				= 0x00d7;
-	const XLS_Type_XF					= 0x00e0;
-	const XLS_Type_MERGEDCELLS			= 0x00e5;
-	const XLS_Type_MSODRAWINGGROUP		= 0x00eb;
-	const XLS_Type_MSODRAWING			= 0x00ec;
-	const XLS_Type_SST					= 0x00fc;
-	const XLS_Type_LABELSST				= 0x00fd;
-	const XLS_Type_EXTSST				= 0x00ff;
-	const XLS_Type_EXTERNALBOOK			= 0x01ae;
-	const XLS_Type_DATAVALIDATIONS		= 0x01b2;
-	const XLS_Type_TXO					= 0x01b6;
-	const XLS_Type_HYPERLINK			= 0x01b8;
-	const XLS_Type_DATAVALIDATION		= 0x01be;
-	const XLS_Type_DIMENSION			= 0x0200;
-	const XLS_Type_BLANK				= 0x0201;
-	const XLS_Type_NUMBER				= 0x0203;
-	const XLS_Type_LABEL				= 0x0204;
-	const XLS_Type_BOOLERR				= 0x0205;
-	const XLS_Type_STRING				= 0x0207;
-	const XLS_Type_ROW					= 0x0208;
-	const XLS_Type_INDEX				= 0x020b;
-	const XLS_Type_ARRAY				= 0x0221;
-	const XLS_Type_DEFAULTROWHEIGHT 	= 0x0225;
-	const XLS_Type_WINDOW2				= 0x023e;
-	const XLS_Type_RK					= 0x027e;
-	const XLS_Type_STYLE				= 0x0293;
-	const XLS_Type_FORMAT				= 0x041e;
-	const XLS_Type_SHAREDFMLA			= 0x04bc;
-	const XLS_Type_BOF					= 0x0809;
-	const XLS_Type_SHEETPROTECTION		= 0x0867;
-	const XLS_Type_RANGEPROTECTION		= 0x0868;
-	const XLS_Type_SHEETLAYOUT			= 0x0862;
-	const XLS_Type_XFEXT				= 0x087d;
-	const XLS_Type_UNKNOWN				= 0xffff;
-
-	/**
-	 *	Read data only?
-	 *	Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
-	 *		or whether it should read both data and formatting
-	 *
-	 *	@var	boolean
-	 */
-	private $_readDataOnly = false;
-
-	/**
-	 *	Restrict which sheets should be loaded?
-	 *	This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
-	 *
-	 *	@var	array of string
-	 */
-	private $_loadSheetsOnly = null;
-
-	/**
-	 * PHPExcel_Reader_IReadFilter instance
-	 *
-	 * @var PHPExcel_Reader_IReadFilter
-	 */
-	private $_readFilter = null;
-
-	/**
-	 * Summary Information stream data.
-	 *
-	 * @var string
-	 */
-	private $_summaryInformation;
-
-	/**
-	 * Extended Summary Information stream data.
-	 *
-	 * @var string
-	 */
-	private $_documentSummaryInformation;
-
-	/**
-	 * User-Defined Properties stream data.
-	 *
-	 * @var string
-	 */
-	private $_userDefinedProperties;
-
-	/**
-	 * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
-	 *
-	 * @var string
-	 */
-	private $_data;
-
-	/**
-	 * Size in bytes of $this->_data
-	 *
-	 * @var int
-	 */
-	private $_dataSize;
-
-	/**
-	 * Current position in stream
-	 *
-	 * @var integer
-	 */
-	private $_pos;
-
-	/**
-	 * Workbook to be returned by the reader.
-	 *
-	 * @var PHPExcel
-	 */
-	private $_phpExcel;
-
-	/**
-	 * Worksheet that is currently being built by the reader.
-	 *
-	 * @var PHPExcel_Worksheet
-	 */
-	private $_phpSheet;
-
-	/**
-	 * BIFF version
-	 *
-	 * @var int
-	 */
-	private $_version;
-
-	/**
-	 * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
-	 * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
-	 *
-	 * @var string
-	 */
-	private $_codepage;
-
-	/**
-	 * Shared formats
-	 *
-	 * @var array
-	 */
-	private $_formats;
-
-	/**
-	 * Shared fonts
-	 *
-	 * @var array
-	 */
-	private $_objFonts;
-
-	/**
-	 * Color palette
-	 *
-	 * @var array
-	 */
-	private $_palette;
-
-	/**
-	 * Worksheets
-	 *
-	 * @var array
-	 */
-	private $_sheets;
-
-	/**
-	 * External books
-	 *
-	 * @var array
-	 */
-	private $_externalBooks;
-
-	/**
-	 * REF structures. Only applies to BIFF8.
-	 *
-	 * @var array
-	 */
-	private $_ref;
-
-	/**
-	 * External names
-	 *
-	 * @var array
-	 */
-	private $_externalNames;
-
-	/**
-	 * Defined names
-	 *
-	 * @var array
-	 */
-	private $_definedname;
-
-	/**
-	 * Shared strings. Only applies to BIFF8.
-	 *
-	 * @var array
-	 */
-	private $_sst;
-
-	/**
-	 * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
-	 *
-	 * @var boolean
-	 */
-	private $_frozen;
-
-	/**
-	 * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
-	 *
-	 * @var boolean
-	 */
-	private $_isFitToPages;
-
-	/**
-	 * Objects. One OBJ record contributes with one entry.
-	 *
-	 * @var array
-	 */
-	private $_objs;
-
-	/**
-	 * Text Objects. One TXO record corresponds with one entry.
-	 *
-	 * @var array
-	 */
-	private $_textObjects;
-
-	/**
-	 * Cell Annotations (BIFF8)
-	 *
-	 * @var array
-	 */
-	private $_cellNotes;
-
-	/**
-	 * The combined MSODRAWINGGROUP data
-	 *
-	 * @var string
-	 */
-	private $_drawingGroupData;
-
-	/**
-	 * The combined MSODRAWING data (per sheet)
-	 *
-	 * @var string
-	 */
-	private $_drawingData;
-
-	/**
-	 * Keep track of XF index
-	 *
-	 * @var int
-	 */
-	private $_xfIndex;
-
-	/**
-	 * Mapping of XF index (that is a cell XF) to final index in cellXf collection
-	 *
-	 * @var array
-	 */
-	private $_mapCellXfIndex;
-
-	/**
-	 * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
-	 *
-	 * @var array
-	 */
-	private $_mapCellStyleXfIndex;
-
-	/**
-	 * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
-	 *
-	 * @var array
-	 */
-	private $_sharedFormulas;
-
-	/**
-	 * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
-	 * refers to a shared formula.
-	 *
-	 * @var array
-	 */
-	private $_sharedFormulaParts;
-
-
-	/**
-	 *	Read data only?
-	 *		If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
-	 *		If false (the default) it will read data and formatting.
-	 *
-	 *	@return	boolean
-	 */
-	public function getReadDataOnly()
-	{
-		return $this->_readDataOnly;
-	}
-
-	/**
-	 *	Set read data only
-	 *		Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
-	 *		Set to false (the default) to advise the Reader to read both data and formatting for cells.
-	 *
-	 *	@param	boolean	$pValue
-	 *
-	 *	@return	PHPExcel_Reader_Excel5
-	 */
-	public function setReadDataOnly($pValue = false)
-	{
-		$this->_readDataOnly = $pValue;
-		return $this;
-	}
-
-	/**
-	 *	Get which sheets to load
-	 *		Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
-	 *			indicating that all worksheets in the workbook should be loaded.
-	 *
-	 *	@return mixed
-	 */
-	public function getLoadSheetsOnly()
-	{
-		return $this->_loadSheetsOnly;
-	}
-
-	/**
-	 *	Set which sheets to load
-	 *
-	 *	@param mixed $value
-	 *		This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
-	 *		If NULL, then it tells the Reader to read all worksheets in the workbook
-	 *
-	 *	@return PHPExcel_Reader_Excel5
-	 */
-	public function setLoadSheetsOnly($value = null)
-	{
-		$this->_loadSheetsOnly = is_array($value) ?
-			$value : array($value);
-		return $this;
-	}
-
-	/**
-	 *	Set all sheets to load
-	 *		Tells the Reader to load all worksheets from the workbook.
-	 *
-	 *	@return	PHPExcel_Reader_Excel5
-	 */
-	public function setLoadAllSheets()
-	{
-		$this->_loadSheetsOnly = null;
-		return $this;
-	}
-
-	/**
-	 * Read filter
-	 *
-	 * @return PHPExcel_Reader_IReadFilter
-	 */
-	public function getReadFilter() {
-		return $this->_readFilter;
-	}
-
-	/**
-	 * Set read filter
-	 *
-	 * @param PHPExcel_Reader_IReadFilter $pValue
-	 * @return PHPExcel_Reader_Excel5
-	 */
-	public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
-		$this->_readFilter = $pValue;
-		return $this;
-	}
-
-	/**
-	 * Create a new PHPExcel_Reader_Excel5 instance
-	 */
-	public function __construct() {
-		$this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
-	}
-
-	/**
-	 * Can the current PHPExcel_Reader_IReader read the file?
-	 *
-	 * @param 	string 		$pFileName
-	 * @return 	boolean
-	 */
-	public function canRead($pFilename)
-	{
-		// Check if file exists
-		if (!file_exists($pFilename)) {
-			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
-		}
-
-		try {
-			// Use ParseXL for the hard work.
-			$ole = new PHPExcel_Shared_OLERead();
-
-			// get excel data
-			$res = $ole->read($pFilename);
-			return true;
-
-		} catch (Exception $e) {
-			return false;
-		}
-	}
-
-	/**
-	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
-	 *
-	 * @param 	string 		$pFilename
-	 * @throws 	Exception
-	 */
-	public function listWorksheetNames($pFilename)
-	{
-		// Check if file exists
-		if (!file_exists($pFilename)) {
-			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
-		}
-
-		$worksheetNames = array();
-
-		// Read the OLE file
-		$this->_loadOLE($pFilename);
-
-		// total byte size of Excel data (workbook global substream + sheet substreams)
-		$this->_dataSize = strlen($this->_data);
-
-		$this->_pos		= 0;
-		$this->_sheets	= array();
-
-		// Parse Workbook Global Substream
-		while ($this->_pos < $this->_dataSize) {
-			$code = self::_GetInt2d($this->_data, $this->_pos);
-
-			switch ($code) {
-				case self::XLS_Type_BOF:	$this->_readBof();		break;
-				case self::XLS_Type_SHEET:	$this->_readSheet();	break;
-				case self::XLS_Type_EOF:	$this->_readDefault();	break 2;
-				default:					$this->_readDefault();	break;
-			}
-		}
-
-		foreach ($this->_sheets as $sheet) {
-			if ($sheet['sheetType'] != 0x00) {
-				// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
-				continue;
-			}
-
-			$worksheetNames[] = $sheet['name'];
-		}
-
-		return $worksheetNames;
-	}
-
-
-	/**
-	 * Loads PHPExcel from file
-	 *
-	 * @param 	string 		$pFilename
-	 * @return 	PHPExcel
-	 * @throws 	Exception
-	 */
-	public function load($pFilename)
-	{
-		// Read the OLE file
-		$this->_loadOLE($pFilename);
-
-		// Initialisations
-		$this->_phpExcel = new PHPExcel;
-		$this->_phpExcel->removeSheetByIndex(0); // remove 1st sheet
-		if (!$this->_readDataOnly) {
-			$this->_phpExcel->removeCellStyleXfByIndex(0); // remove the default style
-			$this->_phpExcel->removeCellXfByIndex(0); // remove the default style
-		}
-
-		// Read the summary information stream (containing meta data)
-		$this->_readSummaryInformation();
-
-		// Read the Additional document summary information stream (containing application-specific meta data)
-		$this->_readDocumentSummaryInformation();
-
-		// total byte size of Excel data (workbook global substream + sheet substreams)
-		$this->_dataSize = strlen($this->_data);
-
-		// initialize
-		$this->_pos					= 0;
-		$this->_codepage			= 'CP1252';
-		$this->_formats				= array();
-		$this->_objFonts			= array();
-		$this->_palette				= array();
-		$this->_sheets				= array();
-		$this->_externalBooks		= array();
-		$this->_ref					= array();
-		$this->_definedname			= array();
-		$this->_sst					= array();
-		$this->_drawingGroupData	= '';
-		$this->_xfIndex				= '';
-		$this->_mapCellXfIndex		= array();
-		$this->_mapCellStyleXfIndex	= array();
-
-		// Parse Workbook Global Substream
-		while ($this->_pos < $this->_dataSize) {
-			$code = self::_GetInt2d($this->_data, $this->_pos);
-
-			switch ($code) {
-				case self::XLS_Type_BOF:			$this->_readBof();				break;
-				case self::XLS_Type_FILEPASS:		$this->_readFilepass();			break;
-				case self::XLS_Type_CODEPAGE:		$this->_readCodepage();			break;
-				case self::XLS_Type_DATEMODE:		$this->_readDateMode();			break;
-				case self::XLS_Type_FONT:			$this->_readFont();				break;
-				case self::XLS_Type_FORMAT:			$this->_readFormat();			break;
-				case self::XLS_Type_XF:				$this->_readXf();				break;
-				case self::XLS_Type_XFEXT:			$this->_readXfExt();			break;
-				case self::XLS_Type_STYLE:			$this->_readStyle();			break;
-				case self::XLS_Type_PALETTE:		$this->_readPalette();			break;
-				case self::XLS_Type_SHEET:			$this->_readSheet();			break;
-				case self::XLS_Type_EXTERNALBOOK:	$this->_readExternalBook();		break;
-				case self::XLS_Type_EXTERNNAME:		$this->_readExternName();		break;
-				case self::XLS_Type_EXTERNSHEET:	$this->_readExternSheet();		break;
-				case self::XLS_Type_DEFINEDNAME:	$this->_readDefinedName();		break;
-				case self::XLS_Type_MSODRAWINGGROUP:	$this->_readMsoDrawingGroup();	break;
-				case self::XLS_Type_SST:			$this->_readSst();				break;
-				case self::XLS_Type_EOF:			$this->_readDefault();			break 2;
-				default:							$this->_readDefault();			break;
-			}
-		}
-
-		// Resolve indexed colors for font, fill, and border colors
-		// Cannot be resolved already in XF record, because PALETTE record comes afterwards
-		if (!$this->_readDataOnly) {
-			foreach ($this->_objFonts as $objFont) {
-				if (isset($objFont->colorIndex)) {
-					$color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version);
-					$objFont->getColor()->setRGB($color['rgb']);
-				}
-			}
-
-			foreach ($this->_phpExcel->getCellXfCollection() as $objStyle) {
-				// fill start and end color
-				$fill = $objStyle->getFill();
-
-				if (isset($fill->startcolorIndex)) {
-					$startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version);
-					$fill->getStartColor()->setRGB($startColor['rgb']);
-				}
-
-				if (isset($fill->endcolorIndex)) {
-					$endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version);
-					$fill->getEndColor()->setRGB($endColor['rgb']);
-				}
-
-				// border colors
-				$top      = $objStyle->getBorders()->getTop();
-				$right    = $objStyle->getBorders()->getRight();
-				$bottom   = $objStyle->getBorders()->getBottom();
-				$left     = $objStyle->getBorders()->getLeft();
-				$diagonal = $objStyle->getBorders()->getDiagonal();
-
-				if (isset($top->colorIndex)) {
-					$borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version);
-					$top->getColor()->setRGB($borderTopColor['rgb']);
-				}
-
-				if (isset($right->colorIndex)) {
-					$borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version);
-					$right->getColor()->setRGB($borderRightColor['rgb']);
-				}
-
-				if (isset($bottom->colorIndex)) {
-					$borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version);
-					$bottom->getColor()->setRGB($borderBottomColor['rgb']);
-				}
-
-				if (isset($left->colorIndex)) {
-					$borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version);
-					$left->getColor()->setRGB($borderLeftColor['rgb']);
-				}
-
-				if (isset($diagonal->colorIndex)) {
-					$borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version);
-					$diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
-				}
-			}
-		}
-
-		// treat MSODRAWINGGROUP records, workbook-level Escher
-		if (!$this->_readDataOnly && $this->_drawingGroupData) {
-			$escherWorkbook = new PHPExcel_Shared_Escher();
-			$reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
-			$escherWorkbook = $reader->load($this->_drawingGroupData);
-
-			// debug Escher stream
-			//$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
-			//$debug->load($this->_drawingGroupData);
-		}
-
-		// Parse the individual sheets
-		foreach ($this->_sheets as $sheet) {
-
-			if ($sheet['sheetType'] != 0x00) {
-				// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
-				continue;
-			}
-
-			// check if sheet should be skipped
-			if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
-				continue;
-			}
-
-			// add sheet to PHPExcel object
-			$this->_phpSheet = $this->_phpExcel->createSheet();
-			$this->_phpSheet->setTitle($sheet['name']);
-			$this->_phpSheet->setSheetState($sheet['sheetState']);
-
-			$this->_pos = $sheet['offset'];
-
-			// Initialize isFitToPages. May change after reading SHEETPR record.
-			$this->_isFitToPages = false;
-
-			// Initialize drawingData
-			$this->_drawingData = '';
-
-			// Initialize objs
-			$this->_objs = array();
-
-			// Initialize shared formula parts
-			$this->_sharedFormulaParts = array();
-
-			// Initialize shared formulas
-			$this->_sharedFormulas = array();
-
-			// Initialize text objs
-			$this->_textObjects = array();
-
-			// Initialize cell annotations
-			$this->_cellNotes = array();
-			$this->textObjRef = -1;
-
-			while ($this->_pos <= $this->_dataSize - 4) {
-				$code = self::_GetInt2d($this->_data, $this->_pos);
-
-				switch ($code) {
-					case self::XLS_Type_BOF:					$this->_readBof();						break;
-					case self::XLS_Type_PRINTGRIDLINES:			$this->_readPrintGridlines();			break;
-					case self::XLS_Type_DEFAULTROWHEIGHT:		$this->_readDefaultRowHeight();			break;
-					case self::XLS_Type_SHEETPR:				$this->_readSheetPr();					break;
-					case self::XLS_Type_HORIZONTALPAGEBREAKS:	$this->_readHorizontalPageBreaks();		break;
-					case self::XLS_Type_VERTICALPAGEBREAKS:		$this->_readVerticalPageBreaks();		break;
-					case self::XLS_Type_HEADER:					$this->_readHeader();					break;
-					case self::XLS_Type_FOOTER:					$this->_readFooter();					break;
-					case self::XLS_Type_HCENTER:				$this->_readHcenter();					break;
-					case self::XLS_Type_VCENTER:				$this->_readVcenter();					break;
-					case self::XLS_Type_LEFTMARGIN:				$this->_readLeftMargin();				break;
-					case self::XLS_Type_RIGHTMARGIN:			$this->_readRightMargin();				break;
-					case self::XLS_Type_TOPMARGIN:				$this->_readTopMargin();				break;
-					case self::XLS_Type_BOTTOMMARGIN:			$this->_readBottomMargin();				break;
-					case self::XLS_Type_PAGESETUP:				$this->_readPageSetup();				break;
-					case self::XLS_Type_PROTECT:				$this->_readProtect();					break;
-					case self::XLS_Type_SCENPROTECT:			$this->_readScenProtect();				break;
-					case self::XLS_Type_OBJECTPROTECT:			$this->_readObjectProtect();			break;
-					case self::XLS_Type_PASSWORD:				$this->_readPassword();					break;
-					case self::XLS_Type_DEFCOLWIDTH:			$this->_readDefColWidth();				break;
-					case self::XLS_Type_COLINFO:				$this->_readColInfo();					break;
-					case self::XLS_Type_DIMENSION:				$this->_readDefault();					break;
-					case self::XLS_Type_ROW:					$this->_readRow();						break;
-					case self::XLS_Type_DBCELL:					$this->_readDefault();					break;
-					case self::XLS_Type_RK:						$this->_readRk();						break;
-					case self::XLS_Type_LABELSST:				$this->_readLabelSst();					break;
-					case self::XLS_Type_MULRK:					$this->_readMulRk();					break;
-					case self::XLS_Type_NUMBER:					$this->_readNumber();					break;
-					case self::XLS_Type_FORMULA:				$this->_readFormula();					break;
-					case self::XLS_Type_SHAREDFMLA:				$this->_readSharedFmla();				break;
-					case self::XLS_Type_BOOLERR:				$this->_readBoolErr();					break;
-					case self::XLS_Type_MULBLANK:				$this->_readMulBlank();					break;
-					case self::XLS_Type_LABEL:					$this->_readLabel();					break;
-					case self::XLS_Type_BLANK:					$this->_readBlank();					break;
-					case self::XLS_Type_MSODRAWING:				$this->_readMsoDrawing();				break;
-					case self::XLS_Type_OBJ:					$this->_readObj();						break;
-					case self::XLS_Type_WINDOW2:				$this->_readWindow2();					break;
-					case self::XLS_Type_SCL:					$this->_readScl();						break;
-					case self::XLS_Type_PANE:					$this->_readPane();						break;
-					case self::XLS_Type_SELECTION:				$this->_readSelection();				break;
-					case self::XLS_Type_MERGEDCELLS:			$this->_readMergedCells();				break;
-					case self::XLS_Type_HYPERLINK:				$this->_readHyperLink();				break;
-					case self::XLS_Type_DATAVALIDATIONS:		$this->_readDataValidations();			break;
-					case self::XLS_Type_DATAVALIDATION:			$this->_readDataValidation();			break;
-					case self::XLS_Type_SHEETLAYOUT:			$this->_readSheetLayout();				break;
-					case self::XLS_Type_SHEETPROTECTION:		$this->_readSheetProtection();			break;
-					case self::XLS_Type_RANGEPROTECTION:		$this->_readRangeProtection();			break;
-					case self::XLS_Type_NOTE:					$this->_readNote();						break;
-					//case self::XLS_Type_IMDATA:				$this->_readImData();					break;
-					case self::XLS_Type_TXO:					$this->_readTextObject();				break;
-					case self::XLS_Type_CONTINUE:				$this->_readContinue();					break;
-					case self::XLS_Type_EOF:					$this->_readDefault();					break 2;
-					default:									$this->_readDefault();					break;
-				}
-
-			}
-
-			// treat MSODRAWING records, sheet-level Escher
-			if (!$this->_readDataOnly && $this->_drawingData) {
-				$escherWorksheet = new PHPExcel_Shared_Escher();
-				$reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
-				$escherWorksheet = $reader->load($this->_drawingData);
-
-				// debug Escher stream
-				//$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
-				//$debug->load($this->_drawingData);
-
-				// get all spContainers in one long array, so they can be mapped to OBJ records
-				$allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
-			}
-
-			// treat OBJ records
-			foreach ($this->_objs as $n => $obj) {
-//				echo '<hr /><b>Object</b> reference is ',$n,'<br />';
-//				var_dump($obj);
-//				echo '<br />';
-
-				// the first shape container never has a corresponding OBJ record, hence $n + 1
-				$spContainer = $allSpContainers[$n + 1];
-
-				// we skip all spContainers that are a part of a group shape since we cannot yet handle those
-				if ($spContainer->getNestingLevel() > 1) {
-					continue;
-				}
-
-				// calculate the width and height of the shape
-				list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
-				list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
-
-				$startOffsetX = $spContainer->getStartOffsetX();
-				$startOffsetY = $spContainer->getStartOffsetY();
-				$endOffsetX = $spContainer->getEndOffsetX();
-				$endOffsetY = $spContainer->getEndOffsetY();
-
-				$width = PHPExcel_Shared_Excel5::getDistanceX($this->_phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
-				$height = PHPExcel_Shared_Excel5::getDistanceY($this->_phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
-
-				// calculate offsetX and offsetY of the shape
-				$offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024;
-				$offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256;
-
-				switch ($obj['otObjType']) {
-
-				case 0x19:
-					// Note
-//					echo 'Cell Annotation Object<br />';
-//					echo 'Object ID is ',$obj['idObjID'],'<br />';
-//
-					if (isset($this->_cellNotes[$obj['idObjID']])) {
-						$cellNote = $this->_cellNotes[$obj['idObjID']];
-
-//						echo '_cellNotes[',$obj['idObjID'],']: ';
-//						var_dump($cellNote);
-//						echo '<br />';
-//
-						if (isset($this->_textObjects[$obj['idObjID']])) {
-							$textObject = $this->_textObjects[$obj['idObjID']];
-//							echo '_textObject: ';
-//							var_dump($textObject);
-//							echo '<br />';
-//
-							$this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
-							$text = $textObject['text'];
-						}
-//						echo $text,'<br />';
-					}
-					break;
-
-				case 0x08:
-//					echo 'Picture Object<br />';
-					// picture
-
-					// get index to BSE entry (1-based)
-					$BSEindex = $spContainer->getOPT(0x0104);
-					$BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
-					$BSE = $BSECollection[$BSEindex - 1];
-					$blipType = $BSE->getBlipType();
-
-					// need check because some blip types are not supported by Escher reader such as EMF
-					if ($blip = $BSE->getBlip()) {
-						$ih = imagecreatefromstring($blip->getData());
-						$drawing = new PHPExcel_Worksheet_MemoryDrawing();
-						$drawing->setImageResource($ih);
-
-						// width, height, offsetX, offsetY
-						$drawing->setResizeProportional(false);
-						$drawing->setWidth($width);
-						$drawing->setHeight($height);
-						$drawing->setOffsetX($offsetX);
-						$drawing->setOffsetY($offsetY);
-
-						switch ($blipType) {
-							case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
-								$drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
-								$drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
-								break;
-
-							case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
-								$drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
-								$drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
-								break;
-						}
-
-						$drawing->setWorksheet($this->_phpSheet);
-						$drawing->setCoordinates($spContainer->getStartCoordinates());
-					}
-
-					break;
-
-				default:
-					// other object type
-					break;
-
-				}
-			}
-
-			// treat SHAREDFMLA records
-			if ($this->_version == self::XLS_BIFF8) {
-				foreach ($this->_sharedFormulaParts as $cell => $baseCell) {
-					list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
-					if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) {
-						$formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell);
-						$this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
-					}
-				}
-			}
-
-			if (count($this->_cellNotes) > 0) {
-				foreach($this->_cellNotes as $note => $noteDetails) {
-//					echo '<b>Cell annotation ',$note,'</b><br />';
-//					var_dump($noteDetails);
-//					echo '<br />';
-					$cellAddress = str_replace('$','',$noteDetails['cellRef']);
-					$this->_phpSheet->getComment( $cellAddress )
-													->setAuthor( $noteDetails['author'] )
-													->setText($this->_parseRichText($noteDetails['objTextData']['text']) );
-				}
-			}
-		}
-
-		// add the named ranges (defined names)
-		foreach ($this->_definedname as $definedName) {
-			if ($definedName['isBuiltInName']) {
-				switch ($definedName['name']) {
-
-				case pack('C', 0x06):
-					// print area
-					//	in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
-
-					$ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
-
-					$extractedRanges = array();
-					foreach ($ranges as $range) {
-						// $range should look like one of these
-						//		Foo!$C$7:$J$66
-						//		Bar!$A$1:$IV$2
-
-						$explodes = explode('!', $range);	// FIXME: what if sheetname contains exclamation mark?
-						$sheetName = $explodes[0];
-
-						if (count($explodes) == 2) {
-							$extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
-						}
-					}
-					if ($docSheet = $this->_phpExcel->getSheetByName($sheetName)) {
-						$docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
-					}
-					break;
-
-				case pack('C', 0x07):
-					// print titles (repeating rows)
-					// Assuming BIFF8, there are 3 cases
-					// 1. repeating rows
-					//		formula looks like this: Sheet!$A$1:$IV$2
-					//		rows 1-2 repeat
-					// 2. repeating columns
-					//		formula looks like this: Sheet!$A$1:$B$65536
-					//		columns A-B repeat
-					// 3. both repeating rows and repeating columns
-					//		formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
-
-					$ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
-
-					foreach ($ranges as $range) {
-						// $range should look like this one of these
-						//		Sheet!$A$1:$B$65536
-						//		Sheet!$A$1:$IV$2
-
-						$explodes = explode('!', $range);
-
-						if (count($explodes) == 2) {
-							if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
-
-								$extractedRange = $explodes[1];
-								$extractedRange = str_replace('$', '', $extractedRange);
-
-								$coordinateStrings = explode(':', $extractedRange);
-								if (count($coordinateStrings) == 2) {
-									list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
-									list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
-
-									if ($firstColumn == 'A' and $lastColumn == 'IV') {
-										// then we have repeating rows
-										$docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
-									} elseif ($firstRow == 1 and $lastRow == 65536) {
-										// then we have repeating columns
-										$docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
-									}
-								}
-							}
-						}
-					}
-					break;
-
-				}
-			} else {
-				// Extract range
-				$explodes = explode('!', $definedName['formula']);
-
-				if (count($explodes) == 2) {
-					if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
-						$extractedRange = $explodes[1];
-						$extractedRange = str_replace('$', '', $extractedRange);
-
-						$localOnly = ($definedName['scope'] == 0) ? false : true;
-						$scope = ($definedName['scope'] == 0) ?
-							null : $this->_phpExcel->getSheetByName($this->_sheets[$definedName['scope'] - 1]['name']);
-
-						$this->_phpExcel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope) );
-					}
-				}
-			}
-		}
-
-		return $this->_phpExcel;
-	}
-
-	/**
-	 * Use OLE reader to extract the relevant data streams from the OLE file
-	 *
-	 * @param string $pFilename
-	 */
-	private function _loadOLE($pFilename)
-	{
-		// OLE reader
-		$ole = new PHPExcel_Shared_OLERead();
-
-		// get excel data,
-		$res = $ole->read($pFilename);
-		// Get workbook data: workbook stream + sheet streams
-		$this->_data = $ole->getStream($ole->wrkbook);
-
-		// Get summary information data
-		$this->_summaryInformation = $ole->getStream($ole->summaryInformation);
-
-		// Get additional document summary information data
-		$this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
-
-		// Get user-defined property data
-//		$this->_userDefinedProperties = $ole->getUserDefinedProperties();
-	}
-
-	/**
-	 * Read summary information
-	 */
-	private function _readSummaryInformation()
-	{
-		if (!isset($this->_summaryInformation)) {
-			return;
-		}
-
-		// offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
-		// offset: 2; size: 2;
-		// offset: 4; size: 2; OS version
-		// offset: 6; size: 2; OS indicator
-		// offset: 8; size: 16
-		// offset: 24; size: 4; section count
-		$secCount = self::_GetInt4d($this->_summaryInformation, 24);
-
-		// offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
-		// offset: 44; size: 4
-		$secOffset = self::_GetInt4d($this->_summaryInformation, 44);
-
-		// section header
-		// offset: $secOffset; size: 4; section length
-		$secLength = self::_GetInt4d($this->_summaryInformation, $secOffset);
-
-		// offset: $secOffset+4; size: 4; property count
-		$countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4);
-
-		// initialize code page (used to resolve string values)
-		$codePage = 'CP1252';
-
-		// offset: ($secOffset+8); size: var
-		// loop through property decarations and properties
-		for ($i = 0; $i < $countProperties; ++$i) {
-
-			// offset: ($secOffset+8) + (8 * $i); size: 4; property ID
-			$id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
-
-			// Use value of property id as appropriate
-			// offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
-			$offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
-
-			$type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset);
-
-			// initialize property value
-			$value = null;
-
-			// extract property value based on property type
-			switch ($type) {
-				case 0x02: // 2 byte signed integer
-					$value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
-					break;
-
-				case 0x03: // 4 byte signed integer
-					$value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
-					break;
-
-				case 0x13: // 4 byte unsigned integer
-					// not needed yet, fix later if necessary
-					break;
-
-				case 0x1E: // null-terminated string prepended by dword string length
-					$byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
-					$value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
-					$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
-					$value = rtrim($value);
-					break;
-
-				case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
-					// PHP-time
-					$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
-					break;
-
-				case 0x47: // Clipboard format
-					// not needed yet, fix later if necessary
-					break;
-			}
-
-			switch ($id) {
-				case 0x01:	//	Code Page
-					$codePage = PHPExcel_Shared_CodePage::NumberToName($value);
-					break;
-
-				case 0x02:	//	Title
-					$this->_phpExcel->getProperties()->setTitle($value);
-					break;
-
-				case 0x03:	//	Subject
-					$this->_phpExcel->getProperties()->setSubject($value);
-					break;
-
-				case 0x04:	//	Author (Creator)
-					$this->_phpExcel->getProperties()->setCreator($value);
-					break;
-
-				case 0x05:	//	Keywords
-					$this->_phpExcel->getProperties()->setKeywords($value);
-					break;
-
-				case 0x06:	//	Comments (Description)
-					$this->_phpExcel->getProperties()->setDescription($value);
-					break;
-
-				case 0x07:	//	Template
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x08:	//	Last Saved By (LastModifiedBy)
-					$this->_phpExcel->getProperties()->setLastModifiedBy($value);
-					break;
-
-				case 0x09:	//	Revision
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0A:	//	Total Editing Time
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0B:	//	Last Printed
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0C:	//	Created Date/Time
-					$this->_phpExcel->getProperties()->setCreated($value);
-					break;
-
-				case 0x0D:	//	Modified Date/Time
-					$this->_phpExcel->getProperties()->setModified($value);
-					break;
-
-				case 0x0E:	//	Number of Pages
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0F:	//	Number of Words
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x10:	//	Number of Characters
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x11:	//	Thumbnail
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x12:	//	Name of creating application
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x13:	//	Security
-					//	Not supported by PHPExcel
-					break;
-
-			}
-		}
-	}
-
-	/**
-	 * Read additional document summary information
-	 */
-	private function _readDocumentSummaryInformation()
-	{
-		if (!isset($this->_documentSummaryInformation)) {
-			return;
-		}
-
-		//	offset: 0;	size: 2;	must be 0xFE 0xFF (UTF-16 LE byte order mark)
-		//	offset: 2;	size: 2;
-		//	offset: 4;	size: 2;	OS version
-		//	offset: 6;	size: 2;	OS indicator
-		//	offset: 8;	size: 16
-		//	offset: 24;	size: 4;	section count
-		$secCount = self::_GetInt4d($this->_documentSummaryInformation, 24);
-//		echo '$secCount = ',$secCount,'<br />';
-
-		// offset: 28;	size: 16;	first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
-		// offset: 44;	size: 4;	first section offset
-		$secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44);
-//		echo '$secOffset = ',$secOffset,'<br />';
-
-		//	section header
-		//	offset: $secOffset;	size: 4;	section length
-		$secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset);
-//		echo '$secLength = ',$secLength,'<br />';
-
-		//	offset: $secOffset+4;	size: 4;	property count
-		$countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
-//		echo '$countProperties = ',$countProperties,'<br />';
-
-		// initialize code page (used to resolve string values)
-		$codePage = 'CP1252';
-
-		//	offset: ($secOffset+8);	size: var
-		//	loop through property decarations and properties
-		for ($i = 0; $i < $countProperties; ++$i) {
-//			echo 'Property ',$i,'<br />';
-			//	offset: ($secOffset+8) + (8 * $i);	size: 4;	property ID
-			$id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
-//			echo 'ID is ',$id,'<br />';
-
-			// Use value of property id as appropriate
-			// offset: 60 + 8 * $i;	size: 4;	offset from beginning of section (48)
-			$offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
-
-			$type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
-//			echo 'Type is ',$type,', ';
-
-			// initialize property value
-			$value = null;
-
-			// extract property value based on property type
-			switch ($type) {
-				case 0x02:	//	2 byte signed integer
-					$value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
-					break;
-
-				case 0x03:	//	4 byte signed integer
-					$value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
-					break;
-
-				case 0x13:	//	4 byte unsigned integer
-					// not needed yet, fix later if necessary
-					break;
-
-				case 0x1E:	//	null-terminated string prepended by dword string length
-					$byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
-					$value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
-					$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
-					$value = rtrim($value);
-					break;
-
-				case 0x40:	//	Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
-					// PHP-Time
-					$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
-					break;
-
-				case 0x47:	//	Clipboard format
-					// not needed yet, fix later if necessary
-					break;
-			}
-
-			switch ($id) {
-				case 0x01:	//	Code Page
-					$codePage = PHPExcel_Shared_CodePage::NumberToName($value);
-					break;
-
-				case 0x02:	//	Category
-					$this->_phpExcel->getProperties()->setCategory($value);
-					break;
-
-				case 0x03:	//	Presentation Target
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x04:	//	Bytes
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x05:	//	Lines
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x06:	//	Paragraphs
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x07:	//	Slides
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x08:	//	Notes
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x09:	//	Hidden Slides
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0A:	//	MM Clips
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0B:	//	Scale Crop
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0C:	//	Heading Pairs
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0D:	//	Titles of Parts
-					//	Not supported by PHPExcel
-					break;
-
-				case 0x0E:	//	Manager
-					$this->_phpExcel->getProperties()->setManager($value);
-					break;
-
-				case 0x0F:	//	Company
-					$this->_phpExcel->getProperties()->setCompany($value);
-					break;
-
-				case 0x10:	//	Links up-to-date
-					//	Not supported by PHPExcel
-					break;
-
-			}
-		}
-	}
-
-	/**
-	 * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
-	 */
-	private function _readDefault()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-//		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-	}
-
-
-	/**
-	 *	The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
-	 *		this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
-	 */
-	private function _readNote()
-	{
-//		echo '<b>Read Cell Annotation</b><br />';
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		$cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
-		if ($this->_version == self::XLS_BIFF8) {
-			$noteObjID = self::_GetInt2d($recordData, 6);
-			$noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
-			$noteAuthor = $noteAuthor['value'];
-//			echo 'Note Address=',$cellAddress,'<br />';
-//			echo 'Note Object ID=',$noteObjID,'<br />';
-//			echo 'Note Author=',$noteAuthor,'<hr />';
-//
-			$this->_cellNotes[$noteObjID] = array('cellRef'		=> $cellAddress,
-												  'objectID'	=> $noteObjID,
-												  'author'		=> $noteAuthor
-												 );
-		} else {
-			$extension = false;
-			if ($cellAddress == '$B$65536') {
-				//	If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
-				//		note from the previous cell annotation. We're not yet handling this, so annotations longer than the
-				//		max 2048 bytes will probably throw a wobbly.
-				$row = self::_GetInt2d($recordData, 0);
-				$extension = true;
-				$cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
-			}
-//			echo 'Note Address=',$cellAddress,'<br />';
-
-			$cellAddress = str_replace('$','',$cellAddress);
-			$noteLength = self::_GetInt2d($recordData, 4);
-			$noteText = trim(substr($recordData, 6));
-//			echo 'Note Length=',$noteLength,'<br />';
-//			echo 'Note Text=',$noteText,'<br />';
-
-			if ($extension) {
-				//	Concatenate this extension with the currently set comment for the cell
-				$comment = $this->_phpSheet->getComment( $cellAddress );
-				$commentText = $comment->getText()->getPlainText();
-				$comment->setText($this->_parseRichText($commentText.$noteText) );
-			} else {
-				//	Set comment for the cell
-				$this->_phpSheet->getComment( $cellAddress )
-//													->setAuthor( $author )
-													->setText($this->_parseRichText($noteText) );
-			}
-		}
-
-	}
-
-	/**
-	 *	The TEXT Object record contains the text associated with a cell annotation.
-	 */
-	private function _readTextObject()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		// recordData consists of an array of subrecords looking like this:
-		//	grbit: 2 bytes; Option Flags
-		//	rot: 2 bytes; rotation
-		//	cchText: 2 bytes; length of the text (in the first continue record)
-		//	cbRuns: 2 bytes; length of the formatting (in the second continue record)
-		// followed by the continuation records containing the actual text and formatting
-		$grbitOpts	= self::_GetInt2d($recordData, 0);
-		$rot		= self::_GetInt2d($recordData, 2);
-		$cchText	= self::_GetInt2d($recordData, 10);
-		$cbRuns		= self::_GetInt2d($recordData, 12);
-		$text		= $this->_getSplicedRecordData();
-
-		$this->_textObjects[$this->textObjRef] = array(
-				'text'		=> substr($text["recordData"],$text["spliceOffsets"][0]+1,$cchText),
-				'format'	=> substr($text["recordData"],$text["spliceOffsets"][1],$cbRuns),
-				'alignment'	=> $grbitOpts,
-				'rotation'	=> $rot
-			 );
-
-//		echo '<b>_readTextObject()</b><br />';
-//		var_dump($this->_textObjects[$this->textObjRef]);
-//		echo '<br />';
-	}
-
-	/**
-	 * Read BOF
-	 */
-	private function _readBof()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 2; size: 2; type of the following data
-		$substreamType = self::_GetInt2d($recordData, 2);
-
-		switch ($substreamType) {
-			case self::XLS_WorkbookGlobals:
-				$version = self::_GetInt2d($recordData, 0);
-				if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) {
-					throw new Exception('Cannot read this Excel file. Version is too old.');
-				}
-				$this->_version = $version;
-				break;
-
-			case self::XLS_Worksheet:
-				// do not use this version information for anything
-				// it is unreliable (OpenOffice doc, 5.8), use only version information from the global stream
-				break;
-
-			default:
-				// substream, e.g. chart
-				// just skip the entire substream
-				do {
-					$code = self::_GetInt2d($this->_data, $this->_pos);
-					$this->_readDefault();
-				} while ($code != self::XLS_Type_EOF && $this->_pos < $this->_dataSize);
-				break;
-		}
-	}
-
-	/**
-	 * FILEPASS
-	 *
-	 * This record is part of the File Protection Block. It
-	 * contains information about the read/write password of the
-	 * file. All record contents following this record will be
-	 * encrypted.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readFilepass()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-//		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		throw new Exception('Cannot read encrypted file');
-	}
-
-	/**
-	 * CODEPAGE
-	 *
-	 * This record stores the text encoding used to write byte
-	 * strings, stored as MS Windows code page identifier.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readCodepage()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; code page identifier
-		$codepage = self::_GetInt2d($recordData, 0);
-
-		$this->_codepage = PHPExcel_Shared_CodePage::NumberToName($codepage);
-	}
-
-	/**
-	 * DATEMODE
-	 *
-	 * This record specifies the base date for displaying date
-	 * values. All dates are stored as count of days past this
-	 * base date. In BIFF2-BIFF4 this record is part of the
-	 * Calculation Settings Block. In BIFF5-BIFF8 it is
-	 * stored in the Workbook Globals Substream.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readDateMode()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; 0 = base 1900, 1 = base 1904
-		PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
-		if (ord($recordData{0}) == 1) {
-			PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
-		}
-	}
-
-	/**
-	 * Read a FONT record
-	 */
-	private function _readFont()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			$objFont = new PHPExcel_Style_Font();
-
-			// offset: 0; size: 2; height of the font (in twips = 1/20 of a point)
-			$size = self::_GetInt2d($recordData, 0);
-			$objFont->setSize($size / 20);
-
-			// offset: 2; size: 2; option flags
-				// bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8)
-				// bit: 1; mask 0x0002; italic
-				$isItalic = (0x0002 & self::_GetInt2d($recordData, 2)) >> 1;
-				if ($isItalic) $objFont->setItalic(true);
-
-				// bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8)
-				// bit: 3; mask 0x0008; strike
-				$isStrike = (0x0008 & self::_GetInt2d($recordData, 2)) >> 3;
-				if ($isStrike) $objFont->setStrikethrough(true);
-
-			// offset: 4; size: 2; colour index
-			$colorIndex = self::_GetInt2d($recordData, 4);
-			$objFont->colorIndex = $colorIndex;
-
-			// offset: 6; size: 2; font weight
-			$weight = self::_GetInt2d($recordData, 6);
-			switch ($weight) {
-				case 0x02BC:
-					$objFont->setBold(true);
-					break;
-			}
-
-			// offset: 8; size: 2; escapement type
-			$escapement = self::_GetInt2d($recordData, 8);
-			switch ($escapement) {
-				case 0x0001:
-					$objFont->setSuperScript(true);
-					break;
-				case 0x0002:
-					$objFont->setSubScript(true);
-					break;
-			}
-
-			// offset: 10; size: 1; underline type
-			$underlineType = ord($recordData{10});
-			switch ($underlineType) {
-				case 0x00:
-					break; // no underline
-				case 0x01:
-					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
-					break;
-				case 0x02:
-					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
-					break;
-				case 0x21:
-					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING);
-					break;
-				case 0x22:
-					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING);
-					break;
-			}
-
-			// offset: 11; size: 1; font family
-			// offset: 12; size: 1; character set
-			// offset: 13; size: 1; not used
-			// offset: 14; size: var; font name
-			if ($this->_version == self::XLS_BIFF8) {
-				$string = self::_readUnicodeStringShort(substr($recordData, 14));
-			} else {
-				$string = $this->_readByteStringShort(substr($recordData, 14));
-			}
-			$objFont->setName($string['value']);
-
-			$this->_objFonts[] = $objFont;
-		}
-	}
-
-	/**
-	 * FORMAT
-	 *
-	 * This record contains information about a number format.
-	 * All FORMAT records occur together in a sequential list.
-	 *
-	 * In BIFF2-BIFF4 other records referencing a FORMAT record
-	 * contain a zero-based index into this list. From BIFF5 on
-	 * the FORMAT record contains the index itself that will be
-	 * used by other records.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readFormat()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			$indexCode = self::_GetInt2d($recordData, 0);
-
-			if ($this->_version == self::XLS_BIFF8) {
-				$string = self::_readUnicodeStringLong(substr($recordData, 2));
-			} else {
-				// BIFF7
-				$string = $this->_readByteStringShort(substr($recordData, 2));
-			}
-
-			$formatString = $string['value'];
-			$this->_formats[$indexCode] = $formatString;
-		}
-	}
-
-	/**
-	 * XF - Extended Format
-	 *
-	 * This record contains formatting information for cells, rows, columns or styles.
-	 * According to http://support.microsoft.com/kb/147732 there are always at least 15 cell style XF
-	 * and 1 cell XF.
-	 * Inspection of Excel files generated by MS Office Excel shows that XF records 0-14 are cell style XF
-	 * and XF record 15 is a cell XF
-	 * We only read the first cell style XF and skip the remaining cell style XF records
-	 * We read all cell XF records.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readXf()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		$objStyle = new PHPExcel_Style();
-
-		if (!$this->_readDataOnly) {
-			// offset:  0; size: 2; Index to FONT record
-			if (self::_GetInt2d($recordData, 0) < 4) {
-				$fontIndex = self::_GetInt2d($recordData, 0);
-			} else {
-				// this has to do with that index 4 is omitted in all BIFF versions for some strange reason
-				// check the OpenOffice documentation of the FONT record
-				$fontIndex = self::_GetInt2d($recordData, 0) - 1;
-			}
-			$objStyle->setFont($this->_objFonts[$fontIndex]);
-
-			// offset:  2; size: 2; Index to FORMAT record
-			$numberFormatIndex = self::_GetInt2d($recordData, 2);
-			if (isset($this->_formats[$numberFormatIndex])) {
-				// then we have user-defined format code
-				$numberformat = array('code' => $this->_formats[$numberFormatIndex]);
-			} elseif (($code = PHPExcel_Style_NumberFormat::builtInFormatCode($numberFormatIndex)) !== '') {
-				// then we have built-in format code
-				$numberformat = array('code' => $code);
-			} else {
-				// we set the general format code
-				$numberformat = array('code' => 'General');
-			}
-			$objStyle->getNumberFormat()->setFormatCode($numberformat['code']);
-
-			// offset:  4; size: 2; XF type, cell protection, and parent style XF
-			// bit 2-0; mask 0x0007; XF_TYPE_PROT
-			$xfTypeProt = self::_GetInt2d($recordData, 4);
-			// bit 0; mask 0x01; 1 = cell is locked
-			$isLocked = (0x01 & $xfTypeProt) >> 0;
-			$objStyle->getProtection()->setLocked($isLocked ?
-				PHPExcel_Style_Protection::PROTECTION_INHERIT : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
-
-			// bit 1; mask 0x02; 1 = Formula is hidden
-			$isHidden = (0x02 & $xfTypeProt) >> 1;
-			$objStyle->getProtection()->setHidden($isHidden ?
-				PHPExcel_Style_Protection::PROTECTION_PROTECTED : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
-
-			// bit 2; mask 0x04; 0 = Cell XF, 1 = Cell Style XF
-			$isCellStyleXf = (0x04 & $xfTypeProt) >> 2;
-
-			// offset:  6; size: 1; Alignment and text break
-			// bit 2-0, mask 0x07; horizontal alignment
-			$horAlign = (0x07 & ord($recordData{6})) >> 0;
-			switch ($horAlign) {
-				case 0:
-					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
-					break;
-				case 1:
-					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
-					break;
-				case 2:
-					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
-					break;
-				case 3:
-					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
-					break;
-				case 5:
-					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);
-					break;
-				case 6:
-					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS);
-					break;
-			}
-			// bit 3, mask 0x08; wrap text
-			$wrapText = (0x08 & ord($recordData{6})) >> 3;
-			switch ($wrapText) {
-				case 0:
-					$objStyle->getAlignment()->setWrapText(false);
-					break;
-				case 1:
-					$objStyle->getAlignment()->setWrapText(true);
-					break;
-			}
-			// bit 6-4, mask 0x70; vertical alignment
-			$vertAlign = (0x70 & ord($recordData{6})) >> 4;
-			switch ($vertAlign) {
-				case 0:
-					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
-					break;
-				case 1:
-					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
-					break;
-				case 2:
-					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);
-					break;
-				case 3:
-					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_JUSTIFY);
-					break;
-			}
-
-			if ($this->_version == self::XLS_BIFF8) {
-				// offset:  7; size: 1; XF_ROTATION: Text rotation angle
-					$angle = ord($recordData{7});
-					$rotation = 0;
-					if ($angle <= 90) {
-						$rotation = $angle;
-					} else if ($angle <= 180) {
-						$rotation = 90 - $angle;
-					} else if ($angle == 255) {
-						$rotation = -165;
-					}
-					$objStyle->getAlignment()->setTextRotation($rotation);
-
-				// offset:  8; size: 1; Indentation, shrink to cell size, and text direction
-					// bit: 3-0; mask: 0x0F; indent level
-					$indent = (0x0F & ord($recordData{8})) >> 0;
-					$objStyle->getAlignment()->setIndent($indent);
-
-					// bit: 4; mask: 0x10; 1 = shrink content to fit into cell
-					$shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
-					switch ($shrinkToFit) {
-						case 0:
-							$objStyle->getAlignment()->setShrinkToFit(false);
-							break;
-						case 1:
-							$objStyle->getAlignment()->setShrinkToFit(true);
-							break;
-					}
-
-				// offset:  9; size: 1; Flags used for attribute groups
-
-				// offset: 10; size: 4; Cell border lines and background area
-					// bit: 3-0; mask: 0x0000000F; left style
-					if ($bordersLeftStyle = self::_mapBorderStyle((0x0000000F & self::_GetInt4d($recordData, 10)) >> 0)) {
-						$objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle);
-					}
-					// bit: 7-4; mask: 0x000000F0; right style
-					if ($bordersRightStyle = self::_mapBorderStyle((0x000000F0 & self::_GetInt4d($recordData, 10)) >> 4)) {
-						$objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle);
-					}
-					// bit: 11-8; mask: 0x00000F00; top style
-					if ($bordersTopStyle = self::_mapBorderStyle((0x00000F00 & self::_GetInt4d($recordData, 10)) >> 8)) {
-						$objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle);
-					}
-					// bit: 15-12; mask: 0x0000F000; bottom style
-					if ($bordersBottomStyle = self::_mapBorderStyle((0x0000F000 & self::_GetInt4d($recordData, 10)) >> 12)) {
-						$objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle);
-					}
-					// bit: 22-16; mask: 0x007F0000; left color
-					$objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::_GetInt4d($recordData, 10)) >> 16;
-
-					// bit: 29-23; mask: 0x3F800000; right color
-					$objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::_GetInt4d($recordData, 10)) >> 23;
-
-					// bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom
-					$diagonalDown = (0x40000000 & self::_GetInt4d($recordData, 10)) >> 30 ?
-						true : false;
-
-					// bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right
-					$diagonalUp = (0x80000000 & self::_GetInt4d($recordData, 10)) >> 31 ?
-						true : false;
-
-					if ($diagonalUp == false && $diagonalDown == false) {
-						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
-					} elseif ($diagonalUp == true && $diagonalDown == false) {
-						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
-					} elseif ($diagonalUp == false && $diagonalDown == true) {
-						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
-					} elseif ($diagonalUp == true && $diagonalDown == true) {
-						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
-					}
-
-				// offset: 14; size: 4;
-					// bit: 6-0; mask: 0x0000007F; top color
-					$objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::_GetInt4d($recordData, 14)) >> 0;
-
-					// bit: 13-7; mask: 0x00003F80; bottom color
-					$objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::_GetInt4d($recordData, 14)) >> 7;
-
-					// bit: 20-14; mask: 0x001FC000; diagonal color
-					$objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::_GetInt4d($recordData, 14)) >> 14;
-
-					// bit: 24-21; mask: 0x01E00000; diagonal style
-					if ($bordersDiagonalStyle = self::_mapBorderStyle((0x01E00000 & self::_GetInt4d($recordData, 14)) >> 21)) {
-						$objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle);
-					}
-
-					// bit: 31-26; mask: 0xFC000000 fill pattern
-					if ($fillType = self::_mapFillPattern((0xFC000000 & self::_GetInt4d($recordData, 14)) >> 26)) {
-						$objStyle->getFill()->setFillType($fillType);
-					}
-				// offset: 18; size: 2; pattern and background colour
-					// bit: 6-0; mask: 0x007F; color index for pattern color
-					$objStyle->getFill()->startcolorIndex = (0x007F & self::_GetInt2d($recordData, 18)) >> 0;
-
-					// bit: 13-7; mask: 0x3F80; color index for pattern background
-					$objStyle->getFill()->endcolorIndex = (0x3F80 & self::_GetInt2d($recordData, 18)) >> 7;
-			} else {
-				// BIFF5
-
-				// offset: 7; size: 1; Text orientation and flags
-				$orientationAndFlags = ord($recordData{7});
-
-				// bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
-				$xfOrientation = (0x03 & $orientationAndFlags) >> 0;
-				switch ($xfOrientation) {
-					case 0:
-						$objStyle->getAlignment()->setTextRotation(0);
-						break;
-					case 1:
-						$objStyle->getAlignment()->setTextRotation(-165);
-						break;
-					case 2:
-						$objStyle->getAlignment()->setTextRotation(90);
-						break;
-					case 3:
-						$objStyle->getAlignment()->setTextRotation(-90);
-						break;
-				}
-
-				// offset: 8; size: 4; cell border lines and background area
-				$borderAndBackground = self::_GetInt4d($recordData, 8);
-
-				// bit: 6-0; mask: 0x0000007F; color index for pattern color
-				$objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0;
-
-				// bit: 13-7; mask: 0x00003F80; color index for pattern background
-				$objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7;
-
-				// bit: 21-16; mask: 0x003F0000; fill pattern
-				$objStyle->getFill()->setFillType(self::_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16));
-
-				// bit: 24-22; mask: 0x01C00000; bottom line style
-				$objStyle->getBorders()->getBottom()->setBorderStyle(self::_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22));
-
-				// bit: 31-25; mask: 0xFE000000; bottom line color
-				$objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25;
-
-				// offset: 12; size: 4; cell border lines
-				$borderLines = self::_GetInt4d($recordData, 12);
-
-				// bit: 2-0; mask: 0x00000007; top line style
-				$objStyle->getBorders()->getTop()->setBorderStyle(self::_mapBorderStyle((0x00000007 & $borderLines) >> 0));
-
-				// bit: 5-3; mask: 0x00000038; left line style
-				$objStyle->getBorders()->getLeft()->setBorderStyle(self::_mapBorderStyle((0x00000038 & $borderLines) >> 3));
-
-				// bit: 8-6; mask: 0x000001C0; right line style
-				$objStyle->getBorders()->getRight()->setBorderStyle(self::_mapBorderStyle((0x000001C0 & $borderLines) >> 6));
-
-				// bit: 15-9; mask: 0x0000FE00; top line color index
-				$objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9;
-
-				// bit: 22-16; mask: 0x007F0000; left line color index
-				$objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $borderLines) >> 16;
-
-				// bit: 29-23; mask: 0x3F800000; right line color index
-				$objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $borderLines) >> 23;
-			}
-
-			// add cellStyleXf or cellXf and update mapping
-			if ($isCellStyleXf) {
-				// we only read one style XF record which is always the first
-				if ($this->_xfIndex == 0) {
-					$this->_phpExcel->addCellStyleXf($objStyle);
-					$this->_mapCellStyleXfIndex[$this->_xfIndex] = 0;
-				}
-			} else {
-				// we read all cell XF records
-				$this->_phpExcel->addCellXf($objStyle);
-				$this->_mapCellXfIndex[$this->_xfIndex] = count($this->_phpExcel->getCellXfCollection()) - 1;
-			}
-
-			// update XF index for when we read next record
-			++$this->_xfIndex;
-		}
-	}
-
-	/**
-	 *
-	 */
-	private function _readXfExt()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; 0x087D = repeated header
-
-			// offset: 2; size: 2
-
-			// offset: 4; size: 8; not used
-
-			// offset: 12; size: 2; record version
-
-			// offset: 14; size: 2; index to XF record which this record modifies
-			$ixfe = self::_GetInt2d($recordData, 14);
-
-			// offset: 16; size: 2; not used
-
-			// offset: 18; size: 2; number of extension properties that follow
-			$cexts = self::_GetInt2d($recordData, 18);
-
-			// start reading the actual extension data
-			$offset = 20;
-			while ($offset < $length) {
-				// extension type
-				$extType = self::_GetInt2d($recordData, $offset);
-
-				// extension length
-				$cb = self::_GetInt2d($recordData, $offset + 2);
-
-				// extension data
-				$extData = substr($recordData, $offset + 4, $cb);
-
-				switch ($extType) {
-					case 4:		// fill start color
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
-								$fill->getStartColor()->setRGB($rgb);
-								unset($fill->startcolorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 5:		// fill end color
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
-								$fill->getEndColor()->setRGB($rgb);
-								unset($fill->endcolorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 7:		// border color top
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$top = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getTop();
-								$top->getColor()->setRGB($rgb);
-								unset($top->colorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 8:		// border color bottom
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$bottom = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getBottom();
-								$bottom->getColor()->setRGB($rgb);
-								unset($bottom->colorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 9:		// border color left
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$left = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getLeft();
-								$left->getColor()->setRGB($rgb);
-								unset($left->colorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 10:		// border color right
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$right = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getRight();
-								$right->getColor()->setRGB($rgb);
-								unset($right->colorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 11:		// border color diagonal
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$diagonal = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getDiagonal();
-								$diagonal->getColor()->setRGB($rgb);
-								unset($diagonal->colorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-
-					case 13:	// font color
-						$xclfType  = self::_GetInt2d($extData, 0); // color type
-						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
-
-						if ($xclfType == 2) {
-							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
-
-							// modify the relevant style property
-							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
-								$font = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFont();
-								$font->getColor()->setRGB($rgb);
-								unset($font->colorIndex); // normal color index does not apply, discard
-							}
-						}
-						break;
-				}
-
-				$offset += $cb;
-			}
-		}
-
-	}
-
-	/**
-	 * Read STYLE record
-	 */
-	private function _readStyle()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; index to XF record and flag for built-in style
-			$ixfe = self::_GetInt2d($recordData, 0);
-
-			// bit: 11-0; mask 0x0FFF; index to XF record
-			$xfIndex = (0x0FFF & $ixfe) >> 0;
-
-			// bit: 15; mask 0x8000; 0 = user-defined style, 1 = built-in style
-			$isBuiltIn = (bool) ((0x8000 & $ixfe) >> 15);
-
-			if ($isBuiltIn) {
-				// offset: 2; size: 1; identifier for built-in style
-				$builtInId = ord($recordData{2});
-
-				switch ($builtInId) {
-				case 0x00:
-					// currently, we are not using this for anything
-					break;
-
-				default:
-					break;
-				}
-
-			} else {
-				// user-defined; not supported by PHPExcel
-			}
-		}
-	}
-
-	/**
-	 * Read PALETTE record
-	 */
-	private function _readPalette()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; number of following colors
-			$nm = self::_GetInt2d($recordData, 0);
-
-			// list of RGB colors
-			for ($i = 0; $i < $nm; ++$i) {
-				$rgb = substr($recordData, 2 + 4 * $i, 4);
-				$this->_palette[] = self::_readRGB($rgb);
-			}
-		}
-	}
-
-	/**
-	 * SHEET
-	 *
-	 * This record is  located in the  Workbook Globals
-	 * Substream  and represents a sheet inside the workbook.
-	 * One SHEET record is written for each sheet. It stores the
-	 * sheet name and a stream offset to the BOF record of the
-	 * respective Sheet Substream within the Workbook Stream.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readSheet()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 4; absolute stream position of the BOF record of the sheet
-		$rec_offset = self::_GetInt4d($recordData, 0);
-
-		// offset: 4; size: 1; sheet state
-		switch (ord($recordData{4})) {
-			case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;    break;
-			case 0x01: $sheetState = PHPExcel_Worksheet::SHEETSTATE_HIDDEN;     break;
-			case 0x02: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN; break;
-			default: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;      break;
-		}
-
-		// offset: 5; size: 1; sheet type
-		$sheetType = ord($recordData{5});
-
-		// offset: 6; size: var; sheet name
-		if ($this->_version == self::XLS_BIFF8) {
-			$string = self::_readUnicodeStringShort(substr($recordData, 6));
-			$rec_name = $string['value'];
-		} elseif ($this->_version == self::XLS_BIFF7) {
-			$string = $this->_readByteStringShort(substr($recordData, 6));
-			$rec_name = $string['value'];
-		}
-
-		$this->_sheets[] = array(
-			'name' => $rec_name,
-			'offset' => $rec_offset,
-			'sheetState' => $sheetState,
-			'sheetType' => $sheetType,
-		);
-	}
-
-	/**
-	 * Read EXTERNALBOOK record
-	 */
-	private function _readExternalBook()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset within record data
-		$offset = 0;
-
-		// there are 4 types of records
-		if (strlen($recordData) > 4) {
-			// external reference
-			// offset: 0; size: 2; number of sheet names ($nm)
-			$nm = self::_GetInt2d($recordData, 0);
-			$offset += 2;
-
-			// offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length)
-			$encodedUrlString = self::_readUnicodeStringLong(substr($recordData, 2));
-			$offset += $encodedUrlString['size'];
-
-			// offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length)
-			$externalSheetNames = array();
-			for ($i = 0; $i < $nm; ++$i) {
-				$externalSheetNameString = self::_readUnicodeStringLong(substr($recordData, $offset));
-				$externalSheetNames[] = $externalSheetNameString['value'];
-				$offset += $externalSheetNameString['size'];
-			}
-
-			// store the record data
-			$this->_externalBooks[] = array(
-				'type' => 'external',
-				'encodedUrl' => $encodedUrlString['value'],
-				'externalSheetNames' => $externalSheetNames,
-			);
-
-		} elseif (substr($recordData, 2, 2) == pack('CC', 0x01, 0x04)) {
-			// internal reference
-			// offset: 0; size: 2; number of sheet in this document
-			// offset: 2; size: 2; 0x01 0x04
-			$this->_externalBooks[] = array(
-				'type' => 'internal',
-			);
-		} elseif (substr($recordData, 0, 4) == pack('vCC', 0x0001, 0x01, 0x3A)) {
-			// add-in function
-			// offset: 0; size: 2; 0x0001
-			$this->_externalBooks[] = array(
-				'type' => 'addInFunction',
-			);
-		} elseif (substr($recordData, 0, 2) == pack('v', 0x0000)) {
-			// DDE links, OLE links
-			// offset: 0; size: 2; 0x0000
-			// offset: 2; size: var; encoded source document name
-			$this->_externalBooks[] = array(
-				'type' => 'DDEorOLE',
-			);
-		}
-	}
-
-	/**
-	 * Read EXTERNNAME record.
-	 */
-	private function _readExternName()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// external sheet references provided for named cells
-		if ($this->_version == self::XLS_BIFF8) {
-			// offset: 0; size: 2; options
-			$options = self::_GetInt2d($recordData, 0);
-
-			// offset: 2; size: 2;
-
-			// offset: 4; size: 2; not used
-
-			// offset: 6; size: var
-			$nameString = self::_readUnicodeStringShort(substr($recordData, 6));
-
-			// offset: var; size: var; formula data
-			$offset = 6 + $nameString['size'];
-			$formula = $this->_getFormulaFromStructure(substr($recordData, $offset));
-
-			$this->_externalNames[] = array(
-				'name' => $nameString['value'],
-				'formula' => $formula,
-			);
-		}
-	}
-
-	/**
-	 * Read EXTERNSHEET record
-	 */
-	private function _readExternSheet()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// external sheet references provided for named cells
-		if ($this->_version == self::XLS_BIFF8) {
-			// offset: 0; size: 2; number of following ref structures
-			$nm = self::_GetInt2d($recordData, 0);
-			for ($i = 0; $i < $nm; ++$i) {
-				$this->_ref[] = array(
-					// offset: 2 + 6 * $i; index to EXTERNALBOOK record
-					'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i),
-					// offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
-					'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i),
-					// offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
-					'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i),
-				);
-			}
-		}
-	}
-
-	/**
-	 * DEFINEDNAME
-	 *
-	 * This record is part of a Link Table. It contains the name
-	 * and the token array of an internal defined name. Token
-	 * arrays of defined names contain tokens with aberrant
-	 * token classes.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readDefinedName()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_version == self::XLS_BIFF8) {
-			// retrieves named cells
-
-			// offset: 0; size: 2; option flags
-			$opts = self::_GetInt2d($recordData, 0);
-
-				// bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name
-				$isBuiltInName = (0x0020 & $opts) >> 5;
-
-			// offset: 2; size: 1; keyboard shortcut
-
-			// offset: 3; size: 1; length of the name (character count)
-			$nlen = ord($recordData{3});
-
-			// offset: 4; size: 2; size of the formula data (it can happen that this is zero)
-			// note: there can also be additional data, this is not included in $flen
-			$flen = self::_GetInt2d($recordData, 4);
-
-			// offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based)
-			$scope = self::_GetInt2d($recordData, 8);
-
-			// offset: 14; size: var; Name (Unicode string without length field)
-			$string = self::_readUnicodeString(substr($recordData, 14), $nlen);
-
-			// offset: var; size: $flen; formula data
-			$offset = 14 + $string['size'];
-			$formulaStructure = pack('v', $flen) . substr($recordData, $offset);
-
-			try {
-				$formula = $this->_getFormulaFromStructure($formulaStructure);
-			} catch (Exception $e) {
-				$formula = '';
-			}
-
-			$this->_definedname[] = array(
-				'isBuiltInName' => $isBuiltInName,
-				'name' => $string['value'],
-				'formula' => $formula,
-				'scope' => $scope,
-			);
-		}
-	}
-
-	/**
-	 * Read MSODRAWINGGROUP record
-	 */
-	private function _readMsoDrawingGroup()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-
-		// get spliced record data
-		$splicedRecordData = $this->_getSplicedRecordData();
-		$recordData = $splicedRecordData['recordData'];
-
-		$this->_drawingGroupData .= $recordData;
-	}
-
-	/**
-	 * SST - Shared String Table
-	 *
-	 * This record contains a list of all strings used anywhere
-	 * in the workbook. Each string occurs only once. The
-	 * workbook uses indexes into the list to reference the
-	 * strings.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 **/
-	private function _readSst()
-	{
-		// offset within (spliced) record data
-		$pos = 0;
-
-		// get spliced record data
-		$splicedRecordData = $this->_getSplicedRecordData();
-
-		$recordData = $splicedRecordData['recordData'];
-		$spliceOffsets = $splicedRecordData['spliceOffsets'];
-
-		// offset: 0; size: 4; total number of strings in the workbook
-		$pos += 4;
-
-		// offset: 4; size: 4; number of following strings ($nm)
-		$nm = self::_GetInt4d($recordData, 4);
-		$pos += 4;
-
-		// loop through the Unicode strings (16-bit length)
-		for ($i = 0; $i < $nm; ++$i) {
-
-			// number of characters in the Unicode string
-			$numChars = self::_GetInt2d($recordData, $pos);
-			$pos += 2;
-
-			// option flags
-			$optionFlags = ord($recordData{$pos});
-			++$pos;
-
-			// bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
-			$isCompressed = (($optionFlags & 0x01) == 0) ;
-
-			// bit: 2; mask: 0x02; 0 = ordinary; 1 = Asian phonetic
-			$hasAsian = (($optionFlags & 0x04) != 0);
-
-			// bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
-			$hasRichText = (($optionFlags & 0x08) != 0);
-
-			if ($hasRichText) {
-				// number of Rich-Text formatting runs
-				$formattingRuns = self::_GetInt2d($recordData, $pos);
-				$pos += 2;
-			}
-
-			if ($hasAsian) {
-				// size of Asian phonetic setting
-				$extendedRunLength = self::_GetInt4d($recordData, $pos);
-				$pos += 4;
-			}
-
-			// expected byte length of character array if not split
-			$len = ($isCompressed) ? $numChars : $numChars * 2;
-
-			// look up limit position
-			foreach ($spliceOffsets as $spliceOffset) {
-				// it can happen that the string is empty, therefore we need
-				// <= and not just <
-				if ($pos <= $spliceOffset) {
-					$limitpos = $spliceOffset;
-					break;
-				}
-			}
-
-			if ($pos + $len <= $limitpos) {
-				// character array is not split between records
-
-				$retstr = substr($recordData, $pos, $len);
-				$pos += $len;
-
-			} else {
-				// character array is split between records
-
-				// first part of character array
-				$retstr = substr($recordData, $pos, $limitpos - $pos);
-
-				$bytesRead = $limitpos - $pos;
-
-				// remaining characters in Unicode string
-				$charsLeft = $numChars - (($isCompressed) ? $bytesRead : ($bytesRead / 2));
-
-				$pos = $limitpos;
-
-				// keep reading the characters
-				while ($charsLeft > 0) {
-
-					// look up next limit position, in case the string span more than one continue record
-					foreach ($spliceOffsets as $spliceOffset) {
-						if ($pos < $spliceOffset) {
-							$limitpos = $spliceOffset;
-							break;
-						}
-					}
-
-					// repeated option flags
-					// OpenOffice.org documentation 5.21
-					$option = ord($recordData{$pos});
-					++$pos;
-
-					if ($isCompressed && ($option == 0)) {
-						// 1st fragment compressed
-						// this fragment compressed
-						$len = min($charsLeft, $limitpos - $pos);
-						$retstr .= substr($recordData, $pos, $len);
-						$charsLeft -= $len;
-						$isCompressed = true;
-
-					} elseif (!$isCompressed && ($option != 0)) {
-						// 1st fragment uncompressed
-						// this fragment uncompressed
-						$len = min($charsLeft * 2, $limitpos - $pos);
-						$retstr .= substr($recordData, $pos, $len);
-						$charsLeft -= $len / 2;
-						$isCompressed = false;
-
-					} elseif (!$isCompressed && ($option == 0)) {
-						// 1st fragment uncompressed
-						// this fragment compressed
-						$len = min($charsLeft, $limitpos - $pos);
-						for ($j = 0; $j < $len; ++$j) {
-							$retstr .= $recordData{$pos + $j} . chr(0);
-						}
-						$charsLeft -= $len;
-						$isCompressed = false;
-
-					} else {
-						// 1st fragment compressed
-						// this fragment uncompressed
-						$newstr = '';
-						for ($j = 0; $j < strlen($retstr); ++$j) {
-							$newstr .= $retstr[$j] . chr(0);
-						}
-						$retstr = $newstr;
-						$len = min($charsLeft * 2, $limitpos - $pos);
-						$retstr .= substr($recordData, $pos, $len);
-						$charsLeft -= $len / 2;
-						$isCompressed = false;
-					}
-
-					$pos += $len;
-				}
-			}
-
-			// convert to UTF-8
-			$retstr = self::_encodeUTF16($retstr, $isCompressed);
-
-			// read additional Rich-Text information, if any
-			$fmtRuns = array();
-			if ($hasRichText) {
-				// list of formatting runs
-				for ($j = 0; $j < $formattingRuns; ++$j) {
-					// first formatted character; zero-based
-					$charPos = self::_GetInt2d($recordData, $pos + $j * 4);
-
-					// index to font record
-					$fontIndex = self::_GetInt2d($recordData, $pos + 2 + $j * 4);
-
-					$fmtRuns[] = array(
-						'charPos' => $charPos,
-						'fontIndex' => $fontIndex,
-					);
-				}
-				$pos += 4 * $formattingRuns;
-			}
-
-			// read additional Asian phonetics information, if any
-			if ($hasAsian) {
-				// For Asian phonetic settings, we skip the extended string data
-				$pos += $extendedRunLength;
-			}
-
-			// store the shared sting
-			$this->_sst[] = array(
-				'value' => $retstr,
-				'fmtRuns' => $fmtRuns,
-			);
-		}
-
-		// _getSplicedRecordData() takes care of moving current position in data stream
-	}
-
-	/**
-	 * Read PRINTGRIDLINES record
-	 */
-	private function _readPrintGridlines()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
-			// offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines
-			$printGridlines = (bool) self::_GetInt2d($recordData, 0);
-			$this->_phpSheet->setPrintGridlines($printGridlines);
-		}
-	}
-
-	/**
-	 * Read DEFAULTROWHEIGHT record
-	 */
-	private function _readDefaultRowHeight()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; option flags
-		// offset: 2; size: 2; default height for unused rows, (twips 1/20 point)
-		$height = self::_GetInt2d($recordData, 2);
-		$this->_phpSheet->getDefaultRowDimension()->setRowHeight($height / 20);
-	}
-
-	/**
-	 * Read SHEETPR record
-	 */
-	private function _readSheetPr()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2
-
-		// bit: 6; mask: 0x0040; 0 = outline buttons above outline group
-		$isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6;
-		$this->_phpSheet->setShowSummaryBelow($isSummaryBelow);
-
-		// bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
-		$isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7;
-		$this->_phpSheet->setShowSummaryRight($isSummaryRight);
-
-		// bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
-		// this corresponds to radio button setting in page setup dialog in Excel
-		$this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8);
-	}
-
-	/**
-	 * Read HORIZONTALPAGEBREAKS record
-	 */
-	private function _readHorizontalPageBreaks()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
-
-			// offset: 0; size: 2; number of the following row index structures
-			$nm = self::_GetInt2d($recordData, 0);
-
-			// offset: 2; size: 6 * $nm; list of $nm row index structures
-			for ($i = 0; $i < $nm; ++$i) {
-				$r = self::_GetInt2d($recordData, 2 + 6 * $i);
-				$cf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
-				$cl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
-
-				// not sure why two column indexes are necessary?
-				$this->_phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW);
-			}
-		}
-	}
-
-	/**
-	 * Read VERTICALPAGEBREAKS record
-	 */
-	private function _readVerticalPageBreaks()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
-			// offset: 0; size: 2; number of the following column index structures
-			$nm = self::_GetInt2d($recordData, 0);
-
-			// offset: 2; size: 6 * $nm; list of $nm row index structures
-			for ($i = 0; $i < $nm; ++$i) {
-				$c = self::_GetInt2d($recordData, 2 + 6 * $i);
-				$rf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
-				$rl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
-
-				// not sure why two row indexes are necessary?
-				$this->_phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN);
-			}
-		}
-	}
-
-	/**
-	 * Read HEADER record
-	 */
-	private function _readHeader()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: var
-			// realized that $recordData can be empty even when record exists
-			if ($recordData) {
-				if ($this->_version == self::XLS_BIFF8) {
-					$string = self::_readUnicodeStringLong($recordData);
-				} else {
-					$string = $this->_readByteStringShort($recordData);
-				}
-
-				$this->_phpSheet->getHeaderFooter()->setOddHeader($string['value']);
-				$this->_phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
-			}
-		}
-	}
-
-	/**
-	 * Read FOOTER record
-	 */
-	private function _readFooter()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: var
-			// realized that $recordData can be empty even when record exists
-			if ($recordData) {
-				if ($this->_version == self::XLS_BIFF8) {
-					$string = self::_readUnicodeStringLong($recordData);
-				} else {
-					$string = $this->_readByteStringShort($recordData);
-				}
-				$this->_phpSheet->getHeaderFooter()->setOddFooter($string['value']);
-				$this->_phpSheet->getHeaderFooter()->setEvenFooter($string['value']);
-			}
-		}
-	}
-
-	/**
-	 * Read HCENTER record
-	 */
-	private function _readHcenter()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally
-			$isHorizontalCentered = (bool) self::_GetInt2d($recordData, 0);
-
-			$this->_phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered);
-		}
-	}
-
-	/**
-	 * Read VCENTER record
-	 */
-	private function _readVcenter()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered
-			$isVerticalCentered = (bool) self::_GetInt2d($recordData, 0);
-
-			$this->_phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered);
-		}
-	}
-
-	/**
-	 * Read LEFTMARGIN record
-	 */
-	private function _readLeftMargin()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 8
-			$this->_phpSheet->getPageMargins()->setLeft(self::_extractNumber($recordData));
-		}
-	}
-
-	/**
-	 * Read RIGHTMARGIN record
-	 */
-	private function _readRightMargin()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 8
-			$this->_phpSheet->getPageMargins()->setRight(self::_extractNumber($recordData));
-		}
-	}
-
-	/**
-	 * Read TOPMARGIN record
-	 */
-	private function _readTopMargin()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 8
-			$this->_phpSheet->getPageMargins()->setTop(self::_extractNumber($recordData));
-		}
-	}
-
-	/**
-	 * Read BOTTOMMARGIN record
-	 */
-	private function _readBottomMargin()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 8
-			$this->_phpSheet->getPageMargins()->setBottom(self::_extractNumber($recordData));
-		}
-	}
-
-	/**
-	 * Read PAGESETUP record
-	 */
-	private function _readPageSetup()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; paper size
-			$paperSize = self::_GetInt2d($recordData, 0);
-
-			// offset: 2; size: 2; scaling factor
-			$scale = self::_GetInt2d($recordData, 2);
-
-			// offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed
-			$fitToWidth = self::_GetInt2d($recordData, 6);
-
-			// offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed
-			$fitToHeight = self::_GetInt2d($recordData, 8);
-
-			// offset: 10; size: 2; option flags
-
-				// bit: 1; mask: 0x0002; 0=landscape, 1=portrait
-				$isPortrait = (0x0002 & self::_GetInt2d($recordData, 10)) >> 1;
-
-				// bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init
-				// when this bit is set, do not use flags for those properties
-				$isNotInit = (0x0004 & self::_GetInt2d($recordData, 10)) >> 2;
-
-			if (!$isNotInit) {
-				$this->_phpSheet->getPageSetup()->setPaperSize($paperSize);
-				switch ($isPortrait) {
-				case 0: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE); break;
-				case 1: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT); break;
-				}
-
-				$this->_phpSheet->getPageSetup()->setScale($scale, false);
-				$this->_phpSheet->getPageSetup()->setFitToPage((bool) $this->_isFitToPages);
-				$this->_phpSheet->getPageSetup()->setFitToWidth($fitToWidth, false);
-				$this->_phpSheet->getPageSetup()->setFitToHeight($fitToHeight, false);
-			}
-
-			// offset: 16; size: 8; header margin (IEEE 754 floating-point value)
-			$marginHeader = self::_extractNumber(substr($recordData, 16, 8));
-			$this->_phpSheet->getPageMargins()->setHeader($marginHeader);
-
-			// offset: 24; size: 8; footer margin (IEEE 754 floating-point value)
-			$marginFooter = self::_extractNumber(substr($recordData, 24, 8));
-			$this->_phpSheet->getPageMargins()->setFooter($marginFooter);
-		}
-	}
-
-	/**
-	 * PROTECT - Sheet protection (BIFF2 through BIFF8)
-	 *   if this record is omitted, then it also means no sheet protection
-	 */
-	private function _readProtect()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		// offset: 0; size: 2;
-
-		// bit 0, mask 0x01; 1 = sheet is protected
-		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
-		$this->_phpSheet->getProtection()->setSheet((bool)$bool);
-	}
-
-	/**
-	 * SCENPROTECT
-	 */
-	private function _readScenProtect()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		// offset: 0; size: 2;
-
-		// bit: 0, mask 0x01; 1 = scenarios are protected
-		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
-
-		$this->_phpSheet->getProtection()->setScenarios((bool)$bool);
-	}
-
-	/**
-	 * OBJECTPROTECT
-	 */
-	private function _readObjectProtect()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		// offset: 0; size: 2;
-
-		// bit: 0, mask 0x01; 1 = objects are protected
-		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
-
-		$this->_phpSheet->getProtection()->setObjects((bool)$bool);
-	}
-
-	/**
-	 * PASSWORD - Sheet protection (hashed) password (BIFF2 through BIFF8)
-	 */
-	private function _readPassword()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; 16-bit hash value of password
-			$password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
-			$this->_phpSheet->getProtection()->setPassword($password, true);
-		}
-	}
-
-	/**
-	 * Read DEFCOLWIDTH record
-	 */
-	private function _readDefColWidth()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; default column width
-		$width = self::_GetInt2d($recordData, 0);
-		if ($width != 8) {
-			$this->_phpSheet->getDefaultColumnDimension()->setWidth($width);
-		}
-	}
-
-	/**
-	 * Read COLINFO record
-	 */
-	private function _readColInfo()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; index to first column in range
-			$fc = self::_GetInt2d($recordData, 0); // first column index
-
-			// offset: 2; size: 2; index to last column in range
-			$lc = self::_GetInt2d($recordData, 2); // first column index
-
-			// offset: 4; size: 2; width of the column in 1/256 of the width of the zero character
-			$width = self::_GetInt2d($recordData, 4);
-
-			// offset: 6; size: 2; index to XF record for default column formatting
-			$xfIndex = self::_GetInt2d($recordData, 6);
-
-			// offset: 8; size: 2; option flags
-
-				// bit: 0; mask: 0x0001; 1= columns are hidden
-				$isHidden = (0x0001 & self::_GetInt2d($recordData, 8)) >> 0;
-
-				// bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline)
-				$level = (0x0700 & self::_GetInt2d($recordData, 8)) >> 8;
-
-				// bit: 12; mask: 0x1000; 1 = collapsed
-				$isCollapsed = (0x1000 & self::_GetInt2d($recordData, 8)) >> 12;
-
-			// offset: 10; size: 2; not used
-
-			for ($i = $fc; $i <= $lc; ++$i) {
-				if ($lc == 255 || $lc == 256) {
-					$this->_phpSheet->getDefaultColumnDimension()->setWidth($width / 256);
-					break;
-				}
-				$this->_phpSheet->getColumnDimensionByColumn($i)->setWidth($width / 256);
-				$this->_phpSheet->getColumnDimensionByColumn($i)->setVisible(!$isHidden);
-				$this->_phpSheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
-				$this->_phpSheet->getColumnDimensionByColumn($i)->setCollapsed($isCollapsed);
-				$this->_phpSheet->getColumnDimensionByColumn($i)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-		}
-	}
-
-	/**
-	 * ROW
-	 *
-	 * This record contains the properties of a single row in a
-	 * sheet. Rows and cells in a sheet are divided into blocks
-	 * of 32 rows.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readRow()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; index of this row
-			$r = self::_GetInt2d($recordData, 0);
-
-			// offset: 2; size: 2; index to column of the first cell which is described by a cell record
-
-			// offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1
-
-			// offset: 6; size: 2;
-
-				// bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
-				$height = (0x7FFF & self::_GetInt2d($recordData, 6)) >> 0;
-
-				// bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
-				$useDefaultHeight = (0x8000 & self::_GetInt2d($recordData, 6)) >> 15;
-
-				if (!$useDefaultHeight) {
-					$this->_phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
-				}
-
-			// offset: 8; size: 2; not used
-
-			// offset: 10; size: 2; not used in BIFF5-BIFF8
-
-			// offset: 12; size: 4; option flags and default row formatting
-
-				// bit: 2-0: mask: 0x00000007; outline level of the row
-				$level = (0x00000007 & self::_GetInt4d($recordData, 12)) >> 0;
-				$this->_phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);
-
-				// bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
-				$isCollapsed = (0x00000010 & self::_GetInt4d($recordData, 12)) >> 4;
-				$this->_phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);
-
-				// bit: 5; mask: 0x00000020; 1 = row is hidden
-				$isHidden = (0x00000020 & self::_GetInt4d($recordData, 12)) >> 5;
-				$this->_phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);
-
-				// bit: 7; mask: 0x00000080; 1 = row has explicit format
-				$hasExplicitFormat = (0x00000080 & self::_GetInt4d($recordData, 12)) >> 7;
-
-				// bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
-				$xfIndex = (0x0FFF0000 & self::_GetInt4d($recordData, 12)) >> 16;
-
-				if ($hasExplicitFormat) {
-					$this->_phpSheet->getRowDimension($r + 1)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-				}
-		}
-	}
-
-	/**
-	 * Read RK record
-	 * This record represents a cell that contains an RK value
-	 * (encoded integer or floating-point value). If a
-	 * floating-point value cannot be encoded to an RK value,
-	 * a NUMBER record will be written. This record replaces the
-	 * record INTEGER written in BIFF2.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readRk()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; index to row
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; index to column
-		$column = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-			// offset: 4; size: 2; index to XF record
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			// offset: 6; size: 4; RK value
-			$rknum = self::_GetInt4d($recordData, 6);
-			$numValue = self::_GetIEEE754($rknum);
-
-			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-			if (!$this->_readDataOnly) {
-				// add style information
-				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-
-			// add cell
-			$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
-		}
-	}
-
-	/**
-	 * Read LABELSST record
-	 * This record represents a cell that contains a string. It
-	 * replaces the LABEL record and RSTRING record used in
-	 * BIFF2-BIFF5.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readLabelSst()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; index to row
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; index to column
-		$column = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-			// offset: 4; size: 2; index to XF record
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			// offset: 6; size: 4; index to SST record
-			$index = self::_GetInt4d($recordData, 6);
-
-			// add cell
-			if (($fmtRuns = $this->_sst[$index]['fmtRuns']) && !$this->_readDataOnly) {
-				// then we should treat as rich text
-				$richText = new PHPExcel_RichText();
-				$charPos = 0;
-				$sstCount = count($this->_sst[$index]['fmtRuns']);
-				for ($i = 0; $i <= $sstCount; ++$i) {
-					if (isset($fmtRuns[$i])) {
-						$text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos);
-						$charPos = $fmtRuns[$i]['charPos'];
-					} else {
-						$text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, PHPExcel_Shared_String::CountCharacters($this->_sst[$index]['value']));
-					}
-
-					if (PHPExcel_Shared_String::CountCharacters($text) > 0) {
-						if ($i == 0) { // first text run, no style
-							$richText->createText($text);
-						} else {
-							$textRun = $richText->createTextRun($text);
-							if (isset($fmtRuns[$i - 1])) {
-								if ($fmtRuns[$i - 1]['fontIndex'] < 4) {
-									$fontIndex = $fmtRuns[$i - 1]['fontIndex'];
-								} else {
-									// this has to do with that index 4 is omitted in all BIFF versions for some strange reason
-									// check the OpenOffice documentation of the FONT record
-									$fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1;
-								}
-								$textRun->setFont(clone $this->_objFonts[$fontIndex]);
-							}
-						}
-					}
-				}
-				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-				$cell->setValueExplicit($richText, PHPExcel_Cell_DataType::TYPE_STRING);
-			} else {
-				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-				$cell->setValueExplicit($this->_sst[$index]['value'], PHPExcel_Cell_DataType::TYPE_STRING);
-			}
-
-			if (!$this->_readDataOnly) {
-				// add style information
-				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-		}
-	}
-
-	/**
-	 * Read MULRK record
-	 * This record represents a cell range containing RK value
-	 * cells. All cells are located in the same row.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readMulRk()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; index to row
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; index to first column
-		$colFirst = self::_GetInt2d($recordData, 2);
-
-		// offset: var; size: 2; index to last column
-		$colLast = self::_GetInt2d($recordData, $length - 2);
-		$columns = $colLast - $colFirst + 1;
-
-		// offset within record data
-		$offset = 4;
-
-		for ($i = 0; $i < $columns; ++$i) {
-			$columnString = PHPExcel_Cell::stringFromColumnIndex($colFirst + $i);
-
-			// Read cell?
-			if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-
-				// offset: var; size: 2; index to XF record
-				$xfIndex = self::_GetInt2d($recordData, $offset);
-
-				// offset: var; size: 4; RK value
-				$numValue = self::_GetIEEE754(self::_GetInt4d($recordData, $offset + 2));
-				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-				if (!$this->_readDataOnly) {
-					// add style
-					$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-				}
-
-				// add cell value
-				$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
-			}
-
-			$offset += 6;
-		}
-	}
-
-	/**
-	 * Read NUMBER record
-	 * This record represents a cell that contains a
-	 * floating-point value.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readNumber()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; index to row
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size 2; index to column
-		$column = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-			// offset 4; size: 2; index to XF record
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			$numValue = self::_extractNumber(substr($recordData, 6, 8));
-
-			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-			if (!$this->_readDataOnly) {
-				// add cell style
-				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-
-			// add cell value
-			$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
-		}
-	}
-
-	/**
-	 * Read FORMULA record + perhaps a following STRING record if formula result is a string
-	 * This record contains the token array and the result of a
-	 * formula cell.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readFormula()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; row index
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; col index
-		$column = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
-
-		// offset: 20: size: variable; formula structure
-		$formulaStructure = substr($recordData, 20);
-
-		// offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
-		$options = self::_GetInt2d($recordData, 14);
-
-		// bit: 0; mask: 0x0001; 1 = recalculate always
-		// bit: 1; mask: 0x0002; 1 = calculate on open
-		// bit: 2; mask: 0x0008; 1 = part of a shared formula
-		$isPartOfSharedFormula = (bool) (0x0008 & $options);
-
-		// WARNING:
-		// We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
-		// the formula data may be ordinary formula data, therefore we need to check
-		// explicitly for the tExp token (0x01)
-		$isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
-
-		if ($isPartOfSharedFormula) {
-			// part of shared formula which means there will be a formula with a tExp token and nothing else
-			// get the base cell, grab tExp token
-			$baseRow = self::_GetInt2d($formulaStructure, 3);
-			$baseCol = self::_GetInt2d($formulaStructure, 5);
-			$this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
-		}
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-
-			if ($isPartOfSharedFormula) {
-				// formula is added to this cell after the sheet has been read
-				$this->_sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
-			}
-
-			// offset: 16: size: 4; not used
-
-			// offset: 4; size: 2; XF index
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			// offset: 6; size: 8; result of the formula
-			if ( (ord($recordData{6}) == 0)
-				&& (ord($recordData{12}) == 255)
-				&& (ord($recordData{13}) == 255) ) {
-
-				// String formula. Result follows in appended STRING record
-				$dataType = PHPExcel_Cell_DataType::TYPE_STRING;
-
-				// read possible SHAREDFMLA record
-				$code = self::_GetInt2d($this->_data, $this->_pos);
-				if ($code == self::XLS_Type_SHAREDFMLA) {
-					$this->_readSharedFmla();
-				}
-
-				// read STRING record
-				$value = $this->_readString();
-
-			} elseif ((ord($recordData{6}) == 1)
-				&& (ord($recordData{12}) == 255)
-				&& (ord($recordData{13}) == 255)) {
-
-				// Boolean formula. Result is in +2; 0=false, 1=true
-				$dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
-				$value = (bool) ord($recordData{8});
-
-			} elseif ((ord($recordData{6}) == 2)
-				&& (ord($recordData{12}) == 255)
-				&& (ord($recordData{13}) == 255)) {
-
-				// Error formula. Error code is in +2
-				$dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
-				$value = self::_mapErrorCode(ord($recordData{8}));
-
-			} elseif ((ord($recordData{6}) == 3)
-				&& (ord($recordData{12}) == 255)
-				&& (ord($recordData{13}) == 255)) {
-
-				// Formula result is a null string
-				$dataType = PHPExcel_Cell_DataType::TYPE_NULL;
-				$value = '';
-
-			} else {
-
-				// forumla result is a number, first 14 bytes like _NUMBER record
-				$dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
-				$value = self::_extractNumber(substr($recordData, 6, 8));
-
-			}
-
-			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-			if (!$this->_readDataOnly) {
-				// add cell style
-				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-
-			// store the formula
-			if (!$isPartOfSharedFormula) {
-				// not part of shared formula
-				// add cell value. If we can read formula, populate with formula, otherwise just used cached value
-				try {
-					if ($this->_version != self::XLS_BIFF8) {
-						throw new Exception('Not BIFF8. Can only read BIFF8 formulas');
-					}
-					$formula = $this->_getFormulaFromStructure($formulaStructure); // get formula in human language
-					$cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
-
-				} catch (Exception $e) {
-					$cell->setValueExplicit($value, $dataType);
-				}
-			} else {
-				if ($this->_version == self::XLS_BIFF8) {
-					// do nothing at this point, formula id added later in the code
-				} else {
-					$cell->setValueExplicit($value, $dataType);
-				}
-			}
-
-			// store the cached calculated value
-			$cell->setCalculatedValue($value);
-		}
-	}
-
-	/**
-	 * Read a SHAREDFMLA record. This function just stores the binary shared formula in the reader,
-	 * which usually contains relative references.
-	 * These will be used to construct the formula in each shared formula part after the sheet is read.
-	 */
-	private function _readSharedFmla()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0, size: 6; cell range address of the area used by the shared formula, not used for anything
-		$cellRange = substr($recordData, 0, 6);
-		$cellRange = $this->_readBIFF5CellRangeAddressFixed($cellRange); // note: even BIFF8 uses BIFF5 syntax
-
-		// offset: 6, size: 1; not used
-
-		// offset: 7, size: 1; number of existing FORMULA records for this shared formula
-		$no = ord($recordData{7});
-
-		// offset: 8, size: var; Binary token array of the shared formula
-		$formula = substr($recordData, 8);
-
-		// at this point we only store the shared formula for later use
-		$this->_sharedFormulas[$this->_baseCell] = $formula;
-
-	}
-
-	/**
-	 * Read a STRING record from current stream position and advance the stream pointer to next record
-	 * This record is used for storing result from FORMULA record when it is a string, and
-	 * it occurs directly after the FORMULA record
-	 *
-	 * @return string The string contents as UTF-8
-	 */
-	private function _readString()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_version == self::XLS_BIFF8) {
-			$string = self::_readUnicodeStringLong($recordData);
-			$value = $string['value'];
-		} else {
-			$string = $this->_readByteStringLong($recordData);
-			$value = $string['value'];
-		}
-
-		return $value;
-	}
-
-	/**
-	 * Read BOOLERR record
-	 * This record represents a Boolean value or error value
-	 * cell.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readBoolErr()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; row index
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; column index
-		$column = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-			// offset: 4; size: 2; index to XF record
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			// offset: 6; size: 1; the boolean value or error value
-			$boolErr = ord($recordData{6});
-
-			// offset: 7; size: 1; 0=boolean; 1=error
-			$isError = ord($recordData{7});
-
-			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-			switch ($isError) {
-				case 0: // boolean
-					$value = (bool) $boolErr;
-
-					// add cell value
-					$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_BOOL);
-					break;
-
-				case 1: // error type
-					$value = self::_mapErrorCode($boolErr);
-
-					// add cell value
-					$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR);
-					break;
-			}
-
-			if (!$this->_readDataOnly) {
-				// add cell style
-				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-		}
-	}
-
-	/**
-	 * Read MULBLANK record
-	 * This record represents a cell range of empty cells. All
-	 * cells are located in the same row
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readMulBlank()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; index to row
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; index to first column
-		$fc = self::_GetInt2d($recordData, 2);
-
-		// offset: 4; size: 2 x nc; list of indexes to XF records
-		// add style information
-		if (!$this->_readDataOnly) {
-			for ($i = 0; $i < $length / 2 - 3; ++$i) {
-				$columnString = PHPExcel_Cell::stringFromColumnIndex($fc + $i);
-
-				// Read cell?
-				if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-					$xfIndex = self::_GetInt2d($recordData, 4 + 2 * $i);
-					$this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-				}
-			}
-		}
-
-		// offset: 6; size 2; index to last column (not needed)
-	}
-
-	/**
-	 * Read LABEL record
-	 * This record represents a cell that contains a string. In
-	 * BIFF8 it is usually replaced by the LABELSST record.
-	 * Excel still uses this record, if it copies unformatted
-	 * text cells to the clipboard.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readLabel()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; index to row
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; index to column
-		$column = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-			// offset: 4; size: 2; XF index
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			// add cell value
-			// todo: what if string is very long? continue record
-			if ($this->_version == self::XLS_BIFF8) {
-				$string = self::_readUnicodeStringLong(substr($recordData, 6));
-				$value = $string['value'];
-			} else {
-				$string = $this->_readByteStringLong(substr($recordData, 6));
-				$value = $string['value'];
-			}
-			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
-			$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
-
-			if (!$this->_readDataOnly) {
-				// add cell style
-				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-		}
-	}
-
-	/**
-	 * Read BLANK record
-	 */
-	private function _readBlank()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; row index
-		$row = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; col index
-		$col = self::_GetInt2d($recordData, 2);
-		$columnString = PHPExcel_Cell::stringFromColumnIndex($col);
-
-		// Read cell?
-		if ( !is_null($this->getReadFilter()) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
-			// offset: 4; size: 2; XF index
-			$xfIndex = self::_GetInt2d($recordData, 4);
-
-			// add style information
-			if (!$this->_readDataOnly) {
-				$this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
-			}
-		}
-
-	}
-
-	/**
-	 * Read MSODRAWING record
-	 */
-	private function _readMsoDrawing()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-
-		// get spliced record data
-		$splicedRecordData = $this->_getSplicedRecordData();
-		$recordData = $splicedRecordData['recordData'];
-
-		$this->_drawingData .= $recordData;
-	}
-
-	/**
-	 * Read OBJ record
-	 */
-	private function _readObj()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly || $this->_version != self::XLS_BIFF8) {
-			return;
-		}
-
-		// recordData consists of an array of subrecords looking like this:
-		//	ft: 2 bytes; ftCmo type (0x15)
-		//	cb: 2 bytes; size in bytes of ftCmo data
-		//	ot: 2 bytes; Object Type
-		//	id: 2 bytes; Object id number
-		//	grbit: 2 bytes; Option Flags
-		//	data: var; subrecord data
-
-		// for now, we are just interested in the second subrecord containing the object type
-		$ftCmoType	= self::_GetInt2d($recordData, 0);
-		$cbCmoSize	= self::_GetInt2d($recordData, 2);
-		$otObjType	= self::_GetInt2d($recordData, 4);
-		$idObjID	= self::_GetInt2d($recordData, 6);
-		$grbitOpts	= self::_GetInt2d($recordData, 6);
-
-		$this->_objs[] = array(
-			'ftCmoType'	=> $ftCmoType,
-			'cbCmoSize'	=> $cbCmoSize,
-			'otObjType'	=> $otObjType,
-			'idObjID'	=> $idObjID,
-			'grbitOpts'	=> $grbitOpts
-		);
-		$this->textObjRef = $idObjID;
-
-//		echo '<b>_readObj()</b><br />';
-//		var_dump(end($this->_objs));
-//		echo '<br />';
-	}
-
-	/**
-	 * Read WINDOW2 record
-	 */
-	private function _readWindow2()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; option flags
-		$options = self::_GetInt2d($recordData, 0);
-
-		// bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines
-		$showGridlines = (bool) ((0x0002 & $options) >> 1);
-		$this->_phpSheet->setShowGridlines($showGridlines);
-
-		// bit: 2; mask: 0x0004; 0 = do not show headers, 1 = show headers
-		$showRowColHeaders = (bool) ((0x0004 & $options) >> 2);
-		$this->_phpSheet->setShowRowColHeaders($showRowColHeaders);
-
-		// bit: 3; mask: 0x0008; 0 = panes are not frozen, 1 = panes are frozen
-		$this->_frozen = (bool) ((0x0008 & $options) >> 3);
-
-		// bit: 6; mask: 0x0040; 0 = columns from left to right, 1 = columns from right to left
-		$this->_phpSheet->setRightToLeft((bool)((0x0040 & $options) >> 6));
-
-		// bit: 10; mask: 0x0400; 0 = sheet not active, 1 = sheet active
-		$isActive = (bool) ((0x0400 & $options) >> 10);
-		if ($isActive) {
-			$this->_phpExcel->setActiveSheetIndex($this->_phpExcel->getIndex($this->_phpSheet));
-		}
-	}
-
-	/**
-	 * Read SCL record
-	 */
-	private function _readScl()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// offset: 0; size: 2; numerator of the view magnification
-		$numerator = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; numerator of the view magnification
-		$denumerator = self::_GetInt2d($recordData, 2);
-
-		// set the zoom scale (in percent)
-		$this->_phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator);
-	}
-
-	/**
-	 * Read PANE record
-	 */
-	private function _readPane()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; position of vertical split
-			$px = self::_GetInt2d($recordData, 0);
-
-			// offset: 2; size: 2; position of horizontal split
-			$py = self::_GetInt2d($recordData, 2);
-
-			if ($this->_frozen) {
-				// frozen panes
-				$this->_phpSheet->freezePane(PHPExcel_Cell::stringFromColumnIndex($px) . ($py + 1));
-			} else {
-				// unfrozen panes; split windows; not supported by PHPExcel core
-			}
-		}
-	}
-
-	/**
-	 * Read SELECTION record. There is one such record for each pane in the sheet.
-	 */
-	private function _readSelection()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 1; pane identifier
-			$paneId = ord($recordData{0});
-
-			// offset: 1; size: 2; index to row of the active cell
-			$r = self::_GetInt2d($recordData, 1);
-
-			// offset: 3; size: 2; index to column of the active cell
-			$c = self::_GetInt2d($recordData, 3);
-
-			// offset: 5; size: 2; index into the following cell range list to the
-			//  entry that contains the active cell
-			$index = self::_GetInt2d($recordData, 5);
-
-			// offset: 7; size: var; cell range address list containing all selected cell ranges
-			$data = substr($recordData, 7);
-			$cellRangeAddressList = $this->_readBIFF5CellRangeAddressList($data); // note: also BIFF8 uses BIFF5 syntax
-
-			$selectedCells = $cellRangeAddressList['cellRangeAddresses'][0];
-
-			// first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
-			if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
-				$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
-			}
-
-			// first row '1' + last row '65536' indicates that full column is selected
-			if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
-				$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
-			}
-
-			// first column 'A' + last column 'IV' indicates that full row is selected
-			if (preg_match('/^(A[0-9]+\:)IV([0-9]+)$/', $selectedCells)) {
-				$selectedCells = preg_replace('/^(A[0-9]+\:)IV([0-9]+)$/', '${1}XFD${2}', $selectedCells);
-			}
-
-			$this->_phpSheet->setSelectedCells($selectedCells);
-		}
-	}
-
-	private function _includeCellRangeFiltered($cellRangeAddress)
-	{
-		$includeCellRange = true;
-		if (!is_null($this->getReadFilter())) {
-			$includeCellRange = false;
-			$rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress);
-			$rangeBoundaries[1][0]++;
-			for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) {
-				for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) {
-					if ($this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle())) {
-						$includeCellRange = true;
-						break 2;
-					}
-				}
-			}
-		}
-		return $includeCellRange;
-	}
-
-	/**
-	 * MERGEDCELLS
-	 *
-	 * This record contains the addresses of merged cell ranges
-	 * in the current sheet.
-	 *
-	 * --	"OpenOffice.org's Documentation of the Microsoft
-	 * 		Excel File Format"
-	 */
-	private function _readMergedCells()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
-			$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($recordData);
-			foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) {
-				if ($this->_includeCellRangeFiltered($cellRangeAddress)) {
-					$this->_phpSheet->mergeCells($cellRangeAddress);
-				}
-			}
-		}
-	}
-
-	/**
-	 * Read HYPERLINK record
-	 */
-	private function _readHyperLink()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer forward to next record
-		$this->_pos += 4 + $length;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 8; cell range address of all cells containing this hyperlink
-			try {
-				$cellRange = $this->_readBIFF8CellRangeAddressFixed($recordData, 0, 8);
-			} catch (Exception $e) {
-				return;
-			}
-
-			// offset: 8, size: 16; GUID of StdLink
-
-			// offset: 24, size: 4; unknown value
-
-			// offset: 28, size: 4; option flags
-
-				// bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL
-				$isFileLinkOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 0;
-
-				// bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL
-				$isAbsPathOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 1;
-
-				// bit: 2 (and 4); mask: 0x00000014; 0 = no description
-				$hasDesc = (0x00000014 & self::_GetInt2d($recordData, 28)) >> 2;
-
-				// bit: 3; mask: 0x00000008; 0 = no text, 1 = has text
-				$hasText = (0x00000008 & self::_GetInt2d($recordData, 28)) >> 3;
-
-				// bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame
-				$hasFrame = (0x00000080 & self::_GetInt2d($recordData, 28)) >> 7;
-
-				// bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name)
-				$isUNC = (0x00000100 & self::_GetInt2d($recordData, 28)) >> 8;
-
-			// offset within record data
-			$offset = 32;
-
-			if ($hasDesc) {
-				// offset: 32; size: var; character count of description text
-				$dl = self::_GetInt4d($recordData, 32);
-				// offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated
-				$desc = self::_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false);
-				$offset += 4 + 2 * $dl;
-			}
-			if ($hasFrame) {
-				$fl = self::_GetInt4d($recordData, $offset);
-				$offset += 4 + 2 * $fl;
-			}
-
-			// detect type of hyperlink (there are 4 types)
-			$hyperlinkType = null;
-
-			if ($isUNC) {
-				$hyperlinkType = 'UNC';
-			} else if (!$isFileLinkOrUrl) {
-				$hyperlinkType = 'workbook';
-			} else if (ord($recordData{$offset}) == 0x03) {
-				$hyperlinkType = 'local';
-			} else if (ord($recordData{$offset}) == 0xE0) {
-				$hyperlinkType = 'URL';
-			}
-
-			switch ($hyperlinkType) {
-			case 'URL':
-				// section 5.58.2: Hyperlink containing a URL
-				// e.g. http://example.org/index.php
-
-				// offset: var; size: 16; GUID of URL Moniker
-				$offset += 16;
-				// offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word
-				$us = self::_GetInt4d($recordData, $offset);
-				$offset += 4;
-				// offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated
-				$url = self::_encodeUTF16(substr($recordData, $offset, $us - 2), false);
-				$url .= $hasText ? '#' : '';
-				$offset += $us;
-				break;
-
-			case 'local':
-				// section 5.58.3: Hyperlink to local file
-				// examples:
-				//   mydoc.txt
-				//   ../../somedoc.xls#Sheet!A1
-
-				// offset: var; size: 16; GUI of File Moniker
-				$offset += 16;
-
-				// offset: var; size: 2; directory up-level count.
-				$upLevelCount = self::_GetInt2d($recordData, $offset);
-				$offset += 2;
-
-				// offset: var; size: 4; character count of the shortened file path and name, including trailing zero word
-				$sl = self::_GetInt4d($recordData, $offset);
-				$offset += 4;
-
-				// offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string)
-				$shortenedFilePath = substr($recordData, $offset, $sl);
-				$shortenedFilePath = self::_encodeUTF16($shortenedFilePath, true);
-				$shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero
-
-				$offset += $sl;
-
-				// offset: var; size: 24; unknown sequence
-				$offset += 24;
-
-				// extended file path
-				// offset: var; size: 4; size of the following file link field including string lenth mark
-				$sz = self::_GetInt4d($recordData, $offset);
-				$offset += 4;
-
-				// only present if $sz > 0
-				if ($sz > 0) {
-					// offset: var; size: 4; size of the character array of the extended file path and name
-					$xl = self::_GetInt4d($recordData, $offset);
-					$offset += 4;
-
-					// offset: var; size 2; unknown
-					$offset += 2;
-
-					// offset: var; size $xl; character array of the extended file path and name.
-					$extendedFilePath = substr($recordData, $offset, $xl);
-					$extendedFilePath = self::_encodeUTF16($extendedFilePath, false);
-					$offset += $xl;
-				}
-
-				// construct the path
-				$url = str_repeat('..\\', $upLevelCount);
-				$url .= ($sz > 0) ?
-					$extendedFilePath : $shortenedFilePath; // use extended path if available
-				$url .= $hasText ? '#' : '';
-
-				break;
-
-
-			case 'UNC':
-				// section 5.58.4: Hyperlink to a File with UNC (Universal Naming Convention) Path
-				// todo: implement
-				return;
-
-			case 'workbook':
-				// section 5.58.5: Hyperlink to the Current Workbook
-				// e.g. Sheet2!B1:C2, stored in text mark field
-				$url = 'sheet://';
-				break;
-
-			default:
-				return;
-
-			}
-
-			if ($hasText) {
-				// offset: var; size: 4; character count of text mark including trailing zero word
-				$tl = self::_GetInt4d($recordData, $offset);
-				$offset += 4;
-				// offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated
-				$text = self::_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false);
-				$url .= $text;
-			}
-
-			// apply the hyperlink to all the relevant cells
-			foreach (PHPExcel_Cell::extractAllCellReferencesInRange($cellRange) as $coordinate) {
-				$this->_phpSheet->getCell($coordinate)->getHyperLink()->setUrl($url);
-			}
-		}
-	}
-
-	/**
-	 * Read DATAVALIDATIONS record
-	 */
-	private function _readDataValidations()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer forward to next record
-		$this->_pos += 4 + $length;
-	}
-
-	/**
-	 * Read DATAVALIDATION record
-	 */
-	private function _readDataValidation()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer forward to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		// offset: 0; size: 4; Options
-		$options = self::_GetInt4d($recordData, 0);
-
-		// bit: 0-3; mask: 0x0000000F; type
-		$type = (0x0000000F & $options) >> 0;
-		switch ($type) {
-			case 0x00:	$type = PHPExcel_Cell_DataValidation::TYPE_NONE;		break;
-			case 0x01:	$type = PHPExcel_Cell_DataValidation::TYPE_WHOLE;		break;
-			case 0x02:	$type = PHPExcel_Cell_DataValidation::TYPE_DECIMAL;		break;
-			case 0x03:	$type = PHPExcel_Cell_DataValidation::TYPE_LIST;		break;
-			case 0x04:	$type = PHPExcel_Cell_DataValidation::TYPE_DATE;		break;
-			case 0x05:	$type = PHPExcel_Cell_DataValidation::TYPE_TIME;		break;
-			case 0x06:	$type = PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH;	break;
-			case 0x07:	$type = PHPExcel_Cell_DataValidation::TYPE_CUSTOM;		break;
-		}
-
-		// bit: 4-6; mask: 0x00000070; error type
-		$errorStyle = (0x00000070 & $options) >> 4;
-		switch ($errorStyle) {
-			case 0x00:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;			break;
-			case 0x01:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_WARNING;		break;
-			case 0x02:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_INFORMATION;	break;
-		}
-
-		// bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list)
-		// I have only seen cases where this is 1
-		$explicitFormula = (0x00000080 & $options) >> 7;
-
-		// bit: 8; mask: 0x00000100; 1= empty cells allowed
-		$allowBlank = (0x00000100 & $options) >> 8;
-
-		// bit: 9; mask: 0x00000200; 1= suppress drop down arrow in list type validity
-		$suppressDropDown = (0x00000200 & $options) >> 9;
-
-		// bit: 18; mask: 0x00040000; 1= show prompt box if cell selected
-		$showInputMessage = (0x00040000 & $options) >> 18;
-
-		// bit: 19; mask: 0x00080000; 1= show error box if invalid values entered
-		$showErrorMessage = (0x00080000 & $options) >> 19;
-
-		// bit: 20-23; mask: 0x00F00000; condition operator
-		$operator = (0x00F00000 & $options) >> 20;
-		switch ($operator) {
-			case 0x00: $operator = PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN			;	break;
-			case 0x01: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN		;	break;
-			case 0x02: $operator = PHPExcel_Cell_DataValidation::OPERATOR_EQUAL				;	break;
-			case 0x03: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL			;	break;
-			case 0x04: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN		;	break;
-			case 0x05: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN			;	break;
-			case 0x06: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL;	break;
-			case 0x07: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL	;	break;
-		}
-
-		// offset: 4; size: var; title of the prompt box
-		$offset = 4;
-		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
-		$promptTitle = $string['value'] !== chr(0) ?
-			$string['value'] : '';
-		$offset += $string['size'];
-
-		// offset: var; size: var; title of the error box
-		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
-		$errorTitle = $string['value'] !== chr(0) ?
-			$string['value'] : '';
-		$offset += $string['size'];
-
-		// offset: var; size: var; text of the prompt box
-		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
-		$prompt = $string['value'] !== chr(0) ?
-			$string['value'] : '';
-		$offset += $string['size'];
-
-		// offset: var; size: var; text of the error box
-		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
-		$error = $string['value'] !== chr(0) ?
-			$string['value'] : '';
-		$offset += $string['size'];
-
-		// offset: var; size: 2; size of the formula data for the first condition
-		$sz1 = self::_GetInt2d($recordData, $offset);
-		$offset += 2;
-
-		// offset: var; size: 2; not used
-		$offset += 2;
-
-		// offset: var; size: $sz1; formula data for first condition (without size field)
-		$formula1 = substr($recordData, $offset, $sz1);
-		$formula1 = pack('v', $sz1) . $formula1; // prepend the length
-		try {
-			$formula1 = $this->_getFormulaFromStructure($formula1);
-
-			// in list type validity, null characters are used as item separators
-			if ($type == PHPExcel_Cell_DataValidation::TYPE_LIST) {
-				$formula1 = str_replace(chr(0), ',', $formula1);
-			}
-		} catch (Exception $e) {
-			return;
-		}
-		$offset += $sz1;
-
-		// offset: var; size: 2; size of the formula data for the first condition
-		$sz2 = self::_GetInt2d($recordData, $offset);
-		$offset += 2;
-
-		// offset: var; size: 2; not used
-		$offset += 2;
-
-		// offset: var; size: $sz2; formula data for second condition (without size field)
-		$formula2 = substr($recordData, $offset, $sz2);
-		$formula2 = pack('v', $sz2) . $formula2; // prepend the length
-		try {
-			$formula2 = $this->_getFormulaFromStructure($formula2);
-		} catch (Exception $e) {
-			return;
-		}
-		$offset += $sz2;
-
-		// offset: var; size: var; cell range address list with
-		$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList(substr($recordData, $offset));
-		$cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses'];
-
-		foreach ($cellRangeAddresses as $cellRange) {
-			$stRange = $this->_phpSheet->shrinkRangeToFit($cellRange);
-			$stRange = PHPExcel_Cell::extractAllCellReferencesInRange($stRange);
-			foreach ($stRange as $coordinate) {
-				$objValidation = $this->_phpSheet->getCell($coordinate)->getDataValidation();
-				$objValidation->setType($type);
-				$objValidation->setErrorStyle($errorStyle);
-				$objValidation->setAllowBlank((bool)$allowBlank);
-				$objValidation->setShowInputMessage((bool)$showInputMessage);
-				$objValidation->setShowErrorMessage((bool)$showErrorMessage);
-				$objValidation->setShowDropDown(!$suppressDropDown);
-				$objValidation->setOperator($operator);
-				$objValidation->setErrorTitle($errorTitle);
-				$objValidation->setError($error);
-				$objValidation->setPromptTitle($promptTitle);
-				$objValidation->setPrompt($prompt);
-				$objValidation->setFormula1($formula1);
-				$objValidation->setFormula2($formula2);
-			}
-		}
-
-	}
-
-	/**
-	 * Read SHEETLAYOUT record. Stores sheet tab color information.
-	 */
-	private function _readSheetLayout()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// local pointer in record data
-		$offset = 0;
-
-		if (!$this->_readDataOnly) {
-			// offset: 0; size: 2; repeated record identifier 0x0862
-
-			// offset: 2; size: 10; not used
-
-			// offset: 12; size: 4; size of record data
-			// Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
-			$sz = self::_GetInt4d($recordData, 12);
-
-			switch ($sz) {
-				case 0x14:
-					// offset: 16; size: 2; color index for sheet tab
-					$colorIndex = self::_GetInt2d($recordData, 16);
-					$color = self::_readColor($colorIndex,$this->_palette,$this->_version);
-					$this->_phpSheet->getTabColor()->setRGB($color['rgb']);
-					break;
-
-				case 0x28:
-					// TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
-					return;
-					break;
-			}
-		}
-	}
-
-	/**
-	 * Read SHEETPROTECTION record (FEATHEADR)
-	 */
-	private function _readSheetProtection()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		if ($this->_readDataOnly) {
-			return;
-		}
-
-		// offset: 0; size: 2; repeated record header
-
-		// offset: 2; size: 2; FRT cell reference flag (=0 currently)
-
-		// offset: 4; size: 8; Currently not used and set to 0
-
-		// offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag)
-		$isf = self::_GetInt2d($recordData, 12);
-		if ($isf != 2) {
-			return;
-		}
-
-		// offset: 14; size: 1; =1 since this is a feat header
-
-		// offset: 15; size: 4; size of rgbHdrSData
-
-		// rgbHdrSData, assume "Enhanced Protection"
-		// offset: 19; size: 2; option flags
-		$options = self::_GetInt2d($recordData, 19);
-
-		// bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects
-		$bool = (0x0001 & $options) >> 0;
-		$this->_phpSheet->getProtection()->setObjects(!$bool);
-
-		// bit: 1; mask 0x0002; edit scenarios
-		$bool = (0x0002 & $options) >> 1;
-		$this->_phpSheet->getProtection()->setScenarios(!$bool);
-
-		// bit: 2; mask 0x0004; format cells
-		$bool = (0x0004 & $options) >> 2;
-		$this->_phpSheet->getProtection()->setFormatCells(!$bool);
-
-		// bit: 3; mask 0x0008; format columns
-		$bool = (0x0008 & $options) >> 3;
-		$this->_phpSheet->getProtection()->setFormatColumns(!$bool);
-
-		// bit: 4; mask 0x0010; format rows
-		$bool = (0x0010 & $options) >> 4;
-		$this->_phpSheet->getProtection()->setFormatRows(!$bool);
-
-		// bit: 5; mask 0x0020; insert columns
-		$bool = (0x0020 & $options) >> 5;
-		$this->_phpSheet->getProtection()->setInsertColumns(!$bool);
-
-		// bit: 6; mask 0x0040; insert rows
-		$bool = (0x0040 & $options) >> 6;
-		$this->_phpSheet->getProtection()->setInsertRows(!$bool);
-
-		// bit: 7; mask 0x0080; insert hyperlinks
-		$bool = (0x0080 & $options) >> 7;
-		$this->_phpSheet->getProtection()->setInsertHyperlinks(!$bool);
-
-		// bit: 8; mask 0x0100; delete columns
-		$bool = (0x0100 & $options) >> 8;
-		$this->_phpSheet->getProtection()->setDeleteColumns(!$bool);
-
-		// bit: 9; mask 0x0200; delete rows
-		$bool = (0x0200 & $options) >> 9;
-		$this->_phpSheet->getProtection()->setDeleteRows(!$bool);
-
-		// bit: 10; mask 0x0400; select locked cells
-		$bool = (0x0400 & $options) >> 10;
-		$this->_phpSheet->getProtection()->setSelectLockedCells(!$bool);
-
-		// bit: 11; mask 0x0800; sort cell range
-		$bool = (0x0800 & $options) >> 11;
-		$this->_phpSheet->getProtection()->setSort(!$bool);
-
-		// bit: 12; mask 0x1000; auto filter
-		$bool = (0x1000 & $options) >> 12;
-		$this->_phpSheet->getProtection()->setAutoFilter(!$bool);
-
-		// bit: 13; mask 0x2000; pivot tables
-		$bool = (0x2000 & $options) >> 13;
-		$this->_phpSheet->getProtection()->setPivotTables(!$bool);
-
-		// bit: 14; mask 0x4000; select unlocked cells
-		$bool = (0x4000 & $options) >> 14;
-		$this->_phpSheet->getProtection()->setSelectUnlockedCells(!$bool);
-
-		// offset: 21; size: 2; not used
-	}
-
-	/**
-	 * Read RANGEPROTECTION record
-	 * Reading of this record is based on Microsoft Office Excel 97-2000 Binary File Format Specification,
-	 * where it is referred to as FEAT record
-	 */
-	private function _readRangeProtection()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-		// local pointer in record data
-		$offset = 0;
-
-		if (!$this->_readDataOnly) {
-			$offset += 12;
-
-			// offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
-			$isf = self::_GetInt2d($recordData, 12);
-			if ($isf != 2) {
-				// we only read FEAT records of type 2
-				return;
-			}
-			$offset += 2;
-
-			$offset += 5;
-
-			// offset: 19; size: 2; count of ref ranges this feature is on
-			$cref = self::_GetInt2d($recordData, 19);
-			$offset += 2;
-
-			$offset += 6;
-
-			// offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
-			$cellRanges = array();
-			for ($i = 0; $i < $cref; ++$i) {
-				try {
-					$cellRange = $this->_readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
-				} catch (Exception $e) {
-					return;
-				}
-				$cellRanges[] = $cellRange;
-				$offset += 8;
-			}
-
-			// offset: var; size: var; variable length of feature specific data
-			$rgbFeat = substr($recordData, $offset);
-			$offset += 4;
-
-			// offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
-			$wPassword = self::_GetInt4d($recordData, $offset);
-			$offset += 4;
-
-			// Apply range protection to sheet
-			if ($cellRanges) {
-				$this->_phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
-			}
-		}
-	}
-
-	/**
-	 * Read IMDATA record
-	 */
-	private function _readImData()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-
-		// get spliced record data
-		$splicedRecordData = $this->_getSplicedRecordData();
-		$recordData = $splicedRecordData['recordData'];
-
-		// UNDER CONSTRUCTION
-
-		// offset: 0; size: 2; image format
-		$cf = self::_GetInt2d($recordData, 0);
-
-		// offset: 2; size: 2; environment from which the file was written
-		$env = self::_GetInt2d($recordData, 2);
-
-		// offset: 4; size: 4; length of the image data
-		$lcb = self::_GetInt4d($recordData, 4);
-
-		// offset: 8; size: var; image data
-		$iData = substr($recordData, 8);
-
-		switch ($cf) {
-		case 0x09: // Windows bitmap format
-			// BITMAPCOREINFO
-			// 1. BITMAPCOREHEADER
-			// offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure
-			$bcSize = self::_GetInt4d($iData, 0);
-//			var_dump($bcSize);
-
-			// offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels
-			$bcWidth = self::_GetInt2d($iData, 4);
-//			var_dump($bcWidth);
-
-			// offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels.
-			$bcHeight = self::_GetInt2d($iData, 6);
-//			var_dump($bcHeight);
-			$ih = imagecreatetruecolor($bcWidth, $bcHeight);
-
-			// offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1
-
-			// offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24
-			$bcBitCount = self::_GetInt2d($iData, 10);
-//			var_dump($bcBitCount);
-
-			$rgbString = substr($iData, 12);
-			$rgbTriples = array();
-			while (strlen($rgbString) > 0) {
-				$rgbTriples[] = unpack('Cb/Cg/Cr', $rgbString);
-				$rgbString = substr($rgbString, 3);
-			}
-			$x = 0;
-			$y = 0;
-			foreach ($rgbTriples as $i => $rgbTriple) {
-				$color = imagecolorallocate($ih, $rgbTriple['r'], $rgbTriple['g'], $rgbTriple['b']);
-				imagesetpixel($ih, $x, $bcHeight - 1 - $y, $color);
-				$x = ($x + 1) % $bcWidth;
-				$y = $y + floor(($x + 1) / $bcWidth);
-			}
-			//imagepng($ih, 'image.png');
-
-			$drawing = new PHPExcel_Worksheet_Drawing();
-			$drawing->setPath($filename);
-			$drawing->setWorksheet($this->_phpSheet);
-
-			break;
-
-		case 0x02: // Windows metafile or Macintosh PICT format
-		case 0x0e: // native format
-		default;
-			break;
-
-		}
-
-		// _getSplicedRecordData() takes care of moving current position in data stream
-	}
-
-	/**
-	 * Read a free CONTINUE record. Free CONTINUE record may be a camouflaged MSODRAWING record
-	 * When MSODRAWING data on a sheet exceeds 8224 bytes, CONTINUE records are used instead. Undocumented.
-	 * In this case, we must treat the CONTINUE record as a MSODRAWING record
-	 */
-	private function _readContinue()
-	{
-		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-		$recordData = substr($this->_data, $this->_pos + 4, $length);
-
-		// check if we are reading drawing data
-		// this is in case a free CONTINUE record occurs in other circumstances we are unaware of
-		if ($this->_drawingData == '') {
-			// move stream pointer to next record
-			$this->_pos += 4 + $length;
-
-			return;
-		}
-
-		// check if record data is at least 4 bytes long, otherwise there is no chance this is MSODRAWING data
-		if ($length < 4) {
-			// move stream pointer to next record
-			$this->_pos += 4 + $length;
-
-			return;
-		}
-
-		// dirty check to see if CONTINUE record could be a camouflaged MSODRAWING record
-		// look inside CONTINUE record to see if it looks like a part of an Escher stream
-		// we know that Escher stream may be split at least at
-		//		0xF003 MsofbtSpgrContainer
-		//		0xF004 MsofbtSpContainer
-		//		0xF00D MsofbtClientTextbox
-		$validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more
-
-		$splitPoint = self::_GetInt2d($recordData, 2);
-		if (in_array($splitPoint, $validSplitPoints)) {
-			// get spliced record data (and move pointer to next record)
-			$splicedRecordData = $this->_getSplicedRecordData();
-			$this->_drawingData .= $splicedRecordData['recordData'];
-
-			return;
-		}
-
-		// move stream pointer to next record
-		$this->_pos += 4 + $length;
-
-	}
-
-
-	/**
-	 * Reads a record from current position in data stream and continues reading data as long as CONTINUE
-	 * records are found. Splices the record data pieces and returns the combined string as if record data
-	 * is in one piece.
-	 * Moves to next current position in data stream to start of next record different from a CONtINUE record
-	 *
-	 * @return array
-	 */
-	private function _getSplicedRecordData()
-	{
-		$data = '';
-		$spliceOffsets = array();
-
-		$i = 0;
-		$spliceOffsets[0] = 0;
-
-		do {
-			++$i;
-
-			// offset: 0; size: 2; identifier
-			$identifier = self::_GetInt2d($this->_data, $this->_pos);
-			// offset: 2; size: 2; length
-			$length = self::_GetInt2d($this->_data, $this->_pos + 2);
-			$data .= substr($this->_data, $this->_pos + 4, $length);
-
-			$spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;
-
-			$this->_pos += 4 + $length;
-			$nextIdentifier = self::_GetInt2d($this->_data, $this->_pos);
-		}
-		while ($nextIdentifier == self::XLS_Type_CONTINUE);
-
-		$splicedData = array(
-			'recordData' => $data,
-			'spliceOffsets' => $spliceOffsets,
-		);
-
-		return $splicedData;
-
-	}
-
-	/**
-	 * Convert formula structure into human readable Excel formula like 'A3+A5*5'
-	 *
-	 * @param string $formulaStructure The complete binary data for the formula
-	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
-	 * @return string Human readable formula
-	 */
-	private function _getFormulaFromStructure($formulaStructure, $baseCell = 'A1')
-	{
-		// offset: 0; size: 2; size of the following formula data
-		$sz = self::_GetInt2d($formulaStructure, 0);
-
-		// offset: 2; size: sz
-		$formulaData = substr($formulaStructure, 2, $sz);
-
-		// for debug: dump the formula data
-		//echo '<xmp>';
-		//echo 'size: ' . $sz . "\n";
-		//echo 'the entire formula data: ';
-		//Debug::dump($formulaData);
-		//echo "\n----\n";
-
-		// offset: 2 + sz; size: variable (optional)
-		if (strlen($formulaStructure) > 2 + $sz) {
-			$additionalData = substr($formulaStructure, 2 + $sz);
-
-			// for debug: dump the additional data
-			//echo 'the entire additional data: ';
-			//Debug::dump($additionalData);
-			//echo "\n----\n";
-
-		} else {
-			$additionalData = '';
-		}
-
-		return $this->_getFormulaFromData($formulaData, $additionalData, $baseCell);
-	}
-
-	/**
-	 * Take formula data and additional data for formula and return human readable formula
-	 *
-	 * @param string $formulaData The binary data for the formula itself
-	 * @param string $additionalData Additional binary data going with the formula
-	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
-	 * @return string Human readable formula
-	 */
-	private function _getFormulaFromData($formulaData,  $additionalData = '', $baseCell = 'A1')
-	{
-		// start parsing the formula data
-		$tokens = array();
-
-		while (strlen($formulaData) > 0 and $token = $this->_getNextToken($formulaData, $baseCell)) {
-			$tokens[] = $token;
-			$formulaData = substr($formulaData, $token['size']);
-
-			// for debug: dump the token
-			//var_dump($token);
-		}
-
-		$formulaString = $this->_createFormulaFromTokens($tokens, $additionalData);
-
-		return $formulaString;
-	}
-
-	/**
-	 * Take array of tokens together with additional data for formula and return human readable formula
-	 *
-	 * @param array $tokens
-	 * @param array $additionalData Additional binary data going with the formula
-	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
-	 * @return string Human readable formula
-	 */
-	private function _createFormulaFromTokens($tokens, $additionalData)
-	{
-		// empty formula?
-		if (count($tokens) == 0) {
-			return '';
-		}
-
-		$formulaStrings = array();
-		foreach ($tokens as $token) {
-			// initialize spaces
-			$space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
-			$space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
-			$space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
-			$space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
-			$space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
-			$space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
-
-			switch ($token['name']) {
-			case 'tAdd': // addition
-			case 'tConcat': // addition
-			case 'tDiv': // division
-			case 'tEQ': // equality
-			case 'tGE': // greater than or equal
-			case 'tGT': // greater than
-			case 'tIsect': // intersection
-			case 'tLE': // less than or equal
-			case 'tList': // less than or equal
-			case 'tLT': // less than
-			case 'tMul': // multiplication
-			case 'tNE': // multiplication
-			case 'tPower': // power
-			case 'tRange': // range
-			case 'tSub': // subtraction
-				$op2 = array_pop($formulaStrings);
-				$op1 = array_pop($formulaStrings);
-				$formulaStrings[] = "$op1$space1$space0{$token['data']}$op2";
-				unset($space0, $space1);
-				break;
-			case 'tUplus': // unary plus
-			case 'tUminus': // unary minus
-				$op = array_pop($formulaStrings);
-				$formulaStrings[] = "$space1$space0{$token['data']}$op";
-				unset($space0, $space1);
-				break;
-			case 'tPercent': // percent sign
-				$op = array_pop($formulaStrings);
-				$formulaStrings[] = "$op$space1$space0{$token['data']}";
-				unset($space0, $space1);
-				break;
-			case 'tAttrVolatile': // indicates volatile function
-			case 'tAttrIf':
-			case 'tAttrSkip':
-			case 'tAttrChoose':
-				// token is only important for Excel formula evaluator
-				// do nothing
-				break;
-			case 'tAttrSpace': // space / carriage return
-				// space will be used when next token arrives, do not alter formulaString stack
-				switch ($token['data']['spacetype']) {
-				case 'type0':
-					$space0 = str_repeat(' ', $token['data']['spacecount']);
-					break;
-				case 'type1':
-					$space1 = str_repeat("\n", $token['data']['spacecount']);
-					break;
-				case 'type2':
-					$space2 = str_repeat(' ', $token['data']['spacecount']);
-					break;
-				case 'type3':
-					$space3 = str_repeat("\n", $token['data']['spacecount']);
-					break;
-				case 'type4':
-					$space4 = str_repeat(' ', $token['data']['spacecount']);
-					break;
-				case 'type5':
-					$space5 = str_repeat("\n", $token['data']['spacecount']);
-					break;
-				}
-				break;
-			case 'tAttrSum': // SUM function with one parameter
-				$op = array_pop($formulaStrings);
-				$formulaStrings[] = "{$space1}{$space0}SUM($op)";
-				unset($space0, $space1);
-				break;
-			case 'tFunc': // function with fixed number of arguments
-			case 'tFuncV': // function with variable number of arguments
-				if ($token['data']['function'] != '') {
-					// normal function
-					$ops = array(); // array of operators
-					for ($i = 0; $i < $token['data']['args']; ++$i) {
-						$ops[] = array_pop($formulaStrings);
-					}
-					$ops = array_reverse($ops);
-					$formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ")";
-					unset($space0, $space1);
-				} else {
-					// add-in function
-					$ops = array(); // array of operators
-					for ($i = 0; $i < $token['data']['args'] - 1; ++$i) {
-						$ops[] = array_pop($formulaStrings);
-					}
-					$ops = array_reverse($ops);
-					$function = array_pop($formulaStrings);
-					$formulaStrings[] = "$space1$space0$function(" . implode(',', $ops) . ")";
-					unset($space0, $space1);
-				}
-				break;
-			case 'tParen': // parenthesis
-				$expression = array_pop($formulaStrings);
-				$formulaStrings[] = "$space3$space2($expression$space5$space4)";
-				unset($space2, $space3, $space4, $space5);
-				break;
-			case 'tArray': // array constant
-				$constantArray = self::_readBIFF8ConstantArray($additionalData);
-				$formulaStrings[] = $space1 . $space0 . $constantArray['value'];
-				$additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data
-				unset($space0, $space1);
-				break;
-			case 'tMemArea':
-				// bite off chunk of additional data
-				$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($additionalData);
-				$additionalData = substr($additionalData, $cellRangeAddressList['size']);
-				$formulaStrings[] = "$space1$space0{$token['data']}";
-				unset($space0, $space1);
-				break;
-			case 'tArea': // cell range address
-			case 'tBool': // boolean
-			case 'tErr': // error code
-			case 'tInt': // integer
-			case 'tMemErr':
-			case 'tMemFunc':
-			case 'tMissArg':
-			case 'tName':
-			case 'tNameX':
-			case 'tNum': // number
-			case 'tRef': // single cell reference
-			case 'tRef3d': // 3d cell reference
-			case 'tArea3d': // 3d cell range reference
-			case 'tRefN':
-			case 'tAreaN':
-			case 'tStr': // string
-				$formulaStrings[] = "$space1$space0{$token['data']}";
-				unset($space0, $space1);
-				break;
-			}
-		}
-		$formulaString = $formulaStrings[0];
-
-		// for debug: dump the human readable formula
-		//echo '----' . "\n";
-		//echo 'Formula: ' . $formulaString;
-
-		return $formulaString;
-	}
-
-	/**
-	 * Fetch next token from binary formula data
-	 *
-	 * @param string Formula data
-	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
-	 * @return array
-	 * @throws Exception
-	 */
-	private function _getNextToken($formulaData, $baseCell = 'A1')
-	{
-		// offset: 0; size: 1; token id
-		$id = ord($formulaData[0]); // token id
-		$name = false; // initialize token name
-
-		switch ($id) {
-		case 0x03: $name = 'tAdd';		$size = 1;	$data = '+';	break;
-		case 0x04: $name = 'tSub';		$size = 1;	$data = '-';	break;
-		case 0x05: $name = 'tMul';		$size = 1;	$data = '*';	break;
-		case 0x06: $name = 'tDiv';		$size = 1;	$data = '/';	break;
-		case 0x07: $name = 'tPower';	$size = 1;	$data = '^';	break;
-		case 0x08: $name = 'tConcat';	$size = 1;	$data = '&';	break;
-		case 0x09: $name = 'tLT';		$size = 1;	$data = '<';	break;
-		case 0x0A: $name = 'tLE';		$size = 1;	$data = '<=';	break;
-		case 0x0B: $name = 'tEQ';		$size = 1;	$data = '=';	break;
-		case 0x0C: $name = 'tGE';		$size = 1;	$data = '>=';	break;
-		case 0x0D: $name = 'tGT';		$size = 1;	$data = '>';	break;
-		case 0x0E: $name = 'tNE';		$size = 1;	$data = '<>';	break;
-		case 0x0F: $name = 'tIsect';	$size = 1;	$data = ' ';	break;
-		case 0x10: $name = 'tList';		$size = 1;	$data = ',';	break;
-		case 0x11: $name = 'tRange';	$size = 1;	$data = ':';	break;
-		case 0x12: $name = 'tUplus';	$size = 1;	$data = '+';	break;
-		case 0x13: $name = 'tUminus';	$size = 1;	$data = '-';	break;
-		case 0x14: $name = 'tPercent';	$size = 1;	$data = '%';	break;
-		case 0x15:	//	parenthesis
-			$name  = 'tParen';
-			$size  = 1;
-			$data = null;
-			break;
-		case 0x16:	//	missing argument
-			$name = 'tMissArg';
-			$size = 1;
-			$data = '';
-			break;
-		case 0x17:	//	string
-			$name = 'tStr';
-			// offset: 1; size: var; Unicode string, 8-bit string length
-			$string = self::_readUnicodeStringShort(substr($formulaData, 1));
-			$size = 1 + $string['size'];
-			$data = self::_UTF8toExcelDoubleQuoted($string['value']);
-			break;
-		case 0x19:	//	Special attribute
-			// offset: 1; size: 1; attribute type flags:
-			switch (ord($formulaData[1])) {
-			case 0x01:
-				$name = 'tAttrVolatile';
-				$size = 4;
-				$data = null;
-				break;
-			case 0x02:
-				$name = 'tAttrIf';
-				$size = 4;
-				$data = null;
-				break;
-			case 0x04:
-				$name = 'tAttrChoose';
-				// offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
-				$nc = self::_GetInt2d($formulaData, 2);
-				// offset: 4; size: 2 * $nc
-				// offset: 4 + 2 * $nc; size: 2
-				$size = 2 * $nc + 6;
-				$data = null;
-				break;
-			case 0x08:
-				$name = 'tAttrSkip';
-				$size = 4;
-				$data = null;
-				break;
-			case 0x10:
-				$name = 'tAttrSum';
-				$size = 4;
-				$data = null;
-				break;
-			case 0x40:
-			case 0x41:
-				$name = 'tAttrSpace';
-				$size = 4;
-				// offset: 2; size: 2; space type and position
-				switch (ord($formulaData[2])) {
-				case 0x00:
-					$spacetype = 'type0';
-					break;
-				case 0x01:
-					$spacetype = 'type1';
-					break;
-				case 0x02:
-					$spacetype = 'type2';
-					break;
-				case 0x03:
-					$spacetype = 'type3';
-					break;
-				case 0x04:
-					$spacetype = 'type4';
-					break;
-				case 0x05:
-					$spacetype = 'type5';
-					break;
-				default:
-					throw new Exception('Unrecognized space type in tAttrSpace token');
-					break;
-				}
-				// offset: 3; size: 1; number of inserted spaces/carriage returns
-				$spacecount = ord($formulaData[3]);
-
-				$data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
-				break;
-			default:
-				throw new Exception('Unrecognized attribute flag in tAttr token');
-				break;
-			}
-			break;
-		case 0x1C:	//	error code
-			// offset: 1; size: 1; error code
-			$name = 'tErr';
-			$size = 2;
-			$data = self::_mapErrorCode(ord($formulaData[1]));
-			break;
-		case 0x1D:	//	boolean
-			// offset: 1; size: 1; 0 = false, 1 = true;
-			$name = 'tBool';
-			$size = 2;
-			$data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
-			break;
-		case 0x1E:	//	integer
-			// offset: 1; size: 2; unsigned 16-bit integer
-			$name = 'tInt';
-			$size = 3;
-			$data = self::_GetInt2d($formulaData, 1);
-			break;
-		case 0x1F:	//	number
-			// offset: 1; size: 8;
-			$name = 'tNum';
-			$size = 9;
-			$data = self::_extractNumber(substr($formulaData, 1));
-			$data = str_replace(',', '.', (string)$data); // in case non-English locale
-			break;
-		case 0x20:	//	array constant
-		case 0x40:
-		case 0x60:
-			// offset: 1; size: 7; not used
-			$name = 'tArray';
-			$size = 8;
-			$data = null;
-			break;
-		case 0x21:	//	function with fixed number of arguments
-		case 0x41:
-		case 0x61:
-			$name = 'tFunc';
-			$size = 3;
-			// offset: 1; size: 2; index to built-in sheet function
-			switch (self::_GetInt2d($formulaData, 1)) {
-			case   2: $function = 'ISNA'; 			$args = 1; 	break;
-			case   3: $function = 'ISERROR'; 		$args = 1; 	break;
-			case  10: $function = 'NA'; 			$args = 0; 	break;
-			case  15: $function = 'SIN'; 			$args = 1; 	break;
-			case  16: $function = 'COS'; 			$args = 1; 	break;
-			case  17: $function = 'TAN'; 			$args = 1; 	break;
-			case  18: $function = 'ATAN'; 			$args = 1; 	break;
-			case  19: $function = 'PI'; 			$args = 0; 	break;
-			case  20: $function = 'SQRT'; 			$args = 1; 	break;
-			case  21: $function = 'EXP'; 			$args = 1; 	break;
-			case  22: $function = 'LN'; 			$args = 1; 	break;
-			case  23: $function = 'LOG10'; 			$args = 1; 	break;
-			case  24: $function = 'ABS'; 			$args = 1; 	break;
-			case  25: $function = 'INT'; 			$args = 1; 	break;
-			case  26: $function = 'SIGN'; 			$args = 1; 	break;
-			case  27: $function = 'ROUND'; 			$args = 2; 	break;
-			case  30: $function = 'REPT'; 			$args = 2; 	break;
-			case  31: $function = 'MID'; 			$args = 3; 	break;
-			case  32: $function = 'LEN'; 			$args = 1; 	break;
-			case  33: $function = 'VALUE'; 			$args = 1; 	break;
-			case  34: $function = 'TRUE'; 			$args = 0; 	break;
-			case  35: $function = 'FALSE'; 			$args = 0; 	break;
-			case  38: $function = 'NOT'; 			$args = 1; 	break;
-			case  39: $function = 'MOD'; 			$args = 2;	break;
-			case  40: $function = 'DCOUNT'; 		$args = 3;	break;
-			case  41: $function = 'DSUM'; 			$args = 3;	break;
-			case  42: $function = 'DAVERAGE'; 		$args = 3;	break;
-			case  43: $function = 'DMIN'; 			$args = 3;	break;
-			case  44: $function = 'DMAX'; 			$args = 3;	break;
-			case  45: $function = 'DSTDEV'; 		$args = 3;	break;
-			case  48: $function = 'TEXT'; 			$args = 2;	break;
-			case  61: $function = 'MIRR'; 			$args = 3;	break;
-			case  63: $function = 'RAND'; 			$args = 0;	break;
-			case  65: $function = 'DATE'; 			$args = 3;	break;
-			case  66: $function = 'TIME'; 			$args = 3;	break;
-			case  67: $function = 'DAY'; 			$args = 1;	break;
-			case  68: $function = 'MONTH'; 			$args = 1;	break;
-			case  69: $function = 'YEAR'; 			$args = 1;	break;
-			case  71: $function = 'HOUR'; 			$args = 1;	break;
-			case  72: $function = 'MINUTE'; 		$args = 1;	break;
-			case  73: $function = 'SECOND'; 		$args = 1;	break;
-			case  74: $function = 'NOW'; 			$args = 0;	break;
-			case  75: $function = 'AREAS'; 			$args = 1;	break;
-			case  76: $function = 'ROWS'; 			$args = 1;	break;
-			case  77: $function = 'COLUMNS'; 		$args = 1;	break;
-			case  83: $function = 'TRANSPOSE'; 		$args = 1;	break;
-			case  86: $function = 'TYPE'; 			$args = 1;	break;
-			case  97: $function = 'ATAN2'; 			$args = 2;	break;
-			case  98: $function = 'ASIN'; 			$args = 1;	break;
-			case  99: $function = 'ACOS'; 			$args = 1;	break;
-			case 105: $function = 'ISREF'; 			$args = 1;	break;
-			case 111: $function = 'CHAR'; 			$args = 1;	break;
-			case 112: $function = 'LOWER'; 			$args = 1;	break;
-			case 113: $function = 'UPPER'; 			$args = 1;	break;
-			case 114: $function = 'PROPER'; 		$args = 1;	break;
-			case 117: $function = 'EXACT'; 			$args = 2;	break;
-			case 118: $function = 'TRIM'; 			$args = 1;	break;
-			case 119: $function = 'REPLACE'; 		$args = 4;	break;
-			case 121: $function = 'CODE'; 			$args = 1;	break;
-			case 126: $function = 'ISERR'; 			$args = 1;	break;
-			case 127: $function = 'ISTEXT'; 		$args = 1;	break;
-			case 128: $function = 'ISNUMBER'; 		$args = 1;	break;
-			case 129: $function = 'ISBLANK'; 		$args = 1;	break;
-			case 130: $function = 'T'; 				$args = 1;	break;
-			case 131: $function = 'N'; 				$args = 1;	break;
-			case 140: $function = 'DATEVALUE'; 		$args = 1;	break;
-			case 141: $function = 'TIMEVALUE'; 		$args = 1;	break;
-			case 142: $function = 'SLN'; 			$args = 3;	break;
-			case 143: $function = 'SYD'; 			$args = 4;	break;
-			case 162: $function = 'CLEAN'; 			$args = 1;	break;
-			case 163: $function = 'MDETERM'; 		$args = 1;	break;
-			case 164: $function = 'MINVERSE'; 		$args = 1;	break;
-			case 165: $function = 'MMULT'; 			$args = 2;	break;
-			case 184: $function = 'FACT'; 			$args = 1;	break;
-			case 189: $function = 'DPRODUCT'; 		$args = 3;	break;
-			case 190: $function = 'ISNONTEXT'; 		$args = 1;	break;
-			case 195: $function = 'DSTDEVP'; 		$args = 3;	break;
-			case 196: $function = 'DVARP'; 			$args = 3;	break;
-			case 198: $function = 'ISLOGICAL'; 		$args = 1;	break;
-			case 199: $function = 'DCOUNTA'; 		$args = 3;	break;
-			case 207: $function = 'REPLACEB'; 		$args = 4;	break;
-			case 210: $function = 'MIDB'; 			$args = 3;	break;
-			case 211: $function = 'LENB'; 			$args = 1;	break;
-			case 212: $function = 'ROUNDUP'; 		$args = 2;	break;
-			case 213: $function = 'ROUNDDOWN'; 		$args = 2;	break;
-			case 214: $function = 'ASC'; 			$args = 1;	break;
-			case 215: $function = 'DBCS'; 			$args = 1;	break;
-			case 221: $function = 'TODAY'; 			$args = 0;	break;
-			case 229: $function = 'SINH'; 			$args = 1;	break;
-			case 230: $function = 'COSH'; 			$args = 1;	break;
-			case 231: $function = 'TANH'; 			$args = 1;	break;
-			case 232: $function = 'ASINH'; 			$args = 1;	break;
-			case 233: $function = 'ACOSH'; 			$args = 1;	break;
-			case 234: $function = 'ATANH'; 			$args = 1;	break;
-			case 235: $function = 'DGET'; 			$args = 3;	break;
-			case 244: $function = 'INFO'; 			$args = 1;	break;
-			case 252: $function = 'FREQUENCY'; 		$args = 2;	break;
-			case 261: $function = 'ERROR.TYPE'; 	$args = 1;	break;
-			case 271: $function = 'GAMMALN'; 		$args = 1;	break;
-			case 273: $function = 'BINOMDIST'; 		$args = 4;	break;
-			case 274: $function = 'CHIDIST'; 		$args = 2;	break;
-			case 275: $function = 'CHIINV'; 		$args = 2;	break;
-			case 276: $function = 'COMBIN'; 		$args = 2;	break;
-			case 277: $function = 'CONFIDENCE'; 	$args = 3;	break;
-			case 278: $function = 'CRITBINOM'; 		$args = 3;	break;
-			case 279: $function = 'EVEN'; 			$args = 1;	break;
-			case 280: $function = 'EXPONDIST'; 		$args = 3;	break;
-			case 281: $function = 'FDIST'; 			$args = 3;	break;
-			case 282: $function = 'FINV'; 			$args = 3;	break;
-			case 283: $function = 'FISHER'; 		$args = 1;	break;
-			case 284: $function = 'FISHERINV'; 		$args = 1;	break;
-			case 285: $function = 'FLOOR'; 			$args = 2;	break;
-			case 286: $function = 'GAMMADIST'; 		$args = 4;	break;
-			case 287: $function = 'GAMMAINV'; 		$args = 3;	break;
-			case 288: $function = 'CEILING'; 		$args = 2;	break;
-			case 289: $function = 'HYPGEOMDIST';	$args = 4;	break;
-			case 290: $function = 'LOGNORMDIST';	$args = 3;	break;
-			case 291: $function = 'LOGINV';			$args = 3;	break;
-			case 292: $function = 'NEGBINOMDIST';	$args = 3;	break;
-			case 293: $function = 'NORMDIST';		$args = 4;	break;
-			case 294: $function = 'NORMSDIST';		$args = 1;	break;
-			case 295: $function = 'NORMINV';		$args = 3;	break;
-			case 296: $function = 'NORMSINV';		$args = 1;	break;
-			case 297: $function = 'STANDARDIZE';	$args = 3;	break;
-			case 298: $function = 'ODD';			$args = 1;	break;
-			case 299: $function = 'PERMUT';			$args = 2;	break;
-			case 300: $function = 'POISSON';		$args = 3;	break;
-			case 301: $function = 'TDIST';			$args = 3;	break;
-			case 302: $function = 'WEIBULL';		$args = 4;	break;
-			case 303: $function = 'SUMXMY2';		$args = 2;	break;
-			case 304: $function = 'SUMX2MY2';		$args = 2;	break;
-			case 305: $function = 'SUMX2PY2';		$args = 2;	break;
-			case 306: $function = 'CHITEST';		$args = 2;	break;
-			case 307: $function = 'CORREL';			$args = 2;	break;
-			case 308: $function = 'COVAR';			$args = 2;	break;
-			case 309: $function = 'FORECAST';		$args = 3;	break;
-			case 310: $function = 'FTEST';			$args = 2;	break;
-			case 311: $function = 'INTERCEPT';		$args = 2;	break;
-			case 312: $function = 'PEARSON';		$args = 2;	break;
-			case 313: $function = 'RSQ';			$args = 2;	break;
-			case 314: $function = 'STEYX';			$args = 2;	break;
-			case 315: $function = 'SLOPE';			$args = 2;	break;
-			case 316: $function = 'TTEST';			$args = 4;	break;
-			case 325: $function = 'LARGE';			$args = 2;	break;
-			case 326: $function = 'SMALL';			$args = 2;	break;
-			case 327: $function = 'QUARTILE';		$args = 2;	break;
-			case 328: $function = 'PERCENTILE';		$args = 2;	break;
-			case 331: $function = 'TRIMMEAN';		$args = 2;	break;
-			case 332: $function = 'TINV';			$args = 2;	break;
-			case 337: $function = 'POWER';			$args = 2;	break;
-			case 342: $function = 'RADIANS';		$args = 1;	break;
-			case 343: $function = 'DEGREES';		$args = 1;	break;
-			case 346: $function = 'COUNTIF';		$args = 2;	break;
-			case 347: $function = 'COUNTBLANK';		$args = 1;	break;
-			case 350: $function = 'ISPMT';			$args = 4;	break;
-			case 351: $function = 'DATEDIF';		$args = 3;	break;
-			case 352: $function = 'DATESTRING';		$args = 1;	break;
-			case 353: $function = 'NUMBERSTRING';	$args = 2;	break;
-			case 360: $function = 'PHONETIC';		$args = 1;	break;
-			case 368: $function = 'BAHTTEXT';		$args = 1;	break;
-			default:
-				throw new Exception('Unrecognized function in formula');
-				break;
-			}
-			$data = array('function' => $function, 'args' => $args);
-			break;
-		case 0x22:	//	function with variable number of arguments
-		case 0x42:
-		case 0x62:
-			$name = 'tFuncV';
-			$size = 4;
-			// offset: 1; size: 1; number of arguments
-			$args = ord($formulaData[1]);
-			// offset: 2: size: 2; index to built-in sheet function
-			$index = self::_GetInt2d($formulaData, 2);
-			switch ($index) {
-			case   0: $function = 'COUNT';			break;
-			case   1: $function = 'IF';				break;
-			case   4: $function = 'SUM';			break;
-			case   5: $function = 'AVERAGE';		break;
-			case   6: $function = 'MIN';			break;
-			case   7: $function = 'MAX';			break;
-			case   8: $function = 'ROW';			break;
-			case   9: $function = 'COLUMN';			break;
-			case  11: $function = 'NPV';			break;
-			case  12: $function = 'STDEV';			break;
-			case  13: $function = 'DOLLAR';			break;
-			case  14: $function = 'FIXED';			break;
-			case  28: $function = 'LOOKUP';			break;
-			case  29: $function = 'INDEX';			break;
-			case  36: $function = 'AND';			break;
-			case  37: $function = 'OR';				break;
-			case  46: $function = 'VAR';			break;
-			case  49: $function = 'LINEST';			break;
-			case  50: $function = 'TREND';			break;
-			case  51: $function = 'LOGEST';			break;
-			case  52: $function = 'GROWTH';			break;
-			case  56: $function = 'PV';				break;
-			case  57: $function = 'FV';				break;
-			case  58: $function = 'NPER';			break;
-			case  59: $function = 'PMT';			break;
-			case  60: $function = 'RATE';			break;
-			case  62: $function = 'IRR';			break;
-			case  64: $function = 'MATCH';			break;
-			case  70: $function = 'WEEKDAY';		break;
-			case  78: $function = 'OFFSET';			break;
-			case  82: $function = 'SEARCH';			break;
-			case 100: $function = 'CHOOSE';			break;
-			case 101: $function = 'HLOOKUP';		break;
-			case 102: $function = 'VLOOKUP';		break;
-			case 109: $function = 'LOG';			break;
-			case 115: $function = 'LEFT';			break;
-			case 116: $function = 'RIGHT';			break;
-			case 120: $function = 'SUBSTITUTE';		break;
-			case 124: $function = 'FIND';			break;
-			case 125: $function = 'CELL';			break;
-			case 144: $function = 'DDB';			break;
-			case 148: $function = 'INDIRECT';		break;
-			case 167: $function = 'IPMT';			break;
-			case 168: $function = 'PPMT';			break;
-			case 169: $function = 'COUNTA';			break;
-			case 183: $function = 'PRODUCT';		break;
-			case 193: $function = 'STDEVP';			break;
-			case 194: $function = 'VARP';			break;
-			case 197: $function = 'TRUNC';			break;
-			case 204: $function = 'USDOLLAR';		break;
-			case 205: $function = 'FINDB';			break;
-			case 206: $function = 'SEARCHB';		break;
-			case 208: $function = 'LEFTB';			break;
-			case 209: $function = 'RIGHTB';			break;
-			case 216: $function = 'RANK';			break;
-			case 219: $function = 'ADDRESS';		break;
-			case 220: $function = 'DAYS360';		break;
-			case 222: $function = 'VDB';			break;
-			case 227: $function = 'MEDIAN';			break;
-			case 228: $function = 'SUMPRODUCT';		break;
-			case 247: $function = 'DB';				break;
-			case 255: $function = '';				break;
-			case 269: $function = 'AVEDEV';			break;
-			case 270: $function = 'BETADIST';		break;
-			case 272: $function = 'BETAINV';		break;
-			case 317: $function = 'PROB';			break;
-			case 318: $function = 'DEVSQ';			break;
-			case 319: $function = 'GEOMEAN';		break;
-			case 320: $function = 'HARMEAN';		break;
-			case 321: $function = 'SUMSQ';			break;
-			case 322: $function = 'KURT';			break;
-			case 323: $function = 'SKEW';			break;
-			case 324: $function = 'ZTEST';			break;
-			case 329: $function = 'PERCENTRANK';	break;
-			case 330: $function = 'MODE';			break;
-			case 336: $function = 'CONCATENATE';	break;
-			case 344: $function = 'SUBTOTAL';		break;
-			case 345: $function = 'SUMIF';			break;
-			case 354: $function = 'ROMAN';			break;
-			case 358: $function = 'GETPIVOTDATA';	break;
-			case 359: $function = 'HYPERLINK';		break;
-			case 361: $function = 'AVERAGEA';		break;
-			case 362: $function = 'MAXA';			break;
-			case 363: $function = 'MINA';			break;
-			case 364: $function = 'STDEVPA';		break;
-			case 365: $function = 'VARPA';			break;
-			case 366: $function = 'STDEVA';			break;
-			case 367: $function = 'VARA';			break;
-			default:
-				throw new Exception('Unrecognized function in formula');
-				break;
-			}
-			$data = array('function' => $function, 'args' => $args);
-			break;
-		case 0x23:	//	index to defined name
-		case 0x43:
-		case 0x63:
-			$name = 'tName';
-			$size = 5;
-			// offset: 1; size: 2; one-based index to definedname record
-			$definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
-			// offset: 2; size: 2; not used
-			$data = $this->_definedname[$definedNameIndex]['name'];
-			break;
-		case 0x24:	//	single cell reference e.g. A5
-		case 0x44:
-		case 0x64:
-			$name = 'tRef';
-			$size = 5;
-			$data = $this->_readBIFF8CellAddress(substr($formulaData, 1, 4));
-			break;
-		case 0x25:	//	cell range reference to cells in the same sheet (2d)
-		case 0x45:
-		case 0x65:
-			$name = 'tArea';
-			$size = 9;
-			$data = $this->_readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
-			break;
-		case 0x26:	//	Constant reference sub-expression
-		case 0x46:
-		case 0x66:
-			$name = 'tMemArea';
-			// offset: 1; size: 4; not used
-			// offset: 5; size: 2; size of the following subexpression
-			$subSize = self::_GetInt2d($formulaData, 5);
-			$size = 7 + $subSize;
-			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
-			break;
-		case 0x27:	//	Deleted constant reference sub-expression
-		case 0x47:
-		case 0x67:
-			$name = 'tMemErr';
-			// offset: 1; size: 4; not used
-			// offset: 5; size: 2; size of the following subexpression
-			$subSize = self::_GetInt2d($formulaData, 5);
-			$size = 7 + $subSize;
-			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
-			break;
-		case 0x29:	//	Variable reference sub-expression
-		case 0x49:
-		case 0x69:
-			$name = 'tMemFunc';
-			// offset: 1; size: 2; size of the following sub-expression
-			$subSize = self::_GetInt2d($formulaData, 1);
-			$size = 3 + $subSize;
-			$data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize));
-			break;
-
-		case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
-		case 0x4C:
-		case 0x6C:
-			$name = 'tRefN';
-			$size = 5;
-			$data = $this->_readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
-			break;
-
-		case 0x2D:	//	Relative 2d range reference
-		case 0x4D:
-		case 0x6D:
-			$name = 'tAreaN';
-			$size = 9;
-			$data = $this->_readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
-			break;
-
-		case 0x39:	//	External name
-		case 0x59:
-		case 0x79:
-			$name = 'tNameX';
-			$size = 7;
-			// offset: 1; size: 2; index to REF entry in EXTERNSHEET record
-			// offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
-			$index = self::_GetInt2d($formulaData, 3);
-			// assume index is to EXTERNNAME record
-			$data = $this->_externalNames[$index - 1]['name'];
-			// offset: 5; size: 2; not used
-			break;
-
-		case 0x3A:	//	3d reference to cell
-		case 0x5A:
-		case 0x7A:
-			$name = 'tRef3d';
-			$size = 7;
-
-			try {
-				// offset: 1; size: 2; index to REF entry
-				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
-				// offset: 3; size: 4; cell address
-				$cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4));
-
-				$data = "$sheetRange!$cellAddress";
-			} catch (Exception $e) {
-				// deleted sheet reference
-				$data = '#REF!';
-			}
-
-			break;
-		case 0x3B:	//	3d reference to cell range
-		case 0x5B:
-		case 0x7B:
-			$name = 'tArea3d';
-			$size = 11;
-
-			try {
-				// offset: 1; size: 2; index to REF entry
-				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
-				// offset: 3; size: 8; cell address
-				$cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8));
-
-				$data = "$sheetRange!$cellRangeAddress";
-			} catch (Exception $e) {
-				// deleted sheet reference
-				$data = '#REF!';
-			}
-
-			break;
-		// Unknown cases	// don't know how to deal with
-		default:
-			throw new Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
-			break;
-		}
-
-		return array(
-			'id' => $id,
-			'name' => $name,
-			'size' => $size,
-			'data' => $data,
-		);
-	}
-
-	/**
-	 * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2'
-	 * section 3.3.4
-	 *
-	 * @param string $cellAddressStructure
-	 * @return string
-	 */
-	private function _readBIFF8CellAddress($cellAddressStructure)
-	{
-		// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
-		$row = self::_GetInt2d($cellAddressStructure, 0) + 1;
-
-		// offset: 2; size: 2; index to column or column offset + relative flags
-
-			// bit: 7-0; mask 0x00FF; column index
-			$column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($cellAddressStructure, 2));
-
-			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
-			if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
-				$column = '$' . $column;
-			}
-			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
-			if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
-				$row = '$' . $row;
-			}
-
-		return $column . $row;
-	}
-
-	/**
-	 * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column
-	 * to indicate offsets from a base cell
-	 * section 3.3.4
-	 *
-	 * @param string $cellAddressStructure
-	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
-	 * @return string
-	 */
-	private function _readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
-	{
-		list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
-		$baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
-
-		// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
-			$rowIndex = self::_GetInt2d($cellAddressStructure, 0);
-			$row = self::_GetInt2d($cellAddressStructure, 0) + 1;
-
-		// offset: 2; size: 2; index to column or column offset + relative flags
-
-			// bit: 7-0; mask 0x00FF; column index
-			$colIndex = 0x00FF & self::_GetInt2d($cellAddressStructure, 2);
-
-			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
-			if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
-				$column = PHPExcel_Cell::stringFromColumnIndex($colIndex);
-				$column = '$' . $column;
-			} else {
-				$colIndex = ($colIndex <= 127) ? $colIndex : $colIndex - 256;
-				$column = PHPExcel_Cell::stringFromColumnIndex($baseCol + $colIndex);
-			}
-
-			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
-			if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
-				$row = '$' . $row;
-			} else {
-				$rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536;
-				$row = $baseRow + $rowIndex;
-			}
-
-		return $column . $row;
-	}
-
-	/**
-	 * Reads a cell range address in BIFF5 e.g. 'A2:B6' or 'A1'
-	 * always fixed range
-	 * section 2.5.14
-	 *
-	 * @param string $subData
-	 * @return string
-	 * @throws Exception
-	 */
-	private function _readBIFF5CellRangeAddressFixed($subData)
-	{
-		// offset: 0; size: 2; index to first row
-		$fr = self::_GetInt2d($subData, 0) + 1;
-
-		// offset: 2; size: 2; index to last row
-		$lr = self::_GetInt2d($subData, 2) + 1;
-
-		// offset: 4; size: 1; index to first column
-		$fc = ord($subData{4});
-
-		// offset: 5; size: 1; index to last column
-		$lc = ord($subData{5});
-
-		// check values
-		if ($fr > $lr || $fc > $lc) {
-			throw new Exception('Not a cell range address');
-		}
-
-		// column index to letter
-		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
-		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);
-
-		if ($fr == $lr and $fc == $lc) {
-			return "$fc$fr";
-		}
-		return "$fc$fr:$lc$lr";
-	}
-
-	/**
-	 * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1'
-	 * always fixed range
-	 * section 2.5.14
-	 *
-	 * @param string $subData
-	 * @return string
-	 * @throws Exception
-	 */
-	private function _readBIFF8CellRangeAddressFixed($subData)
-	{
-		// offset: 0; size: 2; index to first row
-		$fr = self::_GetInt2d($subData, 0) + 1;
-
-		// offset: 2; size: 2; index to last row
-		$lr = self::_GetInt2d($subData, 2) + 1;
-
-		// offset: 4; size: 2; index to first column
-		$fc = self::_GetInt2d($subData, 4);
-
-		// offset: 6; size: 2; index to last column
-		$lc = self::_GetInt2d($subData, 6);
-
-		// check values
-		if ($fr > $lr || $fc > $lc) {
-			throw new Exception('Not a cell range address');
-		}
-
-		// column index to letter
-		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
-		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);
-
-		if ($fr == $lr and $fc == $lc) {
-			return "$fc$fr";
-		}
-		return "$fc$fr:$lc$lr";
-	}
-
-	/**
-	 * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6'
-	 * there are flags indicating whether column/row index is relative
-	 * section 3.3.4
-	 *
-	 * @param string $subData
-	 * @return string
-	 */
-	private function _readBIFF8CellRangeAddress($subData)
-	{
-		// todo: if cell range is just a single cell, should this funciton
-		// not just return e.g. 'A1' and not 'A1:A1' ?
-
-		// offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
-			$fr = self::_GetInt2d($subData, 0) + 1;
-
-		// offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
-			$lr = self::_GetInt2d($subData, 2) + 1;
-
-		// offset: 4; size: 2; index to first column or column offset + relative flags
-
-			// bit: 7-0; mask 0x00FF; column index
-			$fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 4));
-
-			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
-			if (!(0x4000 & self::_GetInt2d($subData, 4))) {
-				$fc = '$' . $fc;
-			}
-
-			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
-			if (!(0x8000 & self::_GetInt2d($subData, 4))) {
-				$fr = '$' . $fr;
-			}
-
-		// offset: 6; size: 2; index to last column or column offset + relative flags
-
-			// bit: 7-0; mask 0x00FF; column index
-			$lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 6));
-
-			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
-			if (!(0x4000 & self::_GetInt2d($subData, 6))) {
-				$lc = '$' . $lc;
-			}
-
-			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
-			if (!(0x8000 & self::_GetInt2d($subData, 6))) {
-				$lr = '$' . $lr;
-			}
-
-		return "$fc$fr:$lc$lr";
-	}
-
-	/**
-	 * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column
-	 * to indicate offsets from a base cell
-	 * section 3.3.4
-	 *
-	 * @param string $subData
-	 * @param string $baseCell Base cell
-	 * @return string Cell range address
-	 */
-	private function _readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
-	{
-		list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
-		$baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
-
-		// TODO: if cell range is just a single cell, should this funciton
-		// not just return e.g. 'A1' and not 'A1:A1' ?
-
-		// offset: 0; size: 2; first row
-		$frIndex = self::_GetInt2d($subData, 0); // adjust below
-
-		// offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767)
-		$lrIndex = self::_GetInt2d($subData, 2); // adjust below
-
-		// offset: 4; size: 2; first column with relative/absolute flags
-
-			// bit: 7-0; mask 0x00FF; column index
-			$fcIndex = 0x00FF & self::_GetInt2d($subData, 4);
-
-			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
-			if (!(0x4000 & self::_GetInt2d($subData, 4))) {
-				// absolute column index
-				$fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex);
-				$fc = '$' . $fc;
-			} else {
-				// column offset
-				$fcIndex = ($fcIndex <= 127) ? $fcIndex : $fcIndex - 256;
-				$fc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $fcIndex);
-			}
-
-			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
-			if (!(0x8000 & self::_GetInt2d($subData, 4))) {
-				// absolute row index
-				$fr = $frIndex + 1;
-				$fr = '$' . $fr;
-			} else {
-				// row offset
-				$frIndex = ($frIndex <= 32767) ? $frIndex : $frIndex - 65536;
-				$fr = $baseRow + $frIndex;
-			}
-
-		// offset: 6; size: 2; last column with relative/absolute flags
-
-			// bit: 7-0; mask 0x00FF; column index
-			$lcIndex = 0x00FF & self::_GetInt2d($subData, 6);
-			$lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
-			$lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
-
-			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
-			if (!(0x4000 & self::_GetInt2d($subData, 6))) {
-				// absolute column index
-				$lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex);
-				$lc = '$' . $lc;
-			} else {
-				// column offset
-				$lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
-				$lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
-			}
-
-			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
-			if (!(0x8000 & self::_GetInt2d($subData, 6))) {
-				// absolute row index
-				$lr = $lrIndex + 1;
-				$lr = '$' . $lr;
-			} else {
-				// row offset
-				$lrIndex = ($lrIndex <= 32767) ? $lrIndex : $lrIndex - 65536;
-				$lr = $baseRow + $lrIndex;
-			}
-
-		return "$fc$fr:$lc$lr";
-	}
-
-	/**
-	 * Read BIFF8 cell range address list
-	 * section 2.5.15
-	 *
-	 * @param string $subData
-	 * @return array
-	 */
-	private function _readBIFF8CellRangeAddressList($subData)
-	{
-		$cellRangeAddresses = array();
-
-		// offset: 0; size: 2; number of the following cell range addresses
-		$nm = self::_GetInt2d($subData, 0);
-
-		$offset = 2;
-		// offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses
-		for ($i = 0; $i < $nm; ++$i) {
-			$cellRangeAddresses[] = $this->_readBIFF8CellRangeAddressFixed(substr($subData, $offset, 8));
-			$offset += 8;
-		}
-
-		return array(
-			'size' => 2 + 8 * $nm,
-			'cellRangeAddresses' => $cellRangeAddresses,
-		);
-	}
-
-	/**
-	 * Read BIFF5 cell range address list
-	 * section 2.5.15
-	 *
-	 * @param string $subData
-	 * @return array
-	 */
-	private function _readBIFF5CellRangeAddressList($subData)
-	{
-		$cellRangeAddresses = array();
-
-		// offset: 0; size: 2; number of the following cell range addresses
-		$nm = self::_GetInt2d($subData, 0);
-
-		$offset = 2;
-		// offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses
-		for ($i = 0; $i < $nm; ++$i) {
-			$cellRangeAddresses[] = $this->_readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6));
-			$offset += 6;
-		}
-
-		return array(
-			'size' => 2 + 6 * $nm,
-			'cellRangeAddresses' => $cellRangeAddresses,
-		);
-	}
-
-	/**
-	 * Get a sheet range like Sheet1:Sheet3 from REF index
-	 * Note: If there is only one sheet in the range, one gets e.g Sheet1
-	 * It can also happen that the REF structure uses the -1 (FFFF) code to indicate deleted sheets,
-	 * in which case an exception is thrown
-	 *
-	 * @param int $index
-	 * @return string|false
-	 * @throws Exception
-	 */
-	private function _readSheetRangeByRefIndex($index)
-	{
-		if (isset($this->_ref[$index])) {
-
-			$type = $this->_externalBooks[$this->_ref[$index]['externalBookIndex']]['type'];
-
-			switch ($type) {
-				case 'internal':
-					// check if we have a deleted 3d reference
-					if ($this->_ref[$index]['firstSheetIndex'] == 0xFFFF or $this->_ref[$index]['lastSheetIndex'] == 0xFFFF) {
-						throw new Exception('Deleted sheet reference');
-					}
-
-					// we have normal sheet range (collapsed or uncollapsed)
-					$firstSheetName = $this->_sheets[$this->_ref[$index]['firstSheetIndex']]['name'];
-					$lastSheetName = $this->_sheets[$this->_ref[$index]['lastSheetIndex']]['name'];
-
-					if ($firstSheetName == $lastSheetName) {
-						// collapsed sheet range
-						$sheetRange = $firstSheetName;
-					} else {
-						$sheetRange = "$firstSheetName:$lastSheetName";
-					}
-
-					// escape the single-quotes
-					$sheetRange = str_replace("'", "''", $sheetRange);
-
-					// if there are special characters, we need to enclose the range in single-quotes
-					// todo: check if we have identified the whole set of special characters
-					// it seems that the following characters are not accepted for sheet names
-					// and we may assume that they are not present: []*/:\?
-					if (preg_match("/[ !\"@#£$%&{()}<>=+'|^,;-]/", $sheetRange)) {
-						$sheetRange = "'$sheetRange'";
-					}
-
-					return $sheetRange;
-					break;
-
-				default:
-					// TODO: external sheet support
-					throw new Exception('Excel5 reader only supports internal sheets in fomulas');
-					break;
-			}
-		}
-		return false;
-	}
-
-	/**
-	 * read BIFF8 constant value array from array data
-	 * returns e.g. array('value' => '{1,2;3,4}', 'size' => 40}
-	 * section 2.5.8
-	 *
-	 * @param string $arrayData
-	 * @return array
-	 */
-	private static function _readBIFF8ConstantArray($arrayData)
-	{
-		// offset: 0; size: 1; number of columns decreased by 1
-		$nc = ord($arrayData[0]);
-
-		// offset: 1; size: 2; number of rows decreased by 1
-		$nr = self::_GetInt2d($arrayData, 1);
-		$size = 3; // initialize
-		$arrayData = substr($arrayData, 3);
-
-		// offset: 3; size: var; list of ($nc + 1) * ($nr + 1) constant values
-		$matrixChunks = array();
-		for ($r = 1; $r <= $nr + 1; ++$r) {
-			$items = array();
-			for ($c = 1; $c <= $nc + 1; ++$c) {
-				$constant = self::_readBIFF8Constant($arrayData);
-				$items[] = $constant['value'];
-				$arrayData = substr($arrayData, $constant['size']);
-				$size += $constant['size'];
-			}
-			$matrixChunks[] = implode(',', $items); // looks like e.g. '1,"hello"'
-		}
-		$matrix = '{' . implode(';', $matrixChunks) . '}';
-
-		return array(
-			'value' => $matrix,
-			'size' => $size,
-		);
-	}
-
-	/**
-	 * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value'
-	 * section 2.5.7
-	 * returns e.g. array('value' => '5', 'size' => 9)
-	 *
-	 * @param string $valueData
-	 * @return array
-	 */
-	private static function _readBIFF8Constant($valueData)
-	{
-		// offset: 0; size: 1; identifier for type of constant
-		$identifier = ord($valueData[0]);
-
-		switch ($identifier) {
-		case 0x00: // empty constant (what is this?)
-			$value = '';
-			$size = 9;
-			break;
-		case 0x01: // number
-			// offset: 1; size: 8; IEEE 754 floating-point value
-			$value = self::_extractNumber(substr($valueData, 1, 8));
-			$size = 9;
-			break;
-		case 0x02: // string value
-			// offset: 1; size: var; Unicode string, 16-bit string length
-			$string = self::_readUnicodeStringLong(substr($valueData, 1));
-			$value = '"' . $string['value'] . '"';
-			$size = 1 + $string['size'];
-			break;
-		case 0x04: // boolean
-			// offset: 1; size: 1; 0 = FALSE, 1 = TRUE
-			if (ord($valueData[1])) {
-				$value = 'TRUE';
-			} else {
-				$value = 'FALSE';
-			}
-			$size = 9;
-			break;
-		case 0x10: // error code
-			// offset: 1; size: 1; error code
-			$value = self::_mapErrorCode(ord($valueData[1]));
-			$size = 9;
-			break;
-		}
-		return array(
-			'value' => $value,
-			'size' => $size,
-		);
-	}
-
-	/**
-	 * Extract RGB color
-	 * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4
-	 *
-	 * @param string $rgb Encoded RGB value (4 bytes)
-	 * @return array
-	 */
-	private static function _readRGB($rgb)
-	{
-		// offset: 0; size 1; Red component
-		$r = ord($rgb{0});
-
-		// offset: 1; size: 1; Green component
-		$g = ord($rgb{1});
-
-		// offset: 2; size: 1; Blue component
-		$b = ord($rgb{2});
-
-		// HEX notation, e.g. 'FF00FC'
-		$rgb = sprintf('%02X%02X%02X', $r, $g, $b);
-
-		return array('rgb' => $rgb);
-	}
-
-	/**
-	 * Read byte string (8-bit string length)
-	 * OpenOffice documentation: 2.5.2
-	 *
-	 * @param string $subData
-	 * @return array
-	 */
-	private function _readByteStringShort($subData)
-	{
-		// offset: 0; size: 1; length of the string (character count)
-		$ln = ord($subData[0]);
-
-		// offset: 1: size: var; character array (8-bit characters)
-		$value = $this->_decodeCodepage(substr($subData, 1, $ln));
-
-		return array(
-			'value' => $value,
-			'size' => 1 + $ln, // size in bytes of data structure
-		);
-	}
-
-	/**
-	 * Read byte string (16-bit string length)
-	 * OpenOffice documentation: 2.5.2
-	 *
-	 * @param string $subData
-	 * @return array
-	 */
-	private function _readByteStringLong($subData)
-	{
-		// offset: 0; size: 2; length of the string (character count)
-		$ln = self::_GetInt2d($subData, 0);
-
-		// offset: 2: size: var; character array (8-bit characters)
-		$value = $this->_decodeCodepage(substr($subData, 2));
-
-		//return $string;
-		return array(
-			'value' => $value,
-			'size' => 2 + $ln, // size in bytes of data structure
-		);
-	}
-
-	/**
-	 * Extracts an Excel Unicode short string (8-bit string length)
-	 * OpenOffice documentation: 2.5.3
-	 * function will automatically find out where the Unicode string ends.
-	 *
-	 * @param string $subData
-	 * @return array
-	 */
-	private static function _readUnicodeStringShort($subData)
-	{
-		$value = '';
-
-		// offset: 0: size: 1; length of the string (character count)
-		$characterCount = ord($subData[0]);
-
-		$string = self::_readUnicodeString(substr($subData, 1), $characterCount);
-
-		// add 1 for the string length
-		$string['size'] += 1;
-
-		return $string;
-	}
-
-	/**
-	 * Extracts an Excel Unicode long string (16-bit string length)
-	 * OpenOffice documentation: 2.5.3
-	 * this function is under construction, needs to support rich text, and Asian phonetic settings
-	 *
-	 * @param string $subData
-	 * @return array
-	 */
-	private static function _readUnicodeStringLong($subData)
-	{
-		$value = '';
-
-		// offset: 0: size: 2; length of the string (character count)
-		$characterCount = self::_GetInt2d($subData, 0);
-
-		$string = self::_readUnicodeString(substr($subData, 2), $characterCount);
-
-		// add 2 for the string length
-		$string['size'] += 2;
-
-		return $string;
-	}
-
-	/**
-	 * Read Unicode string with no string length field, but with known character count
-	 * this function is under construction, needs to support rich text, and Asian phonetic settings
-	 * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3
-	 *
-	 * @param string $subData
-	 * @param int $characterCount
-	 * @return array
-	 */
-	private static function _readUnicodeString($subData, $characterCount)
-	{
-		$value = '';
-
-		// offset: 0: size: 1; option flags
-
-			// bit: 0; mask: 0x01; character compression (0 = compressed 8-bit, 1 = uncompressed 16-bit)
-			$isCompressed = !((0x01 & ord($subData[0])) >> 0);
-
-			// bit: 2; mask: 0x04; Asian phonetic settings
-			$hasAsian = (0x04) & ord($subData[0]) >> 2;
-
-			// bit: 3; mask: 0x08; Rich-Text settings
-			$hasRichText = (0x08) & ord($subData[0]) >> 3;
-
-		// offset: 1: size: var; character array
-		// this offset assumes richtext and Asian phonetic settings are off which is generally wrong
-		// needs to be fixed
-		$value = self::_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed);
-
-		return array(
-			'value' => $value,
-			'size' => $isCompressed ? 1 + $characterCount : 1 + 2 * $characterCount, // the size in bytes including the option flags
-		);
-	}
-
-	/**
-	 * Convert UTF-8 string to string surounded by double quotes. Used for explicit string tokens in formulas.
-	 * Example:  hello"world  -->  "hello""world"
-	 *
-	 * @param string $value UTF-8 encoded string
-	 * @return string
-	 */
-	private static function _UTF8toExcelDoubleQuoted($value)
-	{
-		return '"' . str_replace('"', '""', $value) . '"';
-	}
-
-	/**
-	 * Reads first 8 bytes of a string and return IEEE 754 float
-	 *
-	 * @param string $data Binary string that is at least 8 bytes long
-	 * @return float
-	 */
-	private static function _extractNumber($data)
-	{
-		$rknumhigh = self::_GetInt4d($data, 4);
-		$rknumlow = self::_GetInt4d($data, 0);
-		$sign = ($rknumhigh & 0x80000000) >> 31;
-		$exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023;
-		$mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
-		$mantissalow1 = ($rknumlow & 0x80000000) >> 31;
-		$mantissalow2 = ($rknumlow & 0x7fffffff);
-		$value = $mantissa / pow( 2 , (20 - $exp));
-
-		if ($mantissalow1 != 0) {
-			$value += 1 / pow (2 , (21 - $exp));
-		}
-
-		$value += $mantissalow2 / pow (2 , (52 - $exp));
-		if ($sign) {
-			$value = -1 * $value;
-		}
-
-		return $value;
-	}
-
-	private static function _GetIEEE754($rknum)
-	{
-		if (($rknum & 0x02) != 0) {
-			$value = $rknum >> 2;
-		}
-		else {
-			// changes by mmp, info on IEEE754 encoding from
-			// research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
-			// The RK format calls for using only the most significant 30 bits
-			// of the 64 bit floating point value. The other 34 bits are assumed
-			// to be 0 so we use the upper 30 bits of $rknum as follows...
-			$sign = ($rknum & 0x80000000) >> 31;
-			$exp = ($rknum & 0x7ff00000) >> 20;
-			$mantissa = (0x100000 | ($rknum & 0x000ffffc));
-			$value = $mantissa / pow( 2 , (20- ($exp - 1023)));
-			if ($sign) {
-				$value = -1 * $value;
-			}
-			//end of changes by mmp
-		}
-		if (($rknum & 0x01) != 0) {
-			$value /= 100;
-		}
-		return $value;
-	}
-
-	/**
-	 * Get UTF-8 string from (compressed or uncompressed) UTF-16 string
-	 *
-	 * @param string $string
-	 * @param bool $compressed
-	 * @return string
-	 */
-	private static function _encodeUTF16($string, $compressed = '')
-	{
-		if ($compressed) {
-			$string = self::_uncompressByteString($string);
- 		}
-
-		return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE');
-	}
-
-	/**
-	 * Convert UTF-16 string in compressed notation to uncompressed form. Only used for BIFF8.
-	 *
-	 * @param string $string
-	 * @return string
-	 */
-	private static function _uncompressByteString($string)
-	{
-		$uncompressedString = '';
-		$strLen = strlen($string);
-		for ($i = 0; $i < $strLen; ++$i) {
-			$uncompressedString .= $string[$i] . "\0";
-		}
-
-		return $uncompressedString;
-	}
-
-	/**
-	 * Convert string to UTF-8. Only used for BIFF5.
-	 *
-	 * @param string $string
-	 * @return string
-	 */
-	private function _decodeCodepage($string)
-	{
-		return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage);
-	}
-
-	/**
-	 * Read 16-bit unsigned integer
-	 *
-	 * @param string $data
-	 * @param int $pos
-	 * @return int
-	 */
-	public static function _GetInt2d($data, $pos)
-	{
-		return ord($data[$pos]) | (ord($data[$pos + 1]) << 8);
-	}
-
-	/**
-	 * Read 32-bit signed integer
-	 *
-	 * @param string $data
-	 * @param int $pos
-	 * @return int
-	 */
-	public static function _GetInt4d($data, $pos)
-	{
-		// FIX: represent numbers correctly on 64-bit system
-		// http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
-		// Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
-		$_or_24 = ord($data[$pos + 3]);
-		if ($_or_24 >= 128) {
-			// negative number
-			$_ord_24 = -abs((256 - $_or_24) << 24);
-		} else {
-			$_ord_24 = ($_or_24 & 127) << 24;
-		}
-		return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24;
-	}
-
-	/**
-	 * Read color
-	 *
-	 * @param int $color Indexed color
-	 * @param array $palette Color palette
-	 * @return array RGB color value, example: array('rgb' => 'FF0000')
-	 */
-	private static function _readColor($color,$palette,$version)
-	{
-		if ($color <= 0x07 || $color >= 0x40) {
-			// special built-in color
-			return self::_mapBuiltInColor($color);
-		} elseif (isset($palette) && isset($palette[$color - 8])) {
-			// palette color, color index 0x08 maps to pallete index 0
-			return $palette[$color - 8];
-		} else {
-			// default color table
-			if ($version == self::XLS_BIFF8) {
-				return self::_mapColor($color);
-			} else {
-				// BIFF5
-				return self::_mapColorBIFF5($color);
-			}
-		}
-
-		return $color;
-	}
-
-
-	/**
-	 * Map border style
-	 * OpenOffice documentation: 2.5.11
-	 *
-	 * @param int $index
-	 * @return string
-	 */
-	private static function _mapBorderStyle($index)
-	{
-		switch ($index) {
-			case 0x00: return PHPExcel_Style_Border::BORDER_NONE;
-			case 0x01: return PHPExcel_Style_Border::BORDER_THIN;
-			case 0x02: return PHPExcel_Style_Border::BORDER_MEDIUM;
-			case 0x03: return PHPExcel_Style_Border::BORDER_DASHED;
-			case 0x04: return PHPExcel_Style_Border::BORDER_DOTTED;
-			case 0x05: return PHPExcel_Style_Border::BORDER_THICK;
-			case 0x06: return PHPExcel_Style_Border::BORDER_DOUBLE;
-			case 0x07: return PHPExcel_Style_Border::BORDER_HAIR;
-			case 0x08: return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
-			case 0x09: return PHPExcel_Style_Border::BORDER_DASHDOT;
-			case 0x0A: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
-			case 0x0B: return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
-			case 0x0C: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
-			case 0x0D: return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
-			default:   return PHPExcel_Style_Border::BORDER_NONE;
-		}
-	}
-
-	/**
-	 * Get fill pattern from index
-	 * OpenOffice documentation: 2.5.12
-	 *
-	 * @param int $index
-	 * @return string
-	 */
-	private static function _mapFillPattern($index)
-	{
-		switch ($index) {
-			case 0x00: return PHPExcel_Style_Fill::FILL_NONE;
-			case 0x01: return PHPExcel_Style_Fill::FILL_SOLID;
-			case 0x02: return PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY;
-			case 0x03: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY;
-			case 0x04: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY;
-			case 0x05: return PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL;
-			case 0x06: return PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL;
-			case 0x07: return PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN;
-			case 0x08: return PHPExcel_Style_Fill::FILL_PATTERN_DARKUP;
-			case 0x09: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID;
-			case 0x0A: return PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS;
-			case 0x0B: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL;
-			case 0x0C: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL;
-			case 0x0D: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN;
-			case 0x0E: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP;
-			case 0x0F: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID;
-			case 0x10: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS;
-			case 0x11: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY125;
-			case 0x12: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625;
-			default:   return PHPExcel_Style_Fill::FILL_NONE;
-		}
-	}
-
-	/**
-	 * Map error code, e.g. '#N/A'
-	 *
-	 * @param int $subData
-	 * @return string
-	 */
-	private static function _mapErrorCode($subData)
-	{
-		switch ($subData) {
-			case 0x00: return '#NULL!';		break;
-			case 0x07: return '#DIV/0!';	break;
-			case 0x0F: return '#VALUE!';	break;
-			case 0x17: return '#REF!';		break;
-			case 0x1D: return '#NAME?';		break;
-			case 0x24: return '#NUM!';		break;
-			case 0x2A: return '#N/A';		break;
-			default: return false;
-		}
-	}
-
-	/**
-	 * Map built-in color to RGB value
-	 *
-	 * @param int $color Indexed color
-	 * @return array
-	 */
-	private static function _mapBuiltInColor($color)
-	{
-		switch ($color) {
-			case 0x00: return array('rgb' => '000000');
-			case 0x01: return array('rgb' => 'FFFFFF');
-			case 0x02: return array('rgb' => 'FF0000');
-			case 0x03: return array('rgb' => '00FF00');
-			case 0x04: return array('rgb' => '0000FF');
-			case 0x05: return array('rgb' => 'FFFF00');
-			case 0x06: return array('rgb' => 'FF00FF');
-			case 0x07: return array('rgb' => '00FFFF');
-			case 0x40: return array('rgb' => '000000'); // system window text color
-			case 0x41: return array('rgb' => 'FFFFFF'); // system window background color
-			default:   return array('rgb' => '000000');
-		}
-	}
-
-	/**
-	 * Map color array from BIFF5 built-in color index
-	 *
-	 * @param int $subData
-	 * @return array
-	 */
-	private static function _mapColorBIFF5($subData)
-	{
-		switch ($subData) {
-			case 0x08: return array('rgb' => '000000');
-			case 0x09: return array('rgb' => 'FFFFFF');
-			case 0x0A: return array('rgb' => 'FF0000');
-			case 0x0B: return array('rgb' => '00FF00');
-			case 0x0C: return array('rgb' => '0000FF');
-			case 0x0D: return array('rgb' => 'FFFF00');
-			case 0x0E: return array('rgb' => 'FF00FF');
-			case 0x0F: return array('rgb' => '00FFFF');
-			case 0x10: return array('rgb' => '800000');
-			case 0x11: return array('rgb' => '008000');
-			case 0x12: return array('rgb' => '000080');
-			case 0x13: return array('rgb' => '808000');
-			case 0x14: return array('rgb' => '800080');
-			case 0x15: return array('rgb' => '008080');
-			case 0x16: return array('rgb' => 'C0C0C0');
-			case 0x17: return array('rgb' => '808080');
-			case 0x18: return array('rgb' => '8080FF');
-			case 0x19: return array('rgb' => '802060');
-			case 0x1A: return array('rgb' => 'FFFFC0');
-			case 0x1B: return array('rgb' => 'A0E0F0');
-			case 0x1C: return array('rgb' => '600080');
-			case 0x1D: return array('rgb' => 'FF8080');
-			case 0x1E: return array('rgb' => '0080C0');
-			case 0x1F: return array('rgb' => 'C0C0FF');
-			case 0x20: return array('rgb' => '000080');
-			case 0x21: return array('rgb' => 'FF00FF');
-			case 0x22: return array('rgb' => 'FFFF00');
-			case 0x23: return array('rgb' => '00FFFF');
-			case 0x24: return array('rgb' => '800080');
-			case 0x25: return array('rgb' => '800000');
-			case 0x26: return array('rgb' => '008080');
-			case 0x27: return array('rgb' => '0000FF');
-			case 0x28: return array('rgb' => '00CFFF');
-			case 0x29: return array('rgb' => '69FFFF');
-			case 0x2A: return array('rgb' => 'E0FFE0');
-			case 0x2B: return array('rgb' => 'FFFF80');
-			case 0x2C: return array('rgb' => 'A6CAF0');
-			case 0x2D: return array('rgb' => 'DD9CB3');
-			case 0x2E: return array('rgb' => 'B38FEE');
-			case 0x2F: return array('rgb' => 'E3E3E3');
-			case 0x30: return array('rgb' => '2A6FF9');
-			case 0x31: return array('rgb' => '3FB8CD');
-			case 0x32: return array('rgb' => '488436');
-			case 0x33: return array('rgb' => '958C41');
-			case 0x34: return array('rgb' => '8E5E42');
-			case 0x35: return array('rgb' => 'A0627A');
-			case 0x36: return array('rgb' => '624FAC');
-			case 0x37: return array('rgb' => '969696');
-			case 0x38: return array('rgb' => '1D2FBE');
-			case 0x39: return array('rgb' => '286676');
-			case 0x3A: return array('rgb' => '004500');
-			case 0x3B: return array('rgb' => '453E01');
-			case 0x3C: return array('rgb' => '6A2813');
-			case 0x3D: return array('rgb' => '85396A');
-			case 0x3E: return array('rgb' => '4A3285');
-			case 0x3F: return array('rgb' => '424242');
-			default:   return array('rgb' => '000000');
-		}
-	}
-
-	/**
-	 * Map color array from BIFF8 built-in color index
-	 *
-	 * @param int $subData
-	 * @return array
-	 */
-	private static function _mapColor($subData)
-	{
-		switch ($subData) {
-			case 0x08: return array('rgb' => '000000');
-			case 0x09: return array('rgb' => 'FFFFFF');
-			case 0x0A: return array('rgb' => 'FF0000');
-			case 0x0B: return array('rgb' => '00FF00');
-			case 0x0C: return array('rgb' => '0000FF');
-			case 0x0D: return array('rgb' => 'FFFF00');
-			case 0x0E: return array('rgb' => 'FF00FF');
-			case 0x0F: return array('rgb' => '00FFFF');
-			case 0x10: return array('rgb' => '800000');
-			case 0x11: return array('rgb' => '008000');
-			case 0x12: return array('rgb' => '000080');
-			case 0x13: return array('rgb' => '808000');
-			case 0x14: return array('rgb' => '800080');
-			case 0x15: return array('rgb' => '008080');
-			case 0x16: return array('rgb' => 'C0C0C0');
-			case 0x17: return array('rgb' => '808080');
-			case 0x18: return array('rgb' => '9999FF');
-			case 0x19: return array('rgb' => '993366');
-			case 0x1A: return array('rgb' => 'FFFFCC');
-			case 0x1B: return array('rgb' => 'CCFFFF');
-			case 0x1C: return array('rgb' => '660066');
-			case 0x1D: return array('rgb' => 'FF8080');
-			case 0x1E: return array('rgb' => '0066CC');
-			case 0x1F: return array('rgb' => 'CCCCFF');
-			case 0x20: return array('rgb' => '000080');
-			case 0x21: return array('rgb' => 'FF00FF');
-			case 0x22: return array('rgb' => 'FFFF00');
-			case 0x23: return array('rgb' => '00FFFF');
-			case 0x24: return array('rgb' => '800080');
-			case 0x25: return array('rgb' => '800000');
-			case 0x26: return array('rgb' => '008080');
-			case 0x27: return array('rgb' => '0000FF');
-			case 0x28: return array('rgb' => '00CCFF');
-			case 0x29: return array('rgb' => 'CCFFFF');
-			case 0x2A: return array('rgb' => 'CCFFCC');
-			case 0x2B: return array('rgb' => 'FFFF99');
-			case 0x2C: return array('rgb' => '99CCFF');
-			case 0x2D: return array('rgb' => 'FF99CC');
-			case 0x2E: return array('rgb' => 'CC99FF');
-			case 0x2F: return array('rgb' => 'FFCC99');
-			case 0x30: return array('rgb' => '3366FF');
-			case 0x31: return array('rgb' => '33CCCC');
-			case 0x32: return array('rgb' => '99CC00');
-			case 0x33: return array('rgb' => 'FFCC00');
-			case 0x34: return array('rgb' => 'FF9900');
-			case 0x35: return array('rgb' => 'FF6600');
-			case 0x36: return array('rgb' => '666699');
-			case 0x37: return array('rgb' => '969696');
-			case 0x38: return array('rgb' => '003366');
-			case 0x39: return array('rgb' => '339966');
-			case 0x3A: return array('rgb' => '003300');
-			case 0x3B: return array('rgb' => '333300');
-			case 0x3C: return array('rgb' => '993300');
-			case 0x3D: return array('rgb' => '993366');
-			case 0x3E: return array('rgb' => '333399');
-			case 0x3F: return array('rgb' => '333333');
-			default:   return array('rgb' => '000000');
-		}
-	}
-
-	private function _parseRichText($is = '') {
-		$value = new PHPExcel_RichText();
-
-		$value->createText($is);
-
-		return $value;
-	}
-
-}
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Reader_Excel5
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+// Original file header of ParseXL (used as the base for this class):
+// --------------------------------------------------------------------------------
+// Adapted from Excel_Spreadsheet_Reader developed by users bizon153,
+// trex005, and mmp11 (SourceForge.net)
+// http://sourceforge.net/projects/phpexcelreader/
+// Primary changes made by canyoncasa (dvc) for ParseXL 1.00 ...
+//	 Modelled moreso after Perl Excel Parse/Write modules
+//	 Added Parse_Excel_Spreadsheet object
+//		 Reads a whole worksheet or tab as row,column array or as
+//		 associated hash of indexed rows and named column fields
+//	 Added variables for worksheet (tab) indexes and names
+//	 Added an object call for loading individual woorksheets
+//	 Changed default indexing defaults to 0 based arrays
+//	 Fixed date/time and percent formats
+//	 Includes patches found at SourceForge...
+//		 unicode patch by nobody
+//		 unpack("d") machine depedency patch by matchy
+//		 boundsheet utf16 patch by bjaenichen
+//	 Renamed functions for shorter names
+//	 General code cleanup and rigor, including <80 column width
+//	 Included a testcase Excel file and PHP example calls
+//	 Code works for PHP 5.x
+
+// Primary changes made by canyoncasa (dvc) for ParseXL 1.10 ...
+// http://sourceforge.net/tracker/index.php?func=detail&aid=1466964&group_id=99160&atid=623334
+//	 Decoding of formula conditions, results, and tokens.
+//	 Support for user-defined named cells added as an array "namedcells"
+//		 Patch code for user-defined named cells supports single cells only.
+//		 NOTE: this patch only works for BIFF8 as BIFF5-7 use a different
+//		 external sheet reference structure
+
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+	/**
+	 * @ignore
+	 */
+	define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+	require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_Excel5
+ *
+ * This class uses {@link http://sourceforge.net/projects/phpexcelreader/parseXL}
+ *
+ * @category	PHPExcel
+ * @package		PHPExcel_Reader_Excel5
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Reader_Excel5 implements PHPExcel_Reader_IReader
+{
+	// ParseXL definitions
+	const XLS_BIFF8						= 0x0600;
+	const XLS_BIFF7						= 0x0500;
+	const XLS_WorkbookGlobals			= 0x0005;
+	const XLS_Worksheet					= 0x0010;
+
+	// record identifiers
+	const XLS_Type_FORMULA				= 0x0006;
+	const XLS_Type_EOF					= 0x000a;
+	const XLS_Type_PROTECT				= 0x0012;
+	const XLS_Type_OBJECTPROTECT		= 0x0063;
+	const XLS_Type_SCENPROTECT			= 0x00dd;
+	const XLS_Type_PASSWORD				= 0x0013;
+	const XLS_Type_HEADER				= 0x0014;
+	const XLS_Type_FOOTER				= 0x0015;
+	const XLS_Type_EXTERNSHEET			= 0x0017;
+	const XLS_Type_DEFINEDNAME			= 0x0018;
+	const XLS_Type_VERTICALPAGEBREAKS	= 0x001a;
+	const XLS_Type_HORIZONTALPAGEBREAKS	= 0x001b;
+	const XLS_Type_NOTE					= 0x001c;
+	const XLS_Type_SELECTION			= 0x001d;
+	const XLS_Type_DATEMODE				= 0x0022;
+	const XLS_Type_EXTERNNAME			= 0x0023;
+	const XLS_Type_LEFTMARGIN			= 0x0026;
+	const XLS_Type_RIGHTMARGIN			= 0x0027;
+	const XLS_Type_TOPMARGIN			= 0x0028;
+	const XLS_Type_BOTTOMMARGIN			= 0x0029;
+	const XLS_Type_PRINTGRIDLINES		= 0x002b;
+	const XLS_Type_FILEPASS				= 0x002f;
+	const XLS_Type_FONT					= 0x0031;
+	const XLS_Type_CONTINUE				= 0x003c;
+	const XLS_Type_PANE					= 0x0041;
+	const XLS_Type_CODEPAGE				= 0x0042;
+	const XLS_Type_DEFCOLWIDTH 			= 0x0055;
+	const XLS_Type_OBJ					= 0x005d;
+	const XLS_Type_COLINFO				= 0x007d;
+	const XLS_Type_IMDATA				= 0x007f;
+	const XLS_Type_SHEETPR				= 0x0081;
+	const XLS_Type_HCENTER				= 0x0083;
+	const XLS_Type_VCENTER				= 0x0084;
+	const XLS_Type_SHEET				= 0x0085;
+	const XLS_Type_PALETTE				= 0x0092;
+	const XLS_Type_SCL					= 0x00a0;
+	const XLS_Type_PAGESETUP			= 0x00a1;
+	const XLS_Type_MULRK				= 0x00bd;
+	const XLS_Type_MULBLANK				= 0x00be;
+	const XLS_Type_DBCELL				= 0x00d7;
+	const XLS_Type_XF					= 0x00e0;
+	const XLS_Type_MERGEDCELLS			= 0x00e5;
+	const XLS_Type_MSODRAWINGGROUP		= 0x00eb;
+	const XLS_Type_MSODRAWING			= 0x00ec;
+	const XLS_Type_SST					= 0x00fc;
+	const XLS_Type_LABELSST				= 0x00fd;
+	const XLS_Type_EXTSST				= 0x00ff;
+	const XLS_Type_EXTERNALBOOK			= 0x01ae;
+	const XLS_Type_DATAVALIDATIONS		= 0x01b2;
+	const XLS_Type_TXO					= 0x01b6;
+	const XLS_Type_HYPERLINK			= 0x01b8;
+	const XLS_Type_DATAVALIDATION		= 0x01be;
+	const XLS_Type_DIMENSION			= 0x0200;
+	const XLS_Type_BLANK				= 0x0201;
+	const XLS_Type_NUMBER				= 0x0203;
+	const XLS_Type_LABEL				= 0x0204;
+	const XLS_Type_BOOLERR				= 0x0205;
+	const XLS_Type_STRING				= 0x0207;
+	const XLS_Type_ROW					= 0x0208;
+	const XLS_Type_INDEX				= 0x020b;
+	const XLS_Type_ARRAY				= 0x0221;
+	const XLS_Type_DEFAULTROWHEIGHT 	= 0x0225;
+	const XLS_Type_WINDOW2				= 0x023e;
+	const XLS_Type_RK					= 0x027e;
+	const XLS_Type_STYLE				= 0x0293;
+	const XLS_Type_FORMAT				= 0x041e;
+	const XLS_Type_SHAREDFMLA			= 0x04bc;
+	const XLS_Type_BOF					= 0x0809;
+	const XLS_Type_SHEETPROTECTION		= 0x0867;
+	const XLS_Type_RANGEPROTECTION		= 0x0868;
+	const XLS_Type_SHEETLAYOUT			= 0x0862;
+	const XLS_Type_XFEXT				= 0x087d;
+	const XLS_Type_UNKNOWN				= 0xffff;
+
+
+	/**
+	 * Read data only?
+	 * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
+	 *		or whether it should read both data and formatting
+	 *
+	 * @var	boolean
+	 */
+	private $_readDataOnly = false;
+
+	/**
+	 * Restrict which sheets should be loaded?
+	 * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
+	 *
+	 * @var	array of string
+	 */
+	private $_loadSheetsOnly = null;
+
+	/**
+	 * PHPExcel_Reader_IReadFilter instance
+	 *
+	 * @var PHPExcel_Reader_IReadFilter
+	 */
+	private $_readFilter = null;
+
+	/**
+	 * Summary Information stream data.
+	 *
+	 * @var string
+	 */
+	private $_summaryInformation;
+
+	/**
+	 * Extended Summary Information stream data.
+	 *
+	 * @var string
+	 */
+	private $_documentSummaryInformation;
+
+	/**
+	 * User-Defined Properties stream data.
+	 *
+	 * @var string
+	 */
+	private $_userDefinedProperties;
+
+	/**
+	 * Workbook stream data. (Includes workbook globals substream as well as sheet substreams)
+	 *
+	 * @var string
+	 */
+	private $_data;
+
+	/**
+	 * Size in bytes of $this->_data
+	 *
+	 * @var int
+	 */
+	private $_dataSize;
+
+	/**
+	 * Current position in stream
+	 *
+	 * @var integer
+	 */
+	private $_pos;
+
+	/**
+	 * Workbook to be returned by the reader.
+	 *
+	 * @var PHPExcel
+	 */
+	private $_phpExcel;
+
+	/**
+	 * Worksheet that is currently being built by the reader.
+	 *
+	 * @var PHPExcel_Worksheet
+	 */
+	private $_phpSheet;
+
+	/**
+	 * BIFF version
+	 *
+	 * @var int
+	 */
+	private $_version;
+
+	/**
+	 * Codepage set in the Excel file being read. Only important for BIFF5 (Excel 5.0 - Excel 95)
+	 * For BIFF8 (Excel 97 - Excel 2003) this will always have the value 'UTF-16LE'
+	 *
+	 * @var string
+	 */
+	private $_codepage;
+
+	/**
+	 * Shared formats
+	 *
+	 * @var array
+	 */
+	private $_formats;
+
+	/**
+	 * Shared fonts
+	 *
+	 * @var array
+	 */
+	private $_objFonts;
+
+	/**
+	 * Color palette
+	 *
+	 * @var array
+	 */
+	private $_palette;
+
+	/**
+	 * Worksheets
+	 *
+	 * @var array
+	 */
+	private $_sheets;
+
+	/**
+	 * External books
+	 *
+	 * @var array
+	 */
+	private $_externalBooks;
+
+	/**
+	 * REF structures. Only applies to BIFF8.
+	 *
+	 * @var array
+	 */
+	private $_ref;
+
+	/**
+	 * External names
+	 *
+	 * @var array
+	 */
+	private $_externalNames;
+
+	/**
+	 * Defined names
+	 *
+	 * @var array
+	 */
+	private $_definedname;
+
+	/**
+	 * Shared strings. Only applies to BIFF8.
+	 *
+	 * @var array
+	 */
+	private $_sst;
+
+	/**
+	 * Panes are frozen? (in sheet currently being read). See WINDOW2 record.
+	 *
+	 * @var boolean
+	 */
+	private $_frozen;
+
+	/**
+	 * Fit printout to number of pages? (in sheet currently being read). See SHEETPR record.
+	 *
+	 * @var boolean
+	 */
+	private $_isFitToPages;
+
+	/**
+	 * Objects. One OBJ record contributes with one entry.
+	 *
+	 * @var array
+	 */
+	private $_objs;
+
+	/**
+	 * Text Objects. One TXO record corresponds with one entry.
+	 *
+	 * @var array
+	 */
+	private $_textObjects;
+
+	/**
+	 * Cell Annotations (BIFF8)
+	 *
+	 * @var array
+	 */
+	private $_cellNotes;
+
+	/**
+	 * The combined MSODRAWINGGROUP data
+	 *
+	 * @var string
+	 */
+	private $_drawingGroupData;
+
+	/**
+	 * The combined MSODRAWING data (per sheet)
+	 *
+	 * @var string
+	 */
+	private $_drawingData;
+
+	/**
+	 * Keep track of XF index
+	 *
+	 * @var int
+	 */
+	private $_xfIndex;
+
+	/**
+	 * Mapping of XF index (that is a cell XF) to final index in cellXf collection
+	 *
+	 * @var array
+	 */
+	private $_mapCellXfIndex;
+
+	/**
+	 * Mapping of XF index (that is a style XF) to final index in cellStyleXf collection
+	 *
+	 * @var array
+	 */
+	private $_mapCellStyleXfIndex;
+
+	/**
+	 * The shared formulas in a sheet. One SHAREDFMLA record contributes with one value.
+	 *
+	 * @var array
+	 */
+	private $_sharedFormulas;
+
+	/**
+	 * The shared formula parts in a sheet. One FORMULA record contributes with one value if it
+	 * refers to a shared formula.
+	 *
+	 * @var array
+	 */
+	private $_sharedFormulaParts;
+
+
+	/**
+	 * Create a new PHPExcel_Reader_Excel5 instance
+	 */
+	public function __construct() {
+		$this->_readFilter = new PHPExcel_Reader_DefaultReadFilter();
+	}
+
+
+	/**
+	 * Read data only?
+	 *		If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
+	 *		If false (the default) it will read data and formatting.
+	 *
+	 * @return	boolean
+	 */
+	public function getReadDataOnly()
+	{
+		return $this->_readDataOnly;
+	}
+
+
+	/**
+	 * Set read data only
+	 *		Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
+	 *		Set to false (the default) to advise the Reader to read both data and formatting for cells.
+	 *
+	 * @param	boolean	$pValue
+	 *
+	 * @return	PHPExcel_Reader_Excel5
+	 */
+	public function setReadDataOnly($pValue = false)
+	{
+		$this->_readDataOnly = $pValue;
+		return $this;
+	}
+
+
+	/**
+	 * Get which sheets to load
+	 *		Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
+	 *			indicating that all worksheets in the workbook should be loaded.
+	 *
+	 * @return mixed
+	 */
+	public function getLoadSheetsOnly()
+	{
+		return $this->_loadSheetsOnly;
+	}
+
+
+	/**
+	 * Set which sheets to load
+	 *
+	 * @param mixed $value
+	 *		This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
+	 *		If NULL, then it tells the Reader to read all worksheets in the workbook
+	 *
+	 * @return PHPExcel_Reader_Excel5
+	 */
+	public function setLoadSheetsOnly($value = null)
+	{
+		$this->_loadSheetsOnly = is_array($value) ?
+			$value : array($value);
+		return $this;
+	}
+
+
+	/**
+	 * Set all sheets to load
+	 *		Tells the Reader to load all worksheets from the workbook.
+	 *
+	 * @return	PHPExcel_Reader_Excel5
+	 */
+	public function setLoadAllSheets()
+	{
+		$this->_loadSheetsOnly = null;
+		return $this;
+	}
+
+
+	/**
+	 * Read filter
+	 *
+	 * @return PHPExcel_Reader_IReadFilter
+	 */
+	public function getReadFilter() {
+		return $this->_readFilter;
+	}
+
+
+	/**
+	 * Set read filter
+	 *
+	 * @param PHPExcel_Reader_IReadFilter $pValue
+	 * @return PHPExcel_Reader_Excel5
+	 */
+	public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
+		$this->_readFilter = $pValue;
+		return $this;
+	}
+
+
+	/**
+	 * Can the current PHPExcel_Reader_IReader read the file?
+	 *
+	 * @param 	string 		$pFileName
+	 * @return 	boolean
+	 * @throws Exception
+	 */
+	public function canRead($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		try {
+			// Use ParseXL for the hard work.
+			$ole = new PHPExcel_Shared_OLERead();
+
+			// get excel data
+			$res = $ole->read($pFilename);
+			return true;
+
+		} catch (Exception $e) {
+			return false;
+		}
+	}
+
+
+	/**
+	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
+	 *
+	 * @param 	string 		$pFilename
+	 * @throws 	Exception
+	 */
+	public function listWorksheetNames($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		$worksheetNames = array();
+
+		// Read the OLE file
+		$this->_loadOLE($pFilename);
+
+		// total byte size of Excel data (workbook global substream + sheet substreams)
+		$this->_dataSize = strlen($this->_data);
+
+		$this->_pos		= 0;
+		$this->_sheets	= array();
+
+		// Parse Workbook Global Substream
+		while ($this->_pos < $this->_dataSize) {
+			$code = self::_GetInt2d($this->_data, $this->_pos);
+
+			switch ($code) {
+				case self::XLS_Type_BOF:	$this->_readBof();		break;
+				case self::XLS_Type_SHEET:	$this->_readSheet();	break;
+				case self::XLS_Type_EOF:	$this->_readDefault();	break 2;
+				default:					$this->_readDefault();	break;
+			}
+		}
+
+		foreach ($this->_sheets as $sheet) {
+			if ($sheet['sheetType'] != 0x00) {
+				// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
+				continue;
+			}
+
+			$worksheetNames[] = $sheet['name'];
+		}
+
+		return $worksheetNames;
+	}
+
+
+	/**
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+	 *
+	 * @param   string     $pFilename
+	 * @throws   Exception
+	 */
+	public function listWorksheetInfo($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		$worksheetInfo = array();
+
+		// Read the OLE file
+		$this->_loadOLE($pFilename);
+
+		// total byte size of Excel data (workbook global substream + sheet substreams)
+		$this->_dataSize = strlen($this->_data);
+
+		// initialize
+		$this->_pos    = 0;
+		$this->_sheets = array();
+
+		// Parse Workbook Global Substream
+		while ($this->_pos < $this->_dataSize) {
+			$code = self::_GetInt2d($this->_data, $this->_pos);
+
+			switch ($code) {
+				case self::XLS_Type_BOF:        $this->_readBof();        break;
+				case self::XLS_Type_SHEET:      $this->_readSheet();      break;
+				case self::XLS_Type_EOF:        $this->_readDefault();    break 2;
+				default:                        $this->_readDefault();    break;
+			}
+		}
+
+		// Parse the individual sheets
+		foreach ($this->_sheets as $sheet) {
+
+			if ($sheet['sheetType'] != 0x00) {
+				// 0x00: Worksheet
+				// 0x02: Chart
+				// 0x06: Visual Basic module
+				continue;
+			}
+
+			$tmpInfo = array();
+			$tmpInfo['worksheetName'] = $sheet['name'];
+			$tmpInfo['lastColumnLetter'] = 'A';
+			$tmpInfo['lastColumnIndex'] = 0;
+			$tmpInfo['totalRows'] = 0;
+			$tmpInfo['totalColumns'] = 0;
+
+			$this->_pos = $sheet['offset'];
+
+			while ($this->_pos <= $this->_dataSize - 4) {
+				$code = self::_GetInt2d($this->_data, $this->_pos);
+
+				switch ($code) {
+					case self::XLS_Type_RK:
+					case self::XLS_Type_LABELSST:
+					case self::XLS_Type_NUMBER:
+					case self::XLS_Type_FORMULA:
+					case self::XLS_Type_BOOLERR:
+					case self::XLS_Type_LABEL:
+						$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+						$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+						// move stream pointer to next record
+						$this->_pos += 4 + $length;
+
+						$rowIndex = self::_GetInt2d($recordData, 0) + 1;
+						$columnIndex = self::_GetInt2d($recordData, 2);
+
+						$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+						$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+						break;
+					case self::XLS_Type_BOF:      $this->_readBof();          break;
+					case self::XLS_Type_EOF:      $this->_readDefault();      break 2;
+					default:                      $this->_readDefault();      break;
+				}
+			}
+
+			$tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+			$tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+			$worksheetInfo[] = $tmpInfo;
+		}
+
+		return $worksheetInfo;
+	}
+
+
+	/**
+	 * Loads PHPExcel from file
+	 *
+	 * @param 	string 		$pFilename
+	 * @return 	PHPExcel
+	 * @throws 	Exception
+	 */
+	public function load($pFilename)
+	{
+		// Read the OLE file
+		$this->_loadOLE($pFilename);
+
+		// Initialisations
+		$this->_phpExcel = new PHPExcel;
+		$this->_phpExcel->removeSheetByIndex(0); // remove 1st sheet
+		if (!$this->_readDataOnly) {
+			$this->_phpExcel->removeCellStyleXfByIndex(0); // remove the default style
+			$this->_phpExcel->removeCellXfByIndex(0); // remove the default style
+		}
+
+		// Read the summary information stream (containing meta data)
+		$this->_readSummaryInformation();
+
+		// Read the Additional document summary information stream (containing application-specific meta data)
+		$this->_readDocumentSummaryInformation();
+
+		// total byte size of Excel data (workbook global substream + sheet substreams)
+		$this->_dataSize = strlen($this->_data);
+
+		// initialize
+		$this->_pos					= 0;
+		$this->_codepage			= 'CP1252';
+		$this->_formats				= array();
+		$this->_objFonts			= array();
+		$this->_palette				= array();
+		$this->_sheets				= array();
+		$this->_externalBooks		= array();
+		$this->_ref					= array();
+		$this->_definedname			= array();
+		$this->_sst					= array();
+		$this->_drawingGroupData	= '';
+		$this->_xfIndex				= '';
+		$this->_mapCellXfIndex		= array();
+		$this->_mapCellStyleXfIndex	= array();
+
+		// Parse Workbook Global Substream
+		while ($this->_pos < $this->_dataSize) {
+			$code = self::_GetInt2d($this->_data, $this->_pos);
+
+			switch ($code) {
+				case self::XLS_Type_BOF:			$this->_readBof();				break;
+				case self::XLS_Type_FILEPASS:		$this->_readFilepass();			break;
+				case self::XLS_Type_CODEPAGE:		$this->_readCodepage();			break;
+				case self::XLS_Type_DATEMODE:		$this->_readDateMode();			break;
+				case self::XLS_Type_FONT:			$this->_readFont();				break;
+				case self::XLS_Type_FORMAT:			$this->_readFormat();			break;
+				case self::XLS_Type_XF:				$this->_readXf();				break;
+				case self::XLS_Type_XFEXT:			$this->_readXfExt();			break;
+				case self::XLS_Type_STYLE:			$this->_readStyle();			break;
+				case self::XLS_Type_PALETTE:		$this->_readPalette();			break;
+				case self::XLS_Type_SHEET:			$this->_readSheet();			break;
+				case self::XLS_Type_EXTERNALBOOK:	$this->_readExternalBook();		break;
+				case self::XLS_Type_EXTERNNAME:		$this->_readExternName();		break;
+				case self::XLS_Type_EXTERNSHEET:	$this->_readExternSheet();		break;
+				case self::XLS_Type_DEFINEDNAME:	$this->_readDefinedName();		break;
+				case self::XLS_Type_MSODRAWINGGROUP:	$this->_readMsoDrawingGroup();	break;
+				case self::XLS_Type_SST:			$this->_readSst();				break;
+				case self::XLS_Type_EOF:			$this->_readDefault();			break 2;
+				default:							$this->_readDefault();			break;
+			}
+		}
+
+		// Resolve indexed colors for font, fill, and border colors
+		// Cannot be resolved already in XF record, because PALETTE record comes afterwards
+		if (!$this->_readDataOnly) {
+			foreach ($this->_objFonts as $objFont) {
+				if (isset($objFont->colorIndex)) {
+					$color = self::_readColor($objFont->colorIndex,$this->_palette,$this->_version);
+					$objFont->getColor()->setRGB($color['rgb']);
+				}
+			}
+
+			foreach ($this->_phpExcel->getCellXfCollection() as $objStyle) {
+				// fill start and end color
+				$fill = $objStyle->getFill();
+
+				if (isset($fill->startcolorIndex)) {
+					$startColor = self::_readColor($fill->startcolorIndex,$this->_palette,$this->_version);
+					$fill->getStartColor()->setRGB($startColor['rgb']);
+				}
+
+				if (isset($fill->endcolorIndex)) {
+					$endColor = self::_readColor($fill->endcolorIndex,$this->_palette,$this->_version);
+					$fill->getEndColor()->setRGB($endColor['rgb']);
+				}
+
+				// border colors
+				$top      = $objStyle->getBorders()->getTop();
+				$right    = $objStyle->getBorders()->getRight();
+				$bottom   = $objStyle->getBorders()->getBottom();
+				$left     = $objStyle->getBorders()->getLeft();
+				$diagonal = $objStyle->getBorders()->getDiagonal();
+
+				if (isset($top->colorIndex)) {
+					$borderTopColor = self::_readColor($top->colorIndex,$this->_palette,$this->_version);
+					$top->getColor()->setRGB($borderTopColor['rgb']);
+				}
+
+				if (isset($right->colorIndex)) {
+					$borderRightColor = self::_readColor($right->colorIndex,$this->_palette,$this->_version);
+					$right->getColor()->setRGB($borderRightColor['rgb']);
+				}
+
+				if (isset($bottom->colorIndex)) {
+					$borderBottomColor = self::_readColor($bottom->colorIndex,$this->_palette,$this->_version);
+					$bottom->getColor()->setRGB($borderBottomColor['rgb']);
+				}
+
+				if (isset($left->colorIndex)) {
+					$borderLeftColor = self::_readColor($left->colorIndex,$this->_palette,$this->_version);
+					$left->getColor()->setRGB($borderLeftColor['rgb']);
+				}
+
+				if (isset($diagonal->colorIndex)) {
+					$borderDiagonalColor = self::_readColor($diagonal->colorIndex,$this->_palette,$this->_version);
+					$diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
+				}
+			}
+		}
+
+		// treat MSODRAWINGGROUP records, workbook-level Escher
+		if (!$this->_readDataOnly && $this->_drawingGroupData) {
+			$escherWorkbook = new PHPExcel_Shared_Escher();
+			$reader = new PHPExcel_Reader_Excel5_Escher($escherWorkbook);
+			$escherWorkbook = $reader->load($this->_drawingGroupData);
+
+			// debug Escher stream
+			//$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
+			//$debug->load($this->_drawingGroupData);
+		}
+
+		// Parse the individual sheets
+		foreach ($this->_sheets as $sheet) {
+
+			if ($sheet['sheetType'] != 0x00) {
+				// 0x00: Worksheet, 0x02: Chart, 0x06: Visual Basic module
+				continue;
+			}
+
+			// check if sheet should be skipped
+			if (isset($this->_loadSheetsOnly) && !in_array($sheet['name'], $this->_loadSheetsOnly)) {
+				continue;
+			}
+
+			// add sheet to PHPExcel object
+			$this->_phpSheet = $this->_phpExcel->createSheet();
+			//	Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
+			//		cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
+			//		name in line with the formula, not the reverse
+			$this->_phpSheet->setTitle($sheet['name'],false);
+			$this->_phpSheet->setSheetState($sheet['sheetState']);
+
+			$this->_pos = $sheet['offset'];
+
+			// Initialize isFitToPages. May change after reading SHEETPR record.
+			$this->_isFitToPages = false;
+
+			// Initialize drawingData
+			$this->_drawingData = '';
+
+			// Initialize objs
+			$this->_objs = array();
+
+			// Initialize shared formula parts
+			$this->_sharedFormulaParts = array();
+
+			// Initialize shared formulas
+			$this->_sharedFormulas = array();
+
+			// Initialize text objs
+			$this->_textObjects = array();
+
+			// Initialize cell annotations
+			$this->_cellNotes = array();
+			$this->textObjRef = -1;
+
+			while ($this->_pos <= $this->_dataSize - 4) {
+				$code = self::_GetInt2d($this->_data, $this->_pos);
+
+				switch ($code) {
+					case self::XLS_Type_BOF:					$this->_readBof();						break;
+					case self::XLS_Type_PRINTGRIDLINES:			$this->_readPrintGridlines();			break;
+					case self::XLS_Type_DEFAULTROWHEIGHT:		$this->_readDefaultRowHeight();			break;
+					case self::XLS_Type_SHEETPR:				$this->_readSheetPr();					break;
+					case self::XLS_Type_HORIZONTALPAGEBREAKS:	$this->_readHorizontalPageBreaks();		break;
+					case self::XLS_Type_VERTICALPAGEBREAKS:		$this->_readVerticalPageBreaks();		break;
+					case self::XLS_Type_HEADER:					$this->_readHeader();					break;
+					case self::XLS_Type_FOOTER:					$this->_readFooter();					break;
+					case self::XLS_Type_HCENTER:				$this->_readHcenter();					break;
+					case self::XLS_Type_VCENTER:				$this->_readVcenter();					break;
+					case self::XLS_Type_LEFTMARGIN:				$this->_readLeftMargin();				break;
+					case self::XLS_Type_RIGHTMARGIN:			$this->_readRightMargin();				break;
+					case self::XLS_Type_TOPMARGIN:				$this->_readTopMargin();				break;
+					case self::XLS_Type_BOTTOMMARGIN:			$this->_readBottomMargin();				break;
+					case self::XLS_Type_PAGESETUP:				$this->_readPageSetup();				break;
+					case self::XLS_Type_PROTECT:				$this->_readProtect();					break;
+					case self::XLS_Type_SCENPROTECT:			$this->_readScenProtect();				break;
+					case self::XLS_Type_OBJECTPROTECT:			$this->_readObjectProtect();			break;
+					case self::XLS_Type_PASSWORD:				$this->_readPassword();					break;
+					case self::XLS_Type_DEFCOLWIDTH:			$this->_readDefColWidth();				break;
+					case self::XLS_Type_COLINFO:				$this->_readColInfo();					break;
+					case self::XLS_Type_DIMENSION:				$this->_readDefault();					break;
+					case self::XLS_Type_ROW:					$this->_readRow();						break;
+					case self::XLS_Type_DBCELL:					$this->_readDefault();					break;
+					case self::XLS_Type_RK:						$this->_readRk();						break;
+					case self::XLS_Type_LABELSST:				$this->_readLabelSst();					break;
+					case self::XLS_Type_MULRK:					$this->_readMulRk();					break;
+					case self::XLS_Type_NUMBER:					$this->_readNumber();					break;
+					case self::XLS_Type_FORMULA:				$this->_readFormula();					break;
+					case self::XLS_Type_SHAREDFMLA:				$this->_readSharedFmla();				break;
+					case self::XLS_Type_BOOLERR:				$this->_readBoolErr();					break;
+					case self::XLS_Type_MULBLANK:				$this->_readMulBlank();					break;
+					case self::XLS_Type_LABEL:					$this->_readLabel();					break;
+					case self::XLS_Type_BLANK:					$this->_readBlank();					break;
+					case self::XLS_Type_MSODRAWING:				$this->_readMsoDrawing();				break;
+					case self::XLS_Type_OBJ:					$this->_readObj();						break;
+					case self::XLS_Type_WINDOW2:				$this->_readWindow2();					break;
+					case self::XLS_Type_SCL:					$this->_readScl();						break;
+					case self::XLS_Type_PANE:					$this->_readPane();						break;
+					case self::XLS_Type_SELECTION:				$this->_readSelection();				break;
+					case self::XLS_Type_MERGEDCELLS:			$this->_readMergedCells();				break;
+					case self::XLS_Type_HYPERLINK:				$this->_readHyperLink();				break;
+					case self::XLS_Type_DATAVALIDATIONS:		$this->_readDataValidations();			break;
+					case self::XLS_Type_DATAVALIDATION:			$this->_readDataValidation();			break;
+					case self::XLS_Type_SHEETLAYOUT:			$this->_readSheetLayout();				break;
+					case self::XLS_Type_SHEETPROTECTION:		$this->_readSheetProtection();			break;
+					case self::XLS_Type_RANGEPROTECTION:		$this->_readRangeProtection();			break;
+					case self::XLS_Type_NOTE:					$this->_readNote();						break;
+					//case self::XLS_Type_IMDATA:				$this->_readImData();					break;
+					case self::XLS_Type_TXO:					$this->_readTextObject();				break;
+					case self::XLS_Type_CONTINUE:				$this->_readContinue();					break;
+					case self::XLS_Type_EOF:					$this->_readDefault();					break 2;
+					default:									$this->_readDefault();					break;
+				}
+
+			}
+
+			// treat MSODRAWING records, sheet-level Escher
+			if (!$this->_readDataOnly && $this->_drawingData) {
+				$escherWorksheet = new PHPExcel_Shared_Escher();
+				$reader = new PHPExcel_Reader_Excel5_Escher($escherWorksheet);
+				$escherWorksheet = $reader->load($this->_drawingData);
+
+				// debug Escher stream
+				//$debug = new Debug_Escher(new PHPExcel_Shared_Escher());
+				//$debug->load($this->_drawingData);
+
+				// get all spContainers in one long array, so they can be mapped to OBJ records
+				$allSpContainers = $escherWorksheet->getDgContainer()->getSpgrContainer()->getAllSpContainers();
+			}
+
+			// treat OBJ records
+			foreach ($this->_objs as $n => $obj) {
+//				echo '<hr /><b>Object</b> reference is ',$n,'<br />';
+//				var_dump($obj);
+//				echo '<br />';
+
+				// the first shape container never has a corresponding OBJ record, hence $n + 1
+				if (isset($allSpContainers[$n + 1]) && is_object($allSpContainers[$n + 1])) {
+					$spContainer = $allSpContainers[$n + 1];
+
+					// we skip all spContainers that are a part of a group shape since we cannot yet handle those
+					if ($spContainer->getNestingLevel() > 1) {
+						continue;
+					}
+
+					// calculate the width and height of the shape
+					list($startColumn, $startRow) = PHPExcel_Cell::coordinateFromString($spContainer->getStartCoordinates());
+					list($endColumn, $endRow) = PHPExcel_Cell::coordinateFromString($spContainer->getEndCoordinates());
+
+					$startOffsetX = $spContainer->getStartOffsetX();
+					$startOffsetY = $spContainer->getStartOffsetY();
+					$endOffsetX = $spContainer->getEndOffsetX();
+					$endOffsetY = $spContainer->getEndOffsetY();
+
+					$width = PHPExcel_Shared_Excel5::getDistanceX($this->_phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
+					$height = PHPExcel_Shared_Excel5::getDistanceY($this->_phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);
+
+					// calculate offsetX and offsetY of the shape
+					$offsetX = $startOffsetX * PHPExcel_Shared_Excel5::sizeCol($this->_phpSheet, $startColumn) / 1024;
+					$offsetY = $startOffsetY * PHPExcel_Shared_Excel5::sizeRow($this->_phpSheet, $startRow) / 256;
+
+					switch ($obj['otObjType']) {
+						case 0x19:
+							// Note
+//							echo 'Cell Annotation Object<br />';
+//							echo 'Object ID is ',$obj['idObjID'],'<br />';
+//
+							if (isset($this->_cellNotes[$obj['idObjID']])) {
+								$cellNote = $this->_cellNotes[$obj['idObjID']];
+
+								if (isset($this->_textObjects[$obj['idObjID']])) {
+									$textObject = $this->_textObjects[$obj['idObjID']];
+									$this->_cellNotes[$obj['idObjID']]['objTextData'] = $textObject;
+								}
+							}
+							break;
+
+						case 0x08:
+//							echo 'Picture Object<br />';
+							// picture
+
+							// get index to BSE entry (1-based)
+							$BSEindex = $spContainer->getOPT(0x0104);
+							$BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection();
+							$BSE = $BSECollection[$BSEindex - 1];
+							$blipType = $BSE->getBlipType();
+
+							// need check because some blip types are not supported by Escher reader such as EMF
+							if ($blip = $BSE->getBlip()) {
+								$ih = imagecreatefromstring($blip->getData());
+								$drawing = new PHPExcel_Worksheet_MemoryDrawing();
+								$drawing->setImageResource($ih);
+
+								// width, height, offsetX, offsetY
+								$drawing->setResizeProportional(false);
+								$drawing->setWidth($width);
+								$drawing->setHeight($height);
+								$drawing->setOffsetX($offsetX);
+								$drawing->setOffsetY($offsetY);
+
+								switch ($blipType) {
+									case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
+										$drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_JPEG);
+										$drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_JPEG);
+										break;
+
+									case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
+										$drawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);
+										$drawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_PNG);
+										break;
+								}
+
+								$drawing->setWorksheet($this->_phpSheet);
+								$drawing->setCoordinates($spContainer->getStartCoordinates());
+							}
+
+							break;
+
+						default:
+							// other object type
+							break;
+
+					}
+				}
+			}
+
+			// treat SHAREDFMLA records
+			if ($this->_version == self::XLS_BIFF8) {
+				foreach ($this->_sharedFormulaParts as $cell => $baseCell) {
+					list($column, $row) = PHPExcel_Cell::coordinateFromString($cell);
+					if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle()) ) {
+						$formula = $this->_getFormulaFromStructure($this->_sharedFormulas[$baseCell], $cell);
+						$this->_phpSheet->getCell($cell)->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
+					}
+				}
+			}
+
+			if (!empty($this->_cellNotes)) {
+				foreach($this->_cellNotes as $note => $noteDetails) {
+					if (!isset($noteDetails['objTextData'])) {
+						if (isset($this->_textObjects[$note])) {
+							$textObject = $this->_textObjects[$note];
+							$noteDetails['objTextData'] = $textObject;
+						} else {
+							$noteDetails['objTextData']['text'] = '';
+						}
+					}
+//					echo '<b>Cell annotation ',$note,'</b><br />';
+//					var_dump($noteDetails);
+//					echo '<br />';
+					$cellAddress = str_replace('$','',$noteDetails['cellRef']);
+					$this->_phpSheet->getComment( $cellAddress )
+													->setAuthor( $noteDetails['author'] )
+													->setText($this->_parseRichText($noteDetails['objTextData']['text']) );
+				}
+			}
+		}
+
+		// add the named ranges (defined names)
+		foreach ($this->_definedname as $definedName) {
+			if ($definedName['isBuiltInName']) {
+				switch ($definedName['name']) {
+
+				case pack('C', 0x06):
+					// print area
+					//	in general, formula looks like this: Foo!$C$7:$J$66,Bar!$A$1:$IV$2
+
+					$ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
+
+					$extractedRanges = array();
+					foreach ($ranges as $range) {
+						// $range should look like one of these
+						//		Foo!$C$7:$J$66
+						//		Bar!$A$1:$IV$2
+
+						$explodes = explode('!', $range);	// FIXME: what if sheetname contains exclamation mark?
+						$sheetName = $explodes[0];
+
+						if (count($explodes) == 2) {
+							$extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
+						}
+					}
+					if ($docSheet = $this->_phpExcel->getSheetByName($sheetName)) {
+						$docSheet->getPageSetup()->setPrintArea(implode(',', $extractedRanges)); // C7:J66,A1:IV2
+					}
+					break;
+
+				case pack('C', 0x07):
+					// print titles (repeating rows)
+					// Assuming BIFF8, there are 3 cases
+					// 1. repeating rows
+					//		formula looks like this: Sheet!$A$1:$IV$2
+					//		rows 1-2 repeat
+					// 2. repeating columns
+					//		formula looks like this: Sheet!$A$1:$B$65536
+					//		columns A-B repeat
+					// 3. both repeating rows and repeating columns
+					//		formula looks like this: Sheet!$A$1:$B$65536,Sheet!$A$1:$IV$2
+
+					$ranges = explode(',', $definedName['formula']); // FIXME: what if sheetname contains comma?
+
+					foreach ($ranges as $range) {
+						// $range should look like this one of these
+						//		Sheet!$A$1:$B$65536
+						//		Sheet!$A$1:$IV$2
+
+						$explodes = explode('!', $range);
+
+						if (count($explodes) == 2) {
+							if ($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) {
+
+								$extractedRange = $explodes[1];
+								$extractedRange = str_replace('$', '', $extractedRange);
+
+								$coordinateStrings = explode(':', $extractedRange);
+								if (count($coordinateStrings) == 2) {
+									list($firstColumn, $firstRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[0]);
+									list($lastColumn, $lastRow) = PHPExcel_Cell::coordinateFromString($coordinateStrings[1]);
+
+									if ($firstColumn == 'A' and $lastColumn == 'IV') {
+										// then we have repeating rows
+										$docSheet->getPageSetup()->setRowsToRepeatAtTop(array($firstRow, $lastRow));
+									} elseif ($firstRow == 1 and $lastRow == 65536) {
+										// then we have repeating columns
+										$docSheet->getPageSetup()->setColumnsToRepeatAtLeft(array($firstColumn, $lastColumn));
+									}
+								}
+							}
+						}
+					}
+					break;
+
+				}
+			} else {
+				// Extract range
+				$explodes = explode('!', $definedName['formula']);
+
+				if (count($explodes) == 2) {
+					if (($docSheet = $this->_phpExcel->getSheetByName($explodes[0])) ||
+						($docSheet = $this->_phpExcel->getSheetByName(trim($explodes[0],"'")))) {
+						$extractedRange = $explodes[1];
+						$extractedRange = str_replace('$', '', $extractedRange);
+
+						$localOnly = ($definedName['scope'] == 0) ? false : true;
+
+						$scope = ($definedName['scope'] == 0) ?
+							null : $this->_phpExcel->getSheetByName($this->_sheets[$definedName['scope'] - 1]['name']);
+
+						$this->_phpExcel->addNamedRange( new PHPExcel_NamedRange((string)$definedName['name'], $docSheet, $extractedRange, $localOnly, $scope) );
+					}
+				} else {
+					//	Named Value
+					//	TODO Provide support for named values
+				}
+			}
+		}
+
+		return $this->_phpExcel;
+	}
+
+
+	/**
+	 * Use OLE reader to extract the relevant data streams from the OLE file
+	 *
+	 * @param string $pFilename
+	 */
+	private function _loadOLE($pFilename)
+	{
+		// OLE reader
+		$ole = new PHPExcel_Shared_OLERead();
+
+		// get excel data,
+		$res = $ole->read($pFilename);
+		// Get workbook data: workbook stream + sheet streams
+		$this->_data = $ole->getStream($ole->wrkbook);
+
+		// Get summary information data
+		$this->_summaryInformation = $ole->getStream($ole->summaryInformation);
+
+		// Get additional document summary information data
+		$this->_documentSummaryInformation = $ole->getStream($ole->documentSummaryInformation);
+
+		// Get user-defined property data
+//		$this->_userDefinedProperties = $ole->getUserDefinedProperties();
+	}
+
+
+	/**
+	 * Read summary information
+	 */
+	private function _readSummaryInformation()
+	{
+		if (!isset($this->_summaryInformation)) {
+			return;
+		}
+
+		// offset: 0; size: 2; must be 0xFE 0xFF (UTF-16 LE byte order mark)
+		// offset: 2; size: 2;
+		// offset: 4; size: 2; OS version
+		// offset: 6; size: 2; OS indicator
+		// offset: 8; size: 16
+		// offset: 24; size: 4; section count
+		$secCount = self::_GetInt4d($this->_summaryInformation, 24);
+
+		// offset: 28; size: 16; first section's class id: e0 85 9f f2 f9 4f 68 10 ab 91 08 00 2b 27 b3 d9
+		// offset: 44; size: 4
+		$secOffset = self::_GetInt4d($this->_summaryInformation, 44);
+
+		// section header
+		// offset: $secOffset; size: 4; section length
+		$secLength = self::_GetInt4d($this->_summaryInformation, $secOffset);
+
+		// offset: $secOffset+4; size: 4; property count
+		$countProperties = self::_GetInt4d($this->_summaryInformation, $secOffset+4);
+
+		// initialize code page (used to resolve string values)
+		$codePage = 'CP1252';
+
+		// offset: ($secOffset+8); size: var
+		// loop through property decarations and properties
+		for ($i = 0; $i < $countProperties; ++$i) {
+
+			// offset: ($secOffset+8) + (8 * $i); size: 4; property ID
+			$id = self::_GetInt4d($this->_summaryInformation, ($secOffset+8) + (8 * $i));
+
+			// Use value of property id as appropriate
+			// offset: ($secOffset+12) + (8 * $i); size: 4; offset from beginning of section (48)
+			$offset = self::_GetInt4d($this->_summaryInformation, ($secOffset+12) + (8 * $i));
+
+			$type = self::_GetInt4d($this->_summaryInformation, $secOffset + $offset);
+
+			// initialize property value
+			$value = null;
+
+			// extract property value based on property type
+			switch ($type) {
+				case 0x02: // 2 byte signed integer
+					$value = self::_GetInt2d($this->_summaryInformation, $secOffset + 4 + $offset);
+					break;
+
+				case 0x03: // 4 byte signed integer
+					$value = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
+					break;
+
+				case 0x13: // 4 byte unsigned integer
+					// not needed yet, fix later if necessary
+					break;
+
+				case 0x1E: // null-terminated string prepended by dword string length
+					$byteLength = self::_GetInt4d($this->_summaryInformation, $secOffset + 4 + $offset);
+					$value = substr($this->_summaryInformation, $secOffset + 8 + $offset, $byteLength);
+					$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
+					$value = rtrim($value);
+					break;
+
+				case 0x40: // Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
+					// PHP-time
+					$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_summaryInformation, $secOffset + 4 + $offset, 8));
+					break;
+
+				case 0x47: // Clipboard format
+					// not needed yet, fix later if necessary
+					break;
+			}
+
+			switch ($id) {
+				case 0x01:	//	Code Page
+					$codePage = PHPExcel_Shared_CodePage::NumberToName($value);
+					break;
+
+				case 0x02:	//	Title
+					$this->_phpExcel->getProperties()->setTitle($value);
+					break;
+
+				case 0x03:	//	Subject
+					$this->_phpExcel->getProperties()->setSubject($value);
+					break;
+
+				case 0x04:	//	Author (Creator)
+					$this->_phpExcel->getProperties()->setCreator($value);
+					break;
+
+				case 0x05:	//	Keywords
+					$this->_phpExcel->getProperties()->setKeywords($value);
+					break;
+
+				case 0x06:	//	Comments (Description)
+					$this->_phpExcel->getProperties()->setDescription($value);
+					break;
+
+				case 0x07:	//	Template
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x08:	//	Last Saved By (LastModifiedBy)
+					$this->_phpExcel->getProperties()->setLastModifiedBy($value);
+					break;
+
+				case 0x09:	//	Revision
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0A:	//	Total Editing Time
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0B:	//	Last Printed
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0C:	//	Created Date/Time
+					$this->_phpExcel->getProperties()->setCreated($value);
+					break;
+
+				case 0x0D:	//	Modified Date/Time
+					$this->_phpExcel->getProperties()->setModified($value);
+					break;
+
+				case 0x0E:	//	Number of Pages
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0F:	//	Number of Words
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x10:	//	Number of Characters
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x11:	//	Thumbnail
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x12:	//	Name of creating application
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x13:	//	Security
+					//	Not supported by PHPExcel
+					break;
+
+			}
+		}
+	}
+
+
+	/**
+	 * Read additional document summary information
+	 */
+	private function _readDocumentSummaryInformation()
+	{
+		if (!isset($this->_documentSummaryInformation)) {
+			return;
+		}
+
+		//	offset: 0;	size: 2;	must be 0xFE 0xFF (UTF-16 LE byte order mark)
+		//	offset: 2;	size: 2;
+		//	offset: 4;	size: 2;	OS version
+		//	offset: 6;	size: 2;	OS indicator
+		//	offset: 8;	size: 16
+		//	offset: 24;	size: 4;	section count
+		$secCount = self::_GetInt4d($this->_documentSummaryInformation, 24);
+//		echo '$secCount = ',$secCount,'<br />';
+
+		// offset: 28;	size: 16;	first section's class id: 02 d5 cd d5 9c 2e 1b 10 93 97 08 00 2b 2c f9 ae
+		// offset: 44;	size: 4;	first section offset
+		$secOffset = self::_GetInt4d($this->_documentSummaryInformation, 44);
+//		echo '$secOffset = ',$secOffset,'<br />';
+
+		//	section header
+		//	offset: $secOffset;	size: 4;	section length
+		$secLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset);
+//		echo '$secLength = ',$secLength,'<br />';
+
+		//	offset: $secOffset+4;	size: 4;	property count
+		$countProperties = self::_GetInt4d($this->_documentSummaryInformation, $secOffset+4);
+//		echo '$countProperties = ',$countProperties,'<br />';
+
+		// initialize code page (used to resolve string values)
+		$codePage = 'CP1252';
+
+		//	offset: ($secOffset+8);	size: var
+		//	loop through property decarations and properties
+		for ($i = 0; $i < $countProperties; ++$i) {
+//			echo 'Property ',$i,'<br />';
+			//	offset: ($secOffset+8) + (8 * $i);	size: 4;	property ID
+			$id = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+8) + (8 * $i));
+//			echo 'ID is ',$id,'<br />';
+
+			// Use value of property id as appropriate
+			// offset: 60 + 8 * $i;	size: 4;	offset from beginning of section (48)
+			$offset = self::_GetInt4d($this->_documentSummaryInformation, ($secOffset+12) + (8 * $i));
+
+			$type = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + $offset);
+//			echo 'Type is ',$type,', ';
+
+			// initialize property value
+			$value = null;
+
+			// extract property value based on property type
+			switch ($type) {
+				case 0x02:	//	2 byte signed integer
+					$value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
+					break;
+
+				case 0x03:	//	4 byte signed integer
+					$value = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
+					break;
+
+				case 0x0B:  // Boolean
+					$value = self::_GetInt2d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
+					$value = ($value == 0 ? false : true);
+					break;
+
+				case 0x13:	//	4 byte unsigned integer
+					// not needed yet, fix later if necessary
+					break;
+
+				case 0x1E:	//	null-terminated string prepended by dword string length
+					$byteLength = self::_GetInt4d($this->_documentSummaryInformation, $secOffset + 4 + $offset);
+					$value = substr($this->_documentSummaryInformation, $secOffset + 8 + $offset, $byteLength);
+					$value = PHPExcel_Shared_String::ConvertEncoding($value, 'UTF-8', $codePage);
+					$value = rtrim($value);
+					break;
+
+				case 0x40:	//	Filetime (64-bit value representing the number of 100-nanosecond intervals since January 1, 1601)
+					// PHP-Time
+					$value = PHPExcel_Shared_OLE::OLE2LocalDate(substr($this->_documentSummaryInformation, $secOffset + 4 + $offset, 8));
+					break;
+
+				case 0x47:	//	Clipboard format
+					// not needed yet, fix later if necessary
+					break;
+			}
+
+			switch ($id) {
+				case 0x01:	//	Code Page
+					$codePage = PHPExcel_Shared_CodePage::NumberToName($value);
+					break;
+
+				case 0x02:	//	Category
+					$this->_phpExcel->getProperties()->setCategory($value);
+					break;
+
+				case 0x03:	//	Presentation Target
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x04:	//	Bytes
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x05:	//	Lines
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x06:	//	Paragraphs
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x07:	//	Slides
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x08:	//	Notes
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x09:	//	Hidden Slides
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0A:	//	MM Clips
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0B:	//	Scale Crop
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0C:	//	Heading Pairs
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0D:	//	Titles of Parts
+					//	Not supported by PHPExcel
+					break;
+
+				case 0x0E:	//	Manager
+					$this->_phpExcel->getProperties()->setManager($value);
+					break;
+
+				case 0x0F:	//	Company
+					$this->_phpExcel->getProperties()->setCompany($value);
+					break;
+
+				case 0x10:	//	Links up-to-date
+					//	Not supported by PHPExcel
+					break;
+
+			}
+		}
+	}
+
+
+	/**
+	 * Reads a general type of BIFF record. Does nothing except for moving stream pointer forward to next record.
+	 */
+	private function _readDefault()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+//		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+	}
+
+
+	/**
+	 *	The NOTE record specifies a comment associated with a particular cell. In Excel 95 (BIFF7) and earlier versions,
+	 *		this record stores a note (cell note). This feature was significantly enhanced in Excel 97.
+	 */
+	private function _readNote()
+	{
+//		echo '<b>Read Cell Annotation</b><br />';
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		$cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
+		if ($this->_version == self::XLS_BIFF8) {
+			$noteObjID = self::_GetInt2d($recordData, 6);
+			$noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
+			$noteAuthor = $noteAuthor['value'];
+//			echo 'Note Address=',$cellAddress,'<br />';
+//			echo 'Note Object ID=',$noteObjID,'<br />';
+//			echo 'Note Author=',$noteAuthor,'<hr />';
+//
+			$this->_cellNotes[$noteObjID] = array('cellRef'		=> $cellAddress,
+												  'objectID'	=> $noteObjID,
+												  'author'		=> $noteAuthor
+												 );
+		} else {
+			$extension = false;
+			if ($cellAddress == '$B$65536') {
+				//	If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
+				//		note from the previous cell annotation. We're not yet handling this, so annotations longer than the
+				//		max 2048 bytes will probably throw a wobbly.
+				$row = self::_GetInt2d($recordData, 0);
+				$extension = true;
+				$cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
+			}
+//			echo 'Note Address=',$cellAddress,'<br />';
+
+			$cellAddress = str_replace('$','',$cellAddress);
+			$noteLength = self::_GetInt2d($recordData, 4);
+			$noteText = trim(substr($recordData, 6));
+//			echo 'Note Length=',$noteLength,'<br />';
+//			echo 'Note Text=',$noteText,'<br />';
+
+			if ($extension) {
+				//	Concatenate this extension with the currently set comment for the cell
+				$comment = $this->_phpSheet->getComment( $cellAddress );
+				$commentText = $comment->getText()->getPlainText();
+				$comment->setText($this->_parseRichText($commentText.$noteText) );
+			} else {
+				//	Set comment for the cell
+				$this->_phpSheet->getComment( $cellAddress )
+//													->setAuthor( $author )
+													->setText($this->_parseRichText($noteText) );
+			}
+		}
+
+	}
+
+
+	/**
+	 *	The TEXT Object record contains the text associated with a cell annotation.
+	 */
+	private function _readTextObject()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		// recordData consists of an array of subrecords looking like this:
+		//	grbit: 2 bytes; Option Flags
+		//	rot: 2 bytes; rotation
+		//	cchText: 2 bytes; length of the text (in the first continue record)
+		//	cbRuns: 2 bytes; length of the formatting (in the second continue record)
+		// followed by the continuation records containing the actual text and formatting
+		$grbitOpts	= self::_GetInt2d($recordData, 0);
+		$rot		= self::_GetInt2d($recordData, 2);
+		$cchText	= self::_GetInt2d($recordData, 10);
+		$cbRuns		= self::_GetInt2d($recordData, 12);
+		$text		= $this->_getSplicedRecordData();
+
+		$this->_textObjects[$this->textObjRef] = array(
+				'text'		=> substr($text["recordData"],$text["spliceOffsets"][0]+1,$cchText),
+				'format'	=> substr($text["recordData"],$text["spliceOffsets"][1],$cbRuns),
+				'alignment'	=> $grbitOpts,
+				'rotation'	=> $rot
+			 );
+
+//		echo '<b>_readTextObject()</b><br />';
+//		var_dump($this->_textObjects[$this->textObjRef]);
+//		echo '<br />';
+	}
+
+
+	/**
+	 * Read BOF
+	 */
+	private function _readBof()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 2; size: 2; type of the following data
+		$substreamType = self::_GetInt2d($recordData, 2);
+
+		switch ($substreamType) {
+			case self::XLS_WorkbookGlobals:
+				$version = self::_GetInt2d($recordData, 0);
+				if (($version != self::XLS_BIFF8) && ($version != self::XLS_BIFF7)) {
+					throw new Exception('Cannot read this Excel file. Version is too old.');
+				}
+				$this->_version = $version;
+				break;
+
+			case self::XLS_Worksheet:
+				// do not use this version information for anything
+				// it is unreliable (OpenOffice doc, 5.8), use only version information from the global stream
+				break;
+
+			default:
+				// substream, e.g. chart
+				// just skip the entire substream
+				do {
+					$code = self::_GetInt2d($this->_data, $this->_pos);
+					$this->_readDefault();
+				} while ($code != self::XLS_Type_EOF && $this->_pos < $this->_dataSize);
+				break;
+		}
+	}
+
+
+	/**
+	 * FILEPASS
+	 *
+	 * This record is part of the File Protection Block. It
+	 * contains information about the read/write password of the
+	 * file. All record contents following this record will be
+	 * encrypted.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readFilepass()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+//		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		throw new Exception('Cannot read encrypted file');
+	}
+
+
+	/**
+	 * CODEPAGE
+	 *
+	 * This record stores the text encoding used to write byte
+	 * strings, stored as MS Windows code page identifier.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readCodepage()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; code page identifier
+		$codepage = self::_GetInt2d($recordData, 0);
+
+		$this->_codepage = PHPExcel_Shared_CodePage::NumberToName($codepage);
+	}
+
+
+	/**
+	 * DATEMODE
+	 *
+	 * This record specifies the base date for displaying date
+	 * values. All dates are stored as count of days past this
+	 * base date. In BIFF2-BIFF4 this record is part of the
+	 * Calculation Settings Block. In BIFF5-BIFF8 it is
+	 * stored in the Workbook Globals Substream.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readDateMode()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; 0 = base 1900, 1 = base 1904
+		PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900);
+		if (ord($recordData{0}) == 1) {
+			PHPExcel_Shared_Date::setExcelCalendar(PHPExcel_Shared_Date::CALENDAR_MAC_1904);
+		}
+	}
+
+
+	/**
+	 * Read a FONT record
+	 */
+	private function _readFont()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			$objFont = new PHPExcel_Style_Font();
+
+			// offset: 0; size: 2; height of the font (in twips = 1/20 of a point)
+			$size = self::_GetInt2d($recordData, 0);
+			$objFont->setSize($size / 20);
+
+			// offset: 2; size: 2; option flags
+				// bit: 0; mask 0x0001; bold (redundant in BIFF5-BIFF8)
+				// bit: 1; mask 0x0002; italic
+				$isItalic = (0x0002 & self::_GetInt2d($recordData, 2)) >> 1;
+				if ($isItalic) $objFont->setItalic(true);
+
+				// bit: 2; mask 0x0004; underlined (redundant in BIFF5-BIFF8)
+				// bit: 3; mask 0x0008; strike
+				$isStrike = (0x0008 & self::_GetInt2d($recordData, 2)) >> 3;
+				if ($isStrike) $objFont->setStrikethrough(true);
+
+			// offset: 4; size: 2; colour index
+			$colorIndex = self::_GetInt2d($recordData, 4);
+			$objFont->colorIndex = $colorIndex;
+
+			// offset: 6; size: 2; font weight
+			$weight = self::_GetInt2d($recordData, 6);
+			switch ($weight) {
+				case 0x02BC:
+					$objFont->setBold(true);
+					break;
+			}
+
+			// offset: 8; size: 2; escapement type
+			$escapement = self::_GetInt2d($recordData, 8);
+			switch ($escapement) {
+				case 0x0001:
+					$objFont->setSuperScript(true);
+					break;
+				case 0x0002:
+					$objFont->setSubScript(true);
+					break;
+			}
+
+			// offset: 10; size: 1; underline type
+			$underlineType = ord($recordData{10});
+			switch ($underlineType) {
+				case 0x00:
+					break; // no underline
+				case 0x01:
+					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
+					break;
+				case 0x02:
+					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
+					break;
+				case 0x21:
+					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLEACCOUNTING);
+					break;
+				case 0x22:
+					$objFont->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLEACCOUNTING);
+					break;
+			}
+
+			// offset: 11; size: 1; font family
+			// offset: 12; size: 1; character set
+			// offset: 13; size: 1; not used
+			// offset: 14; size: var; font name
+			if ($this->_version == self::XLS_BIFF8) {
+				$string = self::_readUnicodeStringShort(substr($recordData, 14));
+			} else {
+				$string = $this->_readByteStringShort(substr($recordData, 14));
+			}
+			$objFont->setName($string['value']);
+
+			$this->_objFonts[] = $objFont;
+		}
+	}
+
+
+	/**
+	 * FORMAT
+	 *
+	 * This record contains information about a number format.
+	 * All FORMAT records occur together in a sequential list.
+	 *
+	 * In BIFF2-BIFF4 other records referencing a FORMAT record
+	 * contain a zero-based index into this list. From BIFF5 on
+	 * the FORMAT record contains the index itself that will be
+	 * used by other records.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readFormat()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			$indexCode = self::_GetInt2d($recordData, 0);
+
+			if ($this->_version == self::XLS_BIFF8) {
+				$string = self::_readUnicodeStringLong(substr($recordData, 2));
+			} else {
+				// BIFF7
+				$string = $this->_readByteStringShort(substr($recordData, 2));
+			}
+
+			$formatString = $string['value'];
+			$this->_formats[$indexCode] = $formatString;
+		}
+	}
+
+
+	/**
+	 * XF - Extended Format
+	 *
+	 * This record contains formatting information for cells, rows, columns or styles.
+	 * According to http://support.microsoft.com/kb/147732 there are always at least 15 cell style XF
+	 * and 1 cell XF.
+	 * Inspection of Excel files generated by MS Office Excel shows that XF records 0-14 are cell style XF
+	 * and XF record 15 is a cell XF
+	 * We only read the first cell style XF and skip the remaining cell style XF records
+	 * We read all cell XF records.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readXf()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		$objStyle = new PHPExcel_Style();
+
+		if (!$this->_readDataOnly) {
+			// offset:  0; size: 2; Index to FONT record
+			if (self::_GetInt2d($recordData, 0) < 4) {
+				$fontIndex = self::_GetInt2d($recordData, 0);
+			} else {
+				// this has to do with that index 4 is omitted in all BIFF versions for some strange reason
+				// check the OpenOffice documentation of the FONT record
+				$fontIndex = self::_GetInt2d($recordData, 0) - 1;
+			}
+			$objStyle->setFont($this->_objFonts[$fontIndex]);
+
+			// offset:  2; size: 2; Index to FORMAT record
+			$numberFormatIndex = self::_GetInt2d($recordData, 2);
+			if (isset($this->_formats[$numberFormatIndex])) {
+				// then we have user-defined format code
+				$numberformat = array('code' => $this->_formats[$numberFormatIndex]);
+			} elseif (($code = PHPExcel_Style_NumberFormat::builtInFormatCode($numberFormatIndex)) !== '') {
+				// then we have built-in format code
+				$numberformat = array('code' => $code);
+			} else {
+				// we set the general format code
+				$numberformat = array('code' => 'General');
+			}
+			$objStyle->getNumberFormat()->setFormatCode($numberformat['code']);
+
+			// offset:  4; size: 2; XF type, cell protection, and parent style XF
+			// bit 2-0; mask 0x0007; XF_TYPE_PROT
+			$xfTypeProt = self::_GetInt2d($recordData, 4);
+			// bit 0; mask 0x01; 1 = cell is locked
+			$isLocked = (0x01 & $xfTypeProt) >> 0;
+			$objStyle->getProtection()->setLocked($isLocked ?
+				PHPExcel_Style_Protection::PROTECTION_INHERIT : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
+
+			// bit 1; mask 0x02; 1 = Formula is hidden
+			$isHidden = (0x02 & $xfTypeProt) >> 1;
+			$objStyle->getProtection()->setHidden($isHidden ?
+				PHPExcel_Style_Protection::PROTECTION_PROTECTED : PHPExcel_Style_Protection::PROTECTION_UNPROTECTED);
+
+			// bit 2; mask 0x04; 0 = Cell XF, 1 = Cell Style XF
+			$isCellStyleXf = (0x04 & $xfTypeProt) >> 2;
+
+			// offset:  6; size: 1; Alignment and text break
+			// bit 2-0, mask 0x07; horizontal alignment
+			$horAlign = (0x07 & ord($recordData{6})) >> 0;
+			switch ($horAlign) {
+				case 0:
+					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_GENERAL);
+					break;
+				case 1:
+					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
+					break;
+				case 2:
+					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
+					break;
+				case 3:
+					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
+					break;
+				case 5:
+					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY);
+					break;
+				case 6:
+					$objStyle->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS);
+					break;
+			}
+			// bit 3, mask 0x08; wrap text
+			$wrapText = (0x08 & ord($recordData{6})) >> 3;
+			switch ($wrapText) {
+				case 0:
+					$objStyle->getAlignment()->setWrapText(false);
+					break;
+				case 1:
+					$objStyle->getAlignment()->setWrapText(true);
+					break;
+			}
+			// bit 6-4, mask 0x70; vertical alignment
+			$vertAlign = (0x70 & ord($recordData{6})) >> 4;
+			switch ($vertAlign) {
+				case 0:
+					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_TOP);
+					break;
+				case 1:
+					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
+					break;
+				case 2:
+					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_BOTTOM);
+					break;
+				case 3:
+					$objStyle->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_JUSTIFY);
+					break;
+			}
+
+			if ($this->_version == self::XLS_BIFF8) {
+				// offset:  7; size: 1; XF_ROTATION: Text rotation angle
+					$angle = ord($recordData{7});
+					$rotation = 0;
+					if ($angle <= 90) {
+						$rotation = $angle;
+					} else if ($angle <= 180) {
+						$rotation = 90 - $angle;
+					} else if ($angle == 255) {
+						$rotation = -165;
+					}
+					$objStyle->getAlignment()->setTextRotation($rotation);
+
+				// offset:  8; size: 1; Indentation, shrink to cell size, and text direction
+					// bit: 3-0; mask: 0x0F; indent level
+					$indent = (0x0F & ord($recordData{8})) >> 0;
+					$objStyle->getAlignment()->setIndent($indent);
+
+					// bit: 4; mask: 0x10; 1 = shrink content to fit into cell
+					$shrinkToFit = (0x10 & ord($recordData{8})) >> 4;
+					switch ($shrinkToFit) {
+						case 0:
+							$objStyle->getAlignment()->setShrinkToFit(false);
+							break;
+						case 1:
+							$objStyle->getAlignment()->setShrinkToFit(true);
+							break;
+					}
+
+				// offset:  9; size: 1; Flags used for attribute groups
+
+				// offset: 10; size: 4; Cell border lines and background area
+					// bit: 3-0; mask: 0x0000000F; left style
+					if ($bordersLeftStyle = self::_mapBorderStyle((0x0000000F & self::_GetInt4d($recordData, 10)) >> 0)) {
+						$objStyle->getBorders()->getLeft()->setBorderStyle($bordersLeftStyle);
+					}
+					// bit: 7-4; mask: 0x000000F0; right style
+					if ($bordersRightStyle = self::_mapBorderStyle((0x000000F0 & self::_GetInt4d($recordData, 10)) >> 4)) {
+						$objStyle->getBorders()->getRight()->setBorderStyle($bordersRightStyle);
+					}
+					// bit: 11-8; mask: 0x00000F00; top style
+					if ($bordersTopStyle = self::_mapBorderStyle((0x00000F00 & self::_GetInt4d($recordData, 10)) >> 8)) {
+						$objStyle->getBorders()->getTop()->setBorderStyle($bordersTopStyle);
+					}
+					// bit: 15-12; mask: 0x0000F000; bottom style
+					if ($bordersBottomStyle = self::_mapBorderStyle((0x0000F000 & self::_GetInt4d($recordData, 10)) >> 12)) {
+						$objStyle->getBorders()->getBottom()->setBorderStyle($bordersBottomStyle);
+					}
+					// bit: 22-16; mask: 0x007F0000; left color
+					$objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & self::_GetInt4d($recordData, 10)) >> 16;
+
+					// bit: 29-23; mask: 0x3F800000; right color
+					$objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & self::_GetInt4d($recordData, 10)) >> 23;
+
+					// bit: 30; mask: 0x40000000; 1 = diagonal line from top left to right bottom
+					$diagonalDown = (0x40000000 & self::_GetInt4d($recordData, 10)) >> 30 ?
+						true : false;
+
+					// bit: 31; mask: 0x80000000; 1 = diagonal line from bottom left to top right
+					$diagonalUp = (0x80000000 & self::_GetInt4d($recordData, 10)) >> 31 ?
+						true : false;
+
+					if ($diagonalUp == false && $diagonalDown == false) {
+						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_NONE);
+					} elseif ($diagonalUp == true && $diagonalDown == false) {
+						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_UP);
+					} elseif ($diagonalUp == false && $diagonalDown == true) {
+						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_DOWN);
+					} elseif ($diagonalUp == true && $diagonalDown == true) {
+						$objStyle->getBorders()->setDiagonalDirection(PHPExcel_Style_Borders::DIAGONAL_BOTH);
+					}
+
+				// offset: 14; size: 4;
+					// bit: 6-0; mask: 0x0000007F; top color
+					$objStyle->getBorders()->getTop()->colorIndex = (0x0000007F & self::_GetInt4d($recordData, 14)) >> 0;
+
+					// bit: 13-7; mask: 0x00003F80; bottom color
+					$objStyle->getBorders()->getBottom()->colorIndex = (0x00003F80 & self::_GetInt4d($recordData, 14)) >> 7;
+
+					// bit: 20-14; mask: 0x001FC000; diagonal color
+					$objStyle->getBorders()->getDiagonal()->colorIndex = (0x001FC000 & self::_GetInt4d($recordData, 14)) >> 14;
+
+					// bit: 24-21; mask: 0x01E00000; diagonal style
+					if ($bordersDiagonalStyle = self::_mapBorderStyle((0x01E00000 & self::_GetInt4d($recordData, 14)) >> 21)) {
+						$objStyle->getBorders()->getDiagonal()->setBorderStyle($bordersDiagonalStyle);
+					}
+
+					// bit: 31-26; mask: 0xFC000000 fill pattern
+					if ($fillType = self::_mapFillPattern((0xFC000000 & self::_GetInt4d($recordData, 14)) >> 26)) {
+						$objStyle->getFill()->setFillType($fillType);
+					}
+				// offset: 18; size: 2; pattern and background colour
+					// bit: 6-0; mask: 0x007F; color index for pattern color
+					$objStyle->getFill()->startcolorIndex = (0x007F & self::_GetInt2d($recordData, 18)) >> 0;
+
+					// bit: 13-7; mask: 0x3F80; color index for pattern background
+					$objStyle->getFill()->endcolorIndex = (0x3F80 & self::_GetInt2d($recordData, 18)) >> 7;
+			} else {
+				// BIFF5
+
+				// offset: 7; size: 1; Text orientation and flags
+				$orientationAndFlags = ord($recordData{7});
+
+				// bit: 1-0; mask: 0x03; XF_ORIENTATION: Text orientation
+				$xfOrientation = (0x03 & $orientationAndFlags) >> 0;
+				switch ($xfOrientation) {
+					case 0:
+						$objStyle->getAlignment()->setTextRotation(0);
+						break;
+					case 1:
+						$objStyle->getAlignment()->setTextRotation(-165);
+						break;
+					case 2:
+						$objStyle->getAlignment()->setTextRotation(90);
+						break;
+					case 3:
+						$objStyle->getAlignment()->setTextRotation(-90);
+						break;
+				}
+
+				// offset: 8; size: 4; cell border lines and background area
+				$borderAndBackground = self::_GetInt4d($recordData, 8);
+
+				// bit: 6-0; mask: 0x0000007F; color index for pattern color
+				$objStyle->getFill()->startcolorIndex = (0x0000007F & $borderAndBackground) >> 0;
+
+				// bit: 13-7; mask: 0x00003F80; color index for pattern background
+				$objStyle->getFill()->endcolorIndex = (0x00003F80 & $borderAndBackground) >> 7;
+
+				// bit: 21-16; mask: 0x003F0000; fill pattern
+				$objStyle->getFill()->setFillType(self::_mapFillPattern((0x003F0000 & $borderAndBackground) >> 16));
+
+				// bit: 24-22; mask: 0x01C00000; bottom line style
+				$objStyle->getBorders()->getBottom()->setBorderStyle(self::_mapBorderStyle((0x01C00000 & $borderAndBackground) >> 22));
+
+				// bit: 31-25; mask: 0xFE000000; bottom line color
+				$objStyle->getBorders()->getBottom()->colorIndex = (0xFE000000 & $borderAndBackground) >> 25;
+
+				// offset: 12; size: 4; cell border lines
+				$borderLines = self::_GetInt4d($recordData, 12);
+
+				// bit: 2-0; mask: 0x00000007; top line style
+				$objStyle->getBorders()->getTop()->setBorderStyle(self::_mapBorderStyle((0x00000007 & $borderLines) >> 0));
+
+				// bit: 5-3; mask: 0x00000038; left line style
+				$objStyle->getBorders()->getLeft()->setBorderStyle(self::_mapBorderStyle((0x00000038 & $borderLines) >> 3));
+
+				// bit: 8-6; mask: 0x000001C0; right line style
+				$objStyle->getBorders()->getRight()->setBorderStyle(self::_mapBorderStyle((0x000001C0 & $borderLines) >> 6));
+
+				// bit: 15-9; mask: 0x0000FE00; top line color index
+				$objStyle->getBorders()->getTop()->colorIndex = (0x0000FE00 & $borderLines) >> 9;
+
+				// bit: 22-16; mask: 0x007F0000; left line color index
+				$objStyle->getBorders()->getLeft()->colorIndex = (0x007F0000 & $borderLines) >> 16;
+
+				// bit: 29-23; mask: 0x3F800000; right line color index
+				$objStyle->getBorders()->getRight()->colorIndex = (0x3F800000 & $borderLines) >> 23;
+			}
+
+			// add cellStyleXf or cellXf and update mapping
+			if ($isCellStyleXf) {
+				// we only read one style XF record which is always the first
+				if ($this->_xfIndex == 0) {
+					$this->_phpExcel->addCellStyleXf($objStyle);
+					$this->_mapCellStyleXfIndex[$this->_xfIndex] = 0;
+				}
+			} else {
+				// we read all cell XF records
+				$this->_phpExcel->addCellXf($objStyle);
+				$this->_mapCellXfIndex[$this->_xfIndex] = count($this->_phpExcel->getCellXfCollection()) - 1;
+			}
+
+			// update XF index for when we read next record
+			++$this->_xfIndex;
+		}
+	}
+
+
+	/**
+	 *
+	 */
+	private function _readXfExt()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; 0x087D = repeated header
+
+			// offset: 2; size: 2
+
+			// offset: 4; size: 8; not used
+
+			// offset: 12; size: 2; record version
+
+			// offset: 14; size: 2; index to XF record which this record modifies
+			$ixfe = self::_GetInt2d($recordData, 14);
+
+			// offset: 16; size: 2; not used
+
+			// offset: 18; size: 2; number of extension properties that follow
+			$cexts = self::_GetInt2d($recordData, 18);
+
+			// start reading the actual extension data
+			$offset = 20;
+			while ($offset < $length) {
+				// extension type
+				$extType = self::_GetInt2d($recordData, $offset);
+
+				// extension length
+				$cb = self::_GetInt2d($recordData, $offset + 2);
+
+				// extension data
+				$extData = substr($recordData, $offset + 4, $cb);
+
+				switch ($extType) {
+					case 4:		// fill start color
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
+								$fill->getStartColor()->setRGB($rgb);
+								unset($fill->startcolorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 5:		// fill end color
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$fill = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFill();
+								$fill->getEndColor()->setRGB($rgb);
+								unset($fill->endcolorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 7:		// border color top
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$top = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getTop();
+								$top->getColor()->setRGB($rgb);
+								unset($top->colorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 8:		// border color bottom
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$bottom = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getBottom();
+								$bottom->getColor()->setRGB($rgb);
+								unset($bottom->colorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 9:		// border color left
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$left = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getLeft();
+								$left->getColor()->setRGB($rgb);
+								unset($left->colorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 10:		// border color right
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$right = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getRight();
+								$right->getColor()->setRGB($rgb);
+								unset($right->colorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 11:		// border color diagonal
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$diagonal = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getBorders()->getDiagonal();
+								$diagonal->getColor()->setRGB($rgb);
+								unset($diagonal->colorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+
+					case 13:	// font color
+						$xclfType  = self::_GetInt2d($extData, 0); // color type
+						$xclrValue = substr($extData, 4, 4); // color value (value based on color type)
+
+						if ($xclfType == 2) {
+							$rgb = sprintf('%02X%02X%02X', ord($xclrValue{0}), ord($xclrValue{1}), ord($xclrValue{2}));
+
+							// modify the relevant style property
+							if ( isset($this->_mapCellXfIndex[$ixfe]) ) {
+								$font = $this->_phpExcel->getCellXfByIndex($this->_mapCellXfIndex[$ixfe])->getFont();
+								$font->getColor()->setRGB($rgb);
+								unset($font->colorIndex); // normal color index does not apply, discard
+							}
+						}
+						break;
+				}
+
+				$offset += $cb;
+			}
+		}
+
+	}
+
+
+	/**
+	 * Read STYLE record
+	 */
+	private function _readStyle()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; index to XF record and flag for built-in style
+			$ixfe = self::_GetInt2d($recordData, 0);
+
+			// bit: 11-0; mask 0x0FFF; index to XF record
+			$xfIndex = (0x0FFF & $ixfe) >> 0;
+
+			// bit: 15; mask 0x8000; 0 = user-defined style, 1 = built-in style
+			$isBuiltIn = (bool) ((0x8000 & $ixfe) >> 15);
+
+			if ($isBuiltIn) {
+				// offset: 2; size: 1; identifier for built-in style
+				$builtInId = ord($recordData{2});
+
+				switch ($builtInId) {
+				case 0x00:
+					// currently, we are not using this for anything
+					break;
+
+				default:
+					break;
+				}
+
+			} else {
+				// user-defined; not supported by PHPExcel
+			}
+		}
+	}
+
+
+	/**
+	 * Read PALETTE record
+	 */
+	private function _readPalette()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; number of following colors
+			$nm = self::_GetInt2d($recordData, 0);
+
+			// list of RGB colors
+			for ($i = 0; $i < $nm; ++$i) {
+				$rgb = substr($recordData, 2 + 4 * $i, 4);
+				$this->_palette[] = self::_readRGB($rgb);
+			}
+		}
+	}
+
+
+	/**
+	 * SHEET
+	 *
+	 * This record is  located in the  Workbook Globals
+	 * Substream  and represents a sheet inside the workbook.
+	 * One SHEET record is written for each sheet. It stores the
+	 * sheet name and a stream offset to the BOF record of the
+	 * respective Sheet Substream within the Workbook Stream.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readSheet()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 4; absolute stream position of the BOF record of the sheet
+		$rec_offset = self::_GetInt4d($recordData, 0);
+
+		// offset: 4; size: 1; sheet state
+		switch (ord($recordData{4})) {
+			case 0x00: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;    break;
+			case 0x01: $sheetState = PHPExcel_Worksheet::SHEETSTATE_HIDDEN;     break;
+			case 0x02: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VERYHIDDEN; break;
+			default: $sheetState = PHPExcel_Worksheet::SHEETSTATE_VISIBLE;      break;
+		}
+
+		// offset: 5; size: 1; sheet type
+		$sheetType = ord($recordData{5});
+
+		// offset: 6; size: var; sheet name
+		if ($this->_version == self::XLS_BIFF8) {
+			$string = self::_readUnicodeStringShort(substr($recordData, 6));
+			$rec_name = $string['value'];
+		} elseif ($this->_version == self::XLS_BIFF7) {
+			$string = $this->_readByteStringShort(substr($recordData, 6));
+			$rec_name = $string['value'];
+		}
+
+		$this->_sheets[] = array(
+			'name' => $rec_name,
+			'offset' => $rec_offset,
+			'sheetState' => $sheetState,
+			'sheetType' => $sheetType,
+		);
+	}
+
+
+	/**
+	 * Read EXTERNALBOOK record
+	 */
+	private function _readExternalBook()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset within record data
+		$offset = 0;
+
+		// there are 4 types of records
+		if (strlen($recordData) > 4) {
+			// external reference
+			// offset: 0; size: 2; number of sheet names ($nm)
+			$nm = self::_GetInt2d($recordData, 0);
+			$offset += 2;
+
+			// offset: 2; size: var; encoded URL without sheet name (Unicode string, 16-bit length)
+			$encodedUrlString = self::_readUnicodeStringLong(substr($recordData, 2));
+			$offset += $encodedUrlString['size'];
+
+			// offset: var; size: var; list of $nm sheet names (Unicode strings, 16-bit length)
+			$externalSheetNames = array();
+			for ($i = 0; $i < $nm; ++$i) {
+				$externalSheetNameString = self::_readUnicodeStringLong(substr($recordData, $offset));
+				$externalSheetNames[] = $externalSheetNameString['value'];
+				$offset += $externalSheetNameString['size'];
+			}
+
+			// store the record data
+			$this->_externalBooks[] = array(
+				'type' => 'external',
+				'encodedUrl' => $encodedUrlString['value'],
+				'externalSheetNames' => $externalSheetNames,
+			);
+
+		} elseif (substr($recordData, 2, 2) == pack('CC', 0x01, 0x04)) {
+			// internal reference
+			// offset: 0; size: 2; number of sheet in this document
+			// offset: 2; size: 2; 0x01 0x04
+			$this->_externalBooks[] = array(
+				'type' => 'internal',
+			);
+		} elseif (substr($recordData, 0, 4) == pack('vCC', 0x0001, 0x01, 0x3A)) {
+			// add-in function
+			// offset: 0; size: 2; 0x0001
+			$this->_externalBooks[] = array(
+				'type' => 'addInFunction',
+			);
+		} elseif (substr($recordData, 0, 2) == pack('v', 0x0000)) {
+			// DDE links, OLE links
+			// offset: 0; size: 2; 0x0000
+			// offset: 2; size: var; encoded source document name
+			$this->_externalBooks[] = array(
+				'type' => 'DDEorOLE',
+			);
+		}
+	}
+
+
+	/**
+	 * Read EXTERNNAME record.
+	 */
+	private function _readExternName()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// external sheet references provided for named cells
+		if ($this->_version == self::XLS_BIFF8) {
+			// offset: 0; size: 2; options
+			$options = self::_GetInt2d($recordData, 0);
+
+			// offset: 2; size: 2;
+
+			// offset: 4; size: 2; not used
+
+			// offset: 6; size: var
+			$nameString = self::_readUnicodeStringShort(substr($recordData, 6));
+
+			// offset: var; size: var; formula data
+			$offset = 6 + $nameString['size'];
+			$formula = $this->_getFormulaFromStructure(substr($recordData, $offset));
+
+			$this->_externalNames[] = array(
+				'name' => $nameString['value'],
+				'formula' => $formula,
+			);
+		}
+	}
+
+
+	/**
+	 * Read EXTERNSHEET record
+	 */
+	private function _readExternSheet()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// external sheet references provided for named cells
+		if ($this->_version == self::XLS_BIFF8) {
+			// offset: 0; size: 2; number of following ref structures
+			$nm = self::_GetInt2d($recordData, 0);
+			for ($i = 0; $i < $nm; ++$i) {
+				$this->_ref[] = array(
+					// offset: 2 + 6 * $i; index to EXTERNALBOOK record
+					'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i),
+					// offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
+					'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i),
+					// offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
+					'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i),
+				);
+			}
+		}
+	}
+
+
+	/**
+	 * DEFINEDNAME
+	 *
+	 * This record is part of a Link Table. It contains the name
+	 * and the token array of an internal defined name. Token
+	 * arrays of defined names contain tokens with aberrant
+	 * token classes.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readDefinedName()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_version == self::XLS_BIFF8) {
+			// retrieves named cells
+
+			// offset: 0; size: 2; option flags
+			$opts = self::_GetInt2d($recordData, 0);
+
+				// bit: 5; mask: 0x0020; 0 = user-defined name, 1 = built-in-name
+				$isBuiltInName = (0x0020 & $opts) >> 5;
+
+			// offset: 2; size: 1; keyboard shortcut
+
+			// offset: 3; size: 1; length of the name (character count)
+			$nlen = ord($recordData{3});
+
+			// offset: 4; size: 2; size of the formula data (it can happen that this is zero)
+			// note: there can also be additional data, this is not included in $flen
+			$flen = self::_GetInt2d($recordData, 4);
+
+			// offset: 8; size: 2; 0=Global name, otherwise index to sheet (1-based)
+			$scope = self::_GetInt2d($recordData, 8);
+
+			// offset: 14; size: var; Name (Unicode string without length field)
+			$string = self::_readUnicodeString(substr($recordData, 14), $nlen);
+
+			// offset: var; size: $flen; formula data
+			$offset = 14 + $string['size'];
+			$formulaStructure = pack('v', $flen) . substr($recordData, $offset);
+
+			try {
+				$formula = $this->_getFormulaFromStructure($formulaStructure);
+			} catch (Exception $e) {
+				$formula = '';
+			}
+
+			$this->_definedname[] = array(
+				'isBuiltInName' => $isBuiltInName,
+				'name' => $string['value'],
+				'formula' => $formula,
+				'scope' => $scope,
+			);
+		}
+	}
+
+
+	/**
+	 * Read MSODRAWINGGROUP record
+	 */
+	private function _readMsoDrawingGroup()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+
+		// get spliced record data
+		$splicedRecordData = $this->_getSplicedRecordData();
+		$recordData = $splicedRecordData['recordData'];
+
+		$this->_drawingGroupData .= $recordData;
+	}
+
+
+	/**
+	 * SST - Shared String Table
+	 *
+	 * This record contains a list of all strings used anywhere
+	 * in the workbook. Each string occurs only once. The
+	 * workbook uses indexes into the list to reference the
+	 * strings.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 **/
+	private function _readSst()
+	{
+		// offset within (spliced) record data
+		$pos = 0;
+
+		// get spliced record data
+		$splicedRecordData = $this->_getSplicedRecordData();
+
+		$recordData = $splicedRecordData['recordData'];
+		$spliceOffsets = $splicedRecordData['spliceOffsets'];
+
+		// offset: 0; size: 4; total number of strings in the workbook
+		$pos += 4;
+
+		// offset: 4; size: 4; number of following strings ($nm)
+		$nm = self::_GetInt4d($recordData, 4);
+		$pos += 4;
+
+		// loop through the Unicode strings (16-bit length)
+		for ($i = 0; $i < $nm; ++$i) {
+
+			// number of characters in the Unicode string
+			$numChars = self::_GetInt2d($recordData, $pos);
+			$pos += 2;
+
+			// option flags
+			$optionFlags = ord($recordData{$pos});
+			++$pos;
+
+			// bit: 0; mask: 0x01; 0 = compressed; 1 = uncompressed
+			$isCompressed = (($optionFlags & 0x01) == 0) ;
+
+			// bit: 2; mask: 0x02; 0 = ordinary; 1 = Asian phonetic
+			$hasAsian = (($optionFlags & 0x04) != 0);
+
+			// bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text
+			$hasRichText = (($optionFlags & 0x08) != 0);
+
+			if ($hasRichText) {
+				// number of Rich-Text formatting runs
+				$formattingRuns = self::_GetInt2d($recordData, $pos);
+				$pos += 2;
+			}
+
+			if ($hasAsian) {
+				// size of Asian phonetic setting
+				$extendedRunLength = self::_GetInt4d($recordData, $pos);
+				$pos += 4;
+			}
+
+			// expected byte length of character array if not split
+			$len = ($isCompressed) ? $numChars : $numChars * 2;
+
+			// look up limit position
+			foreach ($spliceOffsets as $spliceOffset) {
+				// it can happen that the string is empty, therefore we need
+				// <= and not just <
+				if ($pos <= $spliceOffset) {
+					$limitpos = $spliceOffset;
+					break;
+				}
+			}
+
+			if ($pos + $len <= $limitpos) {
+				// character array is not split between records
+
+				$retstr = substr($recordData, $pos, $len);
+				$pos += $len;
+
+			} else {
+				// character array is split between records
+
+				// first part of character array
+				$retstr = substr($recordData, $pos, $limitpos - $pos);
+
+				$bytesRead = $limitpos - $pos;
+
+				// remaining characters in Unicode string
+				$charsLeft = $numChars - (($isCompressed) ? $bytesRead : ($bytesRead / 2));
+
+				$pos = $limitpos;
+
+				// keep reading the characters
+				while ($charsLeft > 0) {
+
+					// look up next limit position, in case the string span more than one continue record
+					foreach ($spliceOffsets as $spliceOffset) {
+						if ($pos < $spliceOffset) {
+							$limitpos = $spliceOffset;
+							break;
+						}
+					}
+
+					// repeated option flags
+					// OpenOffice.org documentation 5.21
+					$option = ord($recordData{$pos});
+					++$pos;
+
+					if ($isCompressed && ($option == 0)) {
+						// 1st fragment compressed
+						// this fragment compressed
+						$len = min($charsLeft, $limitpos - $pos);
+						$retstr .= substr($recordData, $pos, $len);
+						$charsLeft -= $len;
+						$isCompressed = true;
+
+					} elseif (!$isCompressed && ($option != 0)) {
+						// 1st fragment uncompressed
+						// this fragment uncompressed
+						$len = min($charsLeft * 2, $limitpos - $pos);
+						$retstr .= substr($recordData, $pos, $len);
+						$charsLeft -= $len / 2;
+						$isCompressed = false;
+
+					} elseif (!$isCompressed && ($option == 0)) {
+						// 1st fragment uncompressed
+						// this fragment compressed
+						$len = min($charsLeft, $limitpos - $pos);
+						for ($j = 0; $j < $len; ++$j) {
+							$retstr .= $recordData{$pos + $j} . chr(0);
+						}
+						$charsLeft -= $len;
+						$isCompressed = false;
+
+					} else {
+						// 1st fragment compressed
+						// this fragment uncompressed
+						$newstr = '';
+						for ($j = 0; $j < strlen($retstr); ++$j) {
+							$newstr .= $retstr[$j] . chr(0);
+						}
+						$retstr = $newstr;
+						$len = min($charsLeft * 2, $limitpos - $pos);
+						$retstr .= substr($recordData, $pos, $len);
+						$charsLeft -= $len / 2;
+						$isCompressed = false;
+					}
+
+					$pos += $len;
+				}
+			}
+
+			// convert to UTF-8
+			$retstr = self::_encodeUTF16($retstr, $isCompressed);
+
+			// read additional Rich-Text information, if any
+			$fmtRuns = array();
+			if ($hasRichText) {
+				// list of formatting runs
+				for ($j = 0; $j < $formattingRuns; ++$j) {
+					// first formatted character; zero-based
+					$charPos = self::_GetInt2d($recordData, $pos + $j * 4);
+
+					// index to font record
+					$fontIndex = self::_GetInt2d($recordData, $pos + 2 + $j * 4);
+
+					$fmtRuns[] = array(
+						'charPos' => $charPos,
+						'fontIndex' => $fontIndex,
+					);
+				}
+				$pos += 4 * $formattingRuns;
+			}
+
+			// read additional Asian phonetics information, if any
+			if ($hasAsian) {
+				// For Asian phonetic settings, we skip the extended string data
+				$pos += $extendedRunLength;
+			}
+
+			// store the shared sting
+			$this->_sst[] = array(
+				'value' => $retstr,
+				'fmtRuns' => $fmtRuns,
+			);
+		}
+
+		// _getSplicedRecordData() takes care of moving current position in data stream
+	}
+
+
+	/**
+	 * Read PRINTGRIDLINES record
+	 */
+	private function _readPrintGridlines()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
+			// offset: 0; size: 2; 0 = do not print sheet grid lines; 1 = print sheet gridlines
+			$printGridlines = (bool) self::_GetInt2d($recordData, 0);
+			$this->_phpSheet->setPrintGridlines($printGridlines);
+		}
+	}
+
+
+	/**
+	 * Read DEFAULTROWHEIGHT record
+	 */
+	private function _readDefaultRowHeight()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; option flags
+		// offset: 2; size: 2; default height for unused rows, (twips 1/20 point)
+		$height = self::_GetInt2d($recordData, 2);
+		$this->_phpSheet->getDefaultRowDimension()->setRowHeight($height / 20);
+	}
+
+
+	/**
+	 * Read SHEETPR record
+	 */
+	private function _readSheetPr()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2
+
+		// bit: 6; mask: 0x0040; 0 = outline buttons above outline group
+		$isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6;
+		$this->_phpSheet->setShowSummaryBelow($isSummaryBelow);
+
+		// bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
+		$isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7;
+		$this->_phpSheet->setShowSummaryRight($isSummaryRight);
+
+		// bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
+		// this corresponds to radio button setting in page setup dialog in Excel
+		$this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8);
+	}
+
+
+	/**
+	 * Read HORIZONTALPAGEBREAKS record
+	 */
+	private function _readHorizontalPageBreaks()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
+
+			// offset: 0; size: 2; number of the following row index structures
+			$nm = self::_GetInt2d($recordData, 0);
+
+			// offset: 2; size: 6 * $nm; list of $nm row index structures
+			for ($i = 0; $i < $nm; ++$i) {
+				$r = self::_GetInt2d($recordData, 2 + 6 * $i);
+				$cf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
+				$cl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
+
+				// not sure why two column indexes are necessary?
+				$this->_phpSheet->setBreakByColumnAndRow($cf, $r, PHPExcel_Worksheet::BREAK_ROW);
+			}
+		}
+	}
+
+
+	/**
+	 * Read VERTICALPAGEBREAKS record
+	 */
+	private function _readVerticalPageBreaks()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
+			// offset: 0; size: 2; number of the following column index structures
+			$nm = self::_GetInt2d($recordData, 0);
+
+			// offset: 2; size: 6 * $nm; list of $nm row index structures
+			for ($i = 0; $i < $nm; ++$i) {
+				$c = self::_GetInt2d($recordData, 2 + 6 * $i);
+				$rf = self::_GetInt2d($recordData, 2 + 6 * $i + 2);
+				$rl = self::_GetInt2d($recordData, 2 + 6 * $i + 4);
+
+				// not sure why two row indexes are necessary?
+				$this->_phpSheet->setBreakByColumnAndRow($c, $rf, PHPExcel_Worksheet::BREAK_COLUMN);
+			}
+		}
+	}
+
+
+	/**
+	 * Read HEADER record
+	 */
+	private function _readHeader()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: var
+			// realized that $recordData can be empty even when record exists
+			if ($recordData) {
+				if ($this->_version == self::XLS_BIFF8) {
+					$string = self::_readUnicodeStringLong($recordData);
+				} else {
+					$string = $this->_readByteStringShort($recordData);
+				}
+
+				$this->_phpSheet->getHeaderFooter()->setOddHeader($string['value']);
+				$this->_phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
+			}
+		}
+	}
+
+
+	/**
+	 * Read FOOTER record
+	 */
+	private function _readFooter()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: var
+			// realized that $recordData can be empty even when record exists
+			if ($recordData) {
+				if ($this->_version == self::XLS_BIFF8) {
+					$string = self::_readUnicodeStringLong($recordData);
+				} else {
+					$string = $this->_readByteStringShort($recordData);
+				}
+				$this->_phpSheet->getHeaderFooter()->setOddFooter($string['value']);
+				$this->_phpSheet->getHeaderFooter()->setEvenFooter($string['value']);
+			}
+		}
+	}
+
+
+	/**
+	 * Read HCENTER record
+	 */
+	private function _readHcenter()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; 0 = print sheet left aligned, 1 = print sheet centered horizontally
+			$isHorizontalCentered = (bool) self::_GetInt2d($recordData, 0);
+
+			$this->_phpSheet->getPageSetup()->setHorizontalCentered($isHorizontalCentered);
+		}
+	}
+
+
+	/**
+	 * Read VCENTER record
+	 */
+	private function _readVcenter()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; 0 = print sheet aligned at top page border, 1 = print sheet vertically centered
+			$isVerticalCentered = (bool) self::_GetInt2d($recordData, 0);
+
+			$this->_phpSheet->getPageSetup()->setVerticalCentered($isVerticalCentered);
+		}
+	}
+
+
+	/**
+	 * Read LEFTMARGIN record
+	 */
+	private function _readLeftMargin()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 8
+			$this->_phpSheet->getPageMargins()->setLeft(self::_extractNumber($recordData));
+		}
+	}
+
+
+	/**
+	 * Read RIGHTMARGIN record
+	 */
+	private function _readRightMargin()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 8
+			$this->_phpSheet->getPageMargins()->setRight(self::_extractNumber($recordData));
+		}
+	}
+
+
+	/**
+	 * Read TOPMARGIN record
+	 */
+	private function _readTopMargin()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 8
+			$this->_phpSheet->getPageMargins()->setTop(self::_extractNumber($recordData));
+		}
+	}
+
+
+	/**
+	 * Read BOTTOMMARGIN record
+	 */
+	private function _readBottomMargin()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 8
+			$this->_phpSheet->getPageMargins()->setBottom(self::_extractNumber($recordData));
+		}
+	}
+
+
+	/**
+	 * Read PAGESETUP record
+	 */
+	private function _readPageSetup()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; paper size
+			$paperSize = self::_GetInt2d($recordData, 0);
+
+			// offset: 2; size: 2; scaling factor
+			$scale = self::_GetInt2d($recordData, 2);
+
+			// offset: 6; size: 2; fit worksheet width to this number of pages, 0 = use as many as needed
+			$fitToWidth = self::_GetInt2d($recordData, 6);
+
+			// offset: 8; size: 2; fit worksheet height to this number of pages, 0 = use as many as needed
+			$fitToHeight = self::_GetInt2d($recordData, 8);
+
+			// offset: 10; size: 2; option flags
+
+				// bit: 1; mask: 0x0002; 0=landscape, 1=portrait
+				$isPortrait = (0x0002 & self::_GetInt2d($recordData, 10)) >> 1;
+
+				// bit: 2; mask: 0x0004; 1= paper size, scaling factor, paper orient. not init
+				// when this bit is set, do not use flags for those properties
+				$isNotInit = (0x0004 & self::_GetInt2d($recordData, 10)) >> 2;
+
+			if (!$isNotInit) {
+				$this->_phpSheet->getPageSetup()->setPaperSize($paperSize);
+				switch ($isPortrait) {
+				case 0: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_LANDSCAPE); break;
+				case 1: $this->_phpSheet->getPageSetup()->setOrientation(PHPExcel_Worksheet_PageSetup::ORIENTATION_PORTRAIT); break;
+				}
+
+				$this->_phpSheet->getPageSetup()->setScale($scale, false);
+				$this->_phpSheet->getPageSetup()->setFitToPage((bool) $this->_isFitToPages);
+				$this->_phpSheet->getPageSetup()->setFitToWidth($fitToWidth, false);
+				$this->_phpSheet->getPageSetup()->setFitToHeight($fitToHeight, false);
+			}
+
+			// offset: 16; size: 8; header margin (IEEE 754 floating-point value)
+			$marginHeader = self::_extractNumber(substr($recordData, 16, 8));
+			$this->_phpSheet->getPageMargins()->setHeader($marginHeader);
+
+			// offset: 24; size: 8; footer margin (IEEE 754 floating-point value)
+			$marginFooter = self::_extractNumber(substr($recordData, 24, 8));
+			$this->_phpSheet->getPageMargins()->setFooter($marginFooter);
+		}
+	}
+
+
+	/**
+	 * PROTECT - Sheet protection (BIFF2 through BIFF8)
+	 *   if this record is omitted, then it also means no sheet protection
+	 */
+	private function _readProtect()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		// offset: 0; size: 2;
+
+		// bit 0, mask 0x01; 1 = sheet is protected
+		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
+		$this->_phpSheet->getProtection()->setSheet((bool)$bool);
+	}
+
+
+	/**
+	 * SCENPROTECT
+	 */
+	private function _readScenProtect()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		// offset: 0; size: 2;
+
+		// bit: 0, mask 0x01; 1 = scenarios are protected
+		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
+
+		$this->_phpSheet->getProtection()->setScenarios((bool)$bool);
+	}
+
+
+	/**
+	 * OBJECTPROTECT
+	 */
+	private function _readObjectProtect()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		// offset: 0; size: 2;
+
+		// bit: 0, mask 0x01; 1 = objects are protected
+		$bool = (0x01 & self::_GetInt2d($recordData, 0)) >> 0;
+
+		$this->_phpSheet->getProtection()->setObjects((bool)$bool);
+	}
+
+
+	/**
+	 * PASSWORD - Sheet protection (hashed) password (BIFF2 through BIFF8)
+	 */
+	private function _readPassword()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; 16-bit hash value of password
+			$password = strtoupper(dechex(self::_GetInt2d($recordData, 0))); // the hashed password
+			$this->_phpSheet->getProtection()->setPassword($password, true);
+		}
+	}
+
+
+	/**
+	 * Read DEFCOLWIDTH record
+	 */
+	private function _readDefColWidth()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; default column width
+		$width = self::_GetInt2d($recordData, 0);
+		if ($width != 8) {
+			$this->_phpSheet->getDefaultColumnDimension()->setWidth($width);
+		}
+	}
+
+
+	/**
+	 * Read COLINFO record
+	 */
+	private function _readColInfo()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; index to first column in range
+			$fc = self::_GetInt2d($recordData, 0); // first column index
+
+			// offset: 2; size: 2; index to last column in range
+			$lc = self::_GetInt2d($recordData, 2); // first column index
+
+			// offset: 4; size: 2; width of the column in 1/256 of the width of the zero character
+			$width = self::_GetInt2d($recordData, 4);
+
+			// offset: 6; size: 2; index to XF record for default column formatting
+			$xfIndex = self::_GetInt2d($recordData, 6);
+
+			// offset: 8; size: 2; option flags
+
+				// bit: 0; mask: 0x0001; 1= columns are hidden
+				$isHidden = (0x0001 & self::_GetInt2d($recordData, 8)) >> 0;
+
+				// bit: 10-8; mask: 0x0700; outline level of the columns (0 = no outline)
+				$level = (0x0700 & self::_GetInt2d($recordData, 8)) >> 8;
+
+				// bit: 12; mask: 0x1000; 1 = collapsed
+				$isCollapsed = (0x1000 & self::_GetInt2d($recordData, 8)) >> 12;
+
+			// offset: 10; size: 2; not used
+
+			for ($i = $fc; $i <= $lc; ++$i) {
+				if ($lc == 255 || $lc == 256) {
+					$this->_phpSheet->getDefaultColumnDimension()->setWidth($width / 256);
+					break;
+				}
+				$this->_phpSheet->getColumnDimensionByColumn($i)->setWidth($width / 256);
+				$this->_phpSheet->getColumnDimensionByColumn($i)->setVisible(!$isHidden);
+				$this->_phpSheet->getColumnDimensionByColumn($i)->setOutlineLevel($level);
+				$this->_phpSheet->getColumnDimensionByColumn($i)->setCollapsed($isCollapsed);
+				$this->_phpSheet->getColumnDimensionByColumn($i)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+		}
+	}
+
+
+	/**
+	 * ROW
+	 *
+	 * This record contains the properties of a single row in a
+	 * sheet. Rows and cells in a sheet are divided into blocks
+	 * of 32 rows.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readRow()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; index of this row
+			$r = self::_GetInt2d($recordData, 0);
+
+			// offset: 2; size: 2; index to column of the first cell which is described by a cell record
+
+			// offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1
+
+			// offset: 6; size: 2;
+
+			// bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
+			$height = (0x7FFF & self::_GetInt2d($recordData, 6)) >> 0;
+
+			// bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
+			$useDefaultHeight = (0x8000 & self::_GetInt2d($recordData, 6)) >> 15;
+
+			if (!$useDefaultHeight) {
+				$this->_phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
+			}
+
+			// offset: 8; size: 2; not used
+
+			// offset: 10; size: 2; not used in BIFF5-BIFF8
+
+			// offset: 12; size: 4; option flags and default row formatting
+
+			// bit: 2-0: mask: 0x00000007; outline level of the row
+			$level = (0x00000007 & self::_GetInt4d($recordData, 12)) >> 0;
+			$this->_phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);
+
+			// bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
+			$isCollapsed = (0x00000010 & self::_GetInt4d($recordData, 12)) >> 4;
+			$this->_phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);
+
+			// bit: 5; mask: 0x00000020; 1 = row is hidden
+			$isHidden = (0x00000020 & self::_GetInt4d($recordData, 12)) >> 5;
+			$this->_phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);
+
+			// bit: 7; mask: 0x00000080; 1 = row has explicit format
+			$hasExplicitFormat = (0x00000080 & self::_GetInt4d($recordData, 12)) >> 7;
+
+			// bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
+			$xfIndex = (0x0FFF0000 & self::_GetInt4d($recordData, 12)) >> 16;
+
+			if ($hasExplicitFormat) {
+				$this->_phpSheet->getRowDimension($r + 1)->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+		}
+	}
+
+
+	/**
+	 * Read RK record
+	 * This record represents a cell that contains an RK value
+	 * (encoded integer or floating-point value). If a
+	 * floating-point value cannot be encoded to an RK value,
+	 * a NUMBER record will be written. This record replaces the
+	 * record INTEGER written in BIFF2.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readRk()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; index to row
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; index to column
+		$column = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+			// offset: 4; size: 2; index to XF record
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			// offset: 6; size: 4; RK value
+			$rknum = self::_GetInt4d($recordData, 6);
+			$numValue = self::_GetIEEE754($rknum);
+
+			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+			if (!$this->_readDataOnly) {
+				// add style information
+				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+
+			// add cell
+			$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+		}
+	}
+
+
+	/**
+	 * Read LABELSST record
+	 * This record represents a cell that contains a string. It
+	 * replaces the LABEL record and RSTRING record used in
+	 * BIFF2-BIFF5.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readLabelSst()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; index to row
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; index to column
+		$column = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+			// offset: 4; size: 2; index to XF record
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			// offset: 6; size: 4; index to SST record
+			$index = self::_GetInt4d($recordData, 6);
+
+			// add cell
+			if (($fmtRuns = $this->_sst[$index]['fmtRuns']) && !$this->_readDataOnly) {
+				// then we should treat as rich text
+				$richText = new PHPExcel_RichText();
+				$charPos = 0;
+				$sstCount = count($this->_sst[$index]['fmtRuns']);
+				for ($i = 0; $i <= $sstCount; ++$i) {
+					if (isset($fmtRuns[$i])) {
+						$text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, $fmtRuns[$i]['charPos'] - $charPos);
+						$charPos = $fmtRuns[$i]['charPos'];
+					} else {
+						$text = PHPExcel_Shared_String::Substring($this->_sst[$index]['value'], $charPos, PHPExcel_Shared_String::CountCharacters($this->_sst[$index]['value']));
+					}
+
+					if (PHPExcel_Shared_String::CountCharacters($text) > 0) {
+						if ($i == 0) { // first text run, no style
+							$richText->createText($text);
+						} else {
+							$textRun = $richText->createTextRun($text);
+							if (isset($fmtRuns[$i - 1])) {
+								if ($fmtRuns[$i - 1]['fontIndex'] < 4) {
+									$fontIndex = $fmtRuns[$i - 1]['fontIndex'];
+								} else {
+									// this has to do with that index 4 is omitted in all BIFF versions for some strange reason
+									// check the OpenOffice documentation of the FONT record
+									$fontIndex = $fmtRuns[$i - 1]['fontIndex'] - 1;
+								}
+								$textRun->setFont(clone $this->_objFonts[$fontIndex]);
+							}
+						}
+					}
+				}
+				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+				$cell->setValueExplicit($richText, PHPExcel_Cell_DataType::TYPE_STRING);
+			} else {
+				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+				$cell->setValueExplicit($this->_sst[$index]['value'], PHPExcel_Cell_DataType::TYPE_STRING);
+			}
+
+			if (!$this->_readDataOnly) {
+				// add style information
+				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+		}
+	}
+
+
+	/**
+	 * Read MULRK record
+	 * This record represents a cell range containing RK value
+	 * cells. All cells are located in the same row.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readMulRk()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; index to row
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; index to first column
+		$colFirst = self::_GetInt2d($recordData, 2);
+
+		// offset: var; size: 2; index to last column
+		$colLast = self::_GetInt2d($recordData, $length - 2);
+		$columns = $colLast - $colFirst + 1;
+
+		// offset within record data
+		$offset = 4;
+
+		for ($i = 0; $i < $columns; ++$i) {
+			$columnString = PHPExcel_Cell::stringFromColumnIndex($colFirst + $i);
+
+			// Read cell?
+			if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+
+				// offset: var; size: 2; index to XF record
+				$xfIndex = self::_GetInt2d($recordData, $offset);
+
+				// offset: var; size: 4; RK value
+				$numValue = self::_GetIEEE754(self::_GetInt4d($recordData, $offset + 2));
+				$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+				if (!$this->_readDataOnly) {
+					// add style
+					$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+				}
+
+				// add cell value
+				$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+			}
+
+			$offset += 6;
+		}
+	}
+
+
+	/**
+	 * Read NUMBER record
+	 * This record represents a cell that contains a
+	 * floating-point value.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readNumber()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; index to row
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size 2; index to column
+		$column = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+			// offset 4; size: 2; index to XF record
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			$numValue = self::_extractNumber(substr($recordData, 6, 8));
+
+			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+			if (!$this->_readDataOnly) {
+				// add cell style
+				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+
+			// add cell value
+			$cell->setValueExplicit($numValue, PHPExcel_Cell_DataType::TYPE_NUMERIC);
+		}
+	}
+
+
+	/**
+	 * Read FORMULA record + perhaps a following STRING record if formula result is a string
+	 * This record contains the token array and the result of a
+	 * formula cell.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readFormula()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; row index
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; col index
+		$column = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+		// offset: 20: size: variable; formula structure
+		$formulaStructure = substr($recordData, 20);
+
+		// offset: 14: size: 2; option flags, recalculate always, recalculate on open etc.
+		$options = self::_GetInt2d($recordData, 14);
+
+		// bit: 0; mask: 0x0001; 1 = recalculate always
+		// bit: 1; mask: 0x0002; 1 = calculate on open
+		// bit: 2; mask: 0x0008; 1 = part of a shared formula
+		$isPartOfSharedFormula = (bool) (0x0008 & $options);
+
+		// WARNING:
+		// We can apparently not rely on $isPartOfSharedFormula. Even when $isPartOfSharedFormula = true
+		// the formula data may be ordinary formula data, therefore we need to check
+		// explicitly for the tExp token (0x01)
+		$isPartOfSharedFormula = $isPartOfSharedFormula && ord($formulaStructure{2}) == 0x01;
+
+		if ($isPartOfSharedFormula) {
+			// part of shared formula which means there will be a formula with a tExp token and nothing else
+			// get the base cell, grab tExp token
+			$baseRow = self::_GetInt2d($formulaStructure, 3);
+			$baseCol = self::_GetInt2d($formulaStructure, 5);
+			$this->_baseCell = PHPExcel_Cell::stringFromColumnIndex($baseCol). ($baseRow + 1);
+		}
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+
+			if ($isPartOfSharedFormula) {
+				// formula is added to this cell after the sheet has been read
+				$this->_sharedFormulaParts[$columnString . ($row + 1)] = $this->_baseCell;
+			}
+
+			// offset: 16: size: 4; not used
+
+			// offset: 4; size: 2; XF index
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			// offset: 6; size: 8; result of the formula
+			if ( (ord($recordData{6}) == 0)
+				&& (ord($recordData{12}) == 255)
+				&& (ord($recordData{13}) == 255) ) {
+
+				// String formula. Result follows in appended STRING record
+				$dataType = PHPExcel_Cell_DataType::TYPE_STRING;
+
+				// read possible SHAREDFMLA record
+				$code = self::_GetInt2d($this->_data, $this->_pos);
+				if ($code == self::XLS_Type_SHAREDFMLA) {
+					$this->_readSharedFmla();
+				}
+
+				// read STRING record
+				$value = $this->_readString();
+
+			} elseif ((ord($recordData{6}) == 1)
+				&& (ord($recordData{12}) == 255)
+				&& (ord($recordData{13}) == 255)) {
+
+				// Boolean formula. Result is in +2; 0=false, 1=true
+				$dataType = PHPExcel_Cell_DataType::TYPE_BOOL;
+				$value = (bool) ord($recordData{8});
+
+			} elseif ((ord($recordData{6}) == 2)
+				&& (ord($recordData{12}) == 255)
+				&& (ord($recordData{13}) == 255)) {
+
+				// Error formula. Error code is in +2
+				$dataType = PHPExcel_Cell_DataType::TYPE_ERROR;
+				$value = self::_mapErrorCode(ord($recordData{8}));
+
+			} elseif ((ord($recordData{6}) == 3)
+				&& (ord($recordData{12}) == 255)
+				&& (ord($recordData{13}) == 255)) {
+
+				// Formula result is a null string
+				$dataType = PHPExcel_Cell_DataType::TYPE_NULL;
+				$value = '';
+
+			} else {
+
+				// forumla result is a number, first 14 bytes like _NUMBER record
+				$dataType = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+				$value = self::_extractNumber(substr($recordData, 6, 8));
+
+			}
+
+			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+			if (!$this->_readDataOnly) {
+				// add cell style
+				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+
+			// store the formula
+			if (!$isPartOfSharedFormula) {
+				// not part of shared formula
+				// add cell value. If we can read formula, populate with formula, otherwise just used cached value
+				try {
+					if ($this->_version != self::XLS_BIFF8) {
+						throw new Exception('Not BIFF8. Can only read BIFF8 formulas');
+					}
+					$formula = $this->_getFormulaFromStructure($formulaStructure); // get formula in human language
+					$cell->setValueExplicit('=' . $formula, PHPExcel_Cell_DataType::TYPE_FORMULA);
+
+				} catch (Exception $e) {
+					$cell->setValueExplicit($value, $dataType);
+				}
+			} else {
+				if ($this->_version == self::XLS_BIFF8) {
+					// do nothing at this point, formula id added later in the code
+				} else {
+					$cell->setValueExplicit($value, $dataType);
+				}
+			}
+
+			// store the cached calculated value
+			$cell->setCalculatedValue($value);
+		}
+	}
+
+
+	/**
+	 * Read a SHAREDFMLA record. This function just stores the binary shared formula in the reader,
+	 * which usually contains relative references.
+	 * These will be used to construct the formula in each shared formula part after the sheet is read.
+	 */
+	private function _readSharedFmla()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0, size: 6; cell range address of the area used by the shared formula, not used for anything
+		$cellRange = substr($recordData, 0, 6);
+		$cellRange = $this->_readBIFF5CellRangeAddressFixed($cellRange); // note: even BIFF8 uses BIFF5 syntax
+
+		// offset: 6, size: 1; not used
+
+		// offset: 7, size: 1; number of existing FORMULA records for this shared formula
+		$no = ord($recordData{7});
+
+		// offset: 8, size: var; Binary token array of the shared formula
+		$formula = substr($recordData, 8);
+
+		// at this point we only store the shared formula for later use
+		$this->_sharedFormulas[$this->_baseCell] = $formula;
+
+	}
+
+
+	/**
+	 * Read a STRING record from current stream position and advance the stream pointer to next record
+	 * This record is used for storing result from FORMULA record when it is a string, and
+	 * it occurs directly after the FORMULA record
+	 *
+	 * @return string The string contents as UTF-8
+	 */
+	private function _readString()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_version == self::XLS_BIFF8) {
+			$string = self::_readUnicodeStringLong($recordData);
+			$value = $string['value'];
+		} else {
+			$string = $this->_readByteStringLong($recordData);
+			$value = $string['value'];
+		}
+
+		return $value;
+	}
+
+
+	/**
+	 * Read BOOLERR record
+	 * This record represents a Boolean value or error value
+	 * cell.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readBoolErr()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; row index
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; column index
+		$column = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+			// offset: 4; size: 2; index to XF record
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			// offset: 6; size: 1; the boolean value or error value
+			$boolErr = ord($recordData{6});
+
+			// offset: 7; size: 1; 0=boolean; 1=error
+			$isError = ord($recordData{7});
+
+			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+			switch ($isError) {
+				case 0: // boolean
+					$value = (bool) $boolErr;
+
+					// add cell value
+					$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_BOOL);
+					break;
+
+				case 1: // error type
+					$value = self::_mapErrorCode($boolErr);
+
+					// add cell value
+					$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_ERROR);
+					break;
+			}
+
+			if (!$this->_readDataOnly) {
+				// add cell style
+				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+		}
+	}
+
+
+	/**
+	 * Read MULBLANK record
+	 * This record represents a cell range of empty cells. All
+	 * cells are located in the same row
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readMulBlank()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; index to row
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; index to first column
+		$fc = self::_GetInt2d($recordData, 2);
+
+		// offset: 4; size: 2 x nc; list of indexes to XF records
+		// add style information
+		if (!$this->_readDataOnly) {
+			for ($i = 0; $i < $length / 2 - 3; ++$i) {
+				$columnString = PHPExcel_Cell::stringFromColumnIndex($fc + $i);
+
+				// Read cell?
+				if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+					$xfIndex = self::_GetInt2d($recordData, 4 + 2 * $i);
+					$this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+				}
+			}
+		}
+
+		// offset: 6; size 2; index to last column (not needed)
+	}
+
+
+	/**
+	 * Read LABEL record
+	 * This record represents a cell that contains a string. In
+	 * BIFF8 it is usually replaced by the LABELSST record.
+	 * Excel still uses this record, if it copies unformatted
+	 * text cells to the clipboard.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readLabel()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; index to row
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; index to column
+		$column = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($column);
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+			// offset: 4; size: 2; XF index
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			// add cell value
+			// todo: what if string is very long? continue record
+			if ($this->_version == self::XLS_BIFF8) {
+				$string = self::_readUnicodeStringLong(substr($recordData, 6));
+				$value = $string['value'];
+			} else {
+				$string = $this->_readByteStringLong(substr($recordData, 6));
+				$value = $string['value'];
+			}
+			$cell = $this->_phpSheet->getCell($columnString . ($row + 1));
+			$cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_STRING);
+
+			if (!$this->_readDataOnly) {
+				// add cell style
+				$cell->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+		}
+	}
+
+
+	/**
+	 * Read BLANK record
+	 */
+	private function _readBlank()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; row index
+		$row = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; col index
+		$col = self::_GetInt2d($recordData, 2);
+		$columnString = PHPExcel_Cell::stringFromColumnIndex($col);
+
+		// Read cell?
+		if (($this->getReadFilter() !== NULL) && $this->getReadFilter()->readCell($columnString, $row + 1, $this->_phpSheet->getTitle()) ) {
+			// offset: 4; size: 2; XF index
+			$xfIndex = self::_GetInt2d($recordData, 4);
+
+			// add style information
+			if (!$this->_readDataOnly) {
+				$this->_phpSheet->getCell($columnString . ($row + 1))->setXfIndex($this->_mapCellXfIndex[$xfIndex]);
+			}
+		}
+
+	}
+
+
+	/**
+	 * Read MSODRAWING record
+	 */
+	private function _readMsoDrawing()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+
+		// get spliced record data
+		$splicedRecordData = $this->_getSplicedRecordData();
+		$recordData = $splicedRecordData['recordData'];
+
+		$this->_drawingData .= $recordData;
+	}
+
+
+	/**
+	 * Read OBJ record
+	 */
+	private function _readObj()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly || $this->_version != self::XLS_BIFF8) {
+			return;
+		}
+
+		// recordData consists of an array of subrecords looking like this:
+		//	ft: 2 bytes; ftCmo type (0x15)
+		//	cb: 2 bytes; size in bytes of ftCmo data
+		//	ot: 2 bytes; Object Type
+		//	id: 2 bytes; Object id number
+		//	grbit: 2 bytes; Option Flags
+		//	data: var; subrecord data
+
+		// for now, we are just interested in the second subrecord containing the object type
+		$ftCmoType	= self::_GetInt2d($recordData, 0);
+		$cbCmoSize	= self::_GetInt2d($recordData, 2);
+		$otObjType	= self::_GetInt2d($recordData, 4);
+		$idObjID	= self::_GetInt2d($recordData, 6);
+		$grbitOpts	= self::_GetInt2d($recordData, 6);
+
+		$this->_objs[] = array(
+			'ftCmoType'	=> $ftCmoType,
+			'cbCmoSize'	=> $cbCmoSize,
+			'otObjType'	=> $otObjType,
+			'idObjID'	=> $idObjID,
+			'grbitOpts'	=> $grbitOpts
+		);
+		$this->textObjRef = $idObjID;
+
+//		echo '<b>_readObj()</b><br />';
+//		var_dump(end($this->_objs));
+//		echo '<br />';
+	}
+
+
+	/**
+	 * Read WINDOW2 record
+	 */
+	private function _readWindow2()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; option flags
+		$options = self::_GetInt2d($recordData, 0);
+
+		// bit: 1; mask: 0x0002; 0 = do not show gridlines, 1 = show gridlines
+		$showGridlines = (bool) ((0x0002 & $options) >> 1);
+		$this->_phpSheet->setShowGridlines($showGridlines);
+
+		// bit: 2; mask: 0x0004; 0 = do not show headers, 1 = show headers
+		$showRowColHeaders = (bool) ((0x0004 & $options) >> 2);
+		$this->_phpSheet->setShowRowColHeaders($showRowColHeaders);
+
+		// bit: 3; mask: 0x0008; 0 = panes are not frozen, 1 = panes are frozen
+		$this->_frozen = (bool) ((0x0008 & $options) >> 3);
+
+		// bit: 6; mask: 0x0040; 0 = columns from left to right, 1 = columns from right to left
+		$this->_phpSheet->setRightToLeft((bool)((0x0040 & $options) >> 6));
+
+		// bit: 10; mask: 0x0400; 0 = sheet not active, 1 = sheet active
+		$isActive = (bool) ((0x0400 & $options) >> 10);
+		if ($isActive) {
+			$this->_phpExcel->setActiveSheetIndex($this->_phpExcel->getIndex($this->_phpSheet));
+		}
+	}
+
+
+	/**
+	 * Read SCL record
+	 */
+	private function _readScl()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// offset: 0; size: 2; numerator of the view magnification
+		$numerator = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; numerator of the view magnification
+		$denumerator = self::_GetInt2d($recordData, 2);
+
+		// set the zoom scale (in percent)
+		$this->_phpSheet->getSheetView()->setZoomScale($numerator * 100 / $denumerator);
+	}
+
+
+	/**
+	 * Read PANE record
+	 */
+	private function _readPane()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; position of vertical split
+			$px = self::_GetInt2d($recordData, 0);
+
+			// offset: 2; size: 2; position of horizontal split
+			$py = self::_GetInt2d($recordData, 2);
+
+			if ($this->_frozen) {
+				// frozen panes
+				$this->_phpSheet->freezePane(PHPExcel_Cell::stringFromColumnIndex($px) . ($py + 1));
+			} else {
+				// unfrozen panes; split windows; not supported by PHPExcel core
+			}
+		}
+	}
+
+
+	/**
+	 * Read SELECTION record. There is one such record for each pane in the sheet.
+	 */
+	private function _readSelection()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 1; pane identifier
+			$paneId = ord($recordData{0});
+
+			// offset: 1; size: 2; index to row of the active cell
+			$r = self::_GetInt2d($recordData, 1);
+
+			// offset: 3; size: 2; index to column of the active cell
+			$c = self::_GetInt2d($recordData, 3);
+
+			// offset: 5; size: 2; index into the following cell range list to the
+			//  entry that contains the active cell
+			$index = self::_GetInt2d($recordData, 5);
+
+			// offset: 7; size: var; cell range address list containing all selected cell ranges
+			$data = substr($recordData, 7);
+			$cellRangeAddressList = $this->_readBIFF5CellRangeAddressList($data); // note: also BIFF8 uses BIFF5 syntax
+
+			$selectedCells = $cellRangeAddressList['cellRangeAddresses'][0];
+
+			// first row '1' + last row '16384' indicates that full column is selected (apparently also in BIFF8!)
+			if (preg_match('/^([A-Z]+1\:[A-Z]+)16384$/', $selectedCells)) {
+				$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)16384$/', '${1}1048576', $selectedCells);
+			}
+
+			// first row '1' + last row '65536' indicates that full column is selected
+			if (preg_match('/^([A-Z]+1\:[A-Z]+)65536$/', $selectedCells)) {
+				$selectedCells = preg_replace('/^([A-Z]+1\:[A-Z]+)65536$/', '${1}1048576', $selectedCells);
+			}
+
+			// first column 'A' + last column 'IV' indicates that full row is selected
+			if (preg_match('/^(A[0-9]+\:)IV([0-9]+)$/', $selectedCells)) {
+				$selectedCells = preg_replace('/^(A[0-9]+\:)IV([0-9]+)$/', '${1}XFD${2}', $selectedCells);
+			}
+
+			$this->_phpSheet->setSelectedCells($selectedCells);
+		}
+	}
+
+
+	private function _includeCellRangeFiltered($cellRangeAddress)
+	{
+		$includeCellRange = true;
+		if ($this->getReadFilter() !== NULL) {
+			$includeCellRange = false;
+			$rangeBoundaries = PHPExcel_Cell::getRangeBoundaries($cellRangeAddress);
+			$rangeBoundaries[1][0]++;
+			for ($row = $rangeBoundaries[0][1]; $row <= $rangeBoundaries[1][1]; $row++) {
+				for ($column = $rangeBoundaries[0][0]; $column != $rangeBoundaries[1][0]; $column++) {
+					if ($this->getReadFilter()->readCell($column, $row, $this->_phpSheet->getTitle())) {
+						$includeCellRange = true;
+						break 2;
+					}
+				}
+			}
+		}
+		return $includeCellRange;
+	}
+
+
+	/**
+	 * MERGEDCELLS
+	 *
+	 * This record contains the addresses of merged cell ranges
+	 * in the current sheet.
+	 *
+	 * --	"OpenOffice.org's Documentation of the Microsoft
+	 * 		Excel File Format"
+	 */
+	private function _readMergedCells()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_version == self::XLS_BIFF8 && !$this->_readDataOnly) {
+			$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($recordData);
+			foreach ($cellRangeAddressList['cellRangeAddresses'] as $cellRangeAddress) {
+				if ((strpos($cellRangeAddress,':') !== FALSE) &&
+					($this->_includeCellRangeFiltered($cellRangeAddress))) {
+					$this->_phpSheet->mergeCells($cellRangeAddress);
+				}
+			}
+		}
+	}
+
+
+	/**
+	 * Read HYPERLINK record
+	 */
+	private function _readHyperLink()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer forward to next record
+		$this->_pos += 4 + $length;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 8; cell range address of all cells containing this hyperlink
+			try {
+				$cellRange = $this->_readBIFF8CellRangeAddressFixed($recordData, 0, 8);
+			} catch (Exception $e) {
+				return;
+			}
+
+			// offset: 8, size: 16; GUID of StdLink
+
+			// offset: 24, size: 4; unknown value
+
+			// offset: 28, size: 4; option flags
+
+				// bit: 0; mask: 0x00000001; 0 = no link or extant, 1 = file link or URL
+				$isFileLinkOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 0;
+
+				// bit: 1; mask: 0x00000002; 0 = relative path, 1 = absolute path or URL
+				$isAbsPathOrUrl = (0x00000001 & self::_GetInt2d($recordData, 28)) >> 1;
+
+				// bit: 2 (and 4); mask: 0x00000014; 0 = no description
+				$hasDesc = (0x00000014 & self::_GetInt2d($recordData, 28)) >> 2;
+
+				// bit: 3; mask: 0x00000008; 0 = no text, 1 = has text
+				$hasText = (0x00000008 & self::_GetInt2d($recordData, 28)) >> 3;
+
+				// bit: 7; mask: 0x00000080; 0 = no target frame, 1 = has target frame
+				$hasFrame = (0x00000080 & self::_GetInt2d($recordData, 28)) >> 7;
+
+				// bit: 8; mask: 0x00000100; 0 = file link or URL, 1 = UNC path (inc. server name)
+				$isUNC = (0x00000100 & self::_GetInt2d($recordData, 28)) >> 8;
+
+			// offset within record data
+			$offset = 32;
+
+			if ($hasDesc) {
+				// offset: 32; size: var; character count of description text
+				$dl = self::_GetInt4d($recordData, 32);
+				// offset: 36; size: var; character array of description text, no Unicode string header, always 16-bit characters, zero terminated
+				$desc = self::_encodeUTF16(substr($recordData, 36, 2 * ($dl - 1)), false);
+				$offset += 4 + 2 * $dl;
+			}
+			if ($hasFrame) {
+				$fl = self::_GetInt4d($recordData, $offset);
+				$offset += 4 + 2 * $fl;
+			}
+
+			// detect type of hyperlink (there are 4 types)
+			$hyperlinkType = null;
+
+			if ($isUNC) {
+				$hyperlinkType = 'UNC';
+			} else if (!$isFileLinkOrUrl) {
+				$hyperlinkType = 'workbook';
+			} else if (ord($recordData{$offset}) == 0x03) {
+				$hyperlinkType = 'local';
+			} else if (ord($recordData{$offset}) == 0xE0) {
+				$hyperlinkType = 'URL';
+			}
+
+			switch ($hyperlinkType) {
+			case 'URL':
+				// section 5.58.2: Hyperlink containing a URL
+				// e.g. http://example.org/index.php
+
+				// offset: var; size: 16; GUID of URL Moniker
+				$offset += 16;
+				// offset: var; size: 4; size (in bytes) of character array of the URL including trailing zero word
+				$us = self::_GetInt4d($recordData, $offset);
+				$offset += 4;
+				// offset: var; size: $us; character array of the URL, no Unicode string header, always 16-bit characters, zero-terminated
+				$url = self::_encodeUTF16(substr($recordData, $offset, $us - 2), false);
+				$url .= $hasText ? '#' : '';
+				$offset += $us;
+				break;
+
+			case 'local':
+				// section 5.58.3: Hyperlink to local file
+				// examples:
+				//   mydoc.txt
+				//   ../../somedoc.xls#Sheet!A1
+
+				// offset: var; size: 16; GUI of File Moniker
+				$offset += 16;
+
+				// offset: var; size: 2; directory up-level count.
+				$upLevelCount = self::_GetInt2d($recordData, $offset);
+				$offset += 2;
+
+				// offset: var; size: 4; character count of the shortened file path and name, including trailing zero word
+				$sl = self::_GetInt4d($recordData, $offset);
+				$offset += 4;
+
+				// offset: var; size: sl; character array of the shortened file path and name in 8.3-DOS-format (compressed Unicode string)
+				$shortenedFilePath = substr($recordData, $offset, $sl);
+				$shortenedFilePath = self::_encodeUTF16($shortenedFilePath, true);
+				$shortenedFilePath = substr($shortenedFilePath, 0, -1); // remove trailing zero
+
+				$offset += $sl;
+
+				// offset: var; size: 24; unknown sequence
+				$offset += 24;
+
+				// extended file path
+				// offset: var; size: 4; size of the following file link field including string lenth mark
+				$sz = self::_GetInt4d($recordData, $offset);
+				$offset += 4;
+
+				// only present if $sz > 0
+				if ($sz > 0) {
+					// offset: var; size: 4; size of the character array of the extended file path and name
+					$xl = self::_GetInt4d($recordData, $offset);
+					$offset += 4;
+
+					// offset: var; size 2; unknown
+					$offset += 2;
+
+					// offset: var; size $xl; character array of the extended file path and name.
+					$extendedFilePath = substr($recordData, $offset, $xl);
+					$extendedFilePath = self::_encodeUTF16($extendedFilePath, false);
+					$offset += $xl;
+				}
+
+				// construct the path
+				$url = str_repeat('..\\', $upLevelCount);
+				$url .= ($sz > 0) ?
+					$extendedFilePath : $shortenedFilePath; // use extended path if available
+				$url .= $hasText ? '#' : '';
+
+				break;
+
+
+			case 'UNC':
+				// section 5.58.4: Hyperlink to a File with UNC (Universal Naming Convention) Path
+				// todo: implement
+				return;
+
+			case 'workbook':
+				// section 5.58.5: Hyperlink to the Current Workbook
+				// e.g. Sheet2!B1:C2, stored in text mark field
+				$url = 'sheet://';
+				break;
+
+			default:
+				return;
+
+			}
+
+			if ($hasText) {
+				// offset: var; size: 4; character count of text mark including trailing zero word
+				$tl = self::_GetInt4d($recordData, $offset);
+				$offset += 4;
+				// offset: var; size: var; character array of the text mark without the # sign, no Unicode header, always 16-bit characters, zero-terminated
+				$text = self::_encodeUTF16(substr($recordData, $offset, 2 * ($tl - 1)), false);
+				$url .= $text;
+			}
+
+			// apply the hyperlink to all the relevant cells
+			foreach (PHPExcel_Cell::extractAllCellReferencesInRange($cellRange) as $coordinate) {
+				$this->_phpSheet->getCell($coordinate)->getHyperLink()->setUrl($url);
+			}
+		}
+	}
+
+
+	/**
+	 * Read DATAVALIDATIONS record
+	 */
+	private function _readDataValidations()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer forward to next record
+		$this->_pos += 4 + $length;
+	}
+
+
+	/**
+	 * Read DATAVALIDATION record
+	 */
+	private function _readDataValidation()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer forward to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		// offset: 0; size: 4; Options
+		$options = self::_GetInt4d($recordData, 0);
+
+		// bit: 0-3; mask: 0x0000000F; type
+		$type = (0x0000000F & $options) >> 0;
+		switch ($type) {
+			case 0x00:	$type = PHPExcel_Cell_DataValidation::TYPE_NONE;		break;
+			case 0x01:	$type = PHPExcel_Cell_DataValidation::TYPE_WHOLE;		break;
+			case 0x02:	$type = PHPExcel_Cell_DataValidation::TYPE_DECIMAL;		break;
+			case 0x03:	$type = PHPExcel_Cell_DataValidation::TYPE_LIST;		break;
+			case 0x04:	$type = PHPExcel_Cell_DataValidation::TYPE_DATE;		break;
+			case 0x05:	$type = PHPExcel_Cell_DataValidation::TYPE_TIME;		break;
+			case 0x06:	$type = PHPExcel_Cell_DataValidation::TYPE_TEXTLENGTH;	break;
+			case 0x07:	$type = PHPExcel_Cell_DataValidation::TYPE_CUSTOM;		break;
+		}
+
+		// bit: 4-6; mask: 0x00000070; error type
+		$errorStyle = (0x00000070 & $options) >> 4;
+		switch ($errorStyle) {
+			case 0x00:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_STOP;			break;
+			case 0x01:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_WARNING;		break;
+			case 0x02:	$errorStyle = PHPExcel_Cell_DataValidation::STYLE_INFORMATION;	break;
+		}
+
+		// bit: 7; mask: 0x00000080; 1= formula is explicit (only applies to list)
+		// I have only seen cases where this is 1
+		$explicitFormula = (0x00000080 & $options) >> 7;
+
+		// bit: 8; mask: 0x00000100; 1= empty cells allowed
+		$allowBlank = (0x00000100 & $options) >> 8;
+
+		// bit: 9; mask: 0x00000200; 1= suppress drop down arrow in list type validity
+		$suppressDropDown = (0x00000200 & $options) >> 9;
+
+		// bit: 18; mask: 0x00040000; 1= show prompt box if cell selected
+		$showInputMessage = (0x00040000 & $options) >> 18;
+
+		// bit: 19; mask: 0x00080000; 1= show error box if invalid values entered
+		$showErrorMessage = (0x00080000 & $options) >> 19;
+
+		// bit: 20-23; mask: 0x00F00000; condition operator
+		$operator = (0x00F00000 & $options) >> 20;
+		switch ($operator) {
+			case 0x00: $operator = PHPExcel_Cell_DataValidation::OPERATOR_BETWEEN			;	break;
+			case 0x01: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTBETWEEN		;	break;
+			case 0x02: $operator = PHPExcel_Cell_DataValidation::OPERATOR_EQUAL				;	break;
+			case 0x03: $operator = PHPExcel_Cell_DataValidation::OPERATOR_NOTEQUAL			;	break;
+			case 0x04: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHAN		;	break;
+			case 0x05: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHAN			;	break;
+			case 0x06: $operator = PHPExcel_Cell_DataValidation::OPERATOR_GREATERTHANOREQUAL;	break;
+			case 0x07: $operator = PHPExcel_Cell_DataValidation::OPERATOR_LESSTHANOREQUAL	;	break;
+		}
+
+		// offset: 4; size: var; title of the prompt box
+		$offset = 4;
+		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
+		$promptTitle = $string['value'] !== chr(0) ?
+			$string['value'] : '';
+		$offset += $string['size'];
+
+		// offset: var; size: var; title of the error box
+		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
+		$errorTitle = $string['value'] !== chr(0) ?
+			$string['value'] : '';
+		$offset += $string['size'];
+
+		// offset: var; size: var; text of the prompt box
+		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
+		$prompt = $string['value'] !== chr(0) ?
+			$string['value'] : '';
+		$offset += $string['size'];
+
+		// offset: var; size: var; text of the error box
+		$string = self::_readUnicodeStringLong(substr($recordData, $offset));
+		$error = $string['value'] !== chr(0) ?
+			$string['value'] : '';
+		$offset += $string['size'];
+
+		// offset: var; size: 2; size of the formula data for the first condition
+		$sz1 = self::_GetInt2d($recordData, $offset);
+		$offset += 2;
+
+		// offset: var; size: 2; not used
+		$offset += 2;
+
+		// offset: var; size: $sz1; formula data for first condition (without size field)
+		$formula1 = substr($recordData, $offset, $sz1);
+		$formula1 = pack('v', $sz1) . $formula1; // prepend the length
+		try {
+			$formula1 = $this->_getFormulaFromStructure($formula1);
+
+			// in list type validity, null characters are used as item separators
+			if ($type == PHPExcel_Cell_DataValidation::TYPE_LIST) {
+				$formula1 = str_replace(chr(0), ',', $formula1);
+			}
+		} catch (Exception $e) {
+			return;
+		}
+		$offset += $sz1;
+
+		// offset: var; size: 2; size of the formula data for the first condition
+		$sz2 = self::_GetInt2d($recordData, $offset);
+		$offset += 2;
+
+		// offset: var; size: 2; not used
+		$offset += 2;
+
+		// offset: var; size: $sz2; formula data for second condition (without size field)
+		$formula2 = substr($recordData, $offset, $sz2);
+		$formula2 = pack('v', $sz2) . $formula2; // prepend the length
+		try {
+			$formula2 = $this->_getFormulaFromStructure($formula2);
+		} catch (Exception $e) {
+			return;
+		}
+		$offset += $sz2;
+
+		// offset: var; size: var; cell range address list with
+		$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList(substr($recordData, $offset));
+		$cellRangeAddresses = $cellRangeAddressList['cellRangeAddresses'];
+
+		foreach ($cellRangeAddresses as $cellRange) {
+			$stRange = $this->_phpSheet->shrinkRangeToFit($cellRange);
+			$stRange = PHPExcel_Cell::extractAllCellReferencesInRange($stRange);
+			foreach ($stRange as $coordinate) {
+				$objValidation = $this->_phpSheet->getCell($coordinate)->getDataValidation();
+				$objValidation->setType($type);
+				$objValidation->setErrorStyle($errorStyle);
+				$objValidation->setAllowBlank((bool)$allowBlank);
+				$objValidation->setShowInputMessage((bool)$showInputMessage);
+				$objValidation->setShowErrorMessage((bool)$showErrorMessage);
+				$objValidation->setShowDropDown(!$suppressDropDown);
+				$objValidation->setOperator($operator);
+				$objValidation->setErrorTitle($errorTitle);
+				$objValidation->setError($error);
+				$objValidation->setPromptTitle($promptTitle);
+				$objValidation->setPrompt($prompt);
+				$objValidation->setFormula1($formula1);
+				$objValidation->setFormula2($formula2);
+			}
+		}
+
+	}
+
+
+	/**
+	 * Read SHEETLAYOUT record. Stores sheet tab color information.
+	 */
+	private function _readSheetLayout()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// local pointer in record data
+		$offset = 0;
+
+		if (!$this->_readDataOnly) {
+			// offset: 0; size: 2; repeated record identifier 0x0862
+
+			// offset: 2; size: 10; not used
+
+			// offset: 12; size: 4; size of record data
+			// Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
+			$sz = self::_GetInt4d($recordData, 12);
+
+			switch ($sz) {
+				case 0x14:
+					// offset: 16; size: 2; color index for sheet tab
+					$colorIndex = self::_GetInt2d($recordData, 16);
+					$color = self::_readColor($colorIndex,$this->_palette,$this->_version);
+					$this->_phpSheet->getTabColor()->setRGB($color['rgb']);
+					break;
+
+				case 0x28:
+					// TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
+					return;
+					break;
+			}
+		}
+	}
+
+
+	/**
+	 * Read SHEETPROTECTION record (FEATHEADR)
+	 */
+	private function _readSheetProtection()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		if ($this->_readDataOnly) {
+			return;
+		}
+
+		// offset: 0; size: 2; repeated record header
+
+		// offset: 2; size: 2; FRT cell reference flag (=0 currently)
+
+		// offset: 4; size: 8; Currently not used and set to 0
+
+		// offset: 12; size: 2; Shared feature type index (2=Enhanced Protetion, 4=SmartTag)
+		$isf = self::_GetInt2d($recordData, 12);
+		if ($isf != 2) {
+			return;
+		}
+
+		// offset: 14; size: 1; =1 since this is a feat header
+
+		// offset: 15; size: 4; size of rgbHdrSData
+
+		// rgbHdrSData, assume "Enhanced Protection"
+		// offset: 19; size: 2; option flags
+		$options = self::_GetInt2d($recordData, 19);
+
+		// bit: 0; mask 0x0001; 1 = user may edit objects, 0 = users must not edit objects
+		$bool = (0x0001 & $options) >> 0;
+		$this->_phpSheet->getProtection()->setObjects(!$bool);
+
+		// bit: 1; mask 0x0002; edit scenarios
+		$bool = (0x0002 & $options) >> 1;
+		$this->_phpSheet->getProtection()->setScenarios(!$bool);
+
+		// bit: 2; mask 0x0004; format cells
+		$bool = (0x0004 & $options) >> 2;
+		$this->_phpSheet->getProtection()->setFormatCells(!$bool);
+
+		// bit: 3; mask 0x0008; format columns
+		$bool = (0x0008 & $options) >> 3;
+		$this->_phpSheet->getProtection()->setFormatColumns(!$bool);
+
+		// bit: 4; mask 0x0010; format rows
+		$bool = (0x0010 & $options) >> 4;
+		$this->_phpSheet->getProtection()->setFormatRows(!$bool);
+
+		// bit: 5; mask 0x0020; insert columns
+		$bool = (0x0020 & $options) >> 5;
+		$this->_phpSheet->getProtection()->setInsertColumns(!$bool);
+
+		// bit: 6; mask 0x0040; insert rows
+		$bool = (0x0040 & $options) >> 6;
+		$this->_phpSheet->getProtection()->setInsertRows(!$bool);
+
+		// bit: 7; mask 0x0080; insert hyperlinks
+		$bool = (0x0080 & $options) >> 7;
+		$this->_phpSheet->getProtection()->setInsertHyperlinks(!$bool);
+
+		// bit: 8; mask 0x0100; delete columns
+		$bool = (0x0100 & $options) >> 8;
+		$this->_phpSheet->getProtection()->setDeleteColumns(!$bool);
+
+		// bit: 9; mask 0x0200; delete rows
+		$bool = (0x0200 & $options) >> 9;
+		$this->_phpSheet->getProtection()->setDeleteRows(!$bool);
+
+		// bit: 10; mask 0x0400; select locked cells
+		$bool = (0x0400 & $options) >> 10;
+		$this->_phpSheet->getProtection()->setSelectLockedCells(!$bool);
+
+		// bit: 11; mask 0x0800; sort cell range
+		$bool = (0x0800 & $options) >> 11;
+		$this->_phpSheet->getProtection()->setSort(!$bool);
+
+		// bit: 12; mask 0x1000; auto filter
+		$bool = (0x1000 & $options) >> 12;
+		$this->_phpSheet->getProtection()->setAutoFilter(!$bool);
+
+		// bit: 13; mask 0x2000; pivot tables
+		$bool = (0x2000 & $options) >> 13;
+		$this->_phpSheet->getProtection()->setPivotTables(!$bool);
+
+		// bit: 14; mask 0x4000; select unlocked cells
+		$bool = (0x4000 & $options) >> 14;
+		$this->_phpSheet->getProtection()->setSelectUnlockedCells(!$bool);
+
+		// offset: 21; size: 2; not used
+	}
+
+
+	/**
+	 * Read RANGEPROTECTION record
+	 * Reading of this record is based on Microsoft Office Excel 97-2000 Binary File Format Specification,
+	 * where it is referred to as FEAT record
+	 */
+	private function _readRangeProtection()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+		// local pointer in record data
+		$offset = 0;
+
+		if (!$this->_readDataOnly) {
+			$offset += 12;
+
+			// offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
+			$isf = self::_GetInt2d($recordData, 12);
+			if ($isf != 2) {
+				// we only read FEAT records of type 2
+				return;
+			}
+			$offset += 2;
+
+			$offset += 5;
+
+			// offset: 19; size: 2; count of ref ranges this feature is on
+			$cref = self::_GetInt2d($recordData, 19);
+			$offset += 2;
+
+			$offset += 6;
+
+			// offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
+			$cellRanges = array();
+			for ($i = 0; $i < $cref; ++$i) {
+				try {
+					$cellRange = $this->_readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
+				} catch (Exception $e) {
+					return;
+				}
+				$cellRanges[] = $cellRange;
+				$offset += 8;
+			}
+
+			// offset: var; size: var; variable length of feature specific data
+			$rgbFeat = substr($recordData, $offset);
+			$offset += 4;
+
+			// offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
+			$wPassword = self::_GetInt4d($recordData, $offset);
+			$offset += 4;
+
+			// Apply range protection to sheet
+			if ($cellRanges) {
+				$this->_phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
+			}
+		}
+	}
+
+
+	/**
+	 * Read IMDATA record
+	 */
+	private function _readImData()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+
+		// get spliced record data
+		$splicedRecordData = $this->_getSplicedRecordData();
+		$recordData = $splicedRecordData['recordData'];
+
+		// UNDER CONSTRUCTION
+
+		// offset: 0; size: 2; image format
+		$cf = self::_GetInt2d($recordData, 0);
+
+		// offset: 2; size: 2; environment from which the file was written
+		$env = self::_GetInt2d($recordData, 2);
+
+		// offset: 4; size: 4; length of the image data
+		$lcb = self::_GetInt4d($recordData, 4);
+
+		// offset: 8; size: var; image data
+		$iData = substr($recordData, 8);
+
+		switch ($cf) {
+		case 0x09: // Windows bitmap format
+			// BITMAPCOREINFO
+			// 1. BITMAPCOREHEADER
+			// offset: 0; size: 4; bcSize, Specifies the number of bytes required by the structure
+			$bcSize = self::_GetInt4d($iData, 0);
+//			var_dump($bcSize);
+
+			// offset: 4; size: 2; bcWidth, specifies the width of the bitmap, in pixels
+			$bcWidth = self::_GetInt2d($iData, 4);
+//			var_dump($bcWidth);
+
+			// offset: 6; size: 2; bcHeight, specifies the height of the bitmap, in pixels.
+			$bcHeight = self::_GetInt2d($iData, 6);
+//			var_dump($bcHeight);
+			$ih = imagecreatetruecolor($bcWidth, $bcHeight);
+
+			// offset: 8; size: 2; bcPlanes, specifies the number of planes for the target device. This value must be 1
+
+			// offset: 10; size: 2; bcBitCount specifies the number of bits-per-pixel. This value must be 1, 4, 8, or 24
+			$bcBitCount = self::_GetInt2d($iData, 10);
+//			var_dump($bcBitCount);
+
+			$rgbString = substr($iData, 12);
+			$rgbTriples = array();
+			while (strlen($rgbString) > 0) {
+				$rgbTriples[] = unpack('Cb/Cg/Cr', $rgbString);
+				$rgbString = substr($rgbString, 3);
+			}
+			$x = 0;
+			$y = 0;
+			foreach ($rgbTriples as $i => $rgbTriple) {
+				$color = imagecolorallocate($ih, $rgbTriple['r'], $rgbTriple['g'], $rgbTriple['b']);
+				imagesetpixel($ih, $x, $bcHeight - 1 - $y, $color);
+				$x = ($x + 1) % $bcWidth;
+				$y = $y + floor(($x + 1) / $bcWidth);
+			}
+			//imagepng($ih, 'image.png');
+
+			$drawing = new PHPExcel_Worksheet_Drawing();
+			$drawing->setPath($filename);
+			$drawing->setWorksheet($this->_phpSheet);
+
+			break;
+
+		case 0x02: // Windows metafile or Macintosh PICT format
+		case 0x0e: // native format
+		default;
+			break;
+
+		}
+
+		// _getSplicedRecordData() takes care of moving current position in data stream
+	}
+
+
+	/**
+	 * Read a free CONTINUE record. Free CONTINUE record may be a camouflaged MSODRAWING record
+	 * When MSODRAWING data on a sheet exceeds 8224 bytes, CONTINUE records are used instead. Undocumented.
+	 * In this case, we must treat the CONTINUE record as a MSODRAWING record
+	 */
+	private function _readContinue()
+	{
+		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+		$recordData = substr($this->_data, $this->_pos + 4, $length);
+
+		// check if we are reading drawing data
+		// this is in case a free CONTINUE record occurs in other circumstances we are unaware of
+		if ($this->_drawingData == '') {
+			// move stream pointer to next record
+			$this->_pos += 4 + $length;
+
+			return;
+		}
+
+		// check if record data is at least 4 bytes long, otherwise there is no chance this is MSODRAWING data
+		if ($length < 4) {
+			// move stream pointer to next record
+			$this->_pos += 4 + $length;
+
+			return;
+		}
+
+		// dirty check to see if CONTINUE record could be a camouflaged MSODRAWING record
+		// look inside CONTINUE record to see if it looks like a part of an Escher stream
+		// we know that Escher stream may be split at least at
+		//		0xF003 MsofbtSpgrContainer
+		//		0xF004 MsofbtSpContainer
+		//		0xF00D MsofbtClientTextbox
+		$validSplitPoints = array(0xF003, 0xF004, 0xF00D); // add identifiers if we find more
+
+		$splitPoint = self::_GetInt2d($recordData, 2);
+		if (in_array($splitPoint, $validSplitPoints)) {
+			// get spliced record data (and move pointer to next record)
+			$splicedRecordData = $this->_getSplicedRecordData();
+			$this->_drawingData .= $splicedRecordData['recordData'];
+
+			return;
+		}
+
+		// move stream pointer to next record
+		$this->_pos += 4 + $length;
+
+	}
+
+
+	/**
+	 * Reads a record from current position in data stream and continues reading data as long as CONTINUE
+	 * records are found. Splices the record data pieces and returns the combined string as if record data
+	 * is in one piece.
+	 * Moves to next current position in data stream to start of next record different from a CONtINUE record
+	 *
+	 * @return array
+	 */
+	private function _getSplicedRecordData()
+	{
+		$data = '';
+		$spliceOffsets = array();
+
+		$i = 0;
+		$spliceOffsets[0] = 0;
+
+		do {
+			++$i;
+
+			// offset: 0; size: 2; identifier
+			$identifier = self::_GetInt2d($this->_data, $this->_pos);
+			// offset: 2; size: 2; length
+			$length = self::_GetInt2d($this->_data, $this->_pos + 2);
+			$data .= substr($this->_data, $this->_pos + 4, $length);
+
+			$spliceOffsets[$i] = $spliceOffsets[$i - 1] + $length;
+
+			$this->_pos += 4 + $length;
+			$nextIdentifier = self::_GetInt2d($this->_data, $this->_pos);
+		}
+		while ($nextIdentifier == self::XLS_Type_CONTINUE);
+
+		$splicedData = array(
+			'recordData' => $data,
+			'spliceOffsets' => $spliceOffsets,
+		);
+
+		return $splicedData;
+
+	}
+
+
+	/**
+	 * Convert formula structure into human readable Excel formula like 'A3+A5*5'
+	 *
+	 * @param string $formulaStructure The complete binary data for the formula
+	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+	 * @return string Human readable formula
+	 */
+	private function _getFormulaFromStructure($formulaStructure, $baseCell = 'A1')
+	{
+		// offset: 0; size: 2; size of the following formula data
+		$sz = self::_GetInt2d($formulaStructure, 0);
+
+		// offset: 2; size: sz
+		$formulaData = substr($formulaStructure, 2, $sz);
+
+		// for debug: dump the formula data
+		//echo '<xmp>';
+		//echo 'size: ' . $sz . "\n";
+		//echo 'the entire formula data: ';
+		//Debug::dump($formulaData);
+		//echo "\n----\n";
+
+		// offset: 2 + sz; size: variable (optional)
+		if (strlen($formulaStructure) > 2 + $sz) {
+			$additionalData = substr($formulaStructure, 2 + $sz);
+
+			// for debug: dump the additional data
+			//echo 'the entire additional data: ';
+			//Debug::dump($additionalData);
+			//echo "\n----\n";
+
+		} else {
+			$additionalData = '';
+		}
+
+		return $this->_getFormulaFromData($formulaData, $additionalData, $baseCell);
+	}
+
+
+	/**
+	 * Take formula data and additional data for formula and return human readable formula
+	 *
+	 * @param string $formulaData The binary data for the formula itself
+	 * @param string $additionalData Additional binary data going with the formula
+	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+	 * @return string Human readable formula
+	 */
+	private function _getFormulaFromData($formulaData,  $additionalData = '', $baseCell = 'A1')
+	{
+		// start parsing the formula data
+		$tokens = array();
+
+		while (strlen($formulaData) > 0 and $token = $this->_getNextToken($formulaData, $baseCell)) {
+			$tokens[] = $token;
+			$formulaData = substr($formulaData, $token['size']);
+
+			// for debug: dump the token
+			//var_dump($token);
+		}
+
+		$formulaString = $this->_createFormulaFromTokens($tokens, $additionalData);
+
+		return $formulaString;
+	}
+
+
+	/**
+	 * Take array of tokens together with additional data for formula and return human readable formula
+	 *
+	 * @param array $tokens
+	 * @param array $additionalData Additional binary data going with the formula
+	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+	 * @return string Human readable formula
+	 */
+	private function _createFormulaFromTokens($tokens, $additionalData)
+	{
+		// empty formula?
+		if (empty($tokens)) {
+			return '';
+		}
+
+		$formulaStrings = array();
+		foreach ($tokens as $token) {
+			// initialize spaces
+			$space0 = isset($space0) ? $space0 : ''; // spaces before next token, not tParen
+			$space1 = isset($space1) ? $space1 : ''; // carriage returns before next token, not tParen
+			$space2 = isset($space2) ? $space2 : ''; // spaces before opening parenthesis
+			$space3 = isset($space3) ? $space3 : ''; // carriage returns before opening parenthesis
+			$space4 = isset($space4) ? $space4 : ''; // spaces before closing parenthesis
+			$space5 = isset($space5) ? $space5 : ''; // carriage returns before closing parenthesis
+
+			switch ($token['name']) {
+			case 'tAdd': // addition
+			case 'tConcat': // addition
+			case 'tDiv': // division
+			case 'tEQ': // equality
+			case 'tGE': // greater than or equal
+			case 'tGT': // greater than
+			case 'tIsect': // intersection
+			case 'tLE': // less than or equal
+			case 'tList': // less than or equal
+			case 'tLT': // less than
+			case 'tMul': // multiplication
+			case 'tNE': // multiplication
+			case 'tPower': // power
+			case 'tRange': // range
+			case 'tSub': // subtraction
+				$op2 = array_pop($formulaStrings);
+				$op1 = array_pop($formulaStrings);
+				$formulaStrings[] = "$op1$space1$space0{$token['data']}$op2";
+				unset($space0, $space1);
+				break;
+			case 'tUplus': // unary plus
+			case 'tUminus': // unary minus
+				$op = array_pop($formulaStrings);
+				$formulaStrings[] = "$space1$space0{$token['data']}$op";
+				unset($space0, $space1);
+				break;
+			case 'tPercent': // percent sign
+				$op = array_pop($formulaStrings);
+				$formulaStrings[] = "$op$space1$space0{$token['data']}";
+				unset($space0, $space1);
+				break;
+			case 'tAttrVolatile': // indicates volatile function
+			case 'tAttrIf':
+			case 'tAttrSkip':
+			case 'tAttrChoose':
+				// token is only important for Excel formula evaluator
+				// do nothing
+				break;
+			case 'tAttrSpace': // space / carriage return
+				// space will be used when next token arrives, do not alter formulaString stack
+				switch ($token['data']['spacetype']) {
+				case 'type0':
+					$space0 = str_repeat(' ', $token['data']['spacecount']);
+					break;
+				case 'type1':
+					$space1 = str_repeat("\n", $token['data']['spacecount']);
+					break;
+				case 'type2':
+					$space2 = str_repeat(' ', $token['data']['spacecount']);
+					break;
+				case 'type3':
+					$space3 = str_repeat("\n", $token['data']['spacecount']);
+					break;
+				case 'type4':
+					$space4 = str_repeat(' ', $token['data']['spacecount']);
+					break;
+				case 'type5':
+					$space5 = str_repeat("\n", $token['data']['spacecount']);
+					break;
+				}
+				break;
+			case 'tAttrSum': // SUM function with one parameter
+				$op = array_pop($formulaStrings);
+				$formulaStrings[] = "{$space1}{$space0}SUM($op)";
+				unset($space0, $space1);
+				break;
+			case 'tFunc': // function with fixed number of arguments
+			case 'tFuncV': // function with variable number of arguments
+				if ($token['data']['function'] != '') {
+					// normal function
+					$ops = array(); // array of operators
+					for ($i = 0; $i < $token['data']['args']; ++$i) {
+						$ops[] = array_pop($formulaStrings);
+					}
+					$ops = array_reverse($ops);
+					$formulaStrings[] = "$space1$space0{$token['data']['function']}(" . implode(',', $ops) . ")";
+					unset($space0, $space1);
+				} else {
+					// add-in function
+					$ops = array(); // array of operators
+					for ($i = 0; $i < $token['data']['args'] - 1; ++$i) {
+						$ops[] = array_pop($formulaStrings);
+					}
+					$ops = array_reverse($ops);
+					$function = array_pop($formulaStrings);
+					$formulaStrings[] = "$space1$space0$function(" . implode(',', $ops) . ")";
+					unset($space0, $space1);
+				}
+				break;
+			case 'tParen': // parenthesis
+				$expression = array_pop($formulaStrings);
+				$formulaStrings[] = "$space3$space2($expression$space5$space4)";
+				unset($space2, $space3, $space4, $space5);
+				break;
+			case 'tArray': // array constant
+				$constantArray = self::_readBIFF8ConstantArray($additionalData);
+				$formulaStrings[] = $space1 . $space0 . $constantArray['value'];
+				$additionalData = substr($additionalData, $constantArray['size']); // bite of chunk of additional data
+				unset($space0, $space1);
+				break;
+			case 'tMemArea':
+				// bite off chunk of additional data
+				$cellRangeAddressList = $this->_readBIFF8CellRangeAddressList($additionalData);
+				$additionalData = substr($additionalData, $cellRangeAddressList['size']);
+				$formulaStrings[] = "$space1$space0{$token['data']}";
+				unset($space0, $space1);
+				break;
+			case 'tArea': // cell range address
+			case 'tBool': // boolean
+			case 'tErr': // error code
+			case 'tInt': // integer
+			case 'tMemErr':
+			case 'tMemFunc':
+			case 'tMissArg':
+			case 'tName':
+			case 'tNameX':
+			case 'tNum': // number
+			case 'tRef': // single cell reference
+			case 'tRef3d': // 3d cell reference
+			case 'tArea3d': // 3d cell range reference
+			case 'tRefN':
+			case 'tAreaN':
+			case 'tStr': // string
+				$formulaStrings[] = "$space1$space0{$token['data']}";
+				unset($space0, $space1);
+				break;
+			}
+		}
+		$formulaString = $formulaStrings[0];
+
+		// for debug: dump the human readable formula
+		//echo '----' . "\n";
+		//echo 'Formula: ' . $formulaString;
+
+		return $formulaString;
+	}
+
+
+	/**
+	 * Fetch next token from binary formula data
+	 *
+	 * @param string Formula data
+	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+	 * @return array
+	 * @throws Exception
+	 */
+	private function _getNextToken($formulaData, $baseCell = 'A1')
+	{
+		// offset: 0; size: 1; token id
+		$id = ord($formulaData[0]); // token id
+		$name = false; // initialize token name
+
+		switch ($id) {
+		case 0x03: $name = 'tAdd';		$size = 1;	$data = '+';	break;
+		case 0x04: $name = 'tSub';		$size = 1;	$data = '-';	break;
+		case 0x05: $name = 'tMul';		$size = 1;	$data = '*';	break;
+		case 0x06: $name = 'tDiv';		$size = 1;	$data = '/';	break;
+		case 0x07: $name = 'tPower';	$size = 1;	$data = '^';	break;
+		case 0x08: $name = 'tConcat';	$size = 1;	$data = '&';	break;
+		case 0x09: $name = 'tLT';		$size = 1;	$data = '<';	break;
+		case 0x0A: $name = 'tLE';		$size = 1;	$data = '<=';	break;
+		case 0x0B: $name = 'tEQ';		$size = 1;	$data = '=';	break;
+		case 0x0C: $name = 'tGE';		$size = 1;	$data = '>=';	break;
+		case 0x0D: $name = 'tGT';		$size = 1;	$data = '>';	break;
+		case 0x0E: $name = 'tNE';		$size = 1;	$data = '<>';	break;
+		case 0x0F: $name = 'tIsect';	$size = 1;	$data = ' ';	break;
+		case 0x10: $name = 'tList';		$size = 1;	$data = ',';	break;
+		case 0x11: $name = 'tRange';	$size = 1;	$data = ':';	break;
+		case 0x12: $name = 'tUplus';	$size = 1;	$data = '+';	break;
+		case 0x13: $name = 'tUminus';	$size = 1;	$data = '-';	break;
+		case 0x14: $name = 'tPercent';	$size = 1;	$data = '%';	break;
+		case 0x15:	//	parenthesis
+			$name  = 'tParen';
+			$size  = 1;
+			$data = null;
+			break;
+		case 0x16:	//	missing argument
+			$name = 'tMissArg';
+			$size = 1;
+			$data = '';
+			break;
+		case 0x17:	//	string
+			$name = 'tStr';
+			// offset: 1; size: var; Unicode string, 8-bit string length
+			$string = self::_readUnicodeStringShort(substr($formulaData, 1));
+			$size = 1 + $string['size'];
+			$data = self::_UTF8toExcelDoubleQuoted($string['value']);
+			break;
+		case 0x19:	//	Special attribute
+			// offset: 1; size: 1; attribute type flags:
+			switch (ord($formulaData[1])) {
+			case 0x01:
+				$name = 'tAttrVolatile';
+				$size = 4;
+				$data = null;
+				break;
+			case 0x02:
+				$name = 'tAttrIf';
+				$size = 4;
+				$data = null;
+				break;
+			case 0x04:
+				$name = 'tAttrChoose';
+				// offset: 2; size: 2; number of choices in the CHOOSE function ($nc, number of parameters decreased by 1)
+				$nc = self::_GetInt2d($formulaData, 2);
+				// offset: 4; size: 2 * $nc
+				// offset: 4 + 2 * $nc; size: 2
+				$size = 2 * $nc + 6;
+				$data = null;
+				break;
+			case 0x08:
+				$name = 'tAttrSkip';
+				$size = 4;
+				$data = null;
+				break;
+			case 0x10:
+				$name = 'tAttrSum';
+				$size = 4;
+				$data = null;
+				break;
+			case 0x40:
+			case 0x41:
+				$name = 'tAttrSpace';
+				$size = 4;
+				// offset: 2; size: 2; space type and position
+				switch (ord($formulaData[2])) {
+				case 0x00:
+					$spacetype = 'type0';
+					break;
+				case 0x01:
+					$spacetype = 'type1';
+					break;
+				case 0x02:
+					$spacetype = 'type2';
+					break;
+				case 0x03:
+					$spacetype = 'type3';
+					break;
+				case 0x04:
+					$spacetype = 'type4';
+					break;
+				case 0x05:
+					$spacetype = 'type5';
+					break;
+				default:
+					throw new Exception('Unrecognized space type in tAttrSpace token');
+					break;
+				}
+				// offset: 3; size: 1; number of inserted spaces/carriage returns
+				$spacecount = ord($formulaData[3]);
+
+				$data = array('spacetype' => $spacetype, 'spacecount' => $spacecount);
+				break;
+			default:
+				throw new Exception('Unrecognized attribute flag in tAttr token');
+				break;
+			}
+			break;
+		case 0x1C:	//	error code
+			// offset: 1; size: 1; error code
+			$name = 'tErr';
+			$size = 2;
+			$data = self::_mapErrorCode(ord($formulaData[1]));
+			break;
+		case 0x1D:	//	boolean
+			// offset: 1; size: 1; 0 = false, 1 = true;
+			$name = 'tBool';
+			$size = 2;
+			$data = ord($formulaData[1]) ? 'TRUE' : 'FALSE';
+			break;
+		case 0x1E:	//	integer
+			// offset: 1; size: 2; unsigned 16-bit integer
+			$name = 'tInt';
+			$size = 3;
+			$data = self::_GetInt2d($formulaData, 1);
+			break;
+		case 0x1F:	//	number
+			// offset: 1; size: 8;
+			$name = 'tNum';
+			$size = 9;
+			$data = self::_extractNumber(substr($formulaData, 1));
+			$data = str_replace(',', '.', (string)$data); // in case non-English locale
+			break;
+		case 0x20:	//	array constant
+		case 0x40:
+		case 0x60:
+			// offset: 1; size: 7; not used
+			$name = 'tArray';
+			$size = 8;
+			$data = null;
+			break;
+		case 0x21:	//	function with fixed number of arguments
+		case 0x41:
+		case 0x61:
+			$name = 'tFunc';
+			$size = 3;
+			// offset: 1; size: 2; index to built-in sheet function
+			switch (self::_GetInt2d($formulaData, 1)) {
+			case   2: $function = 'ISNA'; 			$args = 1; 	break;
+			case   3: $function = 'ISERROR'; 		$args = 1; 	break;
+			case  10: $function = 'NA'; 			$args = 0; 	break;
+			case  15: $function = 'SIN'; 			$args = 1; 	break;
+			case  16: $function = 'COS'; 			$args = 1; 	break;
+			case  17: $function = 'TAN'; 			$args = 1; 	break;
+			case  18: $function = 'ATAN'; 			$args = 1; 	break;
+			case  19: $function = 'PI'; 			$args = 0; 	break;
+			case  20: $function = 'SQRT'; 			$args = 1; 	break;
+			case  21: $function = 'EXP'; 			$args = 1; 	break;
+			case  22: $function = 'LN'; 			$args = 1; 	break;
+			case  23: $function = 'LOG10'; 			$args = 1; 	break;
+			case  24: $function = 'ABS'; 			$args = 1; 	break;
+			case  25: $function = 'INT'; 			$args = 1; 	break;
+			case  26: $function = 'SIGN'; 			$args = 1; 	break;
+			case  27: $function = 'ROUND'; 			$args = 2; 	break;
+			case  30: $function = 'REPT'; 			$args = 2; 	break;
+			case  31: $function = 'MID'; 			$args = 3; 	break;
+			case  32: $function = 'LEN'; 			$args = 1; 	break;
+			case  33: $function = 'VALUE'; 			$args = 1; 	break;
+			case  34: $function = 'TRUE'; 			$args = 0; 	break;
+			case  35: $function = 'FALSE'; 			$args = 0; 	break;
+			case  38: $function = 'NOT'; 			$args = 1; 	break;
+			case  39: $function = 'MOD'; 			$args = 2;	break;
+			case  40: $function = 'DCOUNT'; 		$args = 3;	break;
+			case  41: $function = 'DSUM'; 			$args = 3;	break;
+			case  42: $function = 'DAVERAGE'; 		$args = 3;	break;
+			case  43: $function = 'DMIN'; 			$args = 3;	break;
+			case  44: $function = 'DMAX'; 			$args = 3;	break;
+			case  45: $function = 'DSTDEV'; 		$args = 3;	break;
+			case  48: $function = 'TEXT'; 			$args = 2;	break;
+			case  61: $function = 'MIRR'; 			$args = 3;	break;
+			case  63: $function = 'RAND'; 			$args = 0;	break;
+			case  65: $function = 'DATE'; 			$args = 3;	break;
+			case  66: $function = 'TIME'; 			$args = 3;	break;
+			case  67: $function = 'DAY'; 			$args = 1;	break;
+			case  68: $function = 'MONTH'; 			$args = 1;	break;
+			case  69: $function = 'YEAR'; 			$args = 1;	break;
+			case  71: $function = 'HOUR'; 			$args = 1;	break;
+			case  72: $function = 'MINUTE'; 		$args = 1;	break;
+			case  73: $function = 'SECOND'; 		$args = 1;	break;
+			case  74: $function = 'NOW'; 			$args = 0;	break;
+			case  75: $function = 'AREAS'; 			$args = 1;	break;
+			case  76: $function = 'ROWS'; 			$args = 1;	break;
+			case  77: $function = 'COLUMNS'; 		$args = 1;	break;
+			case  83: $function = 'TRANSPOSE'; 		$args = 1;	break;
+			case  86: $function = 'TYPE'; 			$args = 1;	break;
+			case  97: $function = 'ATAN2'; 			$args = 2;	break;
+			case  98: $function = 'ASIN'; 			$args = 1;	break;
+			case  99: $function = 'ACOS'; 			$args = 1;	break;
+			case 105: $function = 'ISREF'; 			$args = 1;	break;
+			case 111: $function = 'CHAR'; 			$args = 1;	break;
+			case 112: $function = 'LOWER'; 			$args = 1;	break;
+			case 113: $function = 'UPPER'; 			$args = 1;	break;
+			case 114: $function = 'PROPER'; 		$args = 1;	break;
+			case 117: $function = 'EXACT'; 			$args = 2;	break;
+			case 118: $function = 'TRIM'; 			$args = 1;	break;
+			case 119: $function = 'REPLACE'; 		$args = 4;	break;
+			case 121: $function = 'CODE'; 			$args = 1;	break;
+			case 126: $function = 'ISERR'; 			$args = 1;	break;
+			case 127: $function = 'ISTEXT'; 		$args = 1;	break;
+			case 128: $function = 'ISNUMBER'; 		$args = 1;	break;
+			case 129: $function = 'ISBLANK'; 		$args = 1;	break;
+			case 130: $function = 'T'; 				$args = 1;	break;
+			case 131: $function = 'N'; 				$args = 1;	break;
+			case 140: $function = 'DATEVALUE'; 		$args = 1;	break;
+			case 141: $function = 'TIMEVALUE'; 		$args = 1;	break;
+			case 142: $function = 'SLN'; 			$args = 3;	break;
+			case 143: $function = 'SYD'; 			$args = 4;	break;
+			case 162: $function = 'CLEAN'; 			$args = 1;	break;
+			case 163: $function = 'MDETERM'; 		$args = 1;	break;
+			case 164: $function = 'MINVERSE'; 		$args = 1;	break;
+			case 165: $function = 'MMULT'; 			$args = 2;	break;
+			case 184: $function = 'FACT'; 			$args = 1;	break;
+			case 189: $function = 'DPRODUCT'; 		$args = 3;	break;
+			case 190: $function = 'ISNONTEXT'; 		$args = 1;	break;
+			case 195: $function = 'DSTDEVP'; 		$args = 3;	break;
+			case 196: $function = 'DVARP'; 			$args = 3;	break;
+			case 198: $function = 'ISLOGICAL'; 		$args = 1;	break;
+			case 199: $function = 'DCOUNTA'; 		$args = 3;	break;
+			case 207: $function = 'REPLACEB'; 		$args = 4;	break;
+			case 210: $function = 'MIDB'; 			$args = 3;	break;
+			case 211: $function = 'LENB'; 			$args = 1;	break;
+			case 212: $function = 'ROUNDUP'; 		$args = 2;	break;
+			case 213: $function = 'ROUNDDOWN'; 		$args = 2;	break;
+			case 214: $function = 'ASC'; 			$args = 1;	break;
+			case 215: $function = 'DBCS'; 			$args = 1;	break;
+			case 221: $function = 'TODAY'; 			$args = 0;	break;
+			case 229: $function = 'SINH'; 			$args = 1;	break;
+			case 230: $function = 'COSH'; 			$args = 1;	break;
+			case 231: $function = 'TANH'; 			$args = 1;	break;
+			case 232: $function = 'ASINH'; 			$args = 1;	break;
+			case 233: $function = 'ACOSH'; 			$args = 1;	break;
+			case 234: $function = 'ATANH'; 			$args = 1;	break;
+			case 235: $function = 'DGET'; 			$args = 3;	break;
+			case 244: $function = 'INFO'; 			$args = 1;	break;
+			case 252: $function = 'FREQUENCY'; 		$args = 2;	break;
+			case 261: $function = 'ERROR.TYPE'; 	$args = 1;	break;
+			case 271: $function = 'GAMMALN'; 		$args = 1;	break;
+			case 273: $function = 'BINOMDIST'; 		$args = 4;	break;
+			case 274: $function = 'CHIDIST'; 		$args = 2;	break;
+			case 275: $function = 'CHIINV'; 		$args = 2;	break;
+			case 276: $function = 'COMBIN'; 		$args = 2;	break;
+			case 277: $function = 'CONFIDENCE'; 	$args = 3;	break;
+			case 278: $function = 'CRITBINOM'; 		$args = 3;	break;
+			case 279: $function = 'EVEN'; 			$args = 1;	break;
+			case 280: $function = 'EXPONDIST'; 		$args = 3;	break;
+			case 281: $function = 'FDIST'; 			$args = 3;	break;
+			case 282: $function = 'FINV'; 			$args = 3;	break;
+			case 283: $function = 'FISHER'; 		$args = 1;	break;
+			case 284: $function = 'FISHERINV'; 		$args = 1;	break;
+			case 285: $function = 'FLOOR'; 			$args = 2;	break;
+			case 286: $function = 'GAMMADIST'; 		$args = 4;	break;
+			case 287: $function = 'GAMMAINV'; 		$args = 3;	break;
+			case 288: $function = 'CEILING'; 		$args = 2;	break;
+			case 289: $function = 'HYPGEOMDIST';	$args = 4;	break;
+			case 290: $function = 'LOGNORMDIST';	$args = 3;	break;
+			case 291: $function = 'LOGINV';			$args = 3;	break;
+			case 292: $function = 'NEGBINOMDIST';	$args = 3;	break;
+			case 293: $function = 'NORMDIST';		$args = 4;	break;
+			case 294: $function = 'NORMSDIST';		$args = 1;	break;
+			case 295: $function = 'NORMINV';		$args = 3;	break;
+			case 296: $function = 'NORMSINV';		$args = 1;	break;
+			case 297: $function = 'STANDARDIZE';	$args = 3;	break;
+			case 298: $function = 'ODD';			$args = 1;	break;
+			case 299: $function = 'PERMUT';			$args = 2;	break;
+			case 300: $function = 'POISSON';		$args = 3;	break;
+			case 301: $function = 'TDIST';			$args = 3;	break;
+			case 302: $function = 'WEIBULL';		$args = 4;	break;
+			case 303: $function = 'SUMXMY2';		$args = 2;	break;
+			case 304: $function = 'SUMX2MY2';		$args = 2;	break;
+			case 305: $function = 'SUMX2PY2';		$args = 2;	break;
+			case 306: $function = 'CHITEST';		$args = 2;	break;
+			case 307: $function = 'CORREL';			$args = 2;	break;
+			case 308: $function = 'COVAR';			$args = 2;	break;
+			case 309: $function = 'FORECAST';		$args = 3;	break;
+			case 310: $function = 'FTEST';			$args = 2;	break;
+			case 311: $function = 'INTERCEPT';		$args = 2;	break;
+			case 312: $function = 'PEARSON';		$args = 2;	break;
+			case 313: $function = 'RSQ';			$args = 2;	break;
+			case 314: $function = 'STEYX';			$args = 2;	break;
+			case 315: $function = 'SLOPE';			$args = 2;	break;
+			case 316: $function = 'TTEST';			$args = 4;	break;
+			case 325: $function = 'LARGE';			$args = 2;	break;
+			case 326: $function = 'SMALL';			$args = 2;	break;
+			case 327: $function = 'QUARTILE';		$args = 2;	break;
+			case 328: $function = 'PERCENTILE';		$args = 2;	break;
+			case 331: $function = 'TRIMMEAN';		$args = 2;	break;
+			case 332: $function = 'TINV';			$args = 2;	break;
+			case 337: $function = 'POWER';			$args = 2;	break;
+			case 342: $function = 'RADIANS';		$args = 1;	break;
+			case 343: $function = 'DEGREES';		$args = 1;	break;
+			case 346: $function = 'COUNTIF';		$args = 2;	break;
+			case 347: $function = 'COUNTBLANK';		$args = 1;	break;
+			case 350: $function = 'ISPMT';			$args = 4;	break;
+			case 351: $function = 'DATEDIF';		$args = 3;	break;
+			case 352: $function = 'DATESTRING';		$args = 1;	break;
+			case 353: $function = 'NUMBERSTRING';	$args = 2;	break;
+			case 360: $function = 'PHONETIC';		$args = 1;	break;
+			case 368: $function = 'BAHTTEXT';		$args = 1;	break;
+			default:
+				throw new Exception('Unrecognized function in formula');
+				break;
+			}
+			$data = array('function' => $function, 'args' => $args);
+			break;
+		case 0x22:	//	function with variable number of arguments
+		case 0x42:
+		case 0x62:
+			$name = 'tFuncV';
+			$size = 4;
+			// offset: 1; size: 1; number of arguments
+			$args = ord($formulaData[1]);
+			// offset: 2: size: 2; index to built-in sheet function
+			$index = self::_GetInt2d($formulaData, 2);
+			switch ($index) {
+			case   0: $function = 'COUNT';			break;
+			case   1: $function = 'IF';				break;
+			case   4: $function = 'SUM';			break;
+			case   5: $function = 'AVERAGE';		break;
+			case   6: $function = 'MIN';			break;
+			case   7: $function = 'MAX';			break;
+			case   8: $function = 'ROW';			break;
+			case   9: $function = 'COLUMN';			break;
+			case  11: $function = 'NPV';			break;
+			case  12: $function = 'STDEV';			break;
+			case  13: $function = 'DOLLAR';			break;
+			case  14: $function = 'FIXED';			break;
+			case  28: $function = 'LOOKUP';			break;
+			case  29: $function = 'INDEX';			break;
+			case  36: $function = 'AND';			break;
+			case  37: $function = 'OR';				break;
+			case  46: $function = 'VAR';			break;
+			case  49: $function = 'LINEST';			break;
+			case  50: $function = 'TREND';			break;
+			case  51: $function = 'LOGEST';			break;
+			case  52: $function = 'GROWTH';			break;
+			case  56: $function = 'PV';				break;
+			case  57: $function = 'FV';				break;
+			case  58: $function = 'NPER';			break;
+			case  59: $function = 'PMT';			break;
+			case  60: $function = 'RATE';			break;
+			case  62: $function = 'IRR';			break;
+			case  64: $function = 'MATCH';			break;
+			case  70: $function = 'WEEKDAY';		break;
+			case  78: $function = 'OFFSET';			break;
+			case  82: $function = 'SEARCH';			break;
+			case 100: $function = 'CHOOSE';			break;
+			case 101: $function = 'HLOOKUP';		break;
+			case 102: $function = 'VLOOKUP';		break;
+			case 109: $function = 'LOG';			break;
+			case 115: $function = 'LEFT';			break;
+			case 116: $function = 'RIGHT';			break;
+			case 120: $function = 'SUBSTITUTE';		break;
+			case 124: $function = 'FIND';			break;
+			case 125: $function = 'CELL';			break;
+			case 144: $function = 'DDB';			break;
+			case 148: $function = 'INDIRECT';		break;
+			case 167: $function = 'IPMT';			break;
+			case 168: $function = 'PPMT';			break;
+			case 169: $function = 'COUNTA';			break;
+			case 183: $function = 'PRODUCT';		break;
+			case 193: $function = 'STDEVP';			break;
+			case 194: $function = 'VARP';			break;
+			case 197: $function = 'TRUNC';			break;
+			case 204: $function = 'USDOLLAR';		break;
+			case 205: $function = 'FINDB';			break;
+			case 206: $function = 'SEARCHB';		break;
+			case 208: $function = 'LEFTB';			break;
+			case 209: $function = 'RIGHTB';			break;
+			case 216: $function = 'RANK';			break;
+			case 219: $function = 'ADDRESS';		break;
+			case 220: $function = 'DAYS360';		break;
+			case 222: $function = 'VDB';			break;
+			case 227: $function = 'MEDIAN';			break;
+			case 228: $function = 'SUMPRODUCT';		break;
+			case 247: $function = 'DB';				break;
+			case 255: $function = '';				break;
+			case 269: $function = 'AVEDEV';			break;
+			case 270: $function = 'BETADIST';		break;
+			case 272: $function = 'BETAINV';		break;
+			case 317: $function = 'PROB';			break;
+			case 318: $function = 'DEVSQ';			break;
+			case 319: $function = 'GEOMEAN';		break;
+			case 320: $function = 'HARMEAN';		break;
+			case 321: $function = 'SUMSQ';			break;
+			case 322: $function = 'KURT';			break;
+			case 323: $function = 'SKEW';			break;
+			case 324: $function = 'ZTEST';			break;
+			case 329: $function = 'PERCENTRANK';	break;
+			case 330: $function = 'MODE';			break;
+			case 336: $function = 'CONCATENATE';	break;
+			case 344: $function = 'SUBTOTAL';		break;
+			case 345: $function = 'SUMIF';			break;
+			case 354: $function = 'ROMAN';			break;
+			case 358: $function = 'GETPIVOTDATA';	break;
+			case 359: $function = 'HYPERLINK';		break;
+			case 361: $function = 'AVERAGEA';		break;
+			case 362: $function = 'MAXA';			break;
+			case 363: $function = 'MINA';			break;
+			case 364: $function = 'STDEVPA';		break;
+			case 365: $function = 'VARPA';			break;
+			case 366: $function = 'STDEVA';			break;
+			case 367: $function = 'VARA';			break;
+			default:
+				throw new Exception('Unrecognized function in formula');
+				break;
+			}
+			$data = array('function' => $function, 'args' => $args);
+			break;
+		case 0x23:	//	index to defined name
+		case 0x43:
+		case 0x63:
+			$name = 'tName';
+			$size = 5;
+			// offset: 1; size: 2; one-based index to definedname record
+			$definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
+			// offset: 2; size: 2; not used
+			$data = $this->_definedname[$definedNameIndex]['name'];
+			break;
+		case 0x24:	//	single cell reference e.g. A5
+		case 0x44:
+		case 0x64:
+			$name = 'tRef';
+			$size = 5;
+			$data = $this->_readBIFF8CellAddress(substr($formulaData, 1, 4));
+			break;
+		case 0x25:	//	cell range reference to cells in the same sheet (2d)
+		case 0x45:
+		case 0x65:
+			$name = 'tArea';
+			$size = 9;
+			$data = $this->_readBIFF8CellRangeAddress(substr($formulaData, 1, 8));
+			break;
+		case 0x26:	//	Constant reference sub-expression
+		case 0x46:
+		case 0x66:
+			$name = 'tMemArea';
+			// offset: 1; size: 4; not used
+			// offset: 5; size: 2; size of the following subexpression
+			$subSize = self::_GetInt2d($formulaData, 5);
+			$size = 7 + $subSize;
+			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
+			break;
+		case 0x27:	//	Deleted constant reference sub-expression
+		case 0x47:
+		case 0x67:
+			$name = 'tMemErr';
+			// offset: 1; size: 4; not used
+			// offset: 5; size: 2; size of the following subexpression
+			$subSize = self::_GetInt2d($formulaData, 5);
+			$size = 7 + $subSize;
+			$data = $this->_getFormulaFromData(substr($formulaData, 7, $subSize));
+			break;
+		case 0x29:	//	Variable reference sub-expression
+		case 0x49:
+		case 0x69:
+			$name = 'tMemFunc';
+			// offset: 1; size: 2; size of the following sub-expression
+			$subSize = self::_GetInt2d($formulaData, 1);
+			$size = 3 + $subSize;
+			$data = $this->_getFormulaFromData(substr($formulaData, 3, $subSize));
+			break;
+
+		case 0x2C: // Relative 2d cell reference reference, used in shared formulas and some other places
+		case 0x4C:
+		case 0x6C:
+			$name = 'tRefN';
+			$size = 5;
+			$data = $this->_readBIFF8CellAddressB(substr($formulaData, 1, 4), $baseCell);
+			break;
+
+		case 0x2D:	//	Relative 2d range reference
+		case 0x4D:
+		case 0x6D:
+			$name = 'tAreaN';
+			$size = 9;
+			$data = $this->_readBIFF8CellRangeAddressB(substr($formulaData, 1, 8), $baseCell);
+			break;
+
+		case 0x39:	//	External name
+		case 0x59:
+		case 0x79:
+			$name = 'tNameX';
+			$size = 7;
+			// offset: 1; size: 2; index to REF entry in EXTERNSHEET record
+			// offset: 3; size: 2; one-based index to DEFINEDNAME or EXTERNNAME record
+			$index = self::_GetInt2d($formulaData, 3);
+			// assume index is to EXTERNNAME record
+			$data = $this->_externalNames[$index - 1]['name'];
+			// offset: 5; size: 2; not used
+			break;
+
+		case 0x3A:	//	3d reference to cell
+		case 0x5A:
+		case 0x7A:
+			$name = 'tRef3d';
+			$size = 7;
+
+			try {
+				// offset: 1; size: 2; index to REF entry
+				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
+				// offset: 3; size: 4; cell address
+				$cellAddress = $this->_readBIFF8CellAddress(substr($formulaData, 3, 4));
+
+				$data = "$sheetRange!$cellAddress";
+			} catch (Exception $e) {
+				// deleted sheet reference
+				$data = '#REF!';
+			}
+
+			break;
+		case 0x3B:	//	3d reference to cell range
+		case 0x5B:
+		case 0x7B:
+			$name = 'tArea3d';
+			$size = 11;
+
+			try {
+				// offset: 1; size: 2; index to REF entry
+				$sheetRange = $this->_readSheetRangeByRefIndex(self::_GetInt2d($formulaData, 1));
+				// offset: 3; size: 8; cell address
+				$cellRangeAddress = $this->_readBIFF8CellRangeAddress(substr($formulaData, 3, 8));
+
+				$data = "$sheetRange!$cellRangeAddress";
+			} catch (Exception $e) {
+				// deleted sheet reference
+				$data = '#REF!';
+			}
+
+			break;
+		// Unknown cases	// don't know how to deal with
+		default:
+			throw new Exception('Unrecognized token ' . sprintf('%02X', $id) . ' in formula');
+			break;
+		}
+
+		return array(
+			'id' => $id,
+			'name' => $name,
+			'size' => $size,
+			'data' => $data,
+		);
+	}
+
+
+	/**
+	 * Reads a cell address in BIFF8 e.g. 'A2' or '$A$2'
+	 * section 3.3.4
+	 *
+	 * @param string $cellAddressStructure
+	 * @return string
+	 */
+	private function _readBIFF8CellAddress($cellAddressStructure)
+	{
+		// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
+		$row = self::_GetInt2d($cellAddressStructure, 0) + 1;
+
+		// offset: 2; size: 2; index to column or column offset + relative flags
+
+			// bit: 7-0; mask 0x00FF; column index
+			$column = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($cellAddressStructure, 2));
+
+			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+			if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
+				$column = '$' . $column;
+			}
+			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+			if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
+				$row = '$' . $row;
+			}
+
+		return $column . $row;
+	}
+
+
+	/**
+	 * Reads a cell address in BIFF8 for shared formulas. Uses positive and negative values for row and column
+	 * to indicate offsets from a base cell
+	 * section 3.3.4
+	 *
+	 * @param string $cellAddressStructure
+	 * @param string $baseCell Base cell, only needed when formula contains tRefN tokens, e.g. with shared formulas
+	 * @return string
+	 */
+	private function _readBIFF8CellAddressB($cellAddressStructure, $baseCell = 'A1')
+	{
+		list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
+		$baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
+
+		// offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767))
+			$rowIndex = self::_GetInt2d($cellAddressStructure, 0);
+			$row = self::_GetInt2d($cellAddressStructure, 0) + 1;
+
+		// offset: 2; size: 2; index to column or column offset + relative flags
+
+			// bit: 7-0; mask 0x00FF; column index
+			$colIndex = 0x00FF & self::_GetInt2d($cellAddressStructure, 2);
+
+			// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+			if (!(0x4000 & self::_GetInt2d($cellAddressStructure, 2))) {
+				$column = PHPExcel_Cell::stringFromColumnIndex($colIndex);
+				$column = '$' . $column;
+			} else {
+				$colIndex = ($colIndex <= 127) ? $colIndex : $colIndex - 256;
+				$column = PHPExcel_Cell::stringFromColumnIndex($baseCol + $colIndex);
+			}
+
+			// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+			if (!(0x8000 & self::_GetInt2d($cellAddressStructure, 2))) {
+				$row = '$' . $row;
+			} else {
+				$rowIndex = ($rowIndex <= 32767) ? $rowIndex : $rowIndex - 65536;
+				$row = $baseRow + $rowIndex;
+			}
+
+		return $column . $row;
+	}
+
+
+	/**
+	 * Reads a cell range address in BIFF5 e.g. 'A2:B6' or 'A1'
+	 * always fixed range
+	 * section 2.5.14
+	 *
+	 * @param string $subData
+	 * @return string
+	 * @throws Exception
+	 */
+	private function _readBIFF5CellRangeAddressFixed($subData)
+	{
+		// offset: 0; size: 2; index to first row
+		$fr = self::_GetInt2d($subData, 0) + 1;
+
+		// offset: 2; size: 2; index to last row
+		$lr = self::_GetInt2d($subData, 2) + 1;
+
+		// offset: 4; size: 1; index to first column
+		$fc = ord($subData{4});
+
+		// offset: 5; size: 1; index to last column
+		$lc = ord($subData{5});
+
+		// check values
+		if ($fr > $lr || $fc > $lc) {
+			throw new Exception('Not a cell range address');
+		}
+
+		// column index to letter
+		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
+		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);
+
+		if ($fr == $lr and $fc == $lc) {
+			return "$fc$fr";
+		}
+		return "$fc$fr:$lc$lr";
+	}
+
+
+	/**
+	 * Reads a cell range address in BIFF8 e.g. 'A2:B6' or 'A1'
+	 * always fixed range
+	 * section 2.5.14
+	 *
+	 * @param string $subData
+	 * @return string
+	 * @throws Exception
+	 */
+	private function _readBIFF8CellRangeAddressFixed($subData)
+	{
+		// offset: 0; size: 2; index to first row
+		$fr = self::_GetInt2d($subData, 0) + 1;
+
+		// offset: 2; size: 2; index to last row
+		$lr = self::_GetInt2d($subData, 2) + 1;
+
+		// offset: 4; size: 2; index to first column
+		$fc = self::_GetInt2d($subData, 4);
+
+		// offset: 6; size: 2; index to last column
+		$lc = self::_GetInt2d($subData, 6);
+
+		// check values
+		if ($fr > $lr || $fc > $lc) {
+			throw new Exception('Not a cell range address');
+		}
+
+		// column index to letter
+		$fc = PHPExcel_Cell::stringFromColumnIndex($fc);
+		$lc = PHPExcel_Cell::stringFromColumnIndex($lc);
+
+		if ($fr == $lr and $fc == $lc) {
+			return "$fc$fr";
+		}
+		return "$fc$fr:$lc$lr";
+	}
+
+
+	/**
+	 * Reads a cell range address in BIFF8 e.g. 'A2:B6' or '$A$2:$B$6'
+	 * there are flags indicating whether column/row index is relative
+	 * section 3.3.4
+	 *
+	 * @param string $subData
+	 * @return string
+	 */
+	private function _readBIFF8CellRangeAddress($subData)
+	{
+		// todo: if cell range is just a single cell, should this funciton
+		// not just return e.g. 'A1' and not 'A1:A1' ?
+
+		// offset: 0; size: 2; index to first row (0... 65535) (or offset (-32768... 32767))
+			$fr = self::_GetInt2d($subData, 0) + 1;
+
+		// offset: 2; size: 2; index to last row (0... 65535) (or offset (-32768... 32767))
+			$lr = self::_GetInt2d($subData, 2) + 1;
+
+		// offset: 4; size: 2; index to first column or column offset + relative flags
+
+		// bit: 7-0; mask 0x00FF; column index
+		$fc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 4));
+
+		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+		if (!(0x4000 & self::_GetInt2d($subData, 4))) {
+			$fc = '$' . $fc;
+		}
+
+		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+		if (!(0x8000 & self::_GetInt2d($subData, 4))) {
+			$fr = '$' . $fr;
+		}
+
+		// offset: 6; size: 2; index to last column or column offset + relative flags
+
+		// bit: 7-0; mask 0x00FF; column index
+		$lc = PHPExcel_Cell::stringFromColumnIndex(0x00FF & self::_GetInt2d($subData, 6));
+
+		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+		if (!(0x4000 & self::_GetInt2d($subData, 6))) {
+			$lc = '$' . $lc;
+		}
+
+		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+		if (!(0x8000 & self::_GetInt2d($subData, 6))) {
+			$lr = '$' . $lr;
+		}
+
+		return "$fc$fr:$lc$lr";
+	}
+
+
+	/**
+	 * Reads a cell range address in BIFF8 for shared formulas. Uses positive and negative values for row and column
+	 * to indicate offsets from a base cell
+	 * section 3.3.4
+	 *
+	 * @param string $subData
+	 * @param string $baseCell Base cell
+	 * @return string Cell range address
+	 */
+	private function _readBIFF8CellRangeAddressB($subData, $baseCell = 'A1')
+	{
+		list($baseCol, $baseRow) = PHPExcel_Cell::coordinateFromString($baseCell);
+		$baseCol = PHPExcel_Cell::columnIndexFromString($baseCol) - 1;
+
+		// TODO: if cell range is just a single cell, should this funciton
+		// not just return e.g. 'A1' and not 'A1:A1' ?
+
+		// offset: 0; size: 2; first row
+		$frIndex = self::_GetInt2d($subData, 0); // adjust below
+
+		// offset: 2; size: 2; relative index to first row (0... 65535) should be treated as offset (-32768... 32767)
+		$lrIndex = self::_GetInt2d($subData, 2); // adjust below
+
+		// offset: 4; size: 2; first column with relative/absolute flags
+
+		// bit: 7-0; mask 0x00FF; column index
+		$fcIndex = 0x00FF & self::_GetInt2d($subData, 4);
+
+		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+		if (!(0x4000 & self::_GetInt2d($subData, 4))) {
+			// absolute column index
+			$fc = PHPExcel_Cell::stringFromColumnIndex($fcIndex);
+			$fc = '$' . $fc;
+		} else {
+			// column offset
+			$fcIndex = ($fcIndex <= 127) ? $fcIndex : $fcIndex - 256;
+			$fc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $fcIndex);
+		}
+
+		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+		if (!(0x8000 & self::_GetInt2d($subData, 4))) {
+			// absolute row index
+			$fr = $frIndex + 1;
+			$fr = '$' . $fr;
+		} else {
+			// row offset
+			$frIndex = ($frIndex <= 32767) ? $frIndex : $frIndex - 65536;
+			$fr = $baseRow + $frIndex;
+		}
+
+		// offset: 6; size: 2; last column with relative/absolute flags
+
+		// bit: 7-0; mask 0x00FF; column index
+		$lcIndex = 0x00FF & self::_GetInt2d($subData, 6);
+		$lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
+		$lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
+
+		// bit: 14; mask 0x4000; (1 = relative column index, 0 = absolute column index)
+		if (!(0x4000 & self::_GetInt2d($subData, 6))) {
+			// absolute column index
+			$lc = PHPExcel_Cell::stringFromColumnIndex($lcIndex);
+			$lc = '$' . $lc;
+		} else {
+			// column offset
+			$lcIndex = ($lcIndex <= 127) ? $lcIndex : $lcIndex - 256;
+			$lc = PHPExcel_Cell::stringFromColumnIndex($baseCol + $lcIndex);
+		}
+
+		// bit: 15; mask 0x8000; (1 = relative row index, 0 = absolute row index)
+		if (!(0x8000 & self::_GetInt2d($subData, 6))) {
+			// absolute row index
+			$lr = $lrIndex + 1;
+			$lr = '$' . $lr;
+		} else {
+			// row offset
+			$lrIndex = ($lrIndex <= 32767) ? $lrIndex : $lrIndex - 65536;
+			$lr = $baseRow + $lrIndex;
+		}
+
+		return "$fc$fr:$lc$lr";
+	}
+
+
+	/**
+	 * Read BIFF8 cell range address list
+	 * section 2.5.15
+	 *
+	 * @param string $subData
+	 * @return array
+	 */
+	private function _readBIFF8CellRangeAddressList($subData)
+	{
+		$cellRangeAddresses = array();
+
+		// offset: 0; size: 2; number of the following cell range addresses
+		$nm = self::_GetInt2d($subData, 0);
+
+		$offset = 2;
+		// offset: 2; size: 8 * $nm; list of $nm (fixed) cell range addresses
+		for ($i = 0; $i < $nm; ++$i) {
+			$cellRangeAddresses[] = $this->_readBIFF8CellRangeAddressFixed(substr($subData, $offset, 8));
+			$offset += 8;
+		}
+
+		return array(
+			'size' => 2 + 8 * $nm,
+			'cellRangeAddresses' => $cellRangeAddresses,
+		);
+	}
+
+
+	/**
+	 * Read BIFF5 cell range address list
+	 * section 2.5.15
+	 *
+	 * @param string $subData
+	 * @return array
+	 */
+	private function _readBIFF5CellRangeAddressList($subData)
+	{
+		$cellRangeAddresses = array();
+
+		// offset: 0; size: 2; number of the following cell range addresses
+		$nm = self::_GetInt2d($subData, 0);
+
+		$offset = 2;
+		// offset: 2; size: 6 * $nm; list of $nm (fixed) cell range addresses
+		for ($i = 0; $i < $nm; ++$i) {
+			$cellRangeAddresses[] = $this->_readBIFF5CellRangeAddressFixed(substr($subData, $offset, 6));
+			$offset += 6;
+		}
+
+		return array(
+			'size' => 2 + 6 * $nm,
+			'cellRangeAddresses' => $cellRangeAddresses,
+		);
+	}
+
+
+	/**
+	 * Get a sheet range like Sheet1:Sheet3 from REF index
+	 * Note: If there is only one sheet in the range, one gets e.g Sheet1
+	 * It can also happen that the REF structure uses the -1 (FFFF) code to indicate deleted sheets,
+	 * in which case an exception is thrown
+	 *
+	 * @param int $index
+	 * @return string|false
+	 * @throws Exception
+	 */
+	private function _readSheetRangeByRefIndex($index)
+	{
+		if (isset($this->_ref[$index])) {
+
+			$type = $this->_externalBooks[$this->_ref[$index]['externalBookIndex']]['type'];
+
+			switch ($type) {
+				case 'internal':
+					// check if we have a deleted 3d reference
+					if ($this->_ref[$index]['firstSheetIndex'] == 0xFFFF or $this->_ref[$index]['lastSheetIndex'] == 0xFFFF) {
+						throw new Exception('Deleted sheet reference');
+					}
+
+					// we have normal sheet range (collapsed or uncollapsed)
+					$firstSheetName = $this->_sheets[$this->_ref[$index]['firstSheetIndex']]['name'];
+					$lastSheetName = $this->_sheets[$this->_ref[$index]['lastSheetIndex']]['name'];
+
+					if ($firstSheetName == $lastSheetName) {
+						// collapsed sheet range
+						$sheetRange = $firstSheetName;
+					} else {
+						$sheetRange = "$firstSheetName:$lastSheetName";
+					}
+
+					// escape the single-quotes
+					$sheetRange = str_replace("'", "''", $sheetRange);
+
+					// if there are special characters, we need to enclose the range in single-quotes
+					// todo: check if we have identified the whole set of special characters
+					// it seems that the following characters are not accepted for sheet names
+					// and we may assume that they are not present: []*/:\?
+					if (preg_match("/[ !\"@#£$%&{()}<>=+'|^,;-]/", $sheetRange)) {
+						$sheetRange = "'$sheetRange'";
+					}
+
+					return $sheetRange;
+					break;
+
+				default:
+					// TODO: external sheet support
+					throw new Exception('Excel5 reader only supports internal sheets in fomulas');
+					break;
+			}
+		}
+		return false;
+	}
+
+
+	/**
+	 * read BIFF8 constant value array from array data
+	 * returns e.g. array('value' => '{1,2;3,4}', 'size' => 40}
+	 * section 2.5.8
+	 *
+	 * @param string $arrayData
+	 * @return array
+	 */
+	private static function _readBIFF8ConstantArray($arrayData)
+	{
+		// offset: 0; size: 1; number of columns decreased by 1
+		$nc = ord($arrayData[0]);
+
+		// offset: 1; size: 2; number of rows decreased by 1
+		$nr = self::_GetInt2d($arrayData, 1);
+		$size = 3; // initialize
+		$arrayData = substr($arrayData, 3);
+
+		// offset: 3; size: var; list of ($nc + 1) * ($nr + 1) constant values
+		$matrixChunks = array();
+		for ($r = 1; $r <= $nr + 1; ++$r) {
+			$items = array();
+			for ($c = 1; $c <= $nc + 1; ++$c) {
+				$constant = self::_readBIFF8Constant($arrayData);
+				$items[] = $constant['value'];
+				$arrayData = substr($arrayData, $constant['size']);
+				$size += $constant['size'];
+			}
+			$matrixChunks[] = implode(',', $items); // looks like e.g. '1,"hello"'
+		}
+		$matrix = '{' . implode(';', $matrixChunks) . '}';
+
+		return array(
+			'value' => $matrix,
+			'size' => $size,
+		);
+	}
+
+
+	/**
+	 * read BIFF8 constant value which may be 'Empty Value', 'Number', 'String Value', 'Boolean Value', 'Error Value'
+	 * section 2.5.7
+	 * returns e.g. array('value' => '5', 'size' => 9)
+	 *
+	 * @param string $valueData
+	 * @return array
+	 */
+	private static function _readBIFF8Constant($valueData)
+	{
+		// offset: 0; size: 1; identifier for type of constant
+		$identifier = ord($valueData[0]);
+
+		switch ($identifier) {
+		case 0x00: // empty constant (what is this?)
+			$value = '';
+			$size = 9;
+			break;
+		case 0x01: // number
+			// offset: 1; size: 8; IEEE 754 floating-point value
+			$value = self::_extractNumber(substr($valueData, 1, 8));
+			$size = 9;
+			break;
+		case 0x02: // string value
+			// offset: 1; size: var; Unicode string, 16-bit string length
+			$string = self::_readUnicodeStringLong(substr($valueData, 1));
+			$value = '"' . $string['value'] . '"';
+			$size = 1 + $string['size'];
+			break;
+		case 0x04: // boolean
+			// offset: 1; size: 1; 0 = FALSE, 1 = TRUE
+			if (ord($valueData[1])) {
+				$value = 'TRUE';
+			} else {
+				$value = 'FALSE';
+			}
+			$size = 9;
+			break;
+		case 0x10: // error code
+			// offset: 1; size: 1; error code
+			$value = self::_mapErrorCode(ord($valueData[1]));
+			$size = 9;
+			break;
+		}
+		return array(
+			'value' => $value,
+			'size' => $size,
+		);
+	}
+
+
+	/**
+	 * Extract RGB color
+	 * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.4
+	 *
+	 * @param string $rgb Encoded RGB value (4 bytes)
+	 * @return array
+	 */
+	private static function _readRGB($rgb)
+	{
+		// offset: 0; size 1; Red component
+		$r = ord($rgb{0});
+
+		// offset: 1; size: 1; Green component
+		$g = ord($rgb{1});
+
+		// offset: 2; size: 1; Blue component
+		$b = ord($rgb{2});
+
+		// HEX notation, e.g. 'FF00FC'
+		$rgb = sprintf('%02X%02X%02X', $r, $g, $b);
+
+		return array('rgb' => $rgb);
+	}
+
+
+	/**
+	 * Read byte string (8-bit string length)
+	 * OpenOffice documentation: 2.5.2
+	 *
+	 * @param string $subData
+	 * @return array
+	 */
+	private function _readByteStringShort($subData)
+	{
+		// offset: 0; size: 1; length of the string (character count)
+		$ln = ord($subData[0]);
+
+		// offset: 1: size: var; character array (8-bit characters)
+		$value = $this->_decodeCodepage(substr($subData, 1, $ln));
+
+		return array(
+			'value' => $value,
+			'size' => 1 + $ln, // size in bytes of data structure
+		);
+	}
+
+
+	/**
+	 * Read byte string (16-bit string length)
+	 * OpenOffice documentation: 2.5.2
+	 *
+	 * @param string $subData
+	 * @return array
+	 */
+	private function _readByteStringLong($subData)
+	{
+		// offset: 0; size: 2; length of the string (character count)
+		$ln = self::_GetInt2d($subData, 0);
+
+		// offset: 2: size: var; character array (8-bit characters)
+		$value = $this->_decodeCodepage(substr($subData, 2));
+
+		//return $string;
+		return array(
+			'value' => $value,
+			'size' => 2 + $ln, // size in bytes of data structure
+		);
+	}
+
+
+	/**
+	 * Extracts an Excel Unicode short string (8-bit string length)
+	 * OpenOffice documentation: 2.5.3
+	 * function will automatically find out where the Unicode string ends.
+	 *
+	 * @param string $subData
+	 * @return array
+	 */
+	private static function _readUnicodeStringShort($subData)
+	{
+		$value = '';
+
+		// offset: 0: size: 1; length of the string (character count)
+		$characterCount = ord($subData[0]);
+
+		$string = self::_readUnicodeString(substr($subData, 1), $characterCount);
+
+		// add 1 for the string length
+		$string['size'] += 1;
+
+		return $string;
+	}
+
+
+	/**
+	 * Extracts an Excel Unicode long string (16-bit string length)
+	 * OpenOffice documentation: 2.5.3
+	 * this function is under construction, needs to support rich text, and Asian phonetic settings
+	 *
+	 * @param string $subData
+	 * @return array
+	 */
+	private static function _readUnicodeStringLong($subData)
+	{
+		$value = '';
+
+		// offset: 0: size: 2; length of the string (character count)
+		$characterCount = self::_GetInt2d($subData, 0);
+
+		$string = self::_readUnicodeString(substr($subData, 2), $characterCount);
+
+		// add 2 for the string length
+		$string['size'] += 2;
+
+		return $string;
+	}
+
+
+	/**
+	 * Read Unicode string with no string length field, but with known character count
+	 * this function is under construction, needs to support rich text, and Asian phonetic settings
+	 * OpenOffice.org's Documentation of the Microsoft Excel File Format, section 2.5.3
+	 *
+	 * @param string $subData
+	 * @param int $characterCount
+	 * @return array
+	 */
+	private static function _readUnicodeString($subData, $characterCount)
+	{
+		$value = '';
+
+		// offset: 0: size: 1; option flags
+
+			// bit: 0; mask: 0x01; character compression (0 = compressed 8-bit, 1 = uncompressed 16-bit)
+			$isCompressed = !((0x01 & ord($subData[0])) >> 0);
+
+			// bit: 2; mask: 0x04; Asian phonetic settings
+			$hasAsian = (0x04) & ord($subData[0]) >> 2;
+
+			// bit: 3; mask: 0x08; Rich-Text settings
+			$hasRichText = (0x08) & ord($subData[0]) >> 3;
+
+		// offset: 1: size: var; character array
+		// this offset assumes richtext and Asian phonetic settings are off which is generally wrong
+		// needs to be fixed
+		$value = self::_encodeUTF16(substr($subData, 1, $isCompressed ? $characterCount : 2 * $characterCount), $isCompressed);
+
+		return array(
+			'value' => $value,
+			'size' => $isCompressed ? 1 + $characterCount : 1 + 2 * $characterCount, // the size in bytes including the option flags
+		);
+	}
+
+
+	/**
+	 * Convert UTF-8 string to string surounded by double quotes. Used for explicit string tokens in formulas.
+	 * Example:  hello"world  -->  "hello""world"
+	 *
+	 * @param string $value UTF-8 encoded string
+	 * @return string
+	 */
+	private static function _UTF8toExcelDoubleQuoted($value)
+	{
+		return '"' . str_replace('"', '""', $value) . '"';
+	}
+
+
+	/**
+	 * Reads first 8 bytes of a string and return IEEE 754 float
+	 *
+	 * @param string $data Binary string that is at least 8 bytes long
+	 * @return float
+	 */
+	private static function _extractNumber($data)
+	{
+		$rknumhigh = self::_GetInt4d($data, 4);
+		$rknumlow = self::_GetInt4d($data, 0);
+		$sign = ($rknumhigh & 0x80000000) >> 31;
+		$exp = (($rknumhigh & 0x7ff00000) >> 20) - 1023;
+		$mantissa = (0x100000 | ($rknumhigh & 0x000fffff));
+		$mantissalow1 = ($rknumlow & 0x80000000) >> 31;
+		$mantissalow2 = ($rknumlow & 0x7fffffff);
+		$value = $mantissa / pow( 2 , (20 - $exp));
+
+		if ($mantissalow1 != 0) {
+			$value += 1 / pow (2 , (21 - $exp));
+		}
+
+		$value += $mantissalow2 / pow (2 , (52 - $exp));
+		if ($sign) {
+			$value *= -1;
+		}
+
+		return $value;
+	}
+
+
+	private static function _GetIEEE754($rknum)
+	{
+		if (($rknum & 0x02) != 0) {
+			$value = $rknum >> 2;
+		} else {
+			// changes by mmp, info on IEEE754 encoding from
+			// research.microsoft.com/~hollasch/cgindex/coding/ieeefloat.html
+			// The RK format calls for using only the most significant 30 bits
+			// of the 64 bit floating point value. The other 34 bits are assumed
+			// to be 0 so we use the upper 30 bits of $rknum as follows...
+			$sign = ($rknum & 0x80000000) >> 31;
+			$exp = ($rknum & 0x7ff00000) >> 20;
+			$mantissa = (0x100000 | ($rknum & 0x000ffffc));
+			$value = $mantissa / pow( 2 , (20- ($exp - 1023)));
+			if ($sign) {
+				$value = -1 * $value;
+			}
+			//end of changes by mmp
+		}
+		if (($rknum & 0x01) != 0) {
+			$value /= 100;
+		}
+		return $value;
+	}
+
+
+	/**
+	 * Get UTF-8 string from (compressed or uncompressed) UTF-16 string
+	 *
+	 * @param string $string
+	 * @param bool $compressed
+	 * @return string
+	 */
+	private static function _encodeUTF16($string, $compressed = '')
+	{
+		if ($compressed) {
+			$string = self::_uncompressByteString($string);
+ 		}
+
+		return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', 'UTF-16LE');
+	}
+
+
+	/**
+	 * Convert UTF-16 string in compressed notation to uncompressed form. Only used for BIFF8.
+	 *
+	 * @param string $string
+	 * @return string
+	 */
+	private static function _uncompressByteString($string)
+	{
+		$uncompressedString = '';
+		$strLen = strlen($string);
+		for ($i = 0; $i < $strLen; ++$i) {
+			$uncompressedString .= $string[$i] . "\0";
+		}
+
+		return $uncompressedString;
+	}
+
+
+	/**
+	 * Convert string to UTF-8. Only used for BIFF5.
+	 *
+	 * @param string $string
+	 * @return string
+	 */
+	private function _decodeCodepage($string)
+	{
+		return PHPExcel_Shared_String::ConvertEncoding($string, 'UTF-8', $this->_codepage);
+	}
+
+
+	/**
+	 * Read 16-bit unsigned integer
+	 *
+	 * @param string $data
+	 * @param int $pos
+	 * @return int
+	 */
+	public static function _GetInt2d($data, $pos)
+	{
+		return ord($data[$pos]) | (ord($data[$pos+1]) << 8);
+	}
+
+
+	/**
+	 * Read 32-bit signed integer
+	 *
+	 * @param string $data
+	 * @param int $pos
+	 * @return int
+	 */
+	public static function _GetInt4d($data, $pos)
+	{
+		// FIX: represent numbers correctly on 64-bit system
+		// http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
+		// Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
+		$_or_24 = ord($data[$pos + 3]);
+		if ($_or_24 >= 128) {
+			// negative number
+			$_ord_24 = -abs((256 - $_or_24) << 24);
+		} else {
+			$_ord_24 = ($_or_24 & 127) << 24;
+		}
+		return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $_ord_24;
+	}
+
+
+	/**
+	 * Read color
+	 *
+	 * @param int $color Indexed color
+	 * @param array $palette Color palette
+	 * @return array RGB color value, example: array('rgb' => 'FF0000')
+	 */
+	private static function _readColor($color,$palette,$version)
+	{
+		if ($color <= 0x07 || $color >= 0x40) {
+			// special built-in color
+			return self::_mapBuiltInColor($color);
+		} elseif (isset($palette) && isset($palette[$color - 8])) {
+			// palette color, color index 0x08 maps to pallete index 0
+			return $palette[$color - 8];
+		} else {
+			// default color table
+			if ($version == self::XLS_BIFF8) {
+				return self::_mapColor($color);
+			} else {
+				// BIFF5
+				return self::_mapColorBIFF5($color);
+			}
+		}
+
+		return $color;
+	}
+
+
+	/**
+	 * Map border style
+	 * OpenOffice documentation: 2.5.11
+	 *
+	 * @param int $index
+	 * @return string
+	 */
+	private static function _mapBorderStyle($index)
+	{
+		switch ($index) {
+			case 0x00: return PHPExcel_Style_Border::BORDER_NONE;
+			case 0x01: return PHPExcel_Style_Border::BORDER_THIN;
+			case 0x02: return PHPExcel_Style_Border::BORDER_MEDIUM;
+			case 0x03: return PHPExcel_Style_Border::BORDER_DASHED;
+			case 0x04: return PHPExcel_Style_Border::BORDER_DOTTED;
+			case 0x05: return PHPExcel_Style_Border::BORDER_THICK;
+			case 0x06: return PHPExcel_Style_Border::BORDER_DOUBLE;
+			case 0x07: return PHPExcel_Style_Border::BORDER_HAIR;
+			case 0x08: return PHPExcel_Style_Border::BORDER_MEDIUMDASHED;
+			case 0x09: return PHPExcel_Style_Border::BORDER_DASHDOT;
+			case 0x0A: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT;
+			case 0x0B: return PHPExcel_Style_Border::BORDER_DASHDOTDOT;
+			case 0x0C: return PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT;
+			case 0x0D: return PHPExcel_Style_Border::BORDER_SLANTDASHDOT;
+			default:   return PHPExcel_Style_Border::BORDER_NONE;
+		}
+	}
+
+
+	/**
+	 * Get fill pattern from index
+	 * OpenOffice documentation: 2.5.12
+	 *
+	 * @param int $index
+	 * @return string
+	 */
+	private static function _mapFillPattern($index)
+	{
+		switch ($index) {
+			case 0x00: return PHPExcel_Style_Fill::FILL_NONE;
+			case 0x01: return PHPExcel_Style_Fill::FILL_SOLID;
+			case 0x02: return PHPExcel_Style_Fill::FILL_PATTERN_MEDIUMGRAY;
+			case 0x03: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRAY;
+			case 0x04: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRAY;
+			case 0x05: return PHPExcel_Style_Fill::FILL_PATTERN_DARKHORIZONTAL;
+			case 0x06: return PHPExcel_Style_Fill::FILL_PATTERN_DARKVERTICAL;
+			case 0x07: return PHPExcel_Style_Fill::FILL_PATTERN_DARKDOWN;
+			case 0x08: return PHPExcel_Style_Fill::FILL_PATTERN_DARKUP;
+			case 0x09: return PHPExcel_Style_Fill::FILL_PATTERN_DARKGRID;
+			case 0x0A: return PHPExcel_Style_Fill::FILL_PATTERN_DARKTRELLIS;
+			case 0x0B: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTHORIZONTAL;
+			case 0x0C: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTVERTICAL;
+			case 0x0D: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTDOWN;
+			case 0x0E: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTUP;
+			case 0x0F: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTGRID;
+			case 0x10: return PHPExcel_Style_Fill::FILL_PATTERN_LIGHTTRELLIS;
+			case 0x11: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY125;
+			case 0x12: return PHPExcel_Style_Fill::FILL_PATTERN_GRAY0625;
+			default:   return PHPExcel_Style_Fill::FILL_NONE;
+		}
+	}
+
+
+	/**
+	 * Map error code, e.g. '#N/A'
+	 *
+	 * @param int $subData
+	 * @return string
+	 */
+	private static function _mapErrorCode($subData)
+	{
+		switch ($subData) {
+			case 0x00: return '#NULL!';		break;
+			case 0x07: return '#DIV/0!';	break;
+			case 0x0F: return '#VALUE!';	break;
+			case 0x17: return '#REF!';		break;
+			case 0x1D: return '#NAME?';		break;
+			case 0x24: return '#NUM!';		break;
+			case 0x2A: return '#N/A';		break;
+			default: return false;
+		}
+	}
+
+
+	/**
+	 * Map built-in color to RGB value
+	 *
+	 * @param int $color Indexed color
+	 * @return array
+	 */
+	private static function _mapBuiltInColor($color)
+	{
+		switch ($color) {
+			case 0x00: return array('rgb' => '000000');
+			case 0x01: return array('rgb' => 'FFFFFF');
+			case 0x02: return array('rgb' => 'FF0000');
+			case 0x03: return array('rgb' => '00FF00');
+			case 0x04: return array('rgb' => '0000FF');
+			case 0x05: return array('rgb' => 'FFFF00');
+			case 0x06: return array('rgb' => 'FF00FF');
+			case 0x07: return array('rgb' => '00FFFF');
+			case 0x40: return array('rgb' => '000000'); // system window text color
+			case 0x41: return array('rgb' => 'FFFFFF'); // system window background color
+			default:   return array('rgb' => '000000');
+		}
+	}
+
+
+	/**
+	 * Map color array from BIFF5 built-in color index
+	 *
+	 * @param int $subData
+	 * @return array
+	 */
+	private static function _mapColorBIFF5($subData)
+	{
+		switch ($subData) {
+			case 0x08: return array('rgb' => '000000');
+			case 0x09: return array('rgb' => 'FFFFFF');
+			case 0x0A: return array('rgb' => 'FF0000');
+			case 0x0B: return array('rgb' => '00FF00');
+			case 0x0C: return array('rgb' => '0000FF');
+			case 0x0D: return array('rgb' => 'FFFF00');
+			case 0x0E: return array('rgb' => 'FF00FF');
+			case 0x0F: return array('rgb' => '00FFFF');
+			case 0x10: return array('rgb' => '800000');
+			case 0x11: return array('rgb' => '008000');
+			case 0x12: return array('rgb' => '000080');
+			case 0x13: return array('rgb' => '808000');
+			case 0x14: return array('rgb' => '800080');
+			case 0x15: return array('rgb' => '008080');
+			case 0x16: return array('rgb' => 'C0C0C0');
+			case 0x17: return array('rgb' => '808080');
+			case 0x18: return array('rgb' => '8080FF');
+			case 0x19: return array('rgb' => '802060');
+			case 0x1A: return array('rgb' => 'FFFFC0');
+			case 0x1B: return array('rgb' => 'A0E0F0');
+			case 0x1C: return array('rgb' => '600080');
+			case 0x1D: return array('rgb' => 'FF8080');
+			case 0x1E: return array('rgb' => '0080C0');
+			case 0x1F: return array('rgb' => 'C0C0FF');
+			case 0x20: return array('rgb' => '000080');
+			case 0x21: return array('rgb' => 'FF00FF');
+			case 0x22: return array('rgb' => 'FFFF00');
+			case 0x23: return array('rgb' => '00FFFF');
+			case 0x24: return array('rgb' => '800080');
+			case 0x25: return array('rgb' => '800000');
+			case 0x26: return array('rgb' => '008080');
+			case 0x27: return array('rgb' => '0000FF');
+			case 0x28: return array('rgb' => '00CFFF');
+			case 0x29: return array('rgb' => '69FFFF');
+			case 0x2A: return array('rgb' => 'E0FFE0');
+			case 0x2B: return array('rgb' => 'FFFF80');
+			case 0x2C: return array('rgb' => 'A6CAF0');
+			case 0x2D: return array('rgb' => 'DD9CB3');
+			case 0x2E: return array('rgb' => 'B38FEE');
+			case 0x2F: return array('rgb' => 'E3E3E3');
+			case 0x30: return array('rgb' => '2A6FF9');
+			case 0x31: return array('rgb' => '3FB8CD');
+			case 0x32: return array('rgb' => '488436');
+			case 0x33: return array('rgb' => '958C41');
+			case 0x34: return array('rgb' => '8E5E42');
+			case 0x35: return array('rgb' => 'A0627A');
+			case 0x36: return array('rgb' => '624FAC');
+			case 0x37: return array('rgb' => '969696');
+			case 0x38: return array('rgb' => '1D2FBE');
+			case 0x39: return array('rgb' => '286676');
+			case 0x3A: return array('rgb' => '004500');
+			case 0x3B: return array('rgb' => '453E01');
+			case 0x3C: return array('rgb' => '6A2813');
+			case 0x3D: return array('rgb' => '85396A');
+			case 0x3E: return array('rgb' => '4A3285');
+			case 0x3F: return array('rgb' => '424242');
+			default:   return array('rgb' => '000000');
+		}
+	}
+
+
+	/**
+	 * Map color array from BIFF8 built-in color index
+	 *
+	 * @param int $subData
+	 * @return array
+	 */
+	private static function _mapColor($subData)
+	{
+		switch ($subData) {
+			case 0x08: return array('rgb' => '000000');
+			case 0x09: return array('rgb' => 'FFFFFF');
+			case 0x0A: return array('rgb' => 'FF0000');
+			case 0x0B: return array('rgb' => '00FF00');
+			case 0x0C: return array('rgb' => '0000FF');
+			case 0x0D: return array('rgb' => 'FFFF00');
+			case 0x0E: return array('rgb' => 'FF00FF');
+			case 0x0F: return array('rgb' => '00FFFF');
+			case 0x10: return array('rgb' => '800000');
+			case 0x11: return array('rgb' => '008000');
+			case 0x12: return array('rgb' => '000080');
+			case 0x13: return array('rgb' => '808000');
+			case 0x14: return array('rgb' => '800080');
+			case 0x15: return array('rgb' => '008080');
+			case 0x16: return array('rgb' => 'C0C0C0');
+			case 0x17: return array('rgb' => '808080');
+			case 0x18: return array('rgb' => '9999FF');
+			case 0x19: return array('rgb' => '993366');
+			case 0x1A: return array('rgb' => 'FFFFCC');
+			case 0x1B: return array('rgb' => 'CCFFFF');
+			case 0x1C: return array('rgb' => '660066');
+			case 0x1D: return array('rgb' => 'FF8080');
+			case 0x1E: return array('rgb' => '0066CC');
+			case 0x1F: return array('rgb' => 'CCCCFF');
+			case 0x20: return array('rgb' => '000080');
+			case 0x21: return array('rgb' => 'FF00FF');
+			case 0x22: return array('rgb' => 'FFFF00');
+			case 0x23: return array('rgb' => '00FFFF');
+			case 0x24: return array('rgb' => '800080');
+			case 0x25: return array('rgb' => '800000');
+			case 0x26: return array('rgb' => '008080');
+			case 0x27: return array('rgb' => '0000FF');
+			case 0x28: return array('rgb' => '00CCFF');
+			case 0x29: return array('rgb' => 'CCFFFF');
+			case 0x2A: return array('rgb' => 'CCFFCC');
+			case 0x2B: return array('rgb' => 'FFFF99');
+			case 0x2C: return array('rgb' => '99CCFF');
+			case 0x2D: return array('rgb' => 'FF99CC');
+			case 0x2E: return array('rgb' => 'CC99FF');
+			case 0x2F: return array('rgb' => 'FFCC99');
+			case 0x30: return array('rgb' => '3366FF');
+			case 0x31: return array('rgb' => '33CCCC');
+			case 0x32: return array('rgb' => '99CC00');
+			case 0x33: return array('rgb' => 'FFCC00');
+			case 0x34: return array('rgb' => 'FF9900');
+			case 0x35: return array('rgb' => 'FF6600');
+			case 0x36: return array('rgb' => '666699');
+			case 0x37: return array('rgb' => '969696');
+			case 0x38: return array('rgb' => '003366');
+			case 0x39: return array('rgb' => '339966');
+			case 0x3A: return array('rgb' => '003300');
+			case 0x3B: return array('rgb' => '333300');
+			case 0x3C: return array('rgb' => '993300');
+			case 0x3D: return array('rgb' => '993366');
+			case 0x3E: return array('rgb' => '333399');
+			case 0x3F: return array('rgb' => '333333');
+			default:   return array('rgb' => '000000');
+		}
+	}
+
+
+	private function _parseRichText($is = '') {
+		$value = new PHPExcel_RichText();
+
+		$value->createText($is);
+
+		return $value;
+	}
+
+}

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Reader/Excel5/Escher.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader_Excel5
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader_Excel5
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_Excel5_Escher
 {

+ 125 - 57
htdocs/includes/phpexcel/PHPExcel/Reader/Gnumeric.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -36,28 +36,28 @@ if (!defined('PHPEXCEL_ROOT')) {
 }
 
 /**
- *	PHPExcel_Reader_Gnumeric
+ * PHPExcel_Reader_Gnumeric
  *
- *	@category	PHPExcel
- *	@package	PHPExcel_Reader
- *	@copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @category	PHPExcel
+ * @package		PHPExcel_Reader
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 {
 	/**
-	 *	Read data only?
-	 *	Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
+	 * Read data only?
+	 * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
 	 *		or whether it should read both data and formatting
 	 *
-	 *	@var	boolean
+	 * @var	boolean
 	 */
 	private $_readDataOnly = false;
 
 	/**
-	 *	Restrict which sheets should be loaded?
-	 *	This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
+	 * Restrict which sheets should be loaded?
+	 * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
 	 *
-	 *	@var	array of string
+	 * @var	array of string
 	 */
 	private $_loadSheetsOnly = null;
 
@@ -86,50 +86,62 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 
 
 	/**
-	 *	Read data only?
+	 * Create a new PHPExcel_Reader_Gnumeric
+	 */
+	public function __construct() {
+		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
+		$this->_referenceHelper = PHPExcel_ReferenceHelper::getInstance();
+	}
+
+
+	/**
+	 * Read data only?
 	 *		If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
 	 *		If false (the default) it will read data and formatting.
 	 *
-	 *	@return	boolean
+	 * @return	boolean
 	 */
 	public function getReadDataOnly() {
 		return $this->_readDataOnly;
 	}
 
+
 	/**
-	 *	Set read data only
+	 * Set read data only
 	 *		Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
 	 *		Set to false (the default) to advise the Reader to read both data and formatting for cells.
 	 *
-	 *	@param	boolean	$pValue
+	 * @param	boolean	$pValue
 	 *
-	 *	@return	PHPExcel_Reader_Gnumeric
+	 * @return	PHPExcel_Reader_Gnumeric
 	 */
 	public function setReadDataOnly($pValue = false) {
 		$this->_readDataOnly = $pValue;
 		return $this;
 	}
 
+
 	/**
-	 *	Get which sheets to load
-	 *		Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
-	 *			indicating that all worksheets in the workbook should be loaded.
+	 * Get which sheets to load
+	 * Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
+	 *		indicating that all worksheets in the workbook should be loaded.
 	 *
-	 *	@return mixed
+	 * @return mixed
 	 */
 	public function getLoadSheetsOnly()
 	{
 		return $this->_loadSheetsOnly;
 	}
 
+
 	/**
-	 *	Set which sheets to load
+	 * Set which sheets to load
 	 *
-	 *	@param mixed $value
+	 * @param mixed $value
 	 *		This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
 	 *		If NULL, then it tells the Reader to read all worksheets in the workbook
 	 *
-	 *	@return PHPExcel_Reader_Gnumeric
+	 * @return PHPExcel_Reader_Gnumeric
 	 */
 	public function setLoadSheetsOnly($value = null)
 	{
@@ -138,11 +150,12 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
-	 *	Set all sheets to load
+	 * Set all sheets to load
 	 *		Tells the Reader to load all worksheets from the workbook.
 	 *
-	 *	@return PHPExcel_Reader_Gnumeric
+	 * @return PHPExcel_Reader_Gnumeric
 	 */
 	public function setLoadAllSheets()
 	{
@@ -150,6 +163,7 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Read filter
 	 *
@@ -159,6 +173,7 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $this->_readFilter;
 	}
 
+
 	/**
 	 * Set read filter
 	 *
@@ -170,32 +185,26 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
-	/**
-	 * Create a new PHPExcel_Reader_Gnumeric
-	 */
-	public function __construct() {
-		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
-		$this->_referenceHelper = PHPExcel_ReferenceHelper::getInstance();
-	}
 
 	/**
 	 * Can the current PHPExcel_Reader_IReader read the file?
 	 *
 	 * @param 	string 		$pFileName
 	 * @return 	boolean
+	 * @throws Exception
 	 */
 	public function canRead($pFilename)
 	{
-		// Check if gzlib functions are available
-		if (!function_exists('gzread')) {
-			return false;
-		}
-
 		// Check if file exists
 		if (!file_exists($pFilename)) {
 			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
 		}
 
+		// Check if gzlib functions are available
+		if (!function_exists('gzread')) {
+			throw new Exception("gzlib library is not enabled");
+		}
+
 		// Read signature data (first 3 bytes)
 		$fh = fopen($pFilename, 'r');
 		$data = fread($fh, 2);
@@ -208,22 +217,57 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return true;
 	}
 
+
 	/**
-	 * Loads PHPExcel from file
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
 	 *
-	 * @param 	string 		$pFilename
-	 * @return 	PHPExcel
-	 * @throws 	Exception
+	 * @param   string     $pFilename
+	 * @throws   Exception
 	 */
-	public function load($pFilename)
+	public function listWorksheetInfo($pFilename)
 	{
-		// Create new PHPExcel
-		$objPHPExcel = new PHPExcel();
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
 
-		// Load into this instance
-		return $this->loadIntoExisting($pFilename, $objPHPExcel);
+		$gFileData = $this->_gzfileGetContents($pFilename);
+
+		$xml = simplexml_load_string($gFileData);
+		$namespacesMeta = $xml->getNamespaces(true);
+
+		$gnmXML = $xml->children($namespacesMeta['gnm']);
+
+		$worksheetInfo = array();
+
+		foreach ($gnmXML->Sheets->Sheet as $sheet) {
+			$tmpInfo = array();
+			$tmpInfo['worksheetName'] = (string) $sheet->Name;
+			$tmpInfo['lastColumnLetter'] = 'A';
+			$tmpInfo['lastColumnIndex'] = 0;
+			$tmpInfo['totalRows'] = 0;
+			$tmpInfo['totalColumns'] = 0;
+
+			foreach ($sheet->Cells->Cell as $cell) {
+				$cellAttributes = $cell->attributes();
+
+				$rowIndex = (int) $cellAttributes->Row + 1;
+				$columnIndex = (int) $cellAttributes->Col;
+
+				$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
+				$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex);
+			}
+
+			$tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+			$tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+			$worksheetInfo[] = $tmpInfo;
+		}
+
+		return $worksheetInfo;
 	}
 
+
 	private function _gzfileGetContents($filename) {
 		$file = @gzopen($filename, 'rb');
 		if ($file !== false) {
@@ -236,6 +280,24 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $data;
 	}
 
+
+	/**
+	 * Loads PHPExcel from file
+	 *
+	 * @param 	string 		$pFilename
+	 * @return 	PHPExcel
+	 * @throws 	Exception
+	 */
+	public function load($pFilename)
+	{
+		// Create new PHPExcel
+		$objPHPExcel = new PHPExcel();
+
+		// Load into this instance
+		return $this->loadIntoExisting($pFilename, $objPHPExcel);
+	}
+
+
 	/**
 	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
 	 *
@@ -414,7 +476,10 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 			// Create new Worksheet
 			$objPHPExcel->createSheet();
 			$objPHPExcel->setActiveSheetIndex($worksheetID);
-			$objPHPExcel->getActiveSheet()->setTitle($worksheetName);
+			//	Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in formula
+			//		cells... during the load, all formulae should be correct, and we're simply bringing the worksheet
+			//		name in line with the formula, not the reverse
+			$objPHPExcel->getActiveSheet()->setTitle($worksheetName,false);
 
 			if ((!$this->_readDataOnly) && (isset($sheet->PrintInformation))) {
 				if (isset($sheet->PrintInformation->Margins)) {
@@ -461,7 +526,7 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 				$column = PHPExcel_Cell::stringFromColumnIndex($column);
 
 				// Read cell?
-				if (!is_null($this->getReadFilter())) {
+				if ($this->getReadFilter() !== NULL) {
 					if (!$this->getReadFilter()->readCell($column, $row, $worksheetName)) {
 						continue;
 					}
@@ -536,16 +601,13 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 //
 			foreach($sheet->Styles->StyleRegion as $styleRegion) {
 				$styleAttributes = $styleRegion->attributes();
-//				var_dump($styleAttributes);
-//				echo '<br />';
-
 				if (($styleAttributes['startRow'] <= $maxRow) &&
 					($styleAttributes['startCol'] <= $maxCol)) {
 
-					$startColumn = PHPExcel_Cell::stringFromColumnIndex($styleAttributes['startCol']);
+					$startColumn = PHPExcel_Cell::stringFromColumnIndex((int) $styleAttributes['startCol']);
 					$startRow = $styleAttributes['startRow'] + 1;
 
-					$endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : $styleAttributes['endCol'];
+					$endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol'];
 					$endColumn = PHPExcel_Cell::stringFromColumnIndex($endColumn);
 					$endRow = ($styleAttributes['endRow'] > $maxRow) ? $maxRow : $styleAttributes['endRow'];
 					$endRow += 1;
@@ -808,7 +870,9 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 			//	Handle Merged Cells in this worksheet
 			if (isset($sheet->MergedRegions)) {
 				foreach($sheet->MergedRegions->Merge as $mergeCells) {
-					$objPHPExcel->getActiveSheet()->mergeCells($mergeCells);
+					if (strpos($mergeCells,':') !== FALSE) {
+						$objPHPExcel->getActiveSheet()->mergeCells($mergeCells);
+					}
 				}
 			}
 
@@ -838,7 +902,9 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $objPHPExcel;
 	}
 
-	private static function _parseBorderAttributes($borderAttributes) {
+
+	private static function _parseBorderAttributes($borderAttributes)
+	{
 		$styleArray = array();
 
 		if (isset($borderAttributes["Color"])) {
@@ -893,6 +959,7 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $styleArray;
 	}
 
+
 	private function _parseRichText($is = '') {
 		$value = new PHPExcel_RichText();
 
@@ -901,6 +968,7 @@ class PHPExcel_Reader_Gnumeric implements PHPExcel_Reader_IReader
 		return $value;
 	}
 
+
 	private static function _parseGnumericColour($gnmColour) {
 		list($gnmR,$gnmG,$gnmB) = explode(':',$gnmColour);
 		$gnmR = substr(str_pad($gnmR,4,'0',STR_PAD_RIGHT),0,2);

+ 499 - 0
htdocs/includes/phpexcel/PHPExcel/Reader/HTML.php

@@ -0,0 +1,499 @@
+<?php
+/**
+ * PHPExcel
+ *
+ * Copyright (c) 2006 - 2012 PHPExcel
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Reader
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
+ * @version    1.7.8, 2012-10-12
+ */
+
+
+/** PHPExcel root directory */
+if (!defined('PHPEXCEL_ROOT')) {
+	/**
+	 * @ignore
+	 */
+	define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
+	require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
+}
+
+/**
+ * PHPExcel_Reader_HTML
+ *
+ * @category   PHPExcel
+ * @package    PHPExcel_Reader
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
+ */
+class PHPExcel_Reader_HTML implements PHPExcel_Reader_IReader
+{
+	/**
+	 * Input encoding
+	 *
+	 * @var string
+	 */
+	private $_inputEncoding	= 'ANSI';
+
+	/**
+	 * Sheet index to read
+	 *
+	 * @var int
+	 */
+	private $_sheetIndex 	= 0;
+
+	/**
+	 * Formats
+	 *
+	 * @var array
+	 */
+	private $_formats = array( 'h1' => array( 'font' => array( 'bold' => true,
+															   'size' => 24,
+															 ),
+											),	//	Bold, 24pt
+							   'h2' => array( 'font' => array( 'bold' => true,
+															   'size' => 18,
+															 ),
+											),	//	Bold, 18pt
+							   'h3' => array( 'font' => array( 'bold' => true,
+															   'size' => 13.5,
+															 ),
+											),	//	Bold, 13.5pt
+							   'h4' => array( 'font' => array( 'bold' => true,
+															   'size' => 12,
+															 ),
+											),	//	Bold, 12pt
+							   'h5' => array( 'font' => array( 'bold' => true,
+															   'size' => 10,
+															 ),
+											),	//	Bold, 10pt
+							   'h6' => array( 'font' => array( 'bold' => true,
+															   'size' => 7.5,
+															 ),
+											),	//	Bold, 7.5pt
+							   'a'  => array( 'font' => array( 'underline' => true,
+															   'color' => array( 'argb' => PHPExcel_Style_Color::COLOR_BLUE,
+															                   ),
+															 ),
+											),	//	Blue underlined
+							   'hr' => array( 'borders' => array( 'bottom' => array( 'style' => PHPExcel_Style_Border::BORDER_THIN,
+																					 'color' => array( PHPExcel_Style_Color::COLOR_BLACK,
+																					                 ),
+																				   ),
+																),
+											),	//	Bottom border
+							 );
+
+	/**
+	 * PHPExcel_Reader_IReadFilter instance
+	 *
+	 * @var PHPExcel_Reader_IReadFilter
+	 */
+	private $_readFilter = null;
+
+
+	/**
+	 * Create a new PHPExcel_Reader_HTML
+	 */
+	public function __construct() {
+		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
+	}
+
+	/**
+	 *	Can the current PHPExcel_Reader_IReader read the file?
+	 *
+	 *	@param 	string 		$pFileName
+	 *	@return 	boolean
+	 *	@throws Exception
+	 */
+	public function canRead($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		// Read sample data (first 2 KB will do)
+		$fh = fopen($pFilename, 'r');
+		$data = fread($fh, 2048);
+		fclose($fh);
+
+		return true;
+	}
+
+	/**
+	 * Loads PHPExcel from file
+	 *
+	 * @param 	string 		$pFilename
+	 * @return 	PHPExcel
+	 * @throws 	Exception
+	 */
+	public function load($pFilename)
+	{
+		// Create new PHPExcel
+		$objPHPExcel = new PHPExcel();
+
+		// Load into this instance
+		return $this->loadIntoExisting($pFilename, $objPHPExcel);
+	}
+
+	/**
+	 * Read filter
+	 *
+	 * @return PHPExcel_Reader_IReadFilter
+	 */
+	public function getReadFilter() {
+		return $this->_readFilter;
+	}
+
+	/**
+	 * Set read filter
+	 *
+	 * @param PHPExcel_Reader_IReadFilter $pValue
+	 */
+	public function setReadFilter(PHPExcel_Reader_IReadFilter $pValue) {
+		$this->_readFilter = $pValue;
+		return $this;
+	}
+
+	/**
+	 * Set input encoding
+	 *
+	 * @param string $pValue Input encoding
+	 */
+	public function setInputEncoding($pValue = 'ANSI')
+	{
+		$this->_inputEncoding = $pValue;
+		return $this;
+	}
+
+	/**
+	 * Get input encoding
+	 *
+	 * @return string
+	 */
+	public function getInputEncoding()
+	{
+		return $this->_inputEncoding;
+	}
+
+	//	Data Array used for testing only, should write to PHPExcel object on completion of tests
+	private $_dataArray = array();
+
+	private $_tableLevel = 0;
+	private $_nestedColumn = array('A');
+
+	private function _setTableStartColumn($column) {
+		if ($this->_tableLevel == 0)
+			$column = 'A';
+		++$this->_tableLevel;
+		$this->_nestedColumn[$this->_tableLevel] = $column;
+
+		return $this->_nestedColumn[$this->_tableLevel];
+	}
+
+	private function _getTableStartColumn() {
+		return $this->_nestedColumn[$this->_tableLevel];
+	}
+
+	private function _releaseTableStartColumn() {
+		--$this->_tableLevel;
+		return array_pop($this->_nestedColumn);
+	}
+
+	private function _flushCell($sheet,$column,$row,&$cellContent) {
+		if (is_string($cellContent)) {
+			//	Simple String content
+			if (trim($cellContent) > '') {
+				//	Only actually write it if there's content in the string
+				echo 'FLUSH CELL: ' , $column , $row , ' => ' , $cellContent , '<br />';
+				//	Write to worksheet to be done here...
+				//	... we return the cell so we can mess about with styles more easily
+				$cell = $sheet->setCellValue($column.$row,$cellContent,true);
+				$this->_dataArray[$row][$column] = $cellContent;
+			}
+		} else {
+			//	We have a Rich Text run
+			//	TODO
+			$this->_dataArray[$row][$column] = 'RICH TEXT: ' . $cellContent;
+		}
+		$cellContent = (string) '';
+	}
+
+	private function _processDomElement(DOMNode $element, $sheet, &$row, &$column, &$cellContent){
+		foreach($element->childNodes as $child){
+			if ($child instanceOf DOMText) {
+				$domText = preg_replace('/\s+/',' ',trim($child->nodeValue));
+				if (is_string($cellContent)) {
+					//	simply append the text if the cell content is a plain text string
+					$cellContent .= $domText;
+				} else {
+					//	but if we have a rich text run instead, we need to append it correctly
+					//	TODO
+				}
+			} elseif($child instanceOf DOMElement) {
+				echo '<b>DOM ELEMENT: </b>' , strtoupper($child->nodeName) , '<br />';
+
+				$attributeArray = array();
+				foreach($child->attributes as $attribute) {
+					echo '<b>ATTRIBUTE: </b>' , $attribute->name , ' => ' , $attribute->value , '<br />';
+					$attributeArray[$attribute->name] = $attribute->value;
+				}
+
+				switch($child->nodeName) {
+					case 'meta' :
+						foreach($attributeArray as $attributeName => $attributeValue) {
+							switch($attributeName) {
+								case 'content':
+									//	TODO
+									//	Extract character set, so we can convert to UTF-8 if required
+									break;
+							}
+						}
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						break;
+					case 'title' :
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						$sheet->setTitle($cellContent);
+						$cellContent = '';
+						break;
+					case 'span'  :
+					case 'div'   :
+					case 'font'  :
+					case 'i'     :
+					case 'em'    :
+					case 'strong':
+					case 'b'     :
+						echo 'STYLING, SPAN OR DIV<br />';
+						if ($cellContent > '')
+							$cellContent .= ' ';
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						if ($cellContent > '')
+							$cellContent .= ' ';
+						echo 'END OF STYLING, SPAN OR DIV<br />';
+						break;
+					case 'hr' :
+						$this->_flushCell($sheet,$column,$row,$cellContent);
+						++$row;
+						if (isset($this->_formats[$child->nodeName])) {
+							$sheet->getStyle($column.$row)->applyFromArray($this->_formats[$child->nodeName]);
+						} else {
+							$cellContent = '----------';
+							$this->_flushCell($sheet,$column,$row,$cellContent);
+						}
+						++$row;
+					case 'br' :
+						if ($this->_tableLevel > 0) {
+							//	If we're inside a table, replace with a \n
+							$cellContent .= "\n";
+						} else {
+							//	Otherwise flush our existing content and move the row cursor on
+							$this->_flushCell($sheet,$column,$row,$cellContent);
+							++$row;
+						}
+						echo 'HARD LINE BREAK: ' , '<br />';
+						break;
+					case 'a'  :
+						echo 'START OF HYPERLINK: ' , '<br />';
+						foreach($attributeArray as $attributeName => $attributeValue) {
+							switch($attributeName) {
+								case 'href':
+									echo 'Link to ' , $attributeValue , '<br />';
+									$sheet->getCell($column.$row)->getHyperlink()->setUrl($attributeValue);
+									if (isset($this->_formats[$child->nodeName])) {
+										$sheet->getStyle($column.$row)->applyFromArray($this->_formats[$child->nodeName]);
+									}
+									break;
+							}
+						}
+						$cellContent .= ' ';
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						echo 'END OF HYPERLINK:' , '<br />';
+						break;
+					case 'h1' :
+					case 'h2' :
+					case 'h3' :
+					case 'h4' :
+					case 'h5' :
+					case 'h6' :
+					case 'ol' :
+					case 'ul' :
+					case 'p'  :
+						if ($this->_tableLevel > 0) {
+							//	If we're inside a table, replace with a \n
+							$cellContent .= "\n";
+							echo 'LIST ENTRY: ' , '<br />';
+							$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+							echo 'END OF LIST ENTRY:' , '<br />';
+						} else {
+							if ($cellContent > '') {
+								$this->_flushCell($sheet,$column,$row,$cellContent);
+								$row += 2;
+							}
+							echo 'START OF PARAGRAPH: ' , '<br />';
+							$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+							echo 'END OF PARAGRAPH:' , '<br />';
+							$this->_flushCell($sheet,$column,$row,$cellContent);
+
+							if (isset($this->_formats[$child->nodeName])) {
+								$sheet->getStyle($column.$row)->applyFromArray($this->_formats[$child->nodeName]);
+							}
+
+							$row += 2;
+							$column = 'A';
+						}
+						break;
+					case 'li'  :
+						if ($this->_tableLevel > 0) {
+							//	If we're inside a table, replace with a \n
+							$cellContent .= "\n";
+							echo 'LIST ENTRY: ' , '<br />';
+							$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+							echo 'END OF LIST ENTRY:' , '<br />';
+						} else {
+							if ($cellContent > '') {
+								$this->_flushCell($sheet,$column,$row,$cellContent);
+							}
+							++$row;
+							echo 'LIST ENTRY: ' , '<br />';
+							$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+							echo 'END OF LIST ENTRY:' , '<br />';
+							$this->_flushCell($sheet,$column,$row,$cellContent);
+							$column = 'A';
+						}
+						break;
+					case 'table' :
+						$this->_flushCell($sheet,$column,$row,$cellContent);
+						$column = $this->_setTableStartColumn($column);
+						echo 'START OF TABLE LEVEL ' , $this->_tableLevel , '<br />';
+						if ($this->_tableLevel > 1)
+							--$row;
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						echo 'END OF TABLE LEVEL ' , $this->_tableLevel , '<br />';
+						$column = $this->_releaseTableStartColumn();
+						if ($this->_tableLevel > 1) {
+							++$column;
+						} else {
+							++$row;
+						}
+						break;
+					case 'thead' :
+					case 'tbody' :
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						break;
+					case 'tr' :
+						++$row;
+						$column = $this->_getTableStartColumn();
+						$cellContent = '';
+						echo 'START OF TABLE ' , $this->_tableLevel , ' ROW<br />';
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						echo 'END OF TABLE ' , $this->_tableLevel , ' ROW<br />';
+						break;
+					case 'th' :
+					case 'td' :
+						echo 'START OF TABLE ' , $this->_tableLevel , ' CELL<br />';
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						echo 'END OF TABLE ' , $this->_tableLevel , ' CELL<br />';
+						$this->_flushCell($sheet,$column,$row,$cellContent);
+						++$column;
+						break;
+					case 'body' :
+						$row = 1;
+						$column = 'A';
+						$content = '';
+						$this->_tableLevel = 0;
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+						break;
+					default:
+						$this->_processDomElement($child,$sheet,$row,$column,$cellContent);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Loads PHPExcel from file into PHPExcel instance
+	 *
+	 * @param 	string 		$pFilename
+	 * @param	PHPExcel	$objPHPExcel
+	 * @return 	PHPExcel
+	 * @throws 	Exception
+	 */
+	public function loadIntoExisting($pFilename, PHPExcel $objPHPExcel)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		if (!is_file($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! The given file is not a regular file.");
+		}
+
+		// Create new PHPExcel
+		while ($objPHPExcel->getSheetCount() <= $this->_sheetIndex) {
+			$objPHPExcel->createSheet();
+		}
+		$objPHPExcel->setActiveSheetIndex( $this->_sheetIndex );
+
+		//	Create a new DOM object
+		$dom = new domDocument;
+		//	Load the HTML file into the DOM object
+		$loaded = $dom->loadHTMLFile($pFilename);
+		if ($loaded === false) {
+			throw new Exception('Failed to load ',$pFilename,' as a DOM Document');
+		}
+
+		//	Discard white space
+		$dom->preserveWhiteSpace = false;
+
+
+		$row = 0;
+		$column = 'A';
+		$content = '';
+		$this->_processDomElement($dom,$objPHPExcel->getActiveSheet(),$row,$column,$content);
+
+		echo '<hr />';
+		var_dump($this->_dataArray);
+
+		// Return
+		return $objPHPExcel;
+	}
+
+	/**
+	 * Get sheet index
+	 *
+	 * @return int
+	 */
+	public function getSheetIndex() {
+		return $this->_sheetIndex;
+	}
+
+	/**
+	 * Set sheet index
+	 *
+	 * @param	int		$pValue		Sheet index
+	 * @return PHPExcel_Reader_HTML
+	 */
+	public function setSheetIndex($pValue = 0) {
+		$this->_sheetIndex = $pValue;
+		return $this;
+	}
+
+}

+ 7 - 7
htdocs/includes/phpexcel/PHPExcel/Reader/IReadFilter.php

@@ -2,27 +2,27 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 interface PHPExcel_Reader_IReadFilter
 {
@@ -42,6 +42,6 @@ interface PHPExcel_Reader_IReadFilter
 	 * @param 	$row			Row index
 	 * @param	$worksheetName	Optional worksheet name
 	 * @return	boolean
-	 */	
+	 */
 	public function readCell($column, $row, $worksheetName = '');
 }

+ 9 - 9
htdocs/includes/phpexcel/PHPExcel/Reader/IReader.php

@@ -2,27 +2,27 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 interface PHPExcel_Reader_IReader
 {
@@ -40,14 +40,14 @@ interface PHPExcel_Reader_IReader
 	 *
 	 * @param 	string 		$pFileName
 	 * @return 	boolean
-	 */	
+	 */
 	public function canRead($pFilename);
-	
+
 	/**
 	 * Loads PHPExcel from file
 	 *
 	 * @param 	string 		$pFileName
 	 * @throws 	Exception
-	 */	
+	 */
 	public function load($pFilename);
 }

+ 224 - 73
htdocs/includes/phpexcel/PHPExcel/Reader/OOCalc.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -36,28 +36,28 @@ if (!defined('PHPEXCEL_ROOT')) {
 }
 
 /**
- *	PHPExcel_Reader_OOCalc
+ * PHPExcel_Reader_OOCalc
  *
- *	@category	PHPExcel
- *	@package	PHPExcel_Reader
- *	@copyright	Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @category	PHPExcel
+ * @package		PHPExcel_Reader
+ * @copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 {
 	/**
-	 *	Read data only?
-	 *	Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
+	 * Read data only?
+	 * Identifies whether the Reader should only read data values for cells, and ignore any formatting information;
 	 *		or whether it should read both data and formatting
 	 *
-	 *	@var	boolean
+	 * @var	boolean
 	 */
 	private $_readDataOnly = false;
 
 	/**
-	 *	Restrict which sheets should be loaded?
-	 *	This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
+	 * Restrict which sheets should be loaded?
+	 * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded.
 	 *
-	 *	@var	array of string
+	 * @var	array of string
 	 */
 	private $_loadSheetsOnly = null;
 
@@ -77,50 +77,60 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 
 
 	/**
-	 *	Read data only?
+	 * Create a new PHPExcel_Reader_OOCalc
+	 */
+	public function __construct() {
+		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
+	}
+
+
+	/**
+	 * Read data only?
 	 *		If this is true, then the Reader will only read data values for cells, it will not read any formatting information.
 	 *		If false (the default) it will read data and formatting.
 	 *
-	 *	@return	boolean
+	 * @return	boolean
 	 */
 	public function getReadDataOnly() {
 		return $this->_readDataOnly;
 	}
 
+
 	/**
-	 *	Set read data only
+	 * Set read data only
 	 *		Set to true, to advise the Reader only to read data values for cells, and to ignore any formatting information.
 	 *		Set to false (the default) to advise the Reader to read both data and formatting for cells.
 	 *
-	 *	@param	boolean	$pValue
-	 *
-	 *	@return	PHPExcel_Reader_OOCalc
+	 * @param	boolean	$pValue
+	 * @return	PHPExcel_Reader_OOCalc
 	 */
 	public function setReadDataOnly($pValue = false) {
 		$this->_readDataOnly = $pValue;
 		return $this;
 	}
 
+
 	/**
-	 *	Get which sheets to load
+	 * Get which sheets to load
 	 *		Returns either an array of worksheet names (the list of worksheets that should be loaded), or a null
 	 *			indicating that all worksheets in the workbook should be loaded.
 	 *
-	 *	@return mixed
+	 * @return mixed
 	 */
 	public function getLoadSheetsOnly()
 	{
 		return $this->_loadSheetsOnly;
 	}
 
+
 	/**
-	 *	Set which sheets to load
+	 * Set which sheets to load
 	 *
-	 *	@param mixed $value
+	 * @param mixed $value
 	 *		This should be either an array of worksheet names to be loaded, or a string containing a single worksheet name.
 	 *		If NULL, then it tells the Reader to read all worksheets in the workbook
 	 *
-	 *	@return PHPExcel_Reader_OOCalc
+	 * @return PHPExcel_Reader_OOCalc
 	 */
 	public function setLoadSheetsOnly($value = null)
 	{
@@ -129,11 +139,12 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
-	 *	Set all sheets to load
+	 * Set all sheets to load
 	 *		Tells the Reader to load all worksheets from the workbook.
 	 *
-	 *	@return PHPExcel_Reader_OOCalc
+	 * @return PHPExcel_Reader_OOCalc
 	 */
 	public function setLoadAllSheets()
 	{
@@ -141,6 +152,7 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Read filter
 	 *
@@ -150,6 +162,7 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return $this->_readFilter;
 	}
 
+
 	/**
 	 * Set read filter
 	 *
@@ -161,45 +174,47 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
-	/**
-	 * Create a new PHPExcel_Reader_OOCalc
-	 */
-	public function __construct() {
-		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
-	}
 
 	/**
 	 * Can the current PHPExcel_Reader_IReader read the file?
 	 *
 	 * @param 	string 		$pFileName
 	 * @return 	boolean
+	 * @throws Exception
 	 */
 	public function canRead($pFilename)
 	{
-		// Check if zip class exists
-		if (!class_exists('ZipArchive')) {
-			return false;
-		}
-
 		// Check if file exists
 		if (!file_exists($pFilename)) {
 			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
 		}
 
+		// Check if zip class exists
+		if (!class_exists('ZipArchive',FALSE)) {
+			throw new Exception("ZipArchive library is not enabled");
+		}
+
 		// Load file
 		$zip = new ZipArchive;
 		if ($zip->open($pFilename) === true) {
 			// check if it is an OOXML archive
-			$mimeType = $zip->getFromName("mimetype");
+			$stat = $zip->statName('mimetype');
+			if ($stat && ($stat['size'] <= 255)) {
+				$mimeType = $zip->getFromName($stat['name']);
+			} else {
+				$zip->close();
+				return FALSE;
+			}
 
 			$zip->close();
 
 			return ($mimeType === 'application/vnd.oasis.opendocument.spreadsheet');
 		}
 
-		return false;
+		return FALSE;
 	}
 
+
 	/**
 	 * Reads names of the worksheets from a file, without parsing the whole file to a PHPExcel object
 	 *
@@ -252,6 +267,7 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return $this->loadIntoExisting($pFilename, $objPHPExcel);
 	}
 
+
 	private static function identifyFixedStyleValue($styleList,&$styleAttributeValue) {
 		$styleAttributeValue = strtolower($styleAttributeValue);
 		foreach($styleList as $style) {
@@ -263,6 +279,79 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return false;
 	}
 
+
+	/**
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+	 *
+	 * @param   string     $pFilename
+	 * @throws   Exception
+	 */
+	public function listWorksheetInfo($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		$worksheetInfo = array();
+
+		$zip = new ZipArchive;
+		if ($zip->open($pFilename) === true) {
+
+			$xml = simplexml_load_string($zip->getFromName("content.xml"));
+			$namespacesContent = $xml->getNamespaces(true);
+
+			$workbook = $xml->children($namespacesContent['office']);
+			foreach($workbook->body->spreadsheet as $workbookData) {
+				$workbookData = $workbookData->children($namespacesContent['table']);
+				foreach($workbookData->table as $worksheetDataSet) {
+					$worksheetData = $worksheetDataSet->children($namespacesContent['table']);
+					$worksheetDataAttributes = $worksheetDataSet->attributes($namespacesContent['table']);
+
+					$tmpInfo = array();
+					$tmpInfo['worksheetName'] = (string) $worksheetDataAttributes['name'];
+					$tmpInfo['lastColumnLetter'] = 'A';
+					$tmpInfo['lastColumnIndex'] = 0;
+					$tmpInfo['totalRows'] = 0;
+					$tmpInfo['totalColumns'] = 0;
+
+					$rowIndex = 0;
+					foreach ($worksheetData as $key => $rowData) {
+						switch ($key) {
+							case 'table-row' :
+								$rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
+								$rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ?
+										$rowDataTableAttributes['number-rows-repeated'] : 1;
+								$columnIndex = 0;
+
+								foreach ($rowData as $key => $cellData) {
+									$cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
+									$colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ?
+										$cellDataTableAttributes['number-columns-repeated'] : 1;
+									$cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
+									if (isset($cellDataOfficeAttributes['value-type'])) {
+										$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex + $colRepeats - 1);
+										$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex + $rowRepeats);
+									}
+									$columnIndex += $colRepeats;
+								}
+								$rowIndex += $rowRepeats;
+								break;
+						}
+					}
+
+					$tmpInfo['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($tmpInfo['lastColumnIndex']);
+					$tmpInfo['totalColumns'] = $tmpInfo['lastColumnIndex'] + 1;
+
+					$worksheetInfo[] = $tmpInfo;
+				}
+			}
+		}
+
+		return $worksheetInfo;
+	}
+
+
 	/**
 	 * Loads PHPExcel from file into PHPExcel instance
 	 *
@@ -396,7 +485,10 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 					$objPHPExcel->setActiveSheetIndex($worksheetID);
 					if (isset($worksheetDataAttributes['name'])) {
 						$worksheetName = (string) $worksheetDataAttributes['name'];
-						$objPHPExcel->getActiveSheet()->setTitle($worksheetName);
+						//	Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
+						//		formula cells... during the load, all formulae should be correct, and we're simply
+						//		bringing the worksheet name in line with the formula, not the reverse
+						$objPHPExcel->getActiveSheet()->setTitle($worksheetName,false);
 					}
 
 					$rowID = 1;
@@ -409,16 +501,21 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 									break;
 								}
 							case 'table-row' :
+								$rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
+								$rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ?
+										$rowDataTableAttributes['number-rows-repeated'] : 1;
 								$columnID = 'A';
 								foreach($rowData as $key => $cellData) {
-									if (!is_null($this->getReadFilter())) {
+									if ($this->getReadFilter() !== NULL) {
 										if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) {
 											continue;
 										}
 									}
 
 //									echo '<b>'.$columnID.$rowID.'</b><br />';
-									$cellDataText = $cellData->children($namespacesContent['text']);
+									$cellDataText = (isset($namespacesContent['text'])) ?
+										$cellData->children($namespacesContent['text']) :
+										'';
 									$cellDataOffice = $cellData->children($namespacesContent['office']);
 									$cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
 									$cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
@@ -456,11 +553,31 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 									}
 
 									if (isset($cellDataText->p)) {
+										// Consolidate if there are multiple p records (maybe with spans as well)
+										$dataArray = array();
+										// Text can have multiple text:p and within those, multiple text:span.
+										// text:p newlines, but text:span does not.
+										// Also, here we assume there is no text data is span fields are specified, since
+										// we have no way of knowing proper positioning anyway.
+										foreach ($cellDataText->p as $pData) {
+											if (isset($pData->span)) {
+												// span sections do not newline, so we just create one large string here
+												$spanSection = "";
+												foreach ($pData->span as $spanData) {
+													$spanSection .= $spanData;
+												}
+												array_push($dataArray, $spanSection);
+											} else {
+												array_push($dataArray, $pData);
+											}
+										}
+										$allCellDataText = implode($dataArray, "\n");
+
 //										echo 'Value Type is '.$cellDataOfficeAttributes['value-type'].'<br />';
 										switch ($cellDataOfficeAttributes['value-type']) {
-											case 'string' :
+ 											case 'string' :
 													$type = PHPExcel_Cell_DataType::TYPE_STRING;
-													$dataValue = $cellDataText->p;
+													$dataValue = $allCellDataText;
 													if (isset($dataValue->a)) {
 														$dataValue = $dataValue->a;
 														$cellXLinkAttributes = $dataValue->attributes($namespacesContent['xlink']);
@@ -469,14 +586,33 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 													break;
 											case 'boolean' :
 													$type = PHPExcel_Cell_DataType::TYPE_BOOL;
-													$dataValue = ($cellDataText->p == 'TRUE') ? True : False;
+													$dataValue = ($allCellDataText == 'TRUE') ? True : False;
 													break;
-											case 'float' :
+											case 'percentage' :
+													$type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+													$dataValue = (float) $cellDataOfficeAttributes['value'];
+													if (floor($dataValue) == $dataValue) {
+														$dataValue = (integer) $dataValue;
+													}
+													$formatting = PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00;
+													break;
+											case 'currency' :
 													$type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
 													$dataValue = (float) $cellDataOfficeAttributes['value'];
 													if (floor($dataValue) == $dataValue) {
 														$dataValue = (integer) $dataValue;
 													}
+													$formatting = PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE;
+													break;
+											case 'float' :
+													$type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
+													$dataValue = (float) $cellDataOfficeAttributes['value'];
+													if (floor($dataValue) == $dataValue) {
+														if ($dataValue = (integer) $dataValue)
+															$dataValue = (integer) $dataValue;
+														else
+															$dataValue = (float) $dataValue;
+													}
 													break;
 											case 'date' :
 													$type = PHPExcel_Cell_DataType::TYPE_NUMERIC;
@@ -497,9 +633,12 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 													break;
 										}
 //										echo 'Data value is '.$dataValue.'<br />';
-//										if (!is_null($hyperlink)) {
+//										if ($hyperlink !== NULL) {
 //											echo 'Hyperlink is '.$hyperlink.'<br />';
 //										}
+									} else {
+										$type = PHPExcel_Cell_DataType::TYPE_NULL;
+										$dataValue = NULL;
 									}
 
 									if ($hasCalculatedValue) {
@@ -522,42 +661,53 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 //										echo 'Adjusted Formula: '.$cellDataFormula.'<br />';
 									}
 
-									if (!is_null($type)) {
-										$objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $dataValue),$type);
-										if ($hasCalculatedValue) {
-//											echo 'Forumla result is '.$dataValue.'<br />';
-											$objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($dataValue);
-										}
-										if (($cellDataOfficeAttributes['value-type'] == 'date') ||
-											($cellDataOfficeAttributes['value-type'] == 'time')) {
-											$objPHPExcel->getActiveSheet()->getStyle($columnID.$rowID)->getNumberFormat()->setFormatCode($formatting);
-										}
-										if (!is_null($hyperlink)) {
-											$objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->getHyperlink()->setUrl($hyperlink);
+									$colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ?
+										$cellDataTableAttributes['number-columns-repeated'] : 1;
+									if ($type !== NULL) {
+										for ($i = 0; $i < $colRepeats; ++$i) {
+											if ($i > 0) {
+												++$columnID;
+											}
+											if ($type !== PHPExcel_Cell_DataType::TYPE_NULL) {
+												for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) {
+													$rID = $rowID + $rowAdjust;
+													$objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $dataValue),$type);
+													if ($hasCalculatedValue) {
+//														echo 'Forumla result is '.$dataValue.'<br />';
+														$objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setCalculatedValue($dataValue);
+													}
+													if ($formatting !== NULL) {
+														$objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode($formatting);
+													} else {
+														$objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_GENERAL);
+													}
+													if ($hyperlink !== NULL) {
+														$objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->getHyperlink()->setUrl($hyperlink);
+													}
+												}
+											}
 										}
 									}
 
 									//	Merged cells
 									if ((isset($cellDataTableAttributes['number-columns-spanned'])) || (isset($cellDataTableAttributes['number-rows-spanned']))) {
-										$columnTo = $columnID;
-										if (isset($cellDataTableAttributes['number-columns-spanned'])) {
-											$columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-spanned'] -2);
-										}
-										$rowTo = $rowID;
-										if (isset($cellDataTableAttributes['number-rows-spanned'])) {
-											$rowTo = $rowTo + $cellDataTableAttributes['number-rows-spanned'] - 1;
+										if (($type !== PHPExcel_Cell_DataType::TYPE_NULL) || (!$this->_readDataOnly)) {
+											$columnTo = $columnID;
+											if (isset($cellDataTableAttributes['number-columns-spanned'])) {
+												$columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-spanned'] -2);
+											}
+											$rowTo = $rowID;
+											if (isset($cellDataTableAttributes['number-rows-spanned'])) {
+												$rowTo = $rowTo + $cellDataTableAttributes['number-rows-spanned'] - 1;
+											}
+											$cellRange = $columnID.$rowID.':'.$columnTo.$rowTo;
+											$objPHPExcel->getActiveSheet()->mergeCells($cellRange);
 										}
-										$cellRange = $columnID.$rowID.':'.$columnTo.$rowTo;
-										$objPHPExcel->getActiveSheet()->mergeCells($cellRange);
 									}
 
-									if (isset($cellDataTableAttributes['number-columns-repeated'])) {
-//										echo 'Repeated '.$cellDataTableAttributes['number-columns-repeated'].' times<br />';
-										$columnID = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-repeated'] - 2);
-									}
 									++$columnID;
 								}
-								++$rowID;
+								$rowID += $rowRepeats;
 								break;
 						}
 					}
@@ -571,6 +721,7 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
 		return $objPHPExcel;
 	}
 
+
 	private function _parseRichText($is = '') {
 		$value = new PHPExcel_RichText();
 

+ 103 - 20
htdocs/includes/phpexcel/PHPExcel/Reader/SYLK.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -40,7 +40,7 @@ if (!defined('PHPEXCEL_ROOT')) {
  *
  * @category   PHPExcel
  * @package    PHPExcel_Reader
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 {
@@ -79,6 +79,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 	 */
 	private $_readFilter = null;
 
+
 	/**
 	 * Create a new PHPExcel_Reader_SYLK
 	 */
@@ -86,11 +87,13 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		$this->_readFilter 	= new PHPExcel_Reader_DefaultReadFilter();
 	}
 
+
 	/**
 	 * Can the current PHPExcel_Reader_IReader read the file?
 	 *
 	 * @param 	string 		$pFileName
 	 * @return 	boolean
+	 * @throws Exception
 	 */
 	public function canRead($pFilename)
 	{
@@ -119,21 +122,6 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return true;
 	}
 
-	/**
-	 * Loads PHPExcel from file
-	 *
-	 * @param 	string 		$pFilename
-	 * @return 	PHPExcel
-	 * @throws 	Exception
-	 */
-	public function load($pFilename)
-	{
-		// Create new PHPExcel
-		$objPHPExcel = new PHPExcel();
-
-		// Load into this instance
-		return $this->loadIntoExisting($pFilename, $objPHPExcel);
-	}
 
 	/**
 	 * Read filter
@@ -144,6 +132,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return $this->_readFilter;
 	}
 
+
 	/**
 	 * Set read filter
 	 *
@@ -154,6 +143,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Set input encoding
 	 *
@@ -165,6 +155,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return $this;
 	}
 
+
 	/**
 	 * Get input encoding
 	 *
@@ -175,6 +166,96 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return $this->_inputEncoding;
 	}
 
+
+	/**
+	 * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns)
+	 *
+	 * @param   string     $pFilename
+	 * @throws   Exception
+	 */
+	public function listWorksheetInfo($pFilename)
+	{
+		// Check if file exists
+		if (!file_exists($pFilename)) {
+			throw new Exception("Could not open " . $pFilename . " for reading! File does not exist.");
+		}
+
+		// Open file
+		$fileHandle = fopen($pFilename, 'r');
+		if ($fileHandle === false) {
+			throw new Exception("Could not open file " . $pFilename . " for reading.");
+		}
+
+		$worksheetInfo = array();
+		$worksheetInfo[0]['worksheetName'] = 'Worksheet';
+		$worksheetInfo[0]['lastColumnLetter'] = 'A';
+		$worksheetInfo[0]['lastColumnIndex'] = 0;
+		$worksheetInfo[0]['totalRows'] = 0;
+		$worksheetInfo[0]['totalColumns'] = 0;
+
+		// Loop through file
+		$rowData = array();
+
+		// loop through one row (line) at a time in the file
+		$rowIndex = 0;
+		while (($rowData = fgets($fileHandle)) !== FALSE) {
+			$columnIndex = 0;
+
+			// convert SYLK encoded $rowData to UTF-8
+			$rowData = PHPExcel_Shared_String::SYLKtoUTF8($rowData);
+
+			// explode each row at semicolons while taking into account that literal semicolon (;)
+			// is escaped like this (;;)
+			$rowData = explode("\t",str_replace('?',';',str_replace(';',"\t",str_replace(';;','?',rtrim($rowData)))));
+
+			$dataType = array_shift($rowData);
+			if ($dataType == 'C') {
+				//  Read cell value data
+				foreach($rowData as $rowDatum) {
+					switch($rowDatum{0}) {
+						case 'C' :
+						case 'X' :
+							$columnIndex = substr($rowDatum,1) - 1;
+							break;
+						case 'R' :
+						case 'Y' :
+							$rowIndex = substr($rowDatum,1);
+							break;
+					}
+
+					$worksheetInfo[0]['totalRows'] = max($worksheetInfo[0]['totalRows'], $rowIndex);
+					$worksheetInfo[0]['lastColumnIndex'] = max($worksheetInfo[0]['lastColumnIndex'], $columnIndex);
+				}
+			}
+		}
+
+		$worksheetInfo[0]['lastColumnLetter'] = PHPExcel_Cell::stringFromColumnIndex($worksheetInfo[0]['lastColumnIndex']);
+		$worksheetInfo[0]['totalColumns'] = $worksheetInfo[0]['lastColumnIndex'] + 1;
+
+		// Close file
+		fclose($fileHandle);
+
+		return $worksheetInfo;
+	}
+
+
+	/**
+	 * Loads PHPExcel from file
+	 *
+	 * @param 	string 		$pFilename
+	 * @return 	PHPExcel
+	 * @throws 	Exception
+	 */
+	public function load($pFilename)
+	{
+		// Create new PHPExcel
+		$objPHPExcel = new PHPExcel();
+
+		// Load into this instance
+		return $this->loadIntoExisting($pFilename, $objPHPExcel);
+	}
+
+
 	/**
 	 * Loads PHPExcel from file into PHPExcel instance
 	 *
@@ -354,7 +435,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 					$columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
 					$objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($this->_formats[$formatStyle]);
 				}
-				if ((count($styleData) > 0) && ($column > '') && ($row > '')) {
+				if ((!empty($styleData)) && ($column > '') && ($row > '')) {
 					$columnLetter = PHPExcel_Cell::stringFromColumnIndex($column-1);
 					$objPHPExcel->getActiveSheet()->getStyle($columnLetter.$row)->applyFromArray($styleData);
 				}
@@ -392,6 +473,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return $objPHPExcel;
 	}
 
+
 	/**
 	 * Get sheet index
 	 *
@@ -401,6 +483,7 @@ class PHPExcel_Reader_SYLK implements PHPExcel_Reader_IReader
 		return $this->_sheetIndex;
 	}
 
+
 	/**
 	 * Set sheet index
 	 *

+ 63 - 10
htdocs/includes/phpexcel/PHPExcel/ReferenceHelper.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package	PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version	1.7.6, 2011-02-27
+ * @version	1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package	PHPExcel
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_ReferenceHelper
 {
@@ -55,7 +55,7 @@ class PHPExcel_ReferenceHelper
 	 * @return PHPExcel_ReferenceHelper
 	 */
 	public static function getInstance() {
-		if (!isset(self::$_instance) || is_null(self::$_instance)) {
+		if (!isset(self::$_instance) || (self::$_instance === NULL)) {
 			self::$_instance = new PHPExcel_ReferenceHelper();
 		}
 
@@ -214,7 +214,7 @@ class PHPExcel_ReferenceHelper
 
 		// Update worksheet: column dimensions
 		$aColumnDimensions = array_reverse($pSheet->getColumnDimensions(), true);
-		if (count($aColumnDimensions) > 0) {
+		if (!empty($aColumnDimensions)) {
 			foreach ($aColumnDimensions as $objColumnDimension) {
 				$newReference = $this->updateCellReference($objColumnDimension->getColumnIndex() . '1', $pBefore, $pNumCols, $pNumRows);
 				list($newReference) = PHPExcel_Cell::coordinateFromString($newReference);
@@ -228,7 +228,7 @@ class PHPExcel_ReferenceHelper
 
 		// Update worksheet: row dimensions
 		$aRowDimensions = array_reverse($pSheet->getRowDimensions(), true);
-		if (count($aRowDimensions) > 0) {
+		if (!empty($aRowDimensions)) {
 			foreach ($aRowDimensions as $objRowDimension) {
 				$newReference = $this->updateCellReference('A' . $objRowDimension->getRowIndex(), $pBefore, $pNumCols, $pNumRows);
 				list(, $newReference) = PHPExcel_Cell::coordinateFromString($newReference);
@@ -312,8 +312,61 @@ class PHPExcel_ReferenceHelper
 
 
 		// Update worksheet: autofilter
-		if ($pSheet->getAutoFilter() != '') {
-			$pSheet->setAutoFilter( $this->updateCellReference($pSheet->getAutoFilter(), $pBefore, $pNumCols, $pNumRows) );
+		$autoFilter = $pSheet->getAutoFilter();
+		$autoFilterRange = $autoFilter->getRange();
+		if (!empty($autoFilterRange)) {
+			if ($pNumCols != 0) {
+				$autoFilterColumns = array_keys($autoFilter->getColumns());
+				if (count($autoFilterColumns) > 0) {
+					list($column,$row) = sscanf($pBefore,'%[A-Z]%d');
+					$columnIndex = PHPExcel_Cell::columnIndexFromString($column);
+					list($rangeStart,$rangeEnd) = PHPExcel_Cell::rangeBoundaries($autoFilterRange);
+					if ($columnIndex <= $rangeEnd[0]) {
+						if ($pNumCols < 0) {
+							//	If we're actually deleting any columns that fall within the autofilter range,
+							//		then we delete any rules for those columns
+							$deleteColumn = $columnIndex + $pNumCols - 1;
+							$deleteCount = abs($pNumCols);
+							for ($i = 1; $i <= $deleteCount; ++$i) {
+								if (in_array(PHPExcel_Cell::stringFromColumnIndex($deleteColumn),$autoFilterColumns)) {
+									$autoFilter->clearColumn(PHPExcel_Cell::stringFromColumnIndex($deleteColumn));
+								}
+								++$deleteColumn;
+							}
+						}
+						$startCol = ($columnIndex > $rangeStart[0]) ? $columnIndex : $rangeStart[0];
+
+						//	Shuffle columns in autofilter range
+						if ($pNumCols > 0) {
+							//	For insert, we shuffle from end to beginning to avoid overwriting
+							$startColID = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
+							$toColID = PHPExcel_Cell::stringFromColumnIndex($startCol+$pNumCols-1);
+							$endColID = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0]);
+
+							$startColRef = $startCol;
+							$endColRef = $rangeEnd[0];
+							$toColRef = $rangeEnd[0]+$pNumCols;
+
+							do {
+								$autoFilter->shiftColumn(PHPExcel_Cell::stringFromColumnIndex($endColRef-1),PHPExcel_Cell::stringFromColumnIndex($toColRef-1));
+								--$endColRef;
+								--$toColRef;
+							} while ($startColRef <= $endColRef);
+						} else {
+							//	For delete, we shuffle from beginning to end to avoid overwriting
+							$startColID = PHPExcel_Cell::stringFromColumnIndex($startCol-1);
+							$toColID = PHPExcel_Cell::stringFromColumnIndex($startCol+$pNumCols-1);
+							$endColID = PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0]);
+							do {
+								$autoFilter->shiftColumn($startColID,$toColID);
+								++$startColID;
+								++$toColID;
+							} while ($startColID != $endColID);
+						}
+					}
+				}
+			}
+			$pSheet->setAutoFilter( $this->updateCellReference($autoFilterRange, $pBefore, $pNumCols, $pNumRows) );
 		}
 
 
@@ -530,7 +583,7 @@ class PHPExcel_ReferenceHelper
 		foreach ($pPhpExcel->getWorksheetIterator() as $sheet) {
 			foreach ($sheet->getCellCollection(false) as $cellID) {
 				$cell = $sheet->getCell($cellID);
-				if (!is_null($cell) && $cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA) {
+				if (($cell !== NULL) && ($cell->getDataType() == PHPExcel_Cell_DataType::TYPE_FORMULA)) {
 					$formula = $cell->getValue();
 					if (strpos($formula, $oldName) !== false) {
 						$formula = str_replace("'" . $oldName . "'!", "'" . $newName . "'!", $formula);

+ 5 - 5
htdocs/includes/phpexcel/PHPExcel/RichText.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_RichText implements PHPExcel_IComparable
 {
@@ -54,7 +54,7 @@ class PHPExcel_RichText implements PHPExcel_IComparable
     	$this->_richTextElements = array();
 
     	// Rich-Text string attached to cell?
-    	if (!is_null($pCell)) {
+    	if ($pCell !== NULL) {
 	    	// Add cell text and style
 	    	if ($pCell->getValue() != "") {
 	    		$objRun = new PHPExcel_RichText_Run($pCell->getValue());

+ 3 - 3
htdocs/includes/phpexcel/PHPExcel/RichText/ITextElement.php

@@ -18,9 +18,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -29,7 +29,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 interface PHPExcel_RichText_ITextElement
 {

+ 3 - 3
htdocs/includes/phpexcel/PHPExcel/RichText/Run.php

@@ -18,9 +18,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -29,7 +29,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_RichText_Run extends PHPExcel_RichText_TextElement implements PHPExcel_RichText_ITextElement
 {

+ 3 - 3
htdocs/includes/phpexcel/PHPExcel/RichText/TextElement.php

@@ -18,9 +18,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -29,7 +29,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_RichText
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_RichText_TextElement implements PHPExcel_RichText_ITextElement
 {

+ 255 - 16
htdocs/includes/phpexcel/PHPExcel/Settings.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Settings
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /** PHPExcel root directory */
@@ -38,56 +38,295 @@ if (!defined('PHPEXCEL_ROOT')) {
 class PHPExcel_Settings
 {
 	/**	constants */
+	/**	Available Zip library classes */
 	const PCLZIP		= 'PHPExcel_Shared_ZipArchive';
 	const ZIPARCHIVE	= 'ZipArchive';
 
+	/**	Optional Chart Rendering libraries */
+    const CHART_RENDERER_JPGRAPH	= 'jpgraph';
 
+	/**	Optional PDF Rendering libraries */
+    const PDF_RENDERER_TCPDF		= 'tcPDF';
+    const PDF_RENDERER_DOMPDF		= 'DomPDF';
+    const PDF_RENDERER_MPDF			= 'mPDF';
+
+
+	private static $_chartRenderers = array(
+		self::CHART_RENDERER_JPGRAPH,
+	);
+
+	private static $_pdfRenderers = array(
+		self::PDF_RENDERER_TCPDF,
+		self::PDF_RENDERER_DOMPDF,
+		self::PDF_RENDERER_MPDF,
+	);
+
+
+	/**
+	 * Name of the class used for Zip file management
+	 *		e.g.
+	 *			ZipArchive
+	 *
+	 * @var string
+	 */
 	private static $_zipClass	= self::ZIPARCHIVE;
 
 
 	/**
-	 * Set the Zip Class to use (PCLZip or ZipArchive)
+	 * Name of the external Library used for rendering charts
+	 *		e.g.
+	 *			jpgraph
+	 *
+	 * @var string
+	 */
+	private static $_chartRendererName = NULL;
+
+	/**
+	 * Directory Path to the external Library used for rendering charts
+	 *
+	 * @var string
+	 */
+	private static $_chartRendererPath = NULL;
+
+
+	/**
+	 * Name of the external Library used for rendering PDF files
+	 *		e.g.
+	 *			mPDF
+	 *
+	 * @var string
+	 */
+	private static $_pdfRendererName = NULL;
+
+	/**
+	 * Directory Path to the external Library used for rendering PDF files
+	 *
+	 * @var string
+	 */
+	private static $_pdfRendererPath = NULL;
+
+
+	/**
+	 * Set the Zip handler Class that PHPExcel should use for Zip file management (PCLZip or ZipArchive)
 	 *
-	 * @param	 string	$zipClass			PHPExcel_Settings::PCLZip or PHPExcel_Settings::ZipArchive
+	 * @param	 string	$zipClass			The Zip handler class that PHPExcel should use for Zip file management
+	 *											e.g. PHPExcel_Settings::PCLZip or PHPExcel_Settings::ZipArchive
 	 * @return	 boolean					Success or failure
 	 */
 	public static function setZipClass($zipClass) {
-		if (($zipClass == self::PCLZIP) ||
-			($zipClass == self::ZIPARCHIVE)) {
+		if (($zipClass === self::PCLZIP) ||
+			($zipClass === self::ZIPARCHIVE)) {
 			self::$_zipClass = $zipClass;
-			return True;
+			return TRUE;
 		}
-		return False;
+		return FALSE;
 	}	//	function setZipClass()
 
 
 	/**
-	 * Return the Zip Class to use (PCLZip or ZipArchive)
+	 * Return the name of the Zip handler Class that PHPExcel is configured to use (PCLZip or ZipArchive)
+	 *		for Zip file management
 	 *
-	 * @return	 string						Zip Class to use	- PHPExcel_Settings::PCLZip or PHPExcel_Settings::ZipArchive
+	 * @return	 string						Name of the Zip handler Class that PHPExcel is configured to use
+	 *											for Zip file management
+	 *												e.g. PHPExcel_Settings::PCLZip or PHPExcel_Settings::ZipArchive
 	 */
 	public static function getZipClass() {
 		return self::$_zipClass;
 	}	//	function getZipClass()
 
 
+	/**
+	 * Return the name of the method that is currently configured for cell cacheing
+	 *
+	 * @return	string				Name of the cacheing method
+	 */
 	public static function getCacheStorageMethod() {
-		return PHPExcel_CachedObjectStorageFactory::$_cacheStorageMethod;
+		return PHPExcel_CachedObjectStorageFactory::getCacheStorageMethod();
 	}	//	function getCacheStorageMethod()
 
 
+	/**
+	 * Return the name of the class that is currently being used for cell cacheing
+	 *
+	 * @return	string				Name of the class currently being used for cacheing
+	 */
 	public static function getCacheStorageClass() {
-		return PHPExcel_CachedObjectStorageFactory::$_cacheStorageClass;
+		return PHPExcel_CachedObjectStorageFactory::getCacheStorageClass();
 	}	//	function getCacheStorageClass()
 
 
-	public static function setCacheStorageMethod($method = PHPExcel_CachedObjectStorageFactory::cache_in_memory, $arguments = array()) {
-		return PHPExcel_CachedObjectStorageFactory::initialize($method,$arguments);
+	/**
+	 * Set the method that should be used for cell cacheing
+	 *
+	 * @param	string	$method		Name of the cacheing method
+	 * @param	array	$arguments	Optional configuration arguments for the cacheing method
+	 * @return	boolean				Success or failure
+	 */
+	public static function setCacheStorageMethod($method = PHPExcel_CachedObjectStorageFactory::cache_in_memory,
+												 $arguments = array()) {
+		return PHPExcel_CachedObjectStorageFactory::initialize($method, $arguments);
 	}	//	function setCacheStorageMethod()
 
 
-	public static function setLocale($locale){
+	/**
+	 * Set the locale code to use for formula translations and any special formatting
+	 *
+	 * @param	string	$locale		The locale code to use (e.g. "fr" or "pt_br" or "en_uk")
+	 * @return	boolean				Success or failure
+	 */
+	public static function setLocale($locale='en_us') {
 		return PHPExcel_Calculation::getInstance()->setLocale($locale);
 	}	//	function setLocale()
 
+
+	/**
+	 * Set details of the external library that PHPExcel should use for rendering charts
+	 *
+	 * @param	 string	$libraryName		Internal reference name of the library
+	 *											e.g. PHPExcel_Settings::CHART_RENDERER_JPGRAPH
+	 * @param	 string	$libraryBaseDir		Directory path to the library's base folder
+	 * @return	 boolean					Success or failure
+	 */
+	public static function setChartRenderer($libraryName, $libraryBaseDir) {
+		if (!self::setChartRendererName($libraryName))
+			return FALSE;
+		return self::setChartRendererPath($libraryBaseDir);
+	}	//	function setChartRenderer()
+
+
+	/**
+	 * Identify to PHPExcel the external library to use for rendering charts
+	 *
+	 * @param	 string	$libraryName		Internal reference name of the library
+	 *											e.g. PHPExcel_Settings::CHART_RENDERER_JPGRAPH
+	 * @return	 boolean					Success or failure
+	 */
+	public static function setChartRendererName($libraryName) {
+		if (!in_array($libraryName,self::$_chartRenderers)) {
+			return FALSE;
+		}
+
+		self::$_chartRendererName = $libraryName;
+
+		return TRUE;
+	}	//	function setChartRendererName()
+
+
+	/**
+	 * Tell PHPExcel where to find the external library to use for rendering charts
+	 *
+	 * @param	 string	$libraryBaseDir		Directory path to the library's base folder
+	 * @return	 boolean					Success or failure
+	 */
+	public static function setChartRendererPath($libraryBaseDir) {
+		if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) {
+			return FALSE;
+		}
+		self::$_chartRendererPath = $libraryBaseDir;
+
+		return TRUE;
+	}	//	function setChartRendererPath()
+
+
+	/**
+	 * Return the Chart Rendering Library that PHPExcel is currently configured to use (e.g. jpgraph)
+	 *
+	 * @return	 string|NULL				Internal reference name of the Chart Rendering Library that PHPExcel is
+	 *											currently configured to use
+	 *												e.g. PHPExcel_Settings::CHART_RENDERER_JPGRAPH
+	 */
+	public static function getChartRendererName() {
+		return self::$_chartRendererName;
+	}	//	function getChartRendererName()
+
+
+	/**
+	 * Return the directory path to the Chart Rendering Library that PHPExcel is currently configured to use
+	 *
+	 * @return	 string|NULL				Directory Path to the Chart Rendering Library that PHPExcel is
+	 *											currently configured to use
+	 */
+	public static function getChartRendererPath() {
+		return self::$_chartRendererPath;
+	}	//	function getChartRendererPath()
+
+
+	/**
+	 * Set details of the external library that PHPExcel should use for rendering PDF files
+	 *
+	 * @param	 string	$libraryName		Internal reference name of the library
+	 *											e.g. PHPExcel_Settings::PDF_RENDERER_TCPDF,
+	 *												 PHPExcel_Settings::PDF_RENDERER_DOMPDF
+	 *											  or PHPExcel_Settings::PDF_RENDERER_MPDF
+	 * @param	 string	$libraryBaseDir		Directory path to the library's base folder
+	 * @return	 boolean					Success or failure
+	 */
+	public static function setPdfRenderer($libraryName, $libraryBaseDir) {
+		if (!self::setPdfRendererName($libraryName))
+			return FALSE;
+		return self::setPdfRendererPath($libraryBaseDir);
+	}	//	function setPdfRenderer()
+
+
+	/**
+	 * Identify to PHPExcel the external library to use for rendering PDF files
+	 *
+	 * @param	 string	$libraryName		Internal reference name of the library
+	 *											e.g. PHPExcel_Settings::PDF_RENDERER_TCPDF,
+	 *												 PHPExcel_Settings::PDF_RENDERER_DOMPDF
+	 *											  or PHPExcel_Settings::PDF_RENDERER_MPDF
+	 * @return	 boolean					Success or failure
+	 */
+	public static function setPdfRendererName($libraryName) {
+		if (!in_array($libraryName,self::$_pdfRenderers)) {
+			return FALSE;
+		}
+
+		self::$_pdfRendererName = $libraryName;
+
+		return TRUE;
+	}	//	function setPdfRendererName()
+
+
+	/**
+	 * Tell PHPExcel where to find the external library to use for rendering PDF files
+	 *
+	 * @param	 string	$libraryBaseDir		Directory path to the library's base folder
+	 * @return	 boolean					Success or failure
+	 */
+	public static function setPdfRendererPath($libraryBaseDir) {
+		if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) {
+			return FALSE;
+		}
+		self::$_pdfRendererPath = $libraryBaseDir;
+
+		return TRUE;
+	}	//	function setPdfRendererPath()
+
+
+	/**
+	 * Return the PDF Rendering Library that PHPExcel is currently configured to use (e.g. dompdf)
+	 *
+	 * @return	 string|NULL				Internal reference name of the PDF Rendering Library that PHPExcel is
+	 *											currently configured to use
+	 *												e.g. PHPExcel_Settings::PDF_RENDERER_TCPDF,
+	 *													 PHPExcel_Settings::PDF_RENDERER_DOMPDF
+	 *												  or PHPExcel_Settings::PDF_RENDERER_MPDF
+	 */
+	public static function getPdfRendererName() {
+		return self::$_pdfRendererName;
+	}	//	function getPdfRendererName()
+
+
+	/**
+	 * Return the directory path to the PDF Rendering Library that PHPExcel is currently configured to use
+	 *
+	 * @return	 string|NULL				Directory Path to the PDF Rendering Library that PHPExcel is
+	 *											currently configured to use
+	 */
+	public static function getPdfRendererPath() {
+		return self::$_pdfRendererPath;
+	}	//	function getPdfRendererPath()
+
 }

+ 49 - 43
htdocs/includes/phpexcel/PHPExcel/Shared/CodePage.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_CodePage
 {
@@ -46,47 +46,53 @@ class PHPExcel_Shared_CodePage
 	public static function NumberToName($codePage = '1252')
 	{
 		switch ($codePage) {
-			case 367:	return 'ASCII';		break;	//	ASCII
-			case 437:	return 'CP437';		break;	//	OEM US
+			case 367:	return 'ASCII';				break;	//	ASCII
+			case 437:	return 'CP437';				break;	//	OEM US
 			case 720:	throw new Exception('Code page 720 not supported.');
-											break;	//	OEM Arabic
-			case 737:	return 'CP737';		break;	//	OEM Greek
-			case 775:	return 'CP775';		break;	//	OEM Baltic
-			case 850:	return 'CP850';		break;	//	OEM Latin I
-			case 852:	return 'CP852';		break;	//	OEM Latin II (Central European)
-			case 855:	return 'CP855';		break;	//	OEM Cyrillic
-			case 857:	return 'CP857';		break;	//	OEM Turkish
-			case 858:	return 'CP858';		break;	//	OEM Multilingual Latin I with Euro
-			case 860:	return 'CP860';		break;	//	OEM Portugese
-			case 861:	return 'CP861';		break;	//	OEM Icelandic
-			case 862:	return 'CP862';		break;	//	OEM Hebrew
-			case 863:	return 'CP863';		break;	//	OEM Canadian (French)
-			case 864:	return 'CP864';		break;	//	OEM Arabic
-			case 865:	return 'CP865';		break;	//	OEM Nordic
-			case 866:	return 'CP866';		break;	//	OEM Cyrillic (Russian)
-			case 869:	return 'CP869';		break;	//	OEM Greek (Modern)
-			case 874:	return 'CP874';		break;	//	ANSI Thai
-			case 932:	return 'CP932';		break;	//	ANSI Japanese Shift-JIS
-			case 936:	return 'CP936';		break;	//	ANSI Chinese Simplified GBK
-			case 949:	return 'CP949';		break;	//	ANSI Korean (Wansung)
-			case 950:	return 'CP950';		break;	//	ANSI Chinese Traditional BIG5
-			case 1200:	return 'UTF-16LE';	break;	//	UTF-16 (BIFF8)
-			case 1250:	return 'CP1250';	break;	//	ANSI Latin II (Central European)
-			case 1251:	return 'CP1251';	break;	//	ANSI Cyrillic
-			case 0:									//	CodePage is not always correctly set when the xls file was saved by Apple's Numbers program
-			case 1252:	return 'CP1252';	break;	//	ANSI Latin I (BIFF4-BIFF7)
-			case 1253:	return 'CP1253';	break;	//	ANSI Greek
-			case 1254:	return 'CP1254';	break;	//	ANSI Turkish
-			case 1255:	return 'CP1255';	break;	//	ANSI Hebrew
-			case 1256:	return 'CP1256';	break;	//	ANSI Arabic
-			case 1257:	return 'CP1257';	break;	//	ANSI Baltic
-			case 1258:	return 'CP1258';	break;	//	ANSI Vietnamese
-			case 1361:	return 'CP1361';	break;	//	ANSI Korean (Johab)
-			case 10000:	return 'MAC';		break;	//	Apple Roman
-			case 32768:	return 'MAC';		break;	//	Apple Roman
+													break;	//	OEM Arabic
+			case 737:	return 'CP737';				break;	//	OEM Greek
+			case 775:	return 'CP775';				break;	//	OEM Baltic
+			case 850:	return 'CP850';				break;	//	OEM Latin I
+			case 852:	return 'CP852';				break;	//	OEM Latin II (Central European)
+			case 855:	return 'CP855';				break;	//	OEM Cyrillic
+			case 857:	return 'CP857';				break;	//	OEM Turkish
+			case 858:	return 'CP858';				break;	//	OEM Multilingual Latin I with Euro
+			case 860:	return 'CP860';				break;	//	OEM Portugese
+			case 861:	return 'CP861';				break;	//	OEM Icelandic
+			case 862:	return 'CP862';				break;	//	OEM Hebrew
+			case 863:	return 'CP863';				break;	//	OEM Canadian (French)
+			case 864:	return 'CP864';				break;	//	OEM Arabic
+			case 865:	return 'CP865';				break;	//	OEM Nordic
+			case 866:	return 'CP866';				break;	//	OEM Cyrillic (Russian)
+			case 869:	return 'CP869';				break;	//	OEM Greek (Modern)
+			case 874:	return 'CP874';				break;	//	ANSI Thai
+			case 932:	return 'CP932';				break;	//	ANSI Japanese Shift-JIS
+			case 936:	return 'CP936';				break;	//	ANSI Chinese Simplified GBK
+			case 949:	return 'CP949';				break;	//	ANSI Korean (Wansung)
+			case 950:	return 'CP950';				break;	//	ANSI Chinese Traditional BIG5
+			case 1200:	return 'UTF-16LE';			break;	//	UTF-16 (BIFF8)
+			case 1250:	return 'CP1250';			break;	//	ANSI Latin II (Central European)
+			case 1251:	return 'CP1251';			break;	//	ANSI Cyrillic
+			case 0:		//	CodePage is not always correctly set when the xls file was saved by Apple's Numbers program
+			case 1252:	return 'CP1252';			break;	//	ANSI Latin I (BIFF4-BIFF7)
+			case 1253:	return 'CP1253';			break;	//	ANSI Greek
+			case 1254:	return 'CP1254';			break;	//	ANSI Turkish
+			case 1255:	return 'CP1255';			break;	//	ANSI Hebrew
+			case 1256:	return 'CP1256';			break;	//	ANSI Arabic
+			case 1257:	return 'CP1257';			break;	//	ANSI Baltic
+			case 1258:	return 'CP1258';			break;	//	ANSI Vietnamese
+			case 1361:	return 'CP1361';			break;	//	ANSI Korean (Johab)
+			case 10000:	return 'MAC';				break;	//	Apple Roman
+			case 10006:	return 'MACGREEK';			break;	//	Macintosh Greek
+			case 10007:	return 'MACCYRILLIC';		break;	//	Macintosh Cyrillic
+			case 10029:	return 'MACCENTRALEUROPE';	break;	//	Macintosh Central Europe
+			case 10079: return 'MACICELAND';		break;	//	Macintosh Icelandic
+			case 10081: return 'MACTURKISH';		break;	//	Macintosh Turkish
+			case 32768:	return 'MAC';				break;	//	Apple Roman
 			case 32769:	throw new Exception('Code page 32769 not supported.');
-											break;	//	ANSI Latin I (BIFF2-BIFF3)
-			case 65001:	return 'UTF-8';		break;	//	Unicode (UTF-8)
+													break;	//	ANSI Latin I (BIFF2-BIFF3)
+			case 65000:	return 'UTF-7';				break;	//	Unicode (UTF-7)
+			case 65001:	return 'UTF-8';				break;	//	Unicode (UTF-8)
 		}
 
 		throw new Exception('Unknown codepage: ' . $codePage);

+ 73 - 32
htdocs/includes/phpexcel/PHPExcel/Shared/Date.php

@@ -3,7 +3,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,9 +21,9 @@
  *
  * @category   PHPExcel
  * @package	PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version	1.7.6, 2011-02-27
+ * @version	1.7.8, 2012-10-12
  */
 
 
@@ -32,7 +32,7 @@
  *
  * @category   PHPExcel
  * @package	PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Date
 {
@@ -40,8 +40,41 @@ class PHPExcel_Shared_Date
 	const CALENDAR_WINDOWS_1900 = 1900;		//	Base date of 1st Jan 1900 = 1.0
 	const CALENDAR_MAC_1904 = 1904;			//	Base date of 2nd Jan 1904 = 1.0
 
+	/*
+	 * Names of the months of the year, indexed by shortname
+	 * Planned usage for locale settings
+	 *
+	 * @public
+	 * @var	string[]
+	 */
+	public static $_monthNames = array(	'Jan' => 'January',
+										'Feb' => 'February',
+										'Mar' => 'March',
+										'Apr' => 'April',
+										'May' => 'May',
+										'Jun' => 'June',
+										'Jul' => 'July',
+										'Aug' => 'August',
+										'Sep' => 'September',
+										'Oct' => 'October',
+										'Nov' => 'November',
+										'Dec' => 'December'
+									  );
+
+	/*
+	 * Base calendar year to use for calculations
+	 *
+	 * @private
+	 * @var	int
+	 */
 	private static $ExcelBaseDate	= self::CALENDAR_WINDOWS_1900;
 
+	/*
+	 * Object type for PHP Date/Time values
+	 *
+	 * @private
+	 * @var	string
+	 */
 	public static $dateTimeObjectType	= 'DateTime';
 
 
@@ -55,9 +88,9 @@ class PHPExcel_Shared_Date
 		if (($baseDate == self::CALENDAR_WINDOWS_1900) ||
 			($baseDate == self::CALENDAR_MAC_1904)) {
 			self::$ExcelBaseDate = $baseDate;
-			return True;
+			return TRUE;
 		}
-		return False;
+		return FALSE;
 	}	//	function setExcelCalendar()
 
 
@@ -91,14 +124,14 @@ class PHPExcel_Shared_Date
 		// Perform conversion
 		if ($dateValue >= 1) {
 			$utcDays = $dateValue - $myExcelBaseDate;
-			$returnValue = round($utcDays * 24 * 60 * 60);
+			$returnValue = round($utcDays * 86400);
 			if (($returnValue <= PHP_INT_MAX) && ($returnValue >= -PHP_INT_MAX)) {
 				$returnValue = (integer) $returnValue;
 			}
 		} else {
 			$hours = round($dateValue * 24);
-			$mins = round($dateValue * 24 * 60) - round($hours * 60);
-			$secs = round($dateValue * 24 * 60 * 60) - round($hours * 60 * 60) - round($mins * 60);
+			$mins = round($dateValue * 1440) - round($hours * 60);
+			$secs = round($dateValue * 86400) - round($hours * 3600) - round($mins * 60);
 			$returnValue = (integer) gmmktime($hours, $mins, $secs);
 		}
 
@@ -133,12 +166,12 @@ class PHPExcel_Shared_Date
 	 *
 	 * @param	 mixed		$dateValue	PHP serialized date/time or date object
 	 * @return	 mixed					Excel date/time value
-	 *										or boolean False on failure
+	 *										or boolean FALSE on failure
 	 */
 	public static function PHPToExcel($dateValue = 0) {
 		$saveTimeZone = date_default_timezone_get();
 		date_default_timezone_set('UTC');
-		$retValue = False;
+		$retValue = FALSE;
 		if ((is_object($dateValue)) && ($dateValue instanceof self::$dateTimeObjectType)) {
 			$retValue = self::FormattedPHPToExcel( $dateValue->format('Y'), $dateValue->format('m'), $dateValue->format('d'),
 												   $dateValue->format('H'), $dateValue->format('i'), $dateValue->format('s')
@@ -171,19 +204,19 @@ class PHPExcel_Shared_Date
 			//	Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
 			//	This affects every date following 28th February 1900
 			//
-			$excel1900isLeapYear = True;
-			if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = False; }
+			$excel1900isLeapYear = TRUE;
+			if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = FALSE; }
 			$myExcelBaseDate = 2415020;
 		} else {
 			$myExcelBaseDate = 2416481;
-			$excel1900isLeapYear = False;
+			$excel1900isLeapYear = FALSE;
 		}
 
 		//	Julian base date Adjustment
 		if ($month > 2) {
-			$month = $month - 3;
+			$month -= 3;
 		} else {
-			$month = $month + 9;
+			$month += 9;
 			--$year;
 		}
 
@@ -205,7 +238,11 @@ class PHPExcel_Shared_Date
 	 * @return	 boolean
 	 */
 	public static function isDateTime(PHPExcel_Cell $pCell) {
-		return self::isDateTimeFormat($pCell->getParent()->getStyle($pCell->getCoordinate())->getNumberFormat());
+		return self::isDateTimeFormat(
+			$pCell->getParent()->getStyle(
+				$pCell->getCoordinate()
+			)->getNumberFormat()
+		);
 	}	//	function isDateTime()
 
 
@@ -220,7 +257,7 @@ class PHPExcel_Shared_Date
 	}	//	function isDateTimeFormat()
 
 
-	private static	$possibleDateFormatCharacters = 'ymdHs';
+	private static	$possibleDateFormatCharacters = 'eymdHs';
 
 	/**
 	 * Is a given number format code a date/time?
@@ -231,6 +268,10 @@ class PHPExcel_Shared_Date
 	public static function isDateTimeFormatCode($pFormatCode = '') {
 		// Switch on formatcode
 		switch ($pFormatCode) {
+			//	General contains an epoch letter 'e', so we trap for it explicitly here
+			case PHPExcel_Style_NumberFormat::FORMAT_GENERAL:
+				return FALSE;
+			//	Explicitly defined date formats
 			case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD:
 			case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2:
 			case PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY:
@@ -253,32 +294,32 @@ class PHPExcel_Shared_Date
 			case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16:
 			case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17:
 			case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22:
-				return true;
+				return TRUE;
 		}
 
 		//	Typically number, currency or accounting (or occasionally fraction) formats
 		if ((substr($pFormatCode,0,1) == '_') || (substr($pFormatCode,0,2) == '0 ')) {
-			return false;
+			return FALSE;
 		}
 		// Try checking for any of the date formatting characters that don't appear within square braces
 		if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$pFormatCode)) {
 			//	We might also have a format mask containing quoted strings...
 			//		we don't want to test for any of our characters within the quoted blocks
-			if (strpos($pFormatCode,'"') !== false) {
-				$i = false;
+			if (strpos($pFormatCode,'"') !== FALSE) {
+				$i = FALSE;
 				foreach(explode('"',$pFormatCode) as $subVal) {
 					//	Only test in alternate array entries (the non-quoted blocks)
 					if (($i = !$i) && (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$subVal))) {
-						return true;
+						return TRUE;
 					}
 				}
-				return false;
+				return FALSE;
 			}
-			return true;
+			return TRUE;
 		}
 
 		// No date...
-		return false;
+		return FALSE;
 	}	//	function isDateTimeFormatCode()
 
 
@@ -286,23 +327,23 @@ class PHPExcel_Shared_Date
 	 * Convert a date/time string to Excel time
 	 *
 	 * @param	string	$dateValue		Examples: '2009-12-31', '2009-12-31 15:59', '2009-12-31 15:59:10'
-	 * @return	float|false		Excel date/time serial value
+	 * @return	float|FALSE		Excel date/time serial value
 	 */
 	public static function stringToExcel($dateValue = '') {
 		if (strlen($dateValue) < 2)
-			return false;
+			return FALSE;
 		if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue))
-			return false;
+			return FALSE;
 
 		$dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue);
 
 		if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) {
-			return false;
+			return FALSE;
 		} else {
-			if (strpos($dateValue, ':') !== false) {
+			if (strpos($dateValue, ':') !== FALSE) {
 				$timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue);
 				if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) {
-					return false;
+					return FALSE;
 				}
 				$dateValueNew += $timeValue;
 			}

+ 21 - 21
htdocs/includes/phpexcel/PHPExcel/Shared/Drawing.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Drawing
 {
@@ -183,35 +183,35 @@ class PHPExcel_Shared_Drawing
         $read    =    fread($file,10);
         while(!feof($file)&&($read<>""))
             $read    .=    fread($file,1024);
-       
+
         $temp    =    unpack("H*",$read);
         $hex    =    $temp[1];
         $header    =    substr($hex,0,108);
-       
+
         //    Process the header
         //    Structure: http://www.fastgraph.com/help/bmp_header_format.html
         if (substr($header,0,4)=="424d")
         {
             //    Cut it in parts of 2 bytes
             $header_parts    =    str_split($header,2);
-           
+
             //    Get the width        4 bytes
             $width            =    hexdec($header_parts[19].$header_parts[18]);
-           
+
             //    Get the height        4 bytes
             $height            =    hexdec($header_parts[23].$header_parts[22]);
-           
+
             //    Unset the header params
             unset($header_parts);
         }
-       
+
         //    Define starting X and Y
         $x                =    0;
         $y                =    1;
-       
+
         //    Create newimage
         $image            =    imagecreatetruecolor($width,$height);
-       
+
         //    Grab the body from the image
         $body            =    substr($hex,108);
 
@@ -223,7 +223,7 @@ class PHPExcel_Shared_Drawing
 
         //    Use end-line padding? Only when needed
         $usePadding        =    ($body_size>($header_size*3)+4);
-       
+
         //    Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
         //    Calculate the next DWORD-position in the body
         for ($i=0;$i<$body_size;$i+=3)
@@ -235,36 +235,36 @@ class PHPExcel_Shared_Drawing
                 //    Shift i to the ending of the current 32-bit-block
                 if ($usePadding)
                     $i    +=    $width%4;
-               
+
                 //    Reset horizontal position
                 $x    =    0;
-               
+
                 //    Raise the height-position (bottom-up)
                 $y++;
-               
+
                 //    Reached the image-height? Break the for-loop
                 if ($y>$height)
                     break;
             }
-           
+
             //    Calculation of the RGB-pixel (defined as BGR in image-data)
             //    Define $i_pos as absolute position in the body
             $i_pos    =    $i*2;
             $r        =    hexdec($body[$i_pos+4].$body[$i_pos+5]);
             $g        =    hexdec($body[$i_pos+2].$body[$i_pos+3]);
             $b        =    hexdec($body[$i_pos].$body[$i_pos+1]);
-           
+
             //    Calculate and draw the pixel
             $color    =    imagecolorallocate($image,$r,$g,$b);
             imagesetpixel($image,$x,$height-$y,$color);
-           
+
             //    Raise the horizontal position
             $x++;
         }
-       
+
         //    Unset the body / free the memory
         unset($body);
-       
+
         //    Return image-object
         return $image;
 	}

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher
 {

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DgContainer.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DgContainer
 {

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DgContainer_SpgrContainer
 {

+ 31 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer
 {
@@ -55,6 +55,13 @@ class PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer
 	 */
 	private $_spType;
 
+	/**
+	 * Shape flag
+	 *
+	 * @var int
+	 */
+	private $_spFlag;
+
 	/**
 	 * Shape index (usually group shape has index 0, and the rest: 1,2,3...)
 	 *
@@ -171,6 +178,26 @@ class PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer
 		return $this->_spType;
 	}
 
+	/**
+	 * Set the shape flag
+	 *
+	 * @param int $value
+	 */
+	public function setSpFlag($value)
+	{
+		$this->_spFlag = $value;
+	}
+
+	/**
+	 * Get the shape flag
+	 *
+	 * @return int
+	 */
+	public function getSpFlag()
+	{
+		return $this->_spFlag;
+	}
+
 	/**
 	 * Set the shape index
 	 *

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DggContainer
 {

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DggContainer_BstoreContainer
 {

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE
 {

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Escher/DggContainer/BstoreContainer/BSE/Blip.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared_Escher
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip
 {

+ 4 - 4
htdocs/includes/phpexcel/PHPExcel/Shared/Excel5.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 /**
@@ -30,7 +30,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Excel5
 {

+ 8 - 8
htdocs/includes/phpexcel/PHPExcel/Shared/File.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_File
 {
@@ -80,7 +80,7 @@ class PHPExcel_Shared_File
 		}
 
 		// Found something?
-		if ($returnValue == '' || is_null($returnValue)) {
+		if ($returnValue == '' || ($returnValue === NULL)) {
 			$pathArray = explode('/' , $pFilename);
 			while(in_array('..', $pathArray) && $pathArray[0] != '..') {
 				for ($i = 0; $i < count($pathArray); ++$i) {
@@ -110,13 +110,13 @@ class PHPExcel_Shared_File
 
 		if ( !function_exists('sys_get_temp_dir')) {
 			if ($temp = getenv('TMP') ) {
-				if (file_exists($temp)) { return realpath($temp); }
+				if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); }
 			}
 			if ($temp = getenv('TEMP') ) {
-				if (file_exists($temp)) { return realpath($temp); }
+				if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); }
 			}
 			if ($temp = getenv('TMPDIR') ) {
-				if (file_exists($temp)) { return realpath($temp); }
+				if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); }
 			}
 
 			// trick for creating a file in system's temporary dir

+ 20 - 8
htdocs/includes/phpexcel/PHPExcel/Shared/Font.php

@@ -2,7 +2,7 @@
 /**
  * PHPExcel
  *
- * Copyright (c) 2006 - 2011 PHPExcel
+ * Copyright (c) 2006 - 2012 PHPExcel
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,9 +20,9 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
- * @version    1.7.6, 2011-02-27
+ * @version    1.7.8, 2012-10-12
  */
 
 
@@ -31,7 +31,7 @@
  *
  * @category   PHPExcel
  * @package    PHPExcel_Shared
- * @copyright  Copyright (c) 2006 - 2011 PHPExcel (http://www.codeplex.com/PHPExcel)
+ * @copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
  */
 class PHPExcel_Shared_Font
 {
@@ -39,6 +39,11 @@ class PHPExcel_Shared_Font
 	const AUTOSIZE_METHOD_APPROX	= 'approx';
 	const AUTOSIZE_METHOD_EXACT		= 'exact';
 
+	private static $_autoSizeMethods = array(
+		self::AUTOSIZE_METHOD_APPROX,
+		self::AUTOSIZE_METHOD_EXACT,
+	);
+
 	/** Character set codes used by BIFF5-8 in Font records */
 	const CHARSET_ANSI_LATIN				= 0x00;
 	const CHARSET_SYSTEM_DEFAULT			= 0x01;
@@ -47,8 +52,8 @@ class PHPExcel_Shared_Font
 	const CHARSET_ANSI_JAPANESE_SHIFTJIS	= 0x80;
 	const CHARSET_ANSI_KOREAN_HANGUL		= 0x81;
 	const CHARSET_ANSI_KOREAN_JOHAB			= 0x82;
-	const CHARSET_ANSI_CHINESE_SIMIPLIFIED	= 0x86;
-	const CHARSET_ANSI_CHINESE_TRADITIONAL	= 0x88;
+	const CHARSET_ANSI_CHINESE_SIMIPLIFIED	= 0x86;		//	gb2312
+	const CHARSET_ANSI_CHINESE_TRADITIONAL	= 0x88;		//	big5
 	const CHARSET_ANSI_GREEK				= 0xA1;
 	const CHARSET_ANSI_TURKISH				= 0xA2;
 	const CHARSET_ANSI_VIETNAMESE			= 0xA3;
@@ -56,7 +61,7 @@ class PHPExcel_Shared_Font
 	const CHARSET_ANSI_ARABIC				= 0xB2;
 	const CHARSET_ANSI_BALTIC				= 0xBA;
 	const CHARSET_ANSI_CYRILLIC				= 0xCC;
-	const CHARSET_ANSI_THAI					= 0xDE;
+	const CHARSET_ANSI_THAI					= 0xDD;
 	const CHARSET_ANSI_LATIN_II				= 0xEE;
 	const CHARSET_OEM_LATIN_I				= 0xFF;
 
@@ -187,10 +192,17 @@ class PHPExcel_Shared_Font
 	 * Set autoSize method
 	 *
 	 * @param string $pValue
+	 * @return	 boolean					Success or failure
 	 */
-	public static function setAutoSizeMethod($pValue = 'approx')
+	public static function setAutoSizeMethod($pValue = self::AUTOSIZE_METHOD_APPROX)
 	{
+		if (!in_array($pValue,self::$_autoSizeMethods)) {
+			return FALSE;
+		}
+
 		self::$autoSizeMethod = $pValue;
+
+		return TRUE;
 	}
 
 	/**

+ 0 - 6
htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/docs.php

@@ -1,6 +0,0 @@
-<?php
-require_once "includes/header.php";
-require_once "includes/navbar.php";
-require_once "sections/Home.php";
-require_once "includes/footer.php";	
-?>

+ 0 - 65
htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/download.php

@@ -1,65 +0,0 @@
-<?php
-/**
-* Script to create REGRESS package for download
-*
-* @author Mike Bommarito
-* @author Paul Meagher
-* @version 0.3
-* @modified Apr 2, 2006
-*
-* Note: Script requires the PEAR Archive_Tar package be installed:
-*
-* @see http://pear.php.net/package/Archive_Tar
-*/
-
-// name and directory of package
-$pkgName   = "JAMA";
-
-// root of PHP/Math build directory
-$buildDir  = substr(dirname(__FILE__), 0, -5 - strlen($pkgName));
-
-// switch to PHP/Math build directory
-chdir($buildDir);
-
-$tarName = "$pkgName.tar.gz";  
-
-$tarPath = $buildDir.$pkgName."/downloads/".$tarName;
-
-if($_GET['op'] == "download") {  
-  
-	require_once('Archive/Tar.php');  
-	
-	$tar   = new Archive_Tar($tarPath);
-
-  // create $pkgName archive under $pkgName folder
-  $files = glob("$pkgName/*.php");
-  $files = array_merge($files, glob("$pkgName/*.TXT"));
-  $files = array_merge($files, glob("$pkgName/docs/*.php"));
-  $files = array_merge($files, glob("$pkgName/docs/includes/*.php"));
-  $files = array_merge($files, glob("$pkgName/examples/*.php"));
-  $files = array_merge($files, glob("$pkgName/tests/*.php"));  
-  $files = array_merge($files, glob("$pkgName/utils/*.php"));    
-  
-	$tar->create($files);
-		
-	// create the download url
-  $webDir  = substr($_SERVER['PHP_SELF'], 0, -18);
-  $urlPath = "http://".$_SERVER['HTTP_HOST'].$webDir."/downloads";
-  
-  // redirect to download url
-	header("Location: $urlPath/$tarName");
-
-}
-
-include_once "includes/header.php";
-include_once "includes/navbar.php";
-?>
-<p>
-Download current version: 
-</p>
-<ul>
- <li><a href='<?php echo $_SERVER['PHP_SELF']."?op=download"; ?>'><?php echo $tarName ?></a></li>
-</ul>
-<?php
-include_once "includes/footer.php";
-?>

+ 0 - 166
htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/example.php

@@ -1,166 +0,0 @@
-<?php
-include_once "includes/header.php";
-include_once "includes/navbar.php";
-?>
-<h2>Magic Square Example</h2>
-<p>
-The Jama distribution comes with a magic square example that is used to 
-test and benchmark the LU, QR, SVD and symmetric Eig decompositions.  
-The example outputs a multi-column table with these column headings:
-</p>
-
-<table border='1' cellpadding='5' cellspacing='0' align='center'>
-  <tr>
-    <td><b>n</b></td>
-    <td>Order of magic square.</td>
-  </tr>
-  <tr>
-    <td><b>trace</b></td>
-    <td>Diagonal sum, should be the magic sum, (n^3 + n)/2.</td>
-  </tr>
-  <tr>
-    <td><b>max_eig</b></td>
-    <td>Maximum eigenvalue of (A + A')/2, should equal trace.</td>
-  </tr>
-  <tr>
-    <td><b>rank</b></td>
-    <td>Linear algebraic rank, should equal n if n is odd, be less than n if n is even.</td>
-  </tr>
-  <tr>
-    <td><b>cond</b></td>
-    <td>L_2 condition number, ratio of singular values.</td>
-  </tr>
-  <tr>
-    <td><b>lu_res</b></td>
-    <td>test of LU factorization, norm1(L*U-A(p,:))/(n*eps).</td>
-  </tr>
-  <tr>
-    <td><b>qr_res</b></td>
-    <td>test of QR factorization, norm1(Q*R-A)/(n*eps).</td>
-  </tr>
-</table>
-<p>
-Running the Java-based version of the matix square example produces these results:
-</p>
-
-<table border='1' align='center'>
-  <tr>
-    <th> n </th>
-    <th> trace </th>       
-    <th> max_eig </th>   
-    <th> rank </th>        
-    <th> cond </th>      
-    <th> lu_res </th>      
-    <th> qr_res </th>
-  </tr>
-  <tr>
-    <td>3</td><td>15</td><td>15.000</td><td>3</td><td>4.330</td><td>0.000</td><td>11.333</td>
-  </tr>
-  <tr>
-    <td>4</td><td>34</td><td>34.000</td><td>3</td><td> Inf</td><td>0.000</td><td>13.500</td>
-  <tr>
-    <td>5</td><td>65</td><td>65.000</td><td>5</td><td>5.462</td><td>0.000</td><td>14.400</td>
-  </tr>
-  <tr>
-    <td>6</td><td>111</td><td>111.000</td><td>5</td><td> Inf</td><td>5.333</td><td>16.000</td>
-  </tr>
-  <tr>
-    <td>7</td><td>175</td><td>175.000</td><td>7</td><td>7.111</td><td>2.286</td><td>37.714</td>
-  </tr>
-  <tr>
-    <td>8</td><td>260</td><td>260.000</td><td>3</td><td> Inf</td><td>0.000</td><td>59.000</td>
-  </tr>
-  <tr>
-    <td>9</td><td>369</td><td>369.000</td><td>9</td><td>9.102</td><td>7.111</td><td>53.333</td>
-  </tr>
-  <tr>
-    <td>10</td><td>505</td><td>505.000</td><td>7</td><td> Inf</td><td>3.200</td><td>159.200</td>
-  </tr>
-  <tr>
-    <td>11</td><td>671</td><td>671.000</td><td>11</td><td>11.102</td><td>2.909</td><td>215.273</td>
-  </tr>
-  <tr>
-    <td>12</td><td>870</td><td>870.000</td><td>3</td><td> Inf</td><td>0.000</td><td>185.333</td>
-  </tr>
-  <tr>
-    <td>13</td><td>1105</td><td>1105.000</td><td>13</td><td>13.060</td><td>4.923</td><td>313.846</td>
-  </tr>
-  <tr>
-    <td>14</td><td>1379</td><td>1379.000</td><td>9</td><td> Inf</td><td>4.571</td><td>540.571</td>
-  </tr>
-  <tr>
-    <td>15</td><td>1695</td><td>1695.000</td><td>15</td><td>15.062</td><td>4.267</td><td>242.133</td>
-  </tr>
-  <tr>
-    <td>16</td><td>2056</td><td>2056.000</td><td>3</td><td> Inf</td><td>0.000</td><td>488.500</td>
-  </tr>
-  <tr>
-    <td>17</td><td>2465</td><td>2465.000</td><td>17</td><td>17.042</td><td>7.529</td><td>267.294</td>
-  </tr>
-  <tr>
-    <td>18</td><td>2925</td><td>2925.000</td><td>11</td><td> Inf</td><td>7.111</td><td>520.889</td>
-  </tr>
-  <tr>
-    <td>19</td><td>3439</td><td>3439.000</td><td>19</td><td>19.048</td><td>16.842</td><td>387.368</td>
-  </tr>
-  <tr>
-    <td>20</td><td>4010</td><td>4010.000</td><td>3</td><td> Inf</td><td>14.400</td><td>584.800</td>
-  </tr>
-  <tr>
-    <td>21</td><td>4641</td><td>4641.000</td><td>21</td><td>21.035</td><td>6.095</td><td>1158.095</td>
-  </tr>
-  <tr>
-    <td>22</td><td>5335</td><td>5335.000</td><td>13</td><td> Inf</td><td>6.545</td><td>1132.364</td>
-  </tr>
-  <tr>
-    <td>23</td><td>6095</td><td>6095.000</td><td>23</td><td>23.037</td><td>11.130</td><td>1268.870</td>
-  </tr>
-  <tr>
-    <td>24</td><td>6924</td><td>6924.000</td><td>3</td><td> Inf</td><td>10.667</td><td>827.500</td>
-  </tr>
-  <tr>
-    <td>25</td><td>7825</td><td>7825.000</td><td>25</td><td>25.029</td><td>35.840</td><td>1190.400</td>
-  </tr>
-  <tr>
-    <td>26</td><td>8801</td><td>8801.000</td><td>15</td><td> Inf</td><td>4.923</td><td>1859.077</td>
-  </tr>
-  <tr>
-    <td>27</td><td>9855</td><td>9855.000</td><td>27</td><td>27.032</td><td>37.926</td><td>1365.333</td>
-  </tr>
-  <tr>
-    <td>28</td><td>10990</td><td>10990.000</td><td>3</td><td> Inf</td><td>34.286</td><td>1365.714</td>
-  </tr>
-  <tr>
-    <td>29</td><td>12209</td><td>12209.000</td><td>29</td><td>29.025</td><td>30.897</td><td>1647.448</td>
-  </tr>
-  <tr>
-    <td>30</td><td>13515</td><td>13515.000</td><td>17</td><td> Inf</td><td>8.533</td><td>2571.733</td>
-  </tr>
-  <tr>
-    <td>31</td><td>14911</td><td>14911.000</td><td>31</td><td>31.027</td><td>33.032</td><td>1426.581</td>
-  </tr>
-  <tr>
-    <td>32</td><td>16400</td><td>16400.000</td><td>3</td><td> Inf</td><td>0.000</td><td>1600.125</td>
-  </tr>
-</table>
-<center>Elapsed Time =        0.710 seconds</center>
-
-<p>
-The magic square example does not fare well when <a href='../examples/MagicSquareExample.php'>run as a PHP script</a>.  For a 32x32 matrix array 
-it takes around a second to complete just the last row of computations in the above table.  
-Hopefully this result will spur PHP developers to find optimizations and better attuned algorithms 
-to speed things up. Matrix algebra is a great testing ground for ideas about time and memory 
-performance optimation.  Keep in perspective that PHP JAMA scripts are still plenty fast for use as 
-a tool for learning about matrix algebra and quickly extending your knowledge with new scripts 
-to apply knowledge.
-</p> 
-
-<p>
-To learn more about the subject of magic squares you can visit the <a href='http://mathforum.org/alejandre/magic.square.html'>Drexel Math Forum on Magic Squares</a>.
-You can also learn more by carefully examining the <code>MagicSquareExample.php</code> source code below.
-</p>
-
-<?php
-highlight_file("../examples/MagicSquareExample.php");
-include_once "includes/footer.php";	
-?>

+ 0 - 14
htdocs/includes/phpexcel/PHPExcel/Shared/JAMA/docs/includes/credits.php

@@ -1,14 +0,0 @@
-	<div id="credits">
-  <p>
-  Brought to you by:
-  </p>
-	<ul>
-	  <li><a href="http://math.nist.gov/">National Institute of Standards and Technology</a></li>
-	  <li><a href="http://math.nist.gov/">MathWorks</a></li>
-	  <li><a href="http://math.nist.gov/javanumerics/jama/">JAMA : A Java Matrix Package</a></li>	
-	  <li>Paul Meagher</li>
-	  <li>Michael Bommarito</li>
-	  <li>Lukasz Karapuda</li>
-	  <li>Bartek Matosiuk</li>
-	</ul>
-	</div>

Some files were not shown because too many files changed in this diff