Vendor/phpspreadsheet/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xls.php
public function load($pFilename)
    {
        // Read the OLE file
        $this->loadOLE($pFilename);

        // Initialisations
        $this->spreadsheet = new Spreadsheet();
        $this->spreadsheet->removeSheetByIndex(0); // remove 1st sheet
        if (!$this->readDataOnly) {
            $this->spreadsheet->removeCellStyleXfByIndex(0); // remove the default style
            $this->spreadsheet->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 = [];
        $this->objFonts = [];
        $this->palette = [];
        $this->sheets = [];
        $this->externalBooks = [];
        $this->ref = [];
        $this->definedname = [];
        $this->sst = [];
        $this->drawingGroupData = '';
        $this->xfIndex = '';
        $this->mapCellXfIndex = [];
        $this->mapCellStyleXfIndex = [];

        // Parse Workbook Global Substream
        while ($this->pos < $this->dataSize) {
            $code = self::getUInt2d($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 = Xls\Color::map($objFont->colorIndex, $this->palette, $this->version);
                    $objFont->getColor()->setRGB($color['rgb']);
                }
            }

            foreach ($this->spreadsheet->getCellXfCollection() as $objStyle) {
                // fill start and end color
                $fill = $objStyle->getFill();

                if (isset($fill->startcolorIndex)) {
                    $startColor = Xls\Color::map($fill->startcolorIndex, $this->palette, $this->version);
                    $fill->getStartColor()->setRGB($startColor['rgb']);
                }
                if (isset($fill->endcolorIndex)) {
                    $endColor = Xls\Color::map($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 = Xls\Color::map($top->colorIndex, $this->palette, $this->version);
                    $top->getColor()->setRGB($borderTopColor['rgb']);
                }
                if (isset($right->colorIndex)) {
                    $borderRightColor = Xls\Color::map($right->colorIndex, $this->palette, $this->version);
                    $right->getColor()->setRGB($borderRightColor['rgb']);
                }
                if (isset($bottom->colorIndex)) {
                    $borderBottomColor = Xls\Color::map($bottom->colorIndex, $this->palette, $this->version);
                    $bottom->getColor()->setRGB($borderBottomColor['rgb']);
                }
                if (isset($left->colorIndex)) {
                    $borderLeftColor = Xls\Color::map($left->colorIndex, $this->palette, $this->version);
                    $left->getColor()->setRGB($borderLeftColor['rgb']);
                }
                if (isset($diagonal->colorIndex)) {
                    $borderDiagonalColor = Xls\Color::map($diagonal->colorIndex, $this->palette, $this->version);
                    $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
                }
            }
        }

        // treat MSODRAWINGGROUP records, workbook-level Escher
        if (!$this->readDataOnly && $this->drawingGroupData) {
            $escherWorkbook = new Escher();
            $reader = new Xls\Escher($escherWorkbook);
            $escherWorkbook = $reader->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 PhpSpreadsheet object
            $this->phpSheet = $this->spreadsheet->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, 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 = [];

            // Initialize shared formula parts
            $this->sharedFormulaParts = [];

            // Initialize shared formulas
            $this->sharedFormulas = [];

            // Initialize text objs
            $this->textObjects = [];

            // Initialize cell annotations
            $this->cellNotes = [];
            $this->textObjRef = -1;

            while ($this->pos <= $this->dataSize - 4) {
                $code = self::getUInt2d($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_PAGELAYOUTVIEW:
                        $this->readPageLayoutView();

                        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_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 Escher();
                $reader = new Xls\Escher($escherWorksheet);
                $escherWorksheet = $reader->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) {
                // 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) = Coordinate::coordinateFromString($spContainer->getStartCoordinates());
                    list($endColumn, $endRow) = Coordinate::coordinateFromString($spContainer->getEndCoordinates());

                    $startOffsetX = $spContainer->getStartOffsetX();
                    $startOffsetY = $spContainer->getStartOffsetY();
                    $endOffsetX = $spContainer->getEndOffsetX();
                    $endOffsetY = $spContainer->getEndOffsetY();

                    $width = \PhpOffice\PhpSpreadsheet\Shared\Xls::getDistanceX($this->phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
                    $height = \PhpOffice\PhpSpreadsheet\Shared\Xls::getDistanceY($this->phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);

                    // calculate offsetX and offsetY of the shape
                    $offsetX = $startOffsetX * \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, $startColumn) / 1024;
                    $offsetY = $startOffsetY * \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $startRow) / 256;

                    switch ($obj['otObjType']) {
                        case 0x19:
                            // Note
                            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:
                            // picture
                            // get index to BSE entry (1-based)
                            $BSEindex = $spContainer->getOPT(0x0104);

                            // If there is no BSE Index, we will fail here and other fields are not read.
                            // Fix by checking here.
                            // TODO: Why is there no BSE Index? Is this a new Office Version? Password protected field?
                            // More likely : a uncompatible picture
                            if (!$BSEindex) {
                                continue;
                            }

                            $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 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 BSE::BLIPTYPE_JPEG:
                                        $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG);
                                        $drawing->setMimeType(MemoryDrawing::MIMETYPE_JPEG);

                                        break;
                                    case BSE::BLIPTYPE_PNG:
                                        $drawing->setRenderingFunction(MemoryDrawing::RENDERING_PNG);
                                        $drawing->setMimeType(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) = Coordinate::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, 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'] = '';
                        }
                    }
                    $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 = [];
                        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 = trim($explodes[0], "'");
                            if (count($explodes) == 2) {
                                if (strpos($explodes[1], ':') === false) {
                                    $explodes[1] = $explodes[1] . ':' . $explodes[1];
                                }
                                $extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
                            }
                        }
                        if ($docSheet = $this->spreadsheet->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->spreadsheet->getSheetByName($explodes[0])) {
                                    $extractedRange = $explodes[1];
                                    $extractedRange = str_replace('$', '', $extractedRange);

                                    $coordinateStrings = explode(':', $extractedRange);
                                    if (count($coordinateStrings) == 2) {
                                        list($firstColumn, $firstRow) = Coordinate::coordinateFromString($coordinateStrings[0]);
                                        list($lastColumn, $lastRow) = Coordinate::coordinateFromString($coordinateStrings[1]);

                                        if ($firstColumn == 'A' and $lastColumn == 'IV') {
                                            // then we have repeating rows
                                            $docSheet->getPageSetup()->setRowsToRepeatAtTop([$firstRow, $lastRow]);
                                        } elseif ($firstRow == 1 and $lastRow == 65536) {
                                            // then we have repeating columns
                                            $docSheet->getPageSetup()->setColumnsToRepeatAtLeft([$firstColumn, $lastColumn]);
                                        }
                                    }
                                }
                            }
                        }

                        break;
                }
            } else {
                // Extract range
                $explodes = explode('!', $definedName['formula']);

                if (count($explodes) == 2) {
                    if (($docSheet = $this->spreadsheet->getSheetByName($explodes[0])) ||
                        ($docSheet = $this->spreadsheet->getSheetByName(trim($explodes[0], "'")))) {
                        $extractedRange = $explodes[1];
                        $extractedRange = str_replace('$', '', $extractedRange);

                        $localOnly = ($definedName['scope'] == 0) ? false : true;

                        $scope = ($definedName['scope'] == 0) ? null : $this->spreadsheet->getSheetByName($this->sheets[$definedName['scope'] - 1]['name']);

                        $this->spreadsheet->addNamedRange(new NamedRange((string) $definedName['name'], $docSheet, $extractedRange, $localOnly, $scope));
                    }
                }
                //    Named Value
                    //    TODO Provide support for named values
            }
        }
        $this->data = null;

        return $this->spreadsheet;
    }
public function load($pFilename)
    {
        // Read the OLE file
        $this->loadOLE($pFilename);

        // Initialisations
        $this->spreadsheet = new Spreadsheet();
        $this->spreadsheet->removeSheetByIndex(0); // remove 1st sheet
        if (!$this->readDataOnly) {
            $this->spreadsheet->removeCellStyleXfByIndex(0); // remove the default style
            $this->spreadsheet->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 = [];
        $this->objFonts = [];
        $this->palette = [];
        $this->sheets = [];
        $this->externalBooks = [];
        $this->ref = [];
        $this->definedname = [];
        $this->sst = [];
        $this->drawingGroupData = '';
        $this->xfIndex = '';
        $this->mapCellXfIndex = [];
        $this->mapCellStyleXfIndex = [];

        // Parse Workbook Global Substream
        while ($this->pos < $this->dataSize) {
            $code = self::getUInt2d($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 = Xls\Color::map($objFont->colorIndex, $this->palette, $this->version);
                    $objFont->getColor()->setRGB($color['rgb']);
                }
            }

            foreach ($this->spreadsheet->getCellXfCollection() as $objStyle) {
                // fill start and end color
                $fill = $objStyle->getFill();

                if (isset($fill->startcolorIndex)) {
                    $startColor = Xls\Color::map($fill->startcolorIndex, $this->palette, $this->version);
                    $fill->getStartColor()->setRGB($startColor['rgb']);
                }
                if (isset($fill->endcolorIndex)) {
                    $endColor = Xls\Color::map($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 = Xls\Color::map($top->colorIndex, $this->palette, $this->version);
                    $top->getColor()->setRGB($borderTopColor['rgb']);
                }
                if (isset($right->colorIndex)) {
                    $borderRightColor = Xls\Color::map($right->colorIndex, $this->palette, $this->version);
                    $right->getColor()->setRGB($borderRightColor['rgb']);
                }
                if (isset($bottom->colorIndex)) {
                    $borderBottomColor = Xls\Color::map($bottom->colorIndex, $this->palette, $this->version);
                    $bottom->getColor()->setRGB($borderBottomColor['rgb']);
                }
                if (isset($left->colorIndex)) {
                    $borderLeftColor = Xls\Color::map($left->colorIndex, $this->palette, $this->version);
                    $left->getColor()->setRGB($borderLeftColor['rgb']);
                }
                if (isset($diagonal->colorIndex)) {
                    $borderDiagonalColor = Xls\Color::map($diagonal->colorIndex, $this->palette, $this->version);
                    $diagonal->getColor()->setRGB($borderDiagonalColor['rgb']);
                }
            }
        }

        // treat MSODRAWINGGROUP records, workbook-level Escher
        if (!$this->readDataOnly && $this->drawingGroupData) {
            $escherWorkbook = new Escher();
            $reader = new Xls\Escher($escherWorkbook);
            $escherWorkbook = $reader->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 PhpSpreadsheet object
            $this->phpSheet = $this->spreadsheet->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, 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 = [];

            // Initialize shared formula parts
            $this->sharedFormulaParts = [];

            // Initialize shared formulas
            $this->sharedFormulas = [];

            // Initialize text objs
            $this->textObjects = [];

            // Initialize cell annotations
            $this->cellNotes = [];
            $this->textObjRef = -1;

            while ($this->pos <= $this->dataSize - 4) {
                $code = self::getUInt2d($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_PAGELAYOUTVIEW:
                        $this->readPageLayoutView();

                        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_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 Escher();
                $reader = new Xls\Escher($escherWorksheet);
                $escherWorksheet = $reader->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) {
                // 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) = Coordinate::coordinateFromString($spContainer->getStartCoordinates());
                    list($endColumn, $endRow) = Coordinate::coordinateFromString($spContainer->getEndCoordinates());

                    $startOffsetX = $spContainer->getStartOffsetX();
                    $startOffsetY = $spContainer->getStartOffsetY();
                    $endOffsetX = $spContainer->getEndOffsetX();
                    $endOffsetY = $spContainer->getEndOffsetY();

                    $width = \PhpOffice\PhpSpreadsheet\Shared\Xls::getDistanceX($this->phpSheet, $startColumn, $startOffsetX, $endColumn, $endOffsetX);
                    $height = \PhpOffice\PhpSpreadsheet\Shared\Xls::getDistanceY($this->phpSheet, $startRow, $startOffsetY, $endRow, $endOffsetY);

                    // calculate offsetX and offsetY of the shape
                    $offsetX = $startOffsetX * \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeCol($this->phpSheet, $startColumn) / 1024;
                    $offsetY = $startOffsetY * \PhpOffice\PhpSpreadsheet\Shared\Xls::sizeRow($this->phpSheet, $startRow) / 256;

                    switch ($obj['otObjType']) {
                        case 0x19:
                            // Note
                            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:
                            // picture
                            // get index to BSE entry (1-based)
                            $BSEindex = $spContainer->getOPT(0x0104);

                            // If there is no BSE Index, we will fail here and other fields are not read.
                            // Fix by checking here.
                            // TODO: Why is there no BSE Index? Is this a new Office Version? Password protected field?
                            // More likely : a uncompatible picture
                            if (!$BSEindex) {
                                continue;
                            }

                            $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 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 BSE::BLIPTYPE_JPEG:
                                        $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG);
                                        $drawing->setMimeType(MemoryDrawing::MIMETYPE_JPEG);

                                        break;
                                    case BSE::BLIPTYPE_PNG:
                                        $drawing->setRenderingFunction(MemoryDrawing::RENDERING_PNG);
                                        $drawing->setMimeType(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) = Coordinate::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, 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'] = '';
                        }
                    }
                    $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 = [];
                        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 = trim($explodes[0], "'");
                            if (count($explodes) == 2) {
                                if (strpos($explodes[1], ':') === false) {
                                    $explodes[1] = $explodes[1] . ':' . $explodes[1];
                                }
                                $extractedRanges[] = str_replace('$', '', $explodes[1]); // C7:J66
                            }
                        }
                        if ($docSheet = $this->spreadsheet->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->spreadsheet->getSheetByName($explodes[0])) {
                                    $extractedRange = $explodes[1];
                                    $extractedRange = str_replace('$', '', $extractedRange);

                                    $coordinateStrings = explode(':', $extractedRange);
                                    if (count($coordinateStrings) == 2) {
                                        list($firstColumn, $firstRow) = Coordinate::coordinateFromString($coordinateStrings[0]);
                                        list($lastColumn, $lastRow) = Coordinate::coordinateFromString($coordinateStrings[1]);

                                        if ($firstColumn == 'A' and $lastColumn == 'IV') {
                                            // then we have repeating rows
                                            $docSheet->getPageSetup()->setRowsToRepeatAtTop([$firstRow, $lastRow]);
                                        } elseif ($firstRow == 1 and $lastRow == 65536) {
                                            // then we have repeating columns
                                            $docSheet->getPageSetup()->setColumnsToRepeatAtLeft([$firstColumn, $lastColumn]);
                                        }
                                    }
                                }
                            }
                        }

                        break;
                }
            } else {
                // Extract range
                $explodes = explode('!', $definedName['formula']);

                if (count($explodes) == 2) {
                    if (($docSheet = $this->spreadsheet->getSheetByName($explodes[0])) ||
                        ($docSheet = $this->spreadsheet->getSheetByName(trim($explodes[0], "'")))) {
                        $extractedRange = $explodes[1];
                        $extractedRange = str_replace('$', '', $extractedRange);

                        $localOnly = ($definedName['scope'] == 0) ? false : true;

                        $scope = ($definedName['scope'] == 0) ? null : $this->spreadsheet->getSheetByName($this->sheets[$definedName['scope'] - 1]['name']);

                        $this->spreadsheet->addNamedRange(new NamedRange((string) $definedName['name'], $docSheet, $extractedRange, $localOnly, $scope));
                    }
                }
                //    Named Value
                    //    TODO Provide support for named values
            }
        }
        $this->data = null;

        return $this->spreadsheet;
    }
public function load ( $ pFilename ) { // Read the OLE file $ this -> loadOLE ( $ pFilename ) ; // Initialisations $ this -> spreadsheet = new Spreadsheet ( ) ; $ this -> spreadsheet -> removeSheetByIndex ( 0 ) ; // remove 1st sheet if ( ! $ this -> readDataOnly ) { $ this -> spreadsheet -> removeCellStyleXfByIndex ( 0 ) ; // remove the default style $ this -> spreadsheet -> 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 = [ ] ; $ this -> objFonts = [ ] ; $ this -> palette = [ ] ; $ this -> sheets = [ ] ; $ this -> externalBooks = [ ] ; $ this -> ref = [ ] ; $ this -> definedname = [ ] ; $ this -> sst = [ ] ; $ this -> drawingGroupData = '' ; $ this -> xfIndex = '' ; $ this -> mapCellXfIndex = [ ] ; $ this -> mapCellStyleXfIndex = [ ] ; // Parse Workbook Global Substream while ( $ this -> pos < $ this -> dataSize ) { $ code = self :: getUInt2d ( $ 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 = Xls \ Color :: map ( $ objFont -> colorIndex , $ this -> palette , $ this -> version ) ; $ objFont -> getColor ( ) -> setRGB ( $ color [ 'rgb' ] ) ; } } foreach ( $ this -> spreadsheet -> getCellXfCollection ( ) as $ objStyle ) { // fill start and end color $ fill = $ objStyle -> getFill ( ) ; if ( isset ( $ fill -> startcolorIndex ) ) { $ startColor = Xls \ Color :: map ( $ fill -> startcolorIndex , $ this -> palette , $ this -> version ) ; $ fill -> getStartColor ( ) -> setRGB ( $ startColor [ 'rgb' ] ) ; } if ( isset ( $ fill -> endcolorIndex ) ) { $ endColor = Xls \ Color :: map ( $ 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 = Xls \ Color :: map ( $ top -> colorIndex , $ this -> palette , $ this -> version ) ; $ top -> getColor ( ) -> setRGB ( $ borderTopColor [ 'rgb' ] ) ; } if ( isset ( $ right -> colorIndex ) ) { $ borderRightColor = Xls \ Color :: map ( $ right -> colorIndex , $ this -> palette , $ this -> version ) ; $ right -> getColor ( ) -> setRGB ( $ borderRightColor [ 'rgb' ] ) ; } if ( isset ( $ bottom -> colorIndex ) ) { $ borderBottomColor = Xls \ Color :: map ( $ bottom -> colorIndex , $ this -> palette , $ this -> version ) ; $ bottom -> getColor ( ) -> setRGB ( $ borderBottomColor [ 'rgb' ] ) ; } if ( isset ( $ left -> colorIndex ) ) { $ borderLeftColor = Xls \ Color :: map ( $ left -> colorIndex , $ this -> palette , $ this -> version ) ; $ left -> getColor ( ) -> setRGB ( $ borderLeftColor [ 'rgb' ] ) ; } if ( isset ( $ diagonal -> colorIndex ) ) { $ borderDiagonalColor = Xls \ Color :: map ( $ diagonal -> colorIndex , $ this -> palette , $ this -> version ) ; $ diagonal -> getColor ( ) -> setRGB ( $ borderDiagonalColor [ 'rgb' ] ) ; } } } // treat MSODRAWINGGROUP records, workbook-level Escher if ( ! $ this -> readDataOnly && $ this -> drawingGroupData ) { $ escherWorkbook = new Escher ( ) ; $ reader = new Xls \ Escher ( $ escherWorkbook ) ; $ escherWorkbook = $ reader -> 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 PhpSpreadsheet object $ this -> phpSheet = $ this -> spreadsheet -> 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 , 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 = [ ] ; // Initialize shared formula parts $ this -> sharedFormulaParts = [ ] ; // Initialize shared formulas $ this -> sharedFormulas = [ ] ; // Initialize text objs $ this -> textObjects = [ ] ; // Initialize cell annotations $ this -> cellNotes = [ ] ; $ this -> textObjRef = - 1 ; while ( $ this -> pos <= $ this -> dataSize - 4 ) { $ code = self :: getUInt2d ( $ 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_PAGELAYOUTVIEW : $ this -> readPageLayoutView ( ) ; 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_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 Escher ( ) ; $ reader = new Xls \ Escher ( $ escherWorksheet ) ; $ escherWorksheet = $ reader -> 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 ) { // 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 ) = Coordinate :: coordinateFromString ( $ spContainer -> getStartCoordinates ( ) ) ; list ( $ endColumn , $ endRow ) = Coordinate :: coordinateFromString ( $ spContainer -> getEndCoordinates ( ) ) ; $ startOffsetX = $ spContainer -> getStartOffsetX ( ) ; $ startOffsetY = $ spContainer -> getStartOffsetY ( ) ; $ endOffsetX = $ spContainer -> getEndOffsetX ( ) ; $ endOffsetY = $ spContainer -> getEndOffsetY ( ) ; $ width = \ PhpOffice \ PhpSpreadsheet \ Shared \ Xls :: getDistanceX ( $ this -> phpSheet , $ startColumn , $ startOffsetX , $ endColumn , $ endOffsetX ) ; $ height = \ PhpOffice \ PhpSpreadsheet \ Shared \ Xls :: getDistanceY ( $ this -> phpSheet , $ startRow , $ startOffsetY , $ endRow , $ endOffsetY ) ; // calculate offsetX and offsetY of the shape $ offsetX = $ startOffsetX * \ PhpOffice \ PhpSpreadsheet \ Shared \ Xls :: sizeCol ( $ this -> phpSheet , $ startColumn ) / 1024 ; $ offsetY = $ startOffsetY * \ PhpOffice \ PhpSpreadsheet \ Shared \ Xls :: sizeRow ( $ this -> phpSheet , $ startRow ) / 256 ; switch ( $ obj [ 'otObjType' ] ) { case 0x19 : // Note 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 : // picture // get index to BSE entry (1-based) $ BSEindex = $ spContainer -> getOPT ( 0x0104 ) ; // If there is no BSE Index, we will fail here and other fields are not read. // Fix by checking here. // TODO: Why is there no BSE Index? Is this a new Office Version? Password protected field? // More likely : a uncompatible picture if ( ! $ BSEindex ) { continue ; } $ 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 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 BSE :: BLIPTYPE_JPEG : $ drawing -> setRenderingFunction ( MemoryDrawing :: RENDERING_JPEG ) ; $ drawing -> setMimeType ( MemoryDrawing :: MIMETYPE_JPEG ) ; break ; case BSE :: BLIPTYPE_PNG : $ drawing -> setRenderingFunction ( MemoryDrawing :: RENDERING_PNG ) ; $ drawing -> setMimeType ( 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 ) = Coordinate :: 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 , 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' ] = '' ; } } $ 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 = [ ] ; 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 = trim ( $ explodes [ 0 ] , "'" ) ; if ( count ( $ explodes ) == 2 ) { if ( strpos ( $ explodes [ 1 ] , ':' ) === false ) { $ explodes [ 1 ] = $ explodes [ 1 ] . ':' . $ explodes [ 1 ] ; } $ extractedRanges [ ] = str_replace ( '$' , '' , $ explodes [ 1 ] ) ; // C7:J66 } } if ( $ docSheet = $ this -> spreadsheet -> 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 -> spreadsheet -> getSheetByName ( $ explodes [ 0 ] ) ) { $ extractedRange = $ explodes [ 1 ] ; $ extractedRange = str_replace ( '$' , '' , $ extractedRange ) ; $ coordinateStrings = explode ( ':' , $ extractedRange ) ; if ( count ( $ coordinateStrings ) == 2 ) { list ( $ firstColumn , $ firstRow ) = Coordinate :: coordinateFromString ( $ coordinateStrings [ 0 ] ) ; list ( $ lastColumn , $ lastRow ) = Coordinate :: coordinateFromString ( $ coordinateStrings [ 1 ] ) ; if ( $ firstColumn == 'A' and $ lastColumn == 'IV' ) { // then we have repeating rows $ docSheet -> getPageSetup ( ) -> setRowsToRepeatAtTop ( [ $ firstRow , $ lastRow ] ) ; } elseif ( $ firstRow == 1 and $ lastRow == 65536 ) { // then we have repeating columns $ docSheet -> getPageSetup ( ) -> setColumnsToRepeatAtLeft ( [ $ firstColumn , $ lastColumn ] ) ; } } } } } break ; } } else { // Extract range $ explodes = explode ( '!' , $ definedName [ 'formula' ] ) ; if ( count ( $ explodes ) == 2 ) { if ( ( $ docSheet = $ this -> spreadsheet -> getSheetByName ( $ explodes [ 0 ] ) ) || ( $ docSheet = $ this -> spreadsheet -> getSheetByName ( trim ( $ explodes [ 0 ] , "'" ) ) ) ) { $ extractedRange = $ explodes [ 1 ] ; $ extractedRange = str_replace ( '$' , '' , $ extractedRange ) ; $ localOnly = ( $ definedName [ 'scope' ] == 0 ) ? false : true ; $ scope = ( $ definedName [ 'scope' ] == 0 ) ? null : $ this -> spreadsheet -> getSheetByName ( $ this -> sheets [ $ definedName [ 'scope' ] - 1 ] [ 'name' ] ) ; $ this -> spreadsheet -> addNamedRange ( new NamedRange ( ( string ) $ definedName [ 'name' ] , $ docSheet , $ extractedRange , $ localOnly , $ scope ) ) ; } } //    Named Value //    TODO Provide support for named values } } $ this -> data = null ; return $ this -> spreadsheet ; }
Loads PhpSpreadsheet from file.

@param string $pFilename

@throws Exception

@return Spreadsheet
Loads PhpSpreadsheet from file .