Read SHEETPR record
6062
private function _readSheetPr()
	{
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = substr($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		// offset: 0; size: 2

		// bit: 6; mask: 0x0040; 0 = outline buttons above outline group
		$isSummaryBelow = (0x0040 & self::_GetInt2d($recordData, 0)) >> 6;
		$this->_phpSheet->setShowSummaryBelow($isSummaryBelow);

		// bit: 7; mask: 0x0080; 0 = outline buttons left of outline group
		$isSummaryRight = (0x0080 & self::_GetInt2d($recordData, 0)) >> 7;
		$this->_phpSheet->setShowSummaryRight($isSummaryRight);

		// bit: 8; mask: 0x100; 0 = scale printout in percent, 1 = fit printout to number of pages
		// this corresponds to radio button setting in page setup dialog in Excel
		$this->_isFitToPages = (bool) ((0x0100 & self::_GetInt2d($recordData, 0)) >> 8);
	}
831413
private function readSpgrContainer()
    {
        // context is either context DgContainer or SpgrContainer

        $length = PHPExcel_Reader_Excel5::getInt4d($this->data, $this->pos + 4);
        $recordData = substr($this->data, $this->pos + 8, $length);

        // move stream pointer to next record
        $this->pos += 8 + $length;

        // record is a container, read contents
        $spgrContainer = new PHPExcel_Shared_Escher_DgContainer_SpgrContainer();

        if ($this->object instanceof PHPExcel_Shared_Escher_DgContainer) {
            // DgContainer
            $this->object->setSpgrContainer($spgrContainer);
        } else {
            // SpgrContainer
            $this->object->addChild($spgrContainer);
        }

        $reader = new PHPExcel_Reader_Excel5_Escher($spgrContainer);
        $escher = $reader->load($recordData);
    }
1004436
private function readRow()
    {
        $length = self::getInt2d($this->data, $this->pos + 2);
        $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);

        // move stream pointer to next record
        $this->pos += 4 + $length;

        if (!$this->readDataOnly) {
            // offset: 0; size: 2; index of this row
            $r = self::getInt2d($recordData, 0);

            // offset: 2; size: 2; index to column of the first cell which is described by a cell record

            // offset: 4; size: 2; index to column of the last cell which is described by a cell record, increased by 1

            // offset: 6; size: 2;

            // bit: 14-0; mask: 0x7FFF; height of the row, in twips = 1/20 of a point
            $height = (0x7FFF & self::getInt2d($recordData, 6)) >> 0;

            // bit: 15: mask: 0x8000; 0 = row has custom height; 1= row has default height
            $useDefaultHeight = (0x8000 & self::getInt2d($recordData, 6)) >> 15;

            if (!$useDefaultHeight) {
                $this->phpSheet->getRowDimension($r + 1)->setRowHeight($height / 20);
            }

            // offset: 8; size: 2; not used

            // offset: 10; size: 2; not used in BIFF5-BIFF8

            // offset: 12; size: 4; option flags and default row formatting

            // bit: 2-0: mask: 0x00000007; outline level of the row
            $level = (0x00000007 & self::getInt4d($recordData, 12)) >> 0;
            $this->phpSheet->getRowDimension($r + 1)->setOutlineLevel($level);

            // bit: 4; mask: 0x00000010; 1 = outline group start or ends here... and is collapsed
            $isCollapsed = (0x00000010 & self::getInt4d($recordData, 12)) >> 4;
            $this->phpSheet->getRowDimension($r + 1)->setCollapsed($isCollapsed);

            // bit: 5; mask: 0x00000020; 1 = row is hidden
            $isHidden = (0x00000020 & self::getInt4d($recordData, 12)) >> 5;
            $this->phpSheet->getRowDimension($r + 1)->setVisible(!$isHidden);

            // bit: 7; mask: 0x00000080; 1 = row has explicit format
            $hasExplicitFormat = (0x00000080 & self::getInt4d($recordData, 12)) >> 7;

            // bit: 27-16; mask: 0x0FFF0000; only applies when hasExplicitFormat = 1; index to XF record
            $xfIndex = (0x0FFF0000 & self::getInt4d($recordData, 12)) >> 16;

            if ($hasExplicitFormat) {
                $this->phpSheet->getRowDimension($r + 1)->setXfIndex($this->mapCellXfIndex[$xfIndex]);
            }
        }
    }
240140
private function readNote()
    {
//        echo '<b>Read Cell Annotation</b><br />';
        $length = self::getInt2d($this->data, $this->pos + 2);
        $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);

        // move stream pointer to next record
        $this->pos += 4 + $length;

        if ($this->readDataOnly) {
            return;
        }

        $cellAddress = $this->readBIFF8CellAddress(substr($recordData, 0, 4));
        if ($this->version == self::XLS_BIFF8) {
            $noteObjID = self::getInt2d($recordData, 6);
            $noteAuthor = self::readUnicodeStringLong(substr($recordData, 8));
            $noteAuthor = $noteAuthor['value'];
//            echo 'Note Address=', $cellAddress,'<br />';
//            echo 'Note Object ID=', $noteObjID,'<br />';
//            echo 'Note Author=', $noteAuthor,'<hr />';
//
            $this->cellNotes[$noteObjID] = array(
                'cellRef'   => $cellAddress,
                'objectID'  => $noteObjID,
                'author'    => $noteAuthor
            );
        } else {
            $extension = false;
            if ($cellAddress == '$B$65536') {
                //    If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
                //        note from the previous cell annotation. We're not yet handling this, so annotations longer than the
                //        max 2048 bytes will probably throw a wobbly.
                $row = self::getInt2d($recordData, 0);
                $extension = true;
                $cellAddress = array_pop(array_keys($this->phpSheet->getComments()));
            }
//            echo 'Note Address=', $cellAddress,'<br />';

            $cellAddress = str_replace('$', '', $cellAddress);
            $noteLength = self::getInt2d($recordData, 4);
            $noteText = trim(substr($recordData, 6));
//            echo 'Note Length=', $noteLength,'<br />';
//            echo 'Note Text=', $noteText,'<br />';

            if ($extension) {
                //    Concatenate this extension with the currently set comment for the cell
                $comment = $this->phpSheet->getComment($cellAddress);
                $commentText = $comment->getText()->getPlainText();
                $comment->setText($this->parseRichText($commentText.$noteText));
            } else {
                //    Set comment for the cell
                $this->phpSheet->getComment($cellAddress)->setText($this->parseRichText($noteText));
//                                                    ->setAuthor($author)
            }
        }

    }
1157276
public static void checkColumns(final Sheet sheet, final Class<?> recordClass,
            final List<RecordHeader> headers, final AnnotationReader reader, final Configuration config)
                    throws CellNotFoundException {
        
        List<FieldAccessor> properties = FieldAccessorUtils.getPropertiesWithAnnotation(recordClass, reader, XlsColumn.class);
        
        for(FieldAccessor property : properties) {
            final XlsColumn column = property.getAnnotation(XlsColumn.class).get();
            
            if(column.optional()){
                continue;
            }
            
            String columnName = column.columnName();
            boolean find = false;
            for(RecordHeader info: headers){
                if(Utils.matches(info.getLabel(), columnName, config)){
                    find = true;
                    break;
                }
            }
            if(!find){
                throw new CellNotFoundException(sheet.getSheetName(), columnName);
            }
        }
        
    }
301041
private function _readHeader()
	{
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		if (!$this->_readDataOnly) {
			// offset: 0; size: var
			// realized that $recordData can be empty even when record exists
			if ($recordData) {
				if ($this->_version == self::XLS_BIFF8) {
					$string = self::_readUnicodeStringLong($recordData);
				} else {
					$string = $this->_readByteStringShort($recordData);
				}

				$this->_phpSheet->getHeaderFooter()->setOddHeader($string['value']);
				$this->_phpSheet->getHeaderFooter()->setEvenHeader($string['value']);
			}
		}
	}
959568
public void readRecordClass(String strRecordClass)
    {
        String strBaseClass;
        Record recClassInfo = this.getMainRecord();
        if (!this.readThisClass(strRecordClass))
            strBaseClass = "Record";
        else
        {
            strBaseClass = recClassInfo.getField(ClassInfo.BASE_CLASS_NAME).getString();
            if (strBaseClass.equalsIgnoreCase("Record"))
                strBaseClass = "Record";
            if (strBaseClass.length() == 0)
                strBaseClass = "Record";
        }
        recClassInfo.getField(ClassInfo.BASE_CLASS_NAME).setString(strBaseClass);
    }
486650
private function _readRangeProtection()
	{
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = $this->_readRecordData($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		// local pointer in record data
		$offset = 0;

		if (!$this->_readDataOnly) {
			$offset += 12;

			// offset: 12; size: 2; shared feature type, 2 = enhanced protection, 4 = smart tag
			$isf = self::_GetInt2d($recordData, 12);
			if ($isf != 2) {
				// we only read FEAT records of type 2
				return;
			}
			$offset += 2;

			$offset += 5;

			// offset: 19; size: 2; count of ref ranges this feature is on
			$cref = self::_GetInt2d($recordData, 19);
			$offset += 2;

			$offset += 6;

			// offset: 27; size: 8 * $cref; list of cell ranges (like in hyperlink record)
			$cellRanges = array();
			for ($i = 0; $i < $cref; ++$i) {
				try {
					$cellRange = $this->_readBIFF8CellRangeAddressFixed(substr($recordData, 27 + 8 * $i, 8));
				} catch (PHPExcel_Exception $e) {
					return;
				}
				$cellRanges[] = $cellRange;
				$offset += 8;
			}

			// offset: var; size: var; variable length of feature specific data
			$rgbFeat = substr($recordData, $offset);
			$offset += 4;

			// offset: var; size: 4; the encrypted password (only 16-bit although field is 32-bit)
			$wPassword = self::_GetInt4d($recordData, $offset);
			$offset += 4;

			// Apply range protection to sheet
			if ($cellRanges) {
				$this->_phpSheet->protectCells(implode(' ', $cellRanges), strtoupper(dechex($wPassword)), true);
			}
		}
	}
1261930
def parse(self, rrstr):
        # type: (bytes) -> None
        '''
        
        '''
        if self._initialized:
            raise pycdlibexception.PyCdlibInternalError('PD record already initialized!')

        (su_len_unused, su_entry_version_unused) = struct.unpack_from('=BB', rrstr[:4], 2)

        self.padding = rrstr[4:]

        # We assume that the caller has already checked the su_entry_version,
        # so we don't bother.

        self._initialized = True
1104454
def detect_worksheets(archive):
    """"""
    # content types has a list of paths but no titles
    # workbook has a list of titles and relIds but no paths
    # workbook_rels has a list of relIds and paths but no titles
    # rels = {'id':{'title':'', 'path':''} }
    content_types = read_content_types(archive)
    valid_sheets = dict((path, ct) for ct, path in content_types if ct == WORKSHEET_TYPE)
    rels = dict(read_rels(archive))
    for sheet in read_sheets(archive):
        rel = rels[sheet['id']]
        rel['title'] = sheet['name']
        rel['sheet_id'] = sheet['sheetId']
        rel['state'] = sheet.get('state', 'visible')
        if ("/" + rel['path'] in valid_sheets
            or "worksheets" in rel['path']): # fallback in case content type is missing
            yield rel
1228318
private function _readExternSheet()
	{
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = substr($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		// external sheet references provided for named cells
		if ($this->_version == self::XLS_BIFF8) {
			// offset: 0; size: 2; number of following ref structures
			$nm = self::_GetInt2d($recordData, 0);
			for ($i = 0; $i < $nm; ++$i) {
				$this->_ref[] = array(
					// offset: 2 + 6 * $i; index to EXTERNALBOOK record
					'externalBookIndex' => self::_GetInt2d($recordData, 2 + 6 * $i),
					// offset: 4 + 6 * $i; index to first sheet in EXTERNALBOOK record
					'firstSheetIndex' => self::_GetInt2d($recordData, 4 + 6 * $i),
					// offset: 6 + 6 * $i; index to last sheet in EXTERNALBOOK record
					'lastSheetIndex' => self::_GetInt2d($recordData, 6 + 6 * $i),
				);
			}
		}
	}
1091815
private function readSheetLayout()
    {
        $length = self::getInt2d($this->data, $this->pos + 2);
        $recordData = $this->readRecordData($this->data, $this->pos + 4, $length);

        // move stream pointer to next record
        $this->pos += 4 + $length;

        // local pointer in record data
        $offset = 0;

        if (!$this->readDataOnly) {
            // offset: 0; size: 2; repeated record identifier 0x0862

            // offset: 2; size: 10; not used

            // offset: 12; size: 4; size of record data
            // Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
            $sz = self::getInt4d($recordData, 12);

            switch ($sz) {
                case 0x14:
                    // offset: 16; size: 2; color index for sheet tab
                    $colorIndex = self::getInt2d($recordData, 16);
                    $color = self::readColor($colorIndex, $this->palette, $this->version);
                    $this->phpSheet->getTabColor()->setRGB($color['rgb']);
                    break;
                case 0x28:
                    // TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
                    return;
                    break;
            }
        }
    }
918379
public void processRecord(Record record) {
		
		//超过10行空白就不处理了
		if(blankRowNum == 10)return;
		
		int thisRow = -1;
		int thisColumn = -1;
		String thisStr = null;

		switch (record.getSid())
		{
		case BoundSheetRecord.sid:
			boundSheetRecords.add((BoundSheetRecord)record);
			break;
		case BOFRecord.sid:
			BOFRecord br = (BOFRecord)record;
			if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
				// Create sub workbook if required
				if(workbookBuildingListener != null && stubWorkbook == null) {
					stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
				}
				
				// Output the worksheet name
				// Works by ordering the BSRs by the location of
				//  their BOFRecords, and then knowing that we
				//  process BOFRecords in byte offset order
				sheetIndex++;
				if(orderedBSRs == null) {
					orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
				}
				//sheetName
				//System.out.println(orderedBSRs[sheetIndex].getSheetname() + " [" + (sheetIndex+1) + "]:" );
				String sheetname = orderedBSRs[sheetIndex].getSheetname();
				results.add(ExcelValidator.SHEET_NAME_PREFIX + sheetname);
			}
			break;

		case SSTRecord.sid:
			sstRecord = (SSTRecord) record;
			break;

		case BlankRecord.sid:
			BlankRecord brec = (BlankRecord) record;

			thisRow = brec.getRow();
			thisColumn = brec.getColumn();
			thisStr = "";
			break;
		case BoolErrRecord.sid:
			BoolErrRecord berec = (BoolErrRecord) record;

			thisRow = berec.getRow();
			thisColumn = berec.getColumn();
			thisStr = "";
			break;

		case FormulaRecord.sid:
			FormulaRecord frec = (FormulaRecord) record;

			thisRow = frec.getRow();
			thisColumn = frec.getColumn();

			if(outputFormulaValues) {
				if(Double.isNaN( frec.getValue() )) {
					// Formula result is a string
					// This is stored in the next record
					outputNextStringRecord = true;
					nextRow = frec.getRow();
					nextColumn = frec.getColumn();
				} else {
					thisStr = formatListener.formatNumberDateCell(frec);
				}
			} else {
				thisStr = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
			}
			break;
		case StringRecord.sid:
			if(outputNextStringRecord) {
				// String for formula
				StringRecord srec = (StringRecord)record;
				thisStr = srec.getString();
				thisRow = nextRow;
				thisColumn = nextColumn;
				outputNextStringRecord = false;
			}
			break;

		case LabelRecord.sid:
			LabelRecord lrec = (LabelRecord) record;

			thisRow = lrec.getRow();
			thisColumn = lrec.getColumn();
			thisStr = lrec.getValue();
			break;
		case LabelSSTRecord.sid:
			LabelSSTRecord lsrec = (LabelSSTRecord) record;

			thisRow = lsrec.getRow();
			thisColumn = lsrec.getColumn();
			if(sstRecord == null) {
				thisStr = "(No SST Record, can't identify string)";
			} else {
				thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString();
			}
			break;
		case NoteRecord.sid:
			NoteRecord nrec = (NoteRecord) record;

			thisRow = nrec.getRow();
			thisColumn = nrec.getColumn();
			// TODO: Find object to match nrec.getShapeId()
			thisStr = "(TODO)";
			break;
		case NumberRecord.sid:
			NumberRecord numrec = (NumberRecord) record;

			thisRow = numrec.getRow();
			thisColumn = numrec.getColumn();

			// Format
			thisStr = formatListener.formatNumberDateCell(numrec);
			break;
		case RKRecord.sid:
			RKRecord rkrec = (RKRecord) record;

			thisRow = rkrec.getRow();
			thisColumn = rkrec.getColumn();
			thisStr = "(TODO)";
			break;
		default:
			break;
		}

		// Handle new row
		if(thisRow != -1 && thisRow != lastRowNumber) {
			lastColumnNumber = -1;
		}

		// Handle missing column
		if(record instanceof MissingCellDummyRecord) {
			MissingCellDummyRecord mc = (MissingCellDummyRecord)record;
			thisRow = mc.getRow();
			thisColumn = mc.getColumn();
			thisStr = "";
		}


		if(thisStr != null) {
			if(thisColumn > 0) {
				_resultRowTmp.append(ExcelValidator.FIELD_SPLIT);
			}
			_resultRowTmp.append(thisStr);
		}

		// Update column and row count
		if(thisRow > -1)
			lastRowNumber = thisRow;
		if(thisColumn > -1)
			lastColumnNumber = thisColumn;

		// Handle end of row
		if(record instanceof LastCellOfRowDummyRecord) {
			// Print out any missing commas if needed
			if(minColumns > 0) {
				// Columns are 0 based
				if(lastColumnNumber == -1) { lastColumnNumber = 0; }
				for(int i=lastColumnNumber; i<(minColumns); i++) {
					_resultRowTmp.append(',');
				}
			}

			// We're onto a new row
			lastColumnNumber = -1;

			// End the row
			if(!ExcelValidator.isBlankCSVRow(_resultRowTmp.toString())){				
				results.add(_resultRowTmp.toString());
			}else{
				blankRowNum = blankRowNum + 1;
			}
			_resultRowTmp.setLength(0);
		}
	}
1069907
def read(self):
        
        for sheet in self.get_sheet():
            for row in self.template.read_data(sheet, begin=self.begin):
                yield row
1290081
private function _readSheetLayout()
	{
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = substr($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		// local pointer in record data
		$offset = 0;

		if (!$this->_readDataOnly) {
			// offset: 0; size: 2; repeated record identifier 0x0862

			// offset: 2; size: 10; not used

			// offset: 12; size: 4; size of record data
			// Excel 2003 uses size of 0x14 (documented), Excel 2007 uses size of 0x28 (not documented?)
			$sz = self::_GetInt4d($recordData, 12);

			switch ($sz) {
				case 0x14:
					// offset: 16; size: 2; color index for sheet tab
					$colorIndex = self::_GetInt2d($recordData, 16);
					$color = self::_readColor($colorIndex,$this->_palette,$this->_version);
					$this->_phpSheet->getTabColor()->setRGB($color['rgb']);
					break;

				case 0x28:
					// TODO: Investigate structure for .xls SHEETLAYOUT record as saved by MS Office Excel 2007
					return;
					break;
			}
		}
	}
1259077
private function _readNote()
	{
//		echo '<b>Read Cell Annotation</b><br />';
		$length = self::_GetInt2d($this->_data, $this->_pos + 2);
		$recordData = substr($this->_data, $this->_pos + 4, $length);

		// move stream pointer to next record
		$this->_pos += 4 + $length;

		if ($this->_readDataOnly) {
			return;
		}

		$cellAddress = $this->_readBIFF8CellAddress(substr($recordData, 0, 4));
		if ($this->_version == self::XLS_BIFF8) {
			$noteObjID = self::_GetInt2d($recordData, 6);
			$noteAuthor = self::_readUnicodeStringLong(substr($recordData, 8));
			$noteAuthor = $noteAuthor['value'];
//			echo 'Note Address=',$cellAddress,'<br />';
//			echo 'Note Object ID=',$noteObjID,'<br />';
//			echo 'Note Author=',$noteAuthor,'<hr />';
//
			$this->_cellNotes[$noteObjID] = array('cellRef'		=> $cellAddress,
												  'objectID'	=> $noteObjID,
												  'author'		=> $noteAuthor
												 );
		} else {
			$extension = false;
			if ($cellAddress == '$B$65536') {
				//	If the address row is -1 and the column is 0, (which translates as $B$65536) then this is a continuation
				//		note from the previous cell annotation. We're not yet handling this, so annotations longer than the
				//		max 2048 bytes will probably throw a wobbly.
				$row = self::_GetInt2d($recordData, 0);
				$extension = true;
				$cellAddress = array_pop(array_keys($this->_phpSheet->getComments()));
			}
//			echo 'Note Address=',$cellAddress,'<br />';

			$cellAddress = str_replace('$','',$cellAddress);
			$noteLength = self::_GetInt2d($recordData, 4);
			$noteText = trim(substr($recordData, 6));
//			echo 'Note Length=',$noteLength,'<br />';
//			echo 'Note Text=',$noteText,'<br />';

			if ($extension) {
				//	Concatenate this extension with the currently set comment for the cell
				$comment = $this->_phpSheet->getComment( $cellAddress );
				$commentText = $comment->getText()->getPlainText();
				$comment->setText($this->_parseRichText($commentText.$noteText) );
			} else {
				//	Set comment for the cell
				$this->_phpSheet->getComment( $cellAddress )
//													->setAuthor( $author )
													->setText($this->_parseRichText($noteText) );
			}
		}

	}
1062641
@Override
    public void processRecord(Record record) {
        int thisRow = -1;
        int thisColumn = -1;
        String thisStr = null;

        switch (record.getSid()) {
            case BOFRecord.sid:
                BOFRecord br = (BOFRecord) record;
                if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
                    // Create sub workbook if required
                    if (workbookBuildingListener != null && stubWorkbook == null) {
                        stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();
                    }

                    //到这里证明已经是新的一个Sheet了,每开始一个新的Sheet则初始化一些数据
                    this.allSheetInExcel++;
                    this.currentSheetInExcel++;
                    this.currentRowInSheet = -1;
                    this.realRowInSheet = 0;
                }
                break;

            case SSTRecord.sid:
                sstRecord = (SSTRecord) record;
                break;

            case BlankRecord.sid:
                //空单元格
                BlankRecord brec = (BlankRecord) record;
                thisRow = brec.getRow();
                thisColumn = brec.getColumn();
                thisStr = null;
                break;
            case BoolErrRecord.sid:
                BoolErrRecord berec = (BoolErrRecord) record;

                thisRow = berec.getRow();
                thisColumn = berec.getColumn();
                thisStr = berec.isBoolean() ? String.valueOf(berec.getBooleanValue()) : "";
                break;

            case FormulaRecord.sid:
                FormulaRecord frec = (FormulaRecord) record;

                thisRow = frec.getRow();
                thisColumn = frec.getColumn();

                if (outputFormulaValues) {
                    if (Double.isNaN(frec.getValue())) {
                        // Formula result is a string
                        // This is stored in the next record
                        outputNextStringRecord = true;
                        nextRow = frec.getRow();
                        nextColumn = frec.getColumn();
                    } else {
                        thisStr = formatListener.formatNumberDateCell(frec);
                    }
                } else {
                    thisStr =
                            HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression());
                }
                break;
            case StringRecord.sid:
                if (outputNextStringRecord) {
                    // String for formula
                    StringRecord srec = (StringRecord) record;
                    thisStr = srec.getString();
                    thisRow = nextRow;
                    thisColumn = nextColumn;
                    outputNextStringRecord = false;
                }
                break;

            case LabelRecord.sid:
                LabelRecord lrec = (LabelRecord) record;

                thisRow = lrec.getRow();
                thisColumn = lrec.getColumn();
                thisStr = lrec.getValue();
                break;
            case LabelSSTRecord.sid:
                LabelSSTRecord lsrec = (LabelSSTRecord) record;

                thisRow = lsrec.getRow();
                thisColumn = lsrec.getColumn();
                if (sstRecord == null) {
                    thisStr = null;
                } else {
                    thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString();
                }
                break;
            case NoteRecord.sid:
                NoteRecord nrec = (NoteRecord) record;

                thisRow = nrec.getRow();
                thisColumn = nrec.getColumn();
                thisStr = null;
                break;
            case NumberRecord.sid:
                NumberRecord numrec = (NumberRecord) record;

                thisRow = numrec.getRow();
                thisColumn = numrec.getColumn();

                // Format
                thisStr = formatListener.formatNumberDateCell(numrec);
                break;
            case RKRecord.sid:
                RKRecord rkrec = (RKRecord) record;

                thisRow = rkrec.getRow();
                thisColumn = rkrec.getColumn();
                thisStr = null;
                break;
            default:
                break;
        }
        // Handle missing column
        if (record instanceof MissingCellDummyRecord) {
            MissingCellDummyRecord mc = (MissingCellDummyRecord) record;
            thisRow = mc.getRow();
            thisColumn = mc.getColumn();
            thisStr = null;
        }
        // Handle new row
        if (thisRow != -1 && thisRow != lastRowNumber) {
            lastColumnNumber = -1;
            this.isNewRow = true;
            this.currentRowInSheet = thisRow;
            this.currentColInRow = -1;
            if (this.currentRowInSheet > 1) {
                //证明此行是数据行
                this.data = new HashMap<String, Object>();
            }
        }

        /******************************************************************************/
        /******************************************************************************/
        if (this.isNewRow) {
            this.isNewRow = false;
        }
        if (thisColumn > -1) {
            this.currentColInRow = thisColumn;
        }
        if (thisStr != null && !thisStr.isEmpty()) {
            if (this.currentRowInSheet == 0) {
                //标题行
                if (this.currentSheetInExcel == 0) {
                    //第0个Sheet则添加标题，0-based
                    this.titles.add(thisStr);
                }
            } else if (this.currentRowInSheet == 1) {
                //列名行
                if (this.currentSheetInExcel == 0) {
                    //第0个Sheet则添加列名，0-based
                    this.columns.add(thisStr);
                }

            } else {
                //数据行
                String key = this.columns.get(this.currentColInRow);
                Object value = this.getValue(thisStr);
                this.data.put(key, value);
            }
        }
        /******************************************************************************/
        // Update column and row count
        if (thisRow > -1) {
            lastRowNumber = thisRow;
        }
        if (thisColumn > -1) {
            lastColumnNumber = thisColumn;
        }

        // Handle end of row
        if (record instanceof LastCellOfRowDummyRecord) {
            // We're onto a new row
            lastColumnNumber = -1;
            /******************************************************************************/
            /******************************************************************************/
            if (this.currentRowInSheet > 1 && !this.data.isEmpty()) {
                //证明此行是数据行,且不为空行
                this.datas.add(this.data);
                this.realRowInSheet++;
                this.realRowInExcel++;
            }
            //判断用户是否开启限制
            if (this.limit > 0) {
                //开启限制
                if (this.datas.size() >= this.limit) {
                    if (this.callback != null) {
                        //若设置了回调函数则调用
                        try {
                            this.callback
                                    .callback(this.currentRowInSheet, this.currentSheetInExcel, this.realRowInSheet,
                                            this.realRowInExcel, this.allSheetInExcel, this.titles, this.columns,
                                            this.datas);
                        } catch (Exception e) {
                            throw new ReadExcelRuntimeException("SAX parser appears to be broken - " + e.getMessage());
                        }
                    }
                    //超过限制则清空
                    this.datas.clear();
                }
            }
            /******************************************************************************/
        }
    }