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;
    }
Loads PhpSpreadsheet from file.

@param string $pFilename

@throws Exception

@return Spreadsheet