from filetypes.base import *
import malcat
import struct


class BiffRecord(Struct):

    def parse(self):
        yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        if sz:
            yield Bytes(sz, name="Data")

class XLString(Struct):

    def parse(self):
        sz = yield UInt32(name="Size", comment="string size in characters")
        yield StringUtf16le(sz, name="Value", zero_terminated=False)


class DimensionRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        
        yield UInt32(name="Row")
        yield UInt32(name="Column")
        yield UInt32(name="Width")
        yield UInt32(name="Height")

        if len(self) < todo:
            yield Unused(todo - len(self), name="Overlay")


class RowRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        
        yield UInt32(name="Row")

        if len(self) < todo:
            yield Bytes(todo - len(self), name="Rest")            


class BeginSstRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        
        yield UInt32(name="Total")
        yield UInt32(name="Unique")



class SstItemRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz

        yield BitsField(
            Bit(name="RichStr", comment="string has rich information"),
            Bit(name="ExtStr", comment="string has external information"),
            NullBits(6),
            name="Flags", comment="string infos")
        yield XLString(name="String", comment="string content")
        if len(self) < todo:
            yield Bytes(todo - len(self), name="ExtraData")                  


class BundledSheetRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        yield BitsField(
            Bit(name="Hidden", comment="sheet is hidden"),
            Bit(name="VeryHidden", comment="sheet is hidden and cannot be displayed using the user interface"),
            NullBits(30),
            name="State", comment="sheet state")
        yield UInt32(name="TabId", comment="unique sheet identifier")
        yield XLString(name="RelationShip", comment="relationship that specifies the part containing sheet data")
        yield XLString(name="Name", comment="unique case-insensitive name of the sheet")
        if len(self) < todo:
            yield Bytes(todo - len(self), name="Rest")            

class ExternalSheetInfo(Struct):

    def parse(self):
        yield Int32(name="Supporting")
        yield Int32(name="FirstSheetId")
        yield Int32(name="LastSheetId")

class ExternalSheetRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        count = yield UInt32(name="Count", comment="number of external sheet info")
        yield Array(count, ExternalSheetInfo(), name="Externals")

        if len(self) < todo:
            yield Bytes(todo - len(self), name="Rest")            

class FormulaRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        yield UInt32(name="Column")
        yield UInt32(name="Style")
        
        content_ = {
            8: XLString,
            9: UInt64,
            10: UInt8,
            11: UInt8,
        }[op]
        value = yield content_(name="Content")
        
        yield BitsField(
            Bit(name="RecalcAlways"),
            Bit(name="RecalcOnOpen"),
            NullBits(1),
            Bit(name="PartOfShared"),
            NullBits(12),
            name="Flags")
        if len(self) < todo:
            yield Formula(name="Formula")
        if len(self) < todo:
            yield Bytes(todo - len(self), name="Rest")            


class Formula(Struct):
    def parse(self):
        cce = yield UInt32(name="FormulaLen")
        yield Bytes(cce, name="FormulaData")
        cb = yield UInt32(name="FormulaExtraLen")
        if cb:
            yield Bytes(cb, name="FormulaExtra")

class LabelRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        yield BitsField(
            Bit(name="Hidden", comment="defined name is not visible in the list of defined names"),
            Bit(name="Func", comment="defined name represents an XLM macro"),
            Bit(name="OB", comment="defined name represents a VBA macro"),
            Bit(name="Proc", comment="defined name represents a macro"),
            Bit(name="CalcExp", comment="specifies whether formula.rgce contains a call to a function that can return an array"),
            Bit(name="Builtin", comment="defined name represents a built-in name"),
            NullBits(26),
            name="Flags")
        yield UInt8(name="Key", comment="unsigned integer value of the ASCII character that specifies the shortcut key for the macro represented by the defined name")
        yield UInt32(name="ITab", comment="specifies the scope of the defined name")
        yield XLString(name="Name")
        if len(self) < todo:
            yield Formula(name="Formula")
        if len(self) < todo:
            yield Bytes(todo - len(self), name="Overlay")            


class CellRecord(Struct):

    def parse(self):
        op = yield VarUInt64(name="Opcode", values=EXCEL_OPCODE_ENUM)
        sz = yield VarUInt64(name="Size", comment="Opcode content size")
        todo = len(self) + sz
        yield UInt32(name="Column")
        yield UInt32(name="Style")
        
        content_ = {
            1: None,
            2: UInt32,
            3: UInt8,
            4: UInt8,
            5: UInt64,
            6: XLString,
            7: UInt32,
        }[op]
        if content_:
            value = yield content_(name="Content")
        
        if len(self) < todo:
            yield Bytes(todo - len(self), name="Overlay")

    @staticmethod
    def read_rk(number):
        mul_by_100 = number & 1
        signed = number & 2
        number = number >>2
        if signed:
            # signed 30 bits integer
            if number & 30:
                number = - (~number + 1)
        else:
            number = number << 2 + 32
            number, = struct.unpack("<d", struct.pack("<Q", number))
        if mul_by_100:
            number = number * 100
        return number

EXCEL_OPCODES = {}
EXCEL_OPCODE_ENUM = []
PTG_DICT = {}
FUNCTION_NAMES = {}

def delayed_globals():
    # for faster startup times
    global EXCEL_OPCODES
    global EXCEL_OPCODE_ENUM
    global PTG_DICT
    global FUNCTION_NAMES

    # from https://github.com/DissectMalware/pyxlsb2/blob/master/pyxlsb2/recordtypes.py
    EXCEL_OPCODES = {
        0: ("ROW_HDR", "", RowRecord), 
        1: ("CELL_BLANK", "", CellRecord), 
        2: ("CELL_RK", "", CellRecord), 
        3: ("CELL_ERROR", "", CellRecord), 
        4: ("CELL_BOOL", "", CellRecord), 
        5: ("CELL_REAL", "", CellRecord), 
        6: ("CELL_ST", "", CellRecord), 
        7: ("CELL_ISST", "", CellRecord), 
        8: ("FMLA_STRING", "", FormulaRecord), 
        9: ("FMLA_NUM", "", FormulaRecord), 
        10: ("FMLA_BOOL", "", FormulaRecord), 
        11: ("FMLA_ERROR", "", FormulaRecord), 
        19: ("SST_ITEM", "", SstItemRecord), 
        20: ("PCDI_MISSING", "", BiffRecord), 
        21: ("PCDI_NUMBER", "", BiffRecord), 
        22: ("PCDI_BOOLEAN", "", BiffRecord), 
        23: ("PCDI_ERROR", "", BiffRecord), 
        24: ("PCDI_STRING", "", BiffRecord), 
        25: ("PCDI_DATETIME", "", BiffRecord), 
        26: ("PCDI_INDEX", "", BiffRecord), 
        27: ("PCDIA_MISSING", "", BiffRecord), 
        28: ("PCDIA_NUMBER", "", BiffRecord), 
        29: ("PCDIA_BOOLEAN", "", BiffRecord), 
        30: ("PCDIA_ERROR", "", BiffRecord), 
        31: ("PCDIA_STRING", "", BiffRecord), 
        32: ("PCDIA_DATETIME", "", BiffRecord), 
        33: ("PCR_RECORD", "", BiffRecord), 
        34: ("PCR_RECORD_DT", "", BiffRecord), 
        35: ("FRT_BEGIN", "", BiffRecord), 
        36: ("FRT_END", "", BiffRecord), 
        37: ("AC_BEGIN", "", BiffRecord), 
        38: ("AC_END", "", BiffRecord), 
        39: ("NAME", "", LabelRecord), 
        40: ("INDEX_ROW_BLOCK", "", BiffRecord), 
        42: ("INDEX_BLOCK", "", BiffRecord), 
        43: ("FONT", "", BiffRecord), 
        44: ("FMT", "", BiffRecord), 
        45: ("FILL", "", BiffRecord), 
        46: ("BORDER", "", BiffRecord), 
        47: ("XF", "", BiffRecord), 
        48: ("STYLE", "", BiffRecord), 
        49: ("CELL_META", "", BiffRecord), 
        50: ("VALUE_META", "", BiffRecord), 
        51: ("MDB", "", BiffRecord), 
        52: ("BEGIN_FMD", "", BiffRecord), 
        53: ("END_FMD", "", BiffRecord), 
        54: ("BEGIN_MDX", "", BiffRecord), 
        55: ("END_MDX", "", BiffRecord), 
        56: ("BEGIN_MDX_TUPLE", "", BiffRecord), 
        57: ("END_MDX_TUPLE", "", BiffRecord), 
        58: ("MDX_MBR_ISTR", "", BiffRecord), 
        59: ("STR", "", BiffRecord), 
        60: ("COL_INFO", "", BiffRecord), 
        62: ("CELL_R_STRING", "", BiffRecord), 
        64: ("D_VAL", "", BiffRecord), 
        65: ("SXVCELL_NUM", "", BiffRecord), 
        66: ("SXVCELL_STR", "", BiffRecord), 
        67: ("SXVCELL_BOOL", "", BiffRecord), 
        68: ("SXVCELL_ERR", "", BiffRecord), 
        69: ("SXVCELL_DATE", "", BiffRecord), 
        70: ("SXVCELL_NIL", "", BiffRecord), 
        128: ("FILE_VERSION", "", BiffRecord), 
        129: ("BEGIN_SHEET", "", BiffRecord), 
        130: ("END_SHEET", "", BiffRecord), 
        131: ("BEGIN_BOOK", "", BiffRecord), 
        132: ("END_BOOK", "", BiffRecord), 
        133: ("BEGIN_WS_VIEWS", "", BiffRecord), 
        134: ("END_WS_VIEWS", "", BiffRecord), 
        135: ("BEGIN_BOOK_VIEWS", "", BiffRecord), 
        136: ("END_BOOK_VIEWS", "", BiffRecord), 
        137: ("BEGIN_WS_VIEW", "", BiffRecord), 
        138: ("END_WS_VIEW", "", BiffRecord), 
        139: ("BEGIN_CS_VIEWS", "", BiffRecord), 
        140: ("END_CS_VIEWS", "", BiffRecord), 
        141: ("BEGIN_CS_VIEW", "", BiffRecord), 
        142: ("END_CS_VIEW", "", BiffRecord), 
        143: ("BEGIN_BUNDLE_SHS", "", BiffRecord), 
        144: ("END_BUNDLE_SHS", "", BiffRecord), 
        145: ("BEGIN_SHEET_DATA", "", BiffRecord), 
        146: ("END_SHEET_DATA", "", BiffRecord), 
        147: ("WS_PROP", "", BiffRecord), 
        148: ("WS_DIM", "", DimensionRecord), 
        151: ("PANE", "", BiffRecord), 
        152: ("SEL", "", BiffRecord), 
        153: ("WB_PROP", "", BiffRecord), 
        154: ("WB_FACTOID", "", BiffRecord), 
        155: ("FILE_RECOVER", "", BiffRecord), 
        156: ("BUNDLE_SH", "", BundledSheetRecord), 
        157: ("CALC_PROP", "", BiffRecord), 
        158: ("BOOK_VIEW", "", BiffRecord), 
        159: ("BEGIN_SST", "", BeginSstRecord), 
        160: ("END_SST", "", BiffRecord), 
        161: ("BEGIN_A_FILTER", "", BiffRecord), 
        162: ("END_A_FILTER", "", BiffRecord), 
        163: ("BEGIN_FILTER_COLUMN", "", BiffRecord), 
        164: ("END_FILTER_COLUMN", "", BiffRecord), 
        165: ("BEGIN_FILTERS", "", BiffRecord), 
        166: ("END_FILTERS", "", BiffRecord), 
        167: ("FILTER", "", BiffRecord), 
        168: ("COLOR_FILTER", "", BiffRecord), 
        169: ("ICON_FILTER", "", BiffRecord), 
        170: ("TOP10_FILTER", "", BiffRecord), 
        171: ("DYNAMIC_FILTER", "", BiffRecord), 
        172: ("BEGIN_CUSTOM_FILTERS", "", BiffRecord), 
        173: ("END_CUSTOM_FILTERS", "", BiffRecord), 
        174: ("CUSTOM_FILTER", "", BiffRecord), 
        175: ("A_FILTER_DATE_GROUP_ITEM", "", BiffRecord), 
        176: ("MERGE_CELL", "", BiffRecord), 
        177: ("BEGIN_MERGE_CELLS", "", BiffRecord), 
        178: ("END_MERGE_CELLS", "", BiffRecord), 
        179: ("BEGIN_PIVOT_CACHE_DEF", "", BiffRecord), 
        180: ("END_PIVOT_CACHE_DEF", "", BiffRecord), 
        181: ("BEGIN_PCD_FIELDS", "", BiffRecord), 
        182: ("END_PCD_FIELDS", "", BiffRecord), 
        183: ("BEGIN_PCD_FIELD", "", BiffRecord), 
        184: ("END_PCD_FIELD", "", BiffRecord), 
        185: ("BEGIN_PCD_SOURCE", "", BiffRecord), 
        186: ("END_PCD_SOURCE", "", BiffRecord), 
        187: ("BEGIN_PCDS_RANGE", "", BiffRecord), 
        188: ("END_PCDS_RANGE", "", BiffRecord), 
        189: ("BEGIN_PCDF_ATBL", "", BiffRecord), 
        190: ("END_PCDF_ATBL", "", BiffRecord), 
        191: ("BEGIN_PCDI_RUN", "", BiffRecord), 
        192: ("END_PCDI_RUN", "", BiffRecord), 
        194: ("END_PIVOT_CACHE_RECORDS", "", BiffRecord), 
        195: ("BEGIN_PCD_HIERARCHIES", "", BiffRecord), 
        196: ("END_PCD_HIERARCHIES", "", BiffRecord), 
        197: ("BEGIN_PCD_HIERARCHY", "", BiffRecord), 
        198: ("END_PCD_HIERARCHY", "", BiffRecord), 
        199: ("BEGIN_PCDH_FIELDS_USAGE", "", BiffRecord), 
        200: ("END_PCDH_FIELDS_USAGE", "", BiffRecord), 
        201: ("BEGIN_EXT_CONNECTION", "", BiffRecord), 
        202: ("END_EXT_CONNECTION", "", BiffRecord), 
        203: ("BEGIN_EC_DB_PROPS", "", BiffRecord), 
        204: ("END_EC_DB_PROPS", "", BiffRecord), 
        205: ("BEGIN_EC_OLAP_PROPS", "", BiffRecord), 
        206: ("END_EC_OLAP_PROPS", "", BiffRecord), 
        207: ("BEGIN_PCDS_CONSOL", "", BiffRecord), 
        208: ("END_PCDS_CONSOL", "", BiffRecord), 
        209: ("BEGIN_PCDSC_PAGES", "", BiffRecord), 
        210: ("END_PCDSC_PAGES", "", BiffRecord), 
        211: ("BEGIN_PCDSC_PAGE", "", BiffRecord), 
        212: ("END_PCDSC_PAGE", "", BiffRecord), 
        213: ("BEGIN_PCDSCP_ITEM", "", BiffRecord), 
        214: ("END_PCDSCP_ITEM", "", BiffRecord), 
        215: ("BEGIN_PCDSC_SETS", "", BiffRecord), 
        216: ("END_PCDSC_SETS", "", BiffRecord), 
        217: ("BEGIN_PCDSC_SET", "", BiffRecord), 
        218: ("END_PCDSC_SET", "", BiffRecord), 
        219: ("BEGIN_PCDF_GROUP", "", BiffRecord), 
        220: ("END_PCDF_GROUP", "", BiffRecord), 
        221: ("BEGIN_PCDFG_ITEMS", "", BiffRecord), 
        222: ("END_PCDFG_ITEMS", "", BiffRecord), 
        223: ("BEGIN_PCDFG_RANGE", "", BiffRecord), 
        224: ("END_PCDFG_RANGE", "", BiffRecord), 
        225: ("BEGIN_PCDFG_DISCRETE", "", BiffRecord), 
        226: ("END_PCDFG_DISCRETE", "", BiffRecord), 
        228: ("END_PCDSD_TUPLE_CACHE", "", BiffRecord), 
        229: ("BEGIN_PCDSDTC_ENTRIES", "", BiffRecord), 
        230: ("END_PCDSDTC_ENTRIES", "", BiffRecord), 
        234: ("END_PCDSDTCE_MEMBER", "", BiffRecord), 
        235: ("BEGIN_PCDSDTC_QUERIES", "", BiffRecord), 
        236: ("END_PCDSDTC_QUERIES", "", BiffRecord), 
        237: ("BEGIN_PCDSDTC_QUERY", "", BiffRecord), 
        238: ("END_PCDSDTC_QUERY", "", BiffRecord), 
        239: ("BEGIN_PCDSDTC_SETS", "", BiffRecord), 
        240: ("END_PCDSDTC_SETS", "", BiffRecord), 
        241: ("BEGIN_PCDSDTC_SET", "", BiffRecord), 
        242: ("END_PCDSDTC_SET", "", BiffRecord), 
        243: ("BEGIN_PCD_CALC_ITEMS", "", BiffRecord), 
        244: ("END_PCD_CALC_ITEMS", "", BiffRecord), 
        245: ("BEGIN_PCD_CALC_ITEM", "", BiffRecord), 
        246: ("END_PCD_CALC_ITEM", "", BiffRecord), 
        247: ("BEGIN_P_RULE", "", BiffRecord), 
        248: ("END_P_RULE", "", BiffRecord), 
        249: ("BEGIN_PR_FILTERS", "", BiffRecord), 
        250: ("END_PR_FILTERS", "", BiffRecord), 
        251: ("BEGIN_PR_FILTER", "", BiffRecord), 
        252: ("END_PR_FILTER", "", BiffRecord), 
        253: ("BEGIN_P_NAMES", "", BiffRecord), 
        254: ("END_P_NAMES", "", BiffRecord), 
        255: ("BEGIN_P_NAME", "", BiffRecord), 
        256: ("END_P_NAME", "", BiffRecord), 
        257: ("BEGIN_PN_PAIRS", "", BiffRecord), 
        258: ("END_PN_PAIRS", "", BiffRecord), 
        259: ("BEGIN_PN_PAIR", "", BiffRecord), 
        260: ("END_PN_PAIR", "", BiffRecord), 
        261: ("BEGIN_EC_WEB_PROPS", "", BiffRecord), 
        262: ("END_EC_WEB_PROPS", "", BiffRecord), 
        263: ("BEGIN_EC_WP_TABLES", "", BiffRecord), 
        264: ("END_ECWP_TABLES", "", BiffRecord), 
        265: ("BEGIN_EC_PARAMS", "", BiffRecord), 
        266: ("END_EC_PARAMS", "", BiffRecord), 
        267: ("BEGIN_EC_PARAM", "", BiffRecord), 
        268: ("END_EC_PARAM", "", BiffRecord), 
        269: ("BEGIN_PCDKPIS", "", BiffRecord), 
        270: ("END_PCDKPIS", "", BiffRecord), 
        271: ("BEGIN_PCDKPI", "", BiffRecord), 
        272: ("END_PCDKPI", "", BiffRecord), 
        273: ("BEGIN_DIMS", "", BiffRecord), 
        274: ("END_DIMS", "", BiffRecord), 
        275: ("BEGIN_DIM", "", BiffRecord), 
        276: ("END_DIM", "", BiffRecord), 
        277: ("INDEX_PART_END", "", BiffRecord), 
        278: ("BEGIN_STYLE_SHEET", "", BiffRecord), 
        279: ("END_STYLE_SHEET", "", BiffRecord), 
        280: ("BEGIN_SX_VIEW", "", BiffRecord), 
        281: ("END_SXVI", "", BiffRecord), 
        282: ("BEGIN_SXVI", "", BiffRecord), 
        283: ("BEGIN_SXVIS", "", BiffRecord), 
        284: ("END_SXVIS", "", BiffRecord), 
        285: ("BEGIN_SXVD", "", BiffRecord), 
        286: ("END_SXVD", "", BiffRecord), 
        287: ("BEGIN_SXVDS", "", BiffRecord), 
        288: ("END_SXVDS", "", BiffRecord), 
        289: ("BEGIN_SXPI", "", BiffRecord), 
        290: ("END_SXPI", "", BiffRecord), 
        291: ("BEGIN_SXPIS", "", BiffRecord), 
        292: ("END_SXPIS", "", BiffRecord), 
        293: ("BEGIN_SXDI", "", BiffRecord), 
        294: ("END_SXDI", "", BiffRecord), 
        295: ("BEGIN_SXDIS", "", BiffRecord), 
        296: ("END_SXDIS", "", BiffRecord), 
        297: ("BEGIN_SXLI", "", BiffRecord), 
        298: ("END_SXLI", "", BiffRecord), 
        299: ("BEGIN_SXLI_RWS", "", BiffRecord), 
        300: ("END_SXLI_RWS", "", BiffRecord), 
        301: ("BEGIN_SXLI_COLS", "", BiffRecord), 
        302: ("END_SXLI_COLS", "", BiffRecord), 
        303: ("BEGIN_SX_FORMAT", "", BiffRecord), 
        304: ("END_SX_FORMAT", "", BiffRecord), 
        305: ("BEGIN_SX_FORMATS", "", BiffRecord), 
        306: ("END_SX_FORMATS", "", BiffRecord), 
        307: ("BEGIN_SX_SELECT", "", BiffRecord), 
        308: ("END_SX_SELECT", "", BiffRecord), 
        309: ("BEGIN_ISXVD_RWS", "", BiffRecord), 
        310: ("END_ISXVD_RWS", "", BiffRecord), 
        311: ("BEGIN_ISXVD_COLS", "", BiffRecord), 
        312: ("END_ISXVD_COLS", "", BiffRecord), 
        313: ("END_SX_LOCATION", "", BiffRecord), 
        314: ("BEGIN_SX_LOCATION", "", BiffRecord), 
        315: ("END_SX_VIEW", "", BiffRecord), 
        316: ("BEGIN_SXTHS", "", BiffRecord), 
        317: ("END_SXTHS", "", BiffRecord), 
        318: ("BEGIN_SXTH", "", BiffRecord), 
        319: ("END_SXTH", "", BiffRecord), 
        320: ("BEGIN_ISXTH_RWS", "", BiffRecord), 
        321: ("END_ISXTH_RWS", "", BiffRecord), 
        322: ("BEGIN_ISXTH_COLS", "", BiffRecord), 
        323: ("END_ISXTH_COLS", "", BiffRecord), 
        324: ("BEGIN_SXTDMPS", "", BiffRecord), 
        325: ("END_SXTDMPS", "", BiffRecord), 
        326: ("BEGIN_SXTDMP", "", BiffRecord), 
        327: ("END_SXTDMP", "", BiffRecord), 
        328: ("BEGIN_SXTH_ITEMS", "", BiffRecord), 
        329: ("END_SXTH_ITEMS", "", BiffRecord), 
        330: ("BEGIN_SXTH_ITEM", "", BiffRecord), 
        331: ("END_SXTH_ITEM", "", BiffRecord), 
        332: ("BEGIN_METADATA", "", BiffRecord), 
        333: ("END_METADATA", "", BiffRecord), 
        334: ("BEGIN_ESMDTINFO", "", BiffRecord), 
        335: ("MDTINFO", "", BiffRecord), 
        336: ("END_ESMDTINFO", "", BiffRecord), 
        337: ("BEGIN_ESMDB", "", BiffRecord), 
        338: ("END_ESMDB", "", BiffRecord), 
        339: ("BEGIN_ESFMD", "", BiffRecord), 
        340: ("END_ESFMD", "", BiffRecord), 
        341: ("BEGIN_SINGLE_CELLS", "", BiffRecord), 
        342: ("END_SINGLE_CELLS", "", BiffRecord), 
        343: ("BEGIN_LIST", "", BiffRecord), 
        344: ("END_LIST", "", BiffRecord), 
        345: ("BEGIN_LIST_COLS", "", BiffRecord), 
        346: ("END_LIST_COLS", "", BiffRecord), 
        347: ("BEGIN_LIST_COL", "", BiffRecord), 
        348: ("END_LIST_COL", "", BiffRecord), 
        349: ("BEGIN_LIST_XML_C_PR", "", BiffRecord), 
        350: ("END_LIST_XML_C_PR", "", BiffRecord), 
        351: ("LIST_CC_FMLA", "", BiffRecord), 
        352: ("LIST_TR_FMLA", "", BiffRecord), 
        353: ("BEGIN_EXTERNALS", "", BiffRecord), 
        354: ("END_EXTERNALS", "", BiffRecord), 
        355: ("SUP_BOOK_SRC", "", BiffRecord), 
        357: ("SUP_SELF", "", BiffRecord), 
        358: ("SUP_SAME", "", BiffRecord), 
        359: ("SUP_TABS", "", BiffRecord), 
        360: ("BEGIN_SUP_BOOK", "", BiffRecord), 
        361: ("PLACEHOLDER_NAME", "", BiffRecord), 
        362: ("EXTERN_SHEET", "", ExternalSheetRecord), 
        363: ("EXTERN_TABLE_START", "", BiffRecord), 
        364: ("EXTERN_TABLE_END", "", BiffRecord), 
        366: ("EXTERN_ROW_HDR", "", BiffRecord), 
        367: ("EXTERN_CELL_BLANK", "", BiffRecord), 
        368: ("EXTERN_CELL_REAL", "", BiffRecord), 
        369: ("EXTERN_CELL_BOOL", "", BiffRecord), 
        370: ("EXTERN_CELL_ERROR", "", BiffRecord), 
        371: ("EXTERN_CELL_STRING", "", BiffRecord), 
        372: ("BEGIN_ESMDX", "", BiffRecord), 
        373: ("END_ESMDX", "", BiffRecord), 
        374: ("BEGIN_MDX_SET", "", BiffRecord), 
        375: ("END_MDX_SET", "", BiffRecord), 
        376: ("BEGIN_MDX_MBR_PROP", "", BiffRecord), 
        377: ("END_MDX_MBR_PROP", "", BiffRecord), 
        378: ("BEGIN_MDX_KPI", "", BiffRecord), 
        379: ("END_MDX_KPI", "", BiffRecord), 
        380: ("BEGIN_ESSTR", "", BiffRecord), 
        381: ("END_ESSTR", "", BiffRecord), 
        382: ("BEGIN_PRF_ITEM", "", BiffRecord), 
        383: ("END_PRF_ITEM", "", BiffRecord), 
        384: ("BEGIN_PIVOT_CACHE_IDS", "", BiffRecord), 
        385: ("END_PIVOT_CACHE_IDS", "", BiffRecord), 
        386: ("BEGIN_PIVOT_CACHE_ID", "", BiffRecord), 
        387: ("END_PIVOT_CACHE_ID", "", BiffRecord), 
        388: ("BEGIN_ISXVIS", "", BiffRecord), 
        389: ("END_ISXVIS", "", BiffRecord), 
        390: ("BEGIN_COL_INFOS", "", BiffRecord), 
        391: ("END_COL_INFOS", "", BiffRecord), 
        392: ("BEGIN_RW_BRK", "", BiffRecord), 
        393: ("END_RW_BRK", "", BiffRecord), 
        394: ("BEGIN_COL_BRK", "", BiffRecord), 
        395: ("END_COL_BRK", "", BiffRecord), 
        396: ("BRK", "", BiffRecord), 
        397: ("USER_BOOK_VIEW", "", BiffRecord), 
        398: ("INFO", "", BiffRecord), 
        399: ("C_USR", "", BiffRecord), 
        400: ("USR", "", BiffRecord), 
        401: ("BEGIN_USERS", "", BiffRecord), 
        403: ("EOF", "", BiffRecord), 
        404: ("UCR", "", BiffRecord), 
        405: ("RR_INS_DEL", "", BiffRecord), 
        406: ("RR_END_INS_DEL", "", BiffRecord), 
        407: ("RR_MOVE", "", BiffRecord), 
        408: ("RR_END_MOVE", "", BiffRecord), 
        409: ("RR_CHG_CELL", "", BiffRecord), 
        410: ("RR_END_CHG_CELL", "", BiffRecord), 
        411: ("RR_HEADER", "", BiffRecord), 
        412: ("RR_USER_VIEW", "", BiffRecord), 
        413: ("RR_REN_SHEET", "", BiffRecord), 
        414: ("RR_INSERT_SH", "", BiffRecord), 
        415: ("RR_DEF_NAME", "", BiffRecord), 
        416: ("RR_NOTE", "", BiffRecord), 
        417: ("RR_CONFLICT", "", BiffRecord), 
        418: ("RRTQSIF", "", BiffRecord), 
        419: ("RR_FORMAT", "", BiffRecord), 
        420: ("RR_END_FORMAT", "", BiffRecord), 
        421: ("RR_AUTO_FMT", "", BiffRecord), 
        422: ("BEGIN_USER_SH_VIEWS", "", BiffRecord), 
        423: ("BEGIN_USER_SH_VIEW", "", BiffRecord), 
        424: ("END_USER_SH_VIEW", "", BiffRecord), 
        425: ("END_USER_SH_VIEWS", "", BiffRecord), 
        426: ("ARR_FMLA", "", BiffRecord), 
        427: ("SHR_FMLA", "", BiffRecord), 
        428: ("TABLE", "", BiffRecord), 
        429: ("BEGIN_EXT_CONNECTIONS", "", BiffRecord), 
        430: ("END_EXT_CONNECTIONS", "", BiffRecord), 
        431: ("BEGIN_PCD_CALC_MEMS", "", BiffRecord), 
        432: ("END_PCD_CALC_MEMS", "", BiffRecord), 
        433: ("BEGIN_PCD_CALC_MEM", "", BiffRecord), 
        434: ("END_PCD_CALC_MEM", "", BiffRecord), 
        435: ("BEGIN_PCDHG_LEVELS", "", BiffRecord), 
        436: ("END_PCDHG_LEVELS", "", BiffRecord), 
        437: ("BEGIN_PCDHG_LEVEL", "", BiffRecord), 
        438: ("END_PCDHG_LEVEL", "", BiffRecord), 
        439: ("BEGIN_PCDHGL_GROUPS", "", BiffRecord), 
        440: ("END_PCDHGL_GROUPS", "", BiffRecord), 
        441: ("BEGIN_PCDHGL_GROUP", "", BiffRecord), 
        442: ("END_PCDHGL_GROUP", "", BiffRecord), 
        444: ("END_PCDHGLG_MEMBERS", "", BiffRecord), 
        445: ("BEGIN_PCDHGLG_MEMBER", "", BiffRecord), 
        446: ("END_PCDHGLG_MEMBER", "", BiffRecord), 
        447: ("BEGIN_QSI", "", BiffRecord), 
        448: ("END_QSI", "", BiffRecord), 
        449: ("BEGIN_QSIR", "", BiffRecord), 
        450: ("END_QSIR", "", BiffRecord), 
        451: ("BEGIN_DELETED_NAMES", "", BiffRecord), 
        452: ("END_DELETED_NAMES", "", BiffRecord), 
        453: ("BEGIN_DELETED_NAME", "", BiffRecord), 
        454: ("END_DELETED_NAME", "", BiffRecord), 
        455: ("BEGIN_QSIFS", "", BiffRecord), 
        456: ("END_QSIFS", "", BiffRecord), 
        457: ("BEGIN_QSIF", "", BiffRecord), 
        458: ("END_QSIF", "", BiffRecord), 
        459: ("BEGIN_AUTO_SORT_SCOPE", "", BiffRecord), 
        460: ("END_AUTO_SORT_SCOPE", "", BiffRecord), 
        463: ("BEGIN_CF_RULE", "", BiffRecord), 
        464: ("END_CF_RULE", "", BiffRecord), 
        465: ("BEGIN_ICON_SET", "", BiffRecord), 
        466: ("END_ICON_SET", "", BiffRecord), 
        467: ("BEGIN_DATABAR", "", BiffRecord), 
        468: ("END_DATABAR", "", BiffRecord), 
        469: ("BEGIN_COLOR_SCALE", "", BiffRecord), 
        470: ("END_COLOR_SCALE", "", BiffRecord), 
        471: ("CFVO", "", BiffRecord), 
        472: ("EXTERN_VALUE_META", "", BiffRecord), 
        473: ("BEGIN_COLOR_PALETTE", "", BiffRecord), 
        474: ("END_COLOR_PALETTE", "", BiffRecord), 
        475: ("INDEXED_COLOR", "", BiffRecord), 
        476: ("MARGINS", "", BiffRecord), 
        477: ("PRINT_OPTIONS", "", BiffRecord), 
        478: ("PAGE_SETUP", "", BiffRecord), 
        479: ("BEGIN_HEADER_FOOTER", "", BiffRecord), 
        480: ("END_HEADER_FOOTER", "", BiffRecord), 
        481: ("BEGIN_SX_CRT_FORMAT", "", BiffRecord), 
        482: ("END_SX_CRT_FORMAT", "", BiffRecord), 
        483: ("BEGIN_SX_CRT_FORMATS", "", BiffRecord), 
        484: ("END_SX_CRT_FORMATS", "", BiffRecord), 
        485: ("WS_FMT_INFO", "", BiffRecord), 
        486: ("BEGIN_MGS", "", BiffRecord), 
        487: ("END_MGS", "", BiffRecord), 
        488: ("BEGIN_MG_MAPS", "", BiffRecord), 
        489: ("END_MG_MAPS", "", BiffRecord), 
        490: ("BEGIN_MG", "", BiffRecord), 
        491: ("END_MG", "", BiffRecord), 
        492: ("BEGIN_MAP", "", BiffRecord), 
        493: ("END_MAP", "", BiffRecord), 
        494: ("H_LINK", "", BiffRecord), 
        495: ("BEGIN_D_CON", "", BiffRecord), 
        496: ("END_D_CON", "", BiffRecord), 
        497: ("BEGIN_D_REFS", "", BiffRecord), 
        498: ("END_D_REFS", "", BiffRecord), 
        499: ("D_REF", "", BiffRecord), 
        500: ("BEGIN_SCEN_MAN", "", BiffRecord), 
        501: ("END_SCEN_MAN", "", BiffRecord), 
        502: ("BEGIN_SCT", "", BiffRecord), 
        503: ("END_SCT", "", BiffRecord), 
        504: ("SLC", "", BiffRecord), 
        505: ("BEGIN_DXFS", "", BiffRecord), 
        506: ("END_DXFS", "", BiffRecord), 
        507: ("DXF", "", BiffRecord), 
        508: ("BEGIN_TABLE_STYLES", "", BiffRecord), 
        509: ("END_TABLE_STYLES", "", BiffRecord), 
        510: ("BEGIN_TABLE_STYLE", "", BiffRecord), 
        511: ("END_TABLE_STYLE", "", BiffRecord), 
        512: ("TABLE_STYLE_ELEMENT", "", BiffRecord), 
        513: ("TABLE_STYLE_CLIENT", "", BiffRecord), 
        514: ("BEGIN_VOL_DEPS", "", BiffRecord), 
        515: ("END_VOL_DEPS", "", BiffRecord), 
        516: ("BEGIN_VOL_TYPE", "", BiffRecord), 
        517: ("END_VOL_TYPE", "", BiffRecord), 
        518: ("BEGIN_VOL_MAIN", "", BiffRecord), 
        519: ("END_VOL_MAIN", "", BiffRecord), 
        520: ("BEGIN_VOL_TOPIC", "", BiffRecord), 
        521: ("END_VOL_TOPIC", "", BiffRecord), 
        522: ("VOL_SUBTOPIC", "", BiffRecord), 
        523: ("VOL_REF", "", BiffRecord), 
        524: ("VOL_NUM", "", BiffRecord), 
        525: ("VOL_ERR", "", BiffRecord), 
        526: ("VOL_STR", "", BiffRecord), 
        527: ("VOL_BOOL", "", BiffRecord), 
        530: ("BEGIN_SORT_STATE", "", BiffRecord), 
        531: ("END_SORT_STATE", "", BiffRecord), 
        532: ("BEGIN_SORT_COND", "", BiffRecord), 
        533: ("END_SORT_COND", "", BiffRecord), 
        534: ("BOOK_PROTECTION", "", BiffRecord), 
        535: ("SHEET_PROTECTION", "", BiffRecord), 
        536: ("RANGE_PROTECTION", "", BiffRecord), 
        537: ("PHONETIC_INFO", "", BiffRecord), 
        538: ("BEGIN_EC_TXT_WIZ", "", BiffRecord), 
        539: ("END_EC_TXT_WIZ", "", BiffRecord), 
        540: ("BEGIN_ECTW_FLD_INFO_LST", "", BiffRecord), 
        541: ("END_ECTW_FLD_INFO_LST", "", BiffRecord), 
        542: ("BEGIN_EC_TW_FLD_INFO", "", BiffRecord), 
        548: ("FILE_SHARING", "", BiffRecord), 
        549: ("OLE_SIZE", "", BiffRecord), 
        550: ("DRAWING", "", BiffRecord), 
        551: ("LEGACY_DRAWING", "", BiffRecord), 
        552: ("LEGACY_DRAWING_HF", "", BiffRecord), 
        553: ("WEB_OPT", "", BiffRecord), 
        554: ("BEGIN_WEB_PUB_ITEMS", "", BiffRecord), 
        555: ("END_WEB_PUB_ITEMS", "", BiffRecord), 
        556: ("BEGIN_WEB_PUB_ITEM", "", BiffRecord), 
        557: ("END_WEB_PUB_ITEM", "", BiffRecord), 
        558: ("BEGIN_SX_COND_FMT", "", BiffRecord), 
        559: ("END_SX_COND_FMT", "", BiffRecord), 
        560: ("BEGIN_SX_COND_FMTS", "", BiffRecord), 
        561: ("END_SX_COND_FMTS", "", BiffRecord), 
        562: ("BK_HIM", "", BiffRecord), 
        564: ("COLOR", "", BiffRecord), 
        565: ("BEGIN_INDEXED_COLORS", "", BiffRecord), 
        566: ("END_INDEXED_COLORS", "", BiffRecord), 
        569: ("BEGIN_MRU_COLORS", "", BiffRecord), 
        570: ("END_MRU_COLORS", "", BiffRecord), 
        572: ("MRU_COLOR", "", BiffRecord), 
        573: ("BEGIN_D_VALS", "", BiffRecord), 
        574: ("END_D_VALS", "", BiffRecord), 
        577: ("SUP_NAME_START", "", BiffRecord), 
        578: ("SUP_NAME_VALUE_START", "", BiffRecord), 
        579: ("SUP_NAME_VALUE_END", "", BiffRecord), 
        580: ("SUP_NAME_NUM", "", BiffRecord), 
        581: ("SUP_NAME_ERR", "", BiffRecord), 
        582: ("SUP_NAME_ST", "", BiffRecord), 
        583: ("SUP_NAME_NIL", "", BiffRecord), 
        584: ("SUP_NAME_BOOL", "", BiffRecord), 
        585: ("SUP_NAME_FMLA", "", BiffRecord), 
        586: ("SUP_NAME_BITS", "", BiffRecord), 
        587: ("SUP_NAME_END", "", BiffRecord), 
        588: ("END_SUP_BOOK", "", BiffRecord), 
        589: ("CELL_SMART_TAG_PROPERTY", "", BiffRecord), 
        590: ("BEGIN_CELL_SMART_TAG", "", BiffRecord), 
        591: ("END_CELL_SMART_TAG", "", BiffRecord), 
        592: ("BEGIN_CELL_SMART_TAGS", "", BiffRecord), 
        593: ("END_CELL_SMART_TAGS", "", BiffRecord), 
        594: ("BEGIN_SMART_TAGS", "", BiffRecord), 
        595: ("END_SMART_TAGS", "", BiffRecord), 
        596: ("SMART_TAG_TYPE", "", BiffRecord), 
        597: ("BEGIN_SMART_TAG_TYPES", "", BiffRecord), 
        598: ("END_SMART_TAG_TYPES", "", BiffRecord), 
        599: ("BEGIN_SX_FILTERS", "", BiffRecord), 
        600: ("END_SX_FILTERS", "", BiffRecord), 
        601: ("BEGIN_SXFILTER", "", BiffRecord), 
        602: ("END_SX_FILTER", "", BiffRecord), 
        603: ("BEGIN_FILLS", "", BiffRecord), 
        604: ("END_FILLS", "", BiffRecord), 
        605: ("BEGIN_CELL_WATCHES", "", BiffRecord), 
        606: ("END_CELL_WATCHES", "", BiffRecord), 
        607: ("CELL_WATCH", "", BiffRecord), 
        608: ("BEGIN_CR_ERRS", "", BiffRecord), 
        609: ("END_CR_ERRS", "", BiffRecord), 
        610: ("CRASH_REC_ERR", "", BiffRecord), 
        611: ("BEGIN_FONTS", "", BiffRecord), 
        612: ("END_FONTS", "", BiffRecord), 
        613: ("BEGIN_BORDERS", "", BiffRecord), 
        614: ("END_BORDERS", "", BiffRecord), 
        615: ("BEGIN_FMTS", "", BiffRecord), 
        616: ("END_FMTS", "", BiffRecord), 
        617: ("BEGIN_CELL_XFS", "", BiffRecord), 
        618: ("END_CELL_XFS", "", BiffRecord), 
        619: ("BEGIN_STYLES", "", BiffRecord), 
        620: ("END_STYLES", "", BiffRecord), 
        625: ("BIG_NAME", "", BiffRecord), 
        626: ("BEGIN_CELL_STYLE_XFS", "", BiffRecord), 
        627: ("END_CELL_STYLE_XFS", "", BiffRecord), 
        628: ("BEGIN_COMMENTS", "", BiffRecord), 
        629: ("END_COMMENTS", "", BiffRecord), 
        630: ("BEGIN_COMMENT_AUTHORS", "", BiffRecord), 
        631: ("END_COMMENT_AUTHORS", "", BiffRecord), 
        632: ("COMMENT_AUTHOR", "", BiffRecord), 
        633: ("BEGIN_COMMENT_LIST", "", BiffRecord), 
        634: ("END_COMMENT_LIST", "", BiffRecord), 
        635: ("BEGIN_COMMENT", "", BiffRecord), 
        636: ("END_COMMENT", "", BiffRecord), 
        637: ("COMMENT_TEXT", "", BiffRecord), 
        638: ("BEGIN_OLE_OBJECTS", "", BiffRecord), 
        639: ("OLE_OBJECT", "", BiffRecord), 
        640: ("END_OLE_OBJECTS", "", BiffRecord), 
        641: ("BEGIN_SXRULES", "", BiffRecord), 
        642: ("END_SX_RULES", "", BiffRecord), 
        643: ("BEGIN_ACTIVE_X_CONTROLS", "", BiffRecord), 
        644: ("ACTIVE_X", "", BiffRecord), 
        645: ("END_ACTIVE_X_CONTROLS", "", BiffRecord), 
        646: ("BEGIN_PCDSDTCE_MEMBERS_SORT_BY", "", BiffRecord), 
        648: ("BEGIN_CELL_IGNORE_ECS", "", BiffRecord), 
        649: ("CELL_IGNORE_EC", "", BiffRecord), 
        650: ("END_CELL_IGNORE_ECS", "", BiffRecord), 
        651: ("CS_PROP", "", BiffRecord), 
        652: ("CS_PAGE_SETUP", "", BiffRecord), 
        653: ("BEGIN_USER_CS_VIEWS", "", BiffRecord), 
        654: ("END_USER_CS_VIEWS", "", BiffRecord), 
        655: ("BEGIN_USER_CS_VIEW", "", BiffRecord), 
        656: ("END_USER_CS_VIEW", "", BiffRecord), 
        657: ("BEGIN_PCD_SFCI_ENTRIES", "", BiffRecord), 
        658: ("END_PCDSFCI_ENTRIES", "", BiffRecord), 
        659: ("PCDSFCI_ENTRY", "", BiffRecord), 
        660: ("BEGIN_LIST_PARTS", "", BiffRecord), 
        661: ("LIST_PART", "", BiffRecord), 
        662: ("END_LIST_PARTS", "", BiffRecord), 
        663: ("SHEET_CALC_PROP", "", BiffRecord), 
        664: ("BEGIN_FN_GROUP", "", BiffRecord), 
        665: ("FN_GROUP", "", BiffRecord), 
        666: ("END_FN_GROUP", "", BiffRecord), 
        667: ("SUP_ADDIN", "", BiffRecord), 
        668: ("SXTDMP_ORDER", "", BiffRecord), 
        669: ("CS_PROTECTION", "", BiffRecord), 
        671: ("BEGIN_WS_SORT_MAP", "", BiffRecord), 
        672: ("END_WS_SORT_MAP", "", BiffRecord), 
        673: ("BEGIN_RR_SORT", "", BiffRecord), 
        674: ("END_RR_SORT", "", BiffRecord), 
        675: ("RR_SORT_ITEM", "", BiffRecord), 
        676: ("FILE_SHARING_ISO", "", BiffRecord), 
        677: ("BOOK_PROTECTION_ISO", "", BiffRecord), 
        678: ("SHEET_PROTECTION_ISO", "", BiffRecord), 
        679: ("CS_PROTECTION_ISO", "", BiffRecord), 
        680: ("RANGE_PROTECTION_ISO", "", BiffRecord), 
        1024: ("RW_DESCENT", "", BiffRecord), 
        1025: ("KNOWN_FONTS", "", BiffRecord), 
        1026: ("BEGIN_SX_TUPLE_SET", "", BiffRecord), 
        1027: ("END_SX_TUPLE_SET", "", BiffRecord), 
        1029: ("END_SX_TUPLE_SET_HEADER", "", BiffRecord), 
        1031: ("BEGIN_SX_TUPLE_SET_DATA", "", BiffRecord), 
        1032: ("END_SX_TUPLE_SET_DATA", "", BiffRecord), 
        1033: ("BEGIN_SX_TUPLE_SET_ROW", "", BiffRecord), 
        1034: ("END_SX_TUPLE_SET_ROW", "", BiffRecord), 
        1035: ("SX_TUPLE_SET_ROW_ITEM", "", BiffRecord), 
        1036: ("NAME_EXT", "", BiffRecord), 
        1037: ("PCDH14", "", BiffRecord), 
        1038: ("BEGIN_PCD_CALC_MEM14", "", BiffRecord), 
        1039: ("END_PCD_CALC_MEM14", "", BiffRecord), 
        1040: ("SXTH14", "", BiffRecord), 
        1041: ("BEGIN_SPARKLINE_GROUP", "", BiffRecord), 
        1042: ("END_SPARKLINE_GROUP", "", BiffRecord), 
        1043: ("SPARKLINE", "", BiffRecord), 
        1044: ("SXDI14", "", BiffRecord), 
        1045: ("WS_FMT_INFO_EX14", "", BiffRecord), 
        1048: ("BEGIN_CF_RULE14", "", BiffRecord), 
        1049: ("END_CF_RULE14", "", BiffRecord), 
        1050: ("CFVO14", "", BiffRecord), 
        1051: ("BEGIN_DATABAR14", "", BiffRecord), 
        1052: ("BEGIN_ICON_SET14", "", BiffRecord), 
        1053: ("D_VAL14", "", BiffRecord), 
        1054: ("BEGIN_D_VALS14", "", BiffRecord), 
        1055: ("COLOR14", "", BiffRecord), 
        1056: ("BEGIN_SPARKLINES", "", BiffRecord), 
        1057: ("END_SPARKLINES", "", BiffRecord), 
        1058: ("BEGIN_SPARKLINE_GROUPS", "", BiffRecord), 
        1059: ("END_SPARKLINE_GROUPS", "", BiffRecord), 
        1061: ("SXVD14", "", BiffRecord), 
        1062: ("BEGIN_SX_VIEW14", "", BiffRecord), 
        1063: ("END_SX_VIEW14", "", BiffRecord), 
        1064: ("BEGIN_SX_VIEW16", "", BiffRecord), 
        1065: ("END_SX_VIEW16", "", BiffRecord), 
        1066: ("BEGIN_PCD14", "", BiffRecord), 
        1067: ("END_PCD14", "", BiffRecord), 
        1068: ("BEGIN_EXT_CONN14", "", BiffRecord), 
        1069: ("END_EXT_CONN14", "", BiffRecord), 
        1070: ("BEGIN_SLICER_CACHE_IDS", "", BiffRecord), 
        1071: ("END_SLICER_CACHE_IDS", "", BiffRecord), 
        1072: ("BEGIN_SLICER_CACHE_ID", "", BiffRecord), 
        1073: ("END_SLICER_CACHE_ID", "", BiffRecord), 
        1075: ("BEGIN_SLICER_CACHE", "", BiffRecord), 
        1076: ("END_SLICER_CACHE", "", BiffRecord), 
        1077: ("BEGIN_SLICER_CACHE_DEF", "", BiffRecord), 
        1078: ("END_SLICER_CACHE_DEF", "", BiffRecord), 
        1079: ("BEGIN_SLICERS_EX", "", BiffRecord), 
        1080: ("END_SLICERS_EX", "", BiffRecord), 
        1081: ("BEGIN_SLICER_EX", "", BiffRecord), 
        1082: ("END_SLICER_EX", "", BiffRecord), 
        1083: ("BEGIN_SLICER", "", BiffRecord), 
        1084: ("END_SLICER", "", BiffRecord), 
        1085: ("SLICER_CACHE_PIVOT_TABLES", "", BiffRecord), 
        1096: ("SLICER_CACHE_OLAP_ITEM", "", BiffRecord), 
        1098: ("SLICER_CACHE_SELECTION", "", BiffRecord), 
        1101: ("END_SLICER_CACHE_NATIVE", "", BiffRecord), 
        1102: ("SLICER_CACHE_NATIVE_ITEM", "", BiffRecord), 
        1103: ("RANGE_PROTECTION14", "", BiffRecord), 
        1104: ("RANGE_PROTECTION_ISO14", "", BiffRecord), 
        1105: ("CELL_IGNORE_EC14", "", BiffRecord), 
        1111: ("LIST14", "", BiffRecord), 
        1112: ("CF_ICON", "", BiffRecord), 
        1113: ("BEGIN_SLICER_CACHES_PIVOT_CACHE_IDS", "", BiffRecord), 
        1115: ("BEGIN_SLICERS", "", BiffRecord), 
        1116: ("END_SLICERS", "", BiffRecord), 
        1117: ("WB_PROP14", "", BiffRecord), 
        1118: ("BEGIN_SX_EDIT", "", BiffRecord), 
        1119: ("END_SX_EDIT", "", BiffRecord), 
        1120: ("BEGIN_SX_EDITS", "", BiffRecord), 
        1121: ("END_SX_EDITS", "", BiffRecord), 
        1122: ("BEGIN_SX_CHANGE", "", BiffRecord), 
        1123: ("END_SX_CHANGE", "", BiffRecord), 
        1124: ("BEGIN_SX_CHANGES", "", BiffRecord), 
        1125: ("END_SX_CHANGES", "", BiffRecord), 
        1126: ("SX_TUPLE_ITEMS", "", BiffRecord), 
        1128: ("BEGIN_SLICER_STYLE", "", BiffRecord), 
        1129: ("END_SLICER_STYLE", "", BiffRecord), 
        1130: ("SLICER_STYLE_ELEMENT", "", BiffRecord), 
        1131: ("BEGIN_STYLE_SHEET_EXT14", "", BiffRecord), 
        1132: ("END_STYLE_SHEET_EXT14", "", BiffRecord), 
        1133: ("BEGIN_SLICER_CACHES_PIVOT_CACHE_ID", "", BiffRecord), 
        1137: ("BEGIN_PCD_CALC_MEM_EXT", "", BiffRecord), 
        1138: ("END_PCD_CALC_MEM_EXT", "", BiffRecord), 
        1139: ("BEGIN_PCD_CALC_MEMS_EXT", "", BiffRecord), 
        1140: ("END_PCD_CALC_MEMS_EXT", "", BiffRecord), 
        1141: ("PCD_FIELD14", "", BiffRecord), 
        1142: ("BEGIN_SLICER_STYLES", "", BiffRecord), 
        1143: ("END_SLICER_STYLES", "", BiffRecord), 
        1146: ("CF_RULE_EXT", "", BiffRecord), 
        1147: ("BEGIN_SX_COND_FMT14", "", BiffRecord), 
        1148: ("END_SX_COND_FMT14", "", BiffRecord), 
        1149: ("BEGIN_SX_COND_FMTS14", "", BiffRecord), 
        1150: ("END_SX_COND_FMTS14", "", BiffRecord), 
        1152: ("BEGIN_SORT_COND14", "", BiffRecord), 
        1153: ("END_SORT_COND14", "", BiffRecord), 
        1154: ("END_D_VALS14", "", BiffRecord), 
        1155: ("END_ICON_SET14", "", BiffRecord), 
        1156: ("END_DATABAR14", "", BiffRecord), 
        1157: ("BEGIN_COLOR_SCALE14", "", BiffRecord), 
        1158: ("END_COLOR_SCALE14", "", BiffRecord), 
        1159: ("BEGIN_SXRULES14", "", BiffRecord), 
        1160: ("END_SXRULES14", "", BiffRecord), 
        1161: ("BEGIN_P_RULE14", "", BiffRecord), 
        1162: ("END_P_RULE14", "", BiffRecord), 
        1163: ("BEGIN_PR_FILTERS14", "", BiffRecord), 
        1164: ("END_PR_FILTERS14", "", BiffRecord), 
        1165: ("BEGIN_PR_FILTER14", "", BiffRecord), 
        1166: ("END_PR_FILTER14", "", BiffRecord), 
        1167: ("BEGIN_PRF_ITEM14", "", BiffRecord), 
        1168: ("END_PRF_ITEM14", "", BiffRecord), 
        1169: ("BEGIN_CELL_IGNORE_ECS14", "", BiffRecord), 
        1170: ("END_CELL_IGNORE_ECS14", "", BiffRecord), 
        1171: ("DXF14", "", BiffRecord), 
        1172: ("BEGIN_DX_F14S", "", BiffRecord), 
        1173: ("END_DXF14S", "", BiffRecord), 
        1177: ("FILTER14", "", BiffRecord), 
        1178: ("BEGIN_CUSTOM_FILTERS14", "", BiffRecord), 
        1180: ("CUSTOM_FILTER14", "", BiffRecord), 
        1181: ("ICON_FILTER14", "", BiffRecord), 
        2051: ("BEGIN_PIVOT_TABLE_REFS", "", BiffRecord), 
        2052: ("END_PIVOT_TABLE_REFS", "", BiffRecord), 
        2053: ("PIVOT_TABLE_REF", "", BiffRecord), 
        2055: ("BEGIN_SXVCELLS", "", BiffRecord), 
        2056: ("END_SXVCELLS", "", BiffRecord), 
        2057: ("BEGIN_SX_ROW", "", BiffRecord), 
        2058: ("END_SX_ROW", "", BiffRecord), 
        2060: ("PCD_CALC_MEM15", "", BiffRecord), 
        2067: ("QSI15", "", BiffRecord), 
        2068: ("BEGIN_WEB_EXTENSIONS", "", BiffRecord), 
        2069: ("END_WEB_EXTENSIONS", "", BiffRecord), 
        2070: ("WEB_EXTENSION", "", BiffRecord), 
        2071: ("ABS_PATH15", "", BiffRecord), 
        2075: ("TABLE_SLICER_CACHE_IDS", "", BiffRecord), 
        2076: ("TABLE_SLICER_CACHE_ID", "", BiffRecord), 
        2077: ("BEGIN_TABLE_SLICER_CACHE", "", BiffRecord), 
        2078: ("END_TABLE_SLICER_CACHE", "", BiffRecord), 
        2079: ("SX_FILTER15", "", BiffRecord), 
        2080: ("BEGIN_TIMELINE_CACHE_PIVOT_CACHE_IDS", "", BiffRecord), 
        2081: ("END_TIMELINE_CACHE_PIVOT_CACHE_IDS", "", BiffRecord), 
        2084: ("END_TIMELINE_CACHE_IDS", "", BiffRecord), 
        2085: ("BEGIN_TIMELINE_CACHE_ID", "", BiffRecord), 
        2086: ("END_TIMELINE_CACHE_ID", "", BiffRecord), 
        2087: ("BEGIN_TIMELINES_EX", "", BiffRecord), 
        2088: ("END_TIMELINES_EX", "", BiffRecord), 
        2089: ("BEGIN_TIMELINE_EX", "", BiffRecord), 
        2090: ("END_TIMELINE_EX", "", BiffRecord), 
        2091: ("WORK_BOOK_PR15", "", BiffRecord), 
        2092: ("PCDH15", "", BiffRecord), 
        2093: ("BEGIN_TIMELINE_STYLE", "", BiffRecord), 
        2094: ("END_TIMELINE_STYLE", "", BiffRecord), 
        2095: ("TIMELINE_STYLE_ELEMENT", "", BiffRecord), 
        2096: ("BEGIN_TIMELINE_STYLESHEET_EXT15", "", BiffRecord), 
        2097: ("END_TIMELINE_STYLESHEET_EXT15", "", BiffRecord), 
        2098: ("BEGIN_TIMELINE_STYLES", "", BiffRecord), 
        2099: ("END_TIMELINE_STYLES", "", BiffRecord), 
        2102: ("DXF15", "", BiffRecord), 
        2103: ("BEGIN_DXFS15", "", BiffRecord), 
        2104: ("END_DXFS15", "", BiffRecord), 
        2105: ("SLICER_CACHE_HIDE_ITEMS_WITH_NO_DATA", "", BiffRecord), 
        2106: ("BEGIN_ITEM_UNIQUE_NAMES", "", BiffRecord), 
        2107: ("END_ITEM_UNIQUE_NAMES", "", BiffRecord), 
        2108: ("ITEM_UNIQUE_NAME", "", BiffRecord), 
        2109: ("BEGIN_EXT_CONN15", "", BiffRecord), 
        2110: ("END_EXT_CONN15", "", BiffRecord), 
        2111: ("BEGIN_OLEDB_PR15", "", BiffRecord), 
        2112: ("END_OLEDB_PR15", "", BiffRecord), 
        2113: ("BEGIN_DATA_FEED_PR15", "", BiffRecord), 
        2114: ("END_DATA_FEED_PR15", "", BiffRecord), 
        2115: ("TEXT_PR15", "", BiffRecord), 
        2116: ("RANGE_PR15", "", BiffRecord), 
        2117: ("DB_COMMAND15", "", BiffRecord), 
        2118: ("BEGIN_DB_TABLES15", "", BiffRecord), 
        2119: ("END_DB_TABLES15", "", BiffRecord), 
        2120: ("DB_TABLE15", "", BiffRecord), 
        2121: ("BEGIN_DATA_MODEL", "", BiffRecord), 
        2122: ("END_DATA_MODEL", "", BiffRecord), 
        2123: ("BEGIN_MODEL_TABLES", "", BiffRecord), 
        2124: ("END_MODEL_TABLES", "", BiffRecord), 
        2125: ("MODEL_TABLE", "", BiffRecord), 
        2127: ("END_MODEL_RELATIONSHIPS", "", BiffRecord), 
        2128: ("MODEL_RELATIONSHIP", "", BiffRecord), 
        2129: ("BEGIN_EC_TXT_WIZ15", "", BiffRecord), 
        2130: ("END_EC_TXT_WIZ15", "", BiffRecord), 
        2131: ("BEGIN_ECTW_FLD_INFO_LST15", "", BiffRecord), 
        2132: ("END_ECTW_FLD_INFO_LST15", "", BiffRecord), 
        2133: ("BEGIN_ECTW_FLD_INFO15", "", BiffRecord), 
        2134: ("FIELD_LIST_ACTIVE_ITEM", "", BiffRecord), 
        2135: ("PIVOT_CACHE_ID_VERSION", "", BiffRecord), 
        2136: ("SXDI15", "", BiffRecord), 
        3073: ("REVISION_PTR", "", BiffRecord), 
    }

    EXCEL_OPCODE_ENUM = [(v[0], k) for k,v in EXCEL_OPCODES.items()]

    PTG_DICT = {
        # Unary operators
        UPlusPtg.ptg:   UPlusPtg,
        UMinusPtg.ptg:  UMinusPtg,
        PercentPtg.ptg: PercentPtg,

        # Binary operators
        AddPtg.ptg:          AddPtg,
        SubstractPtg.ptg:    SubstractPtg,
        MultiplyPtg.ptg:     MultiplyPtg,
        DividePtg.ptg:       DividePtg,
        PowerPtg.ptg:        PowerPtg,
        ConcatPtg.ptg:       ConcatPtg,
        LessPtg.ptg:         LessPtg,
        LessEqualPtg.ptg:    LessEqualPtg,
        EqualPtg.ptg:        EqualPtg,
        GreaterEqualPtg.ptg: GreaterEqualPtg,
        GreaterPtg.ptg:      GreaterPtg,
        NotEqualPtg.ptg:     NotEqualPtg,
        IntersectionPtg.ptg: IntersectionPtg,
        UnionPtg.ptg:        UnionPtg,
        RangePtg.ptg:        RangePtg,

        # Operands
        MissArgPtg.ptg:   MissArgPtg,
        StringPtg.ptg:    StringPtg,
        ErrorPtg.ptg:     ErrorPtg,
        BooleanPtg.ptg:   BooleanPtg,
        IntegerPtg.ptg:   IntegerPtg,
        NumberPtg.ptg:    NumberPtg,
        ArrayPtg.ptg:     ArrayPtg,
        NamePtg.ptg:      NamePtg,
        RefPtg.ptg:       RefPtg,
        AreaPtg.ptg:      AreaPtg,
        MemAreaPtg.ptg:   MemAreaPtg,
        MemErrPtg.ptg:    MemErrPtg,
        RefErrPtg.ptg:    RefErrPtg,
        AreaErrPtg.ptg:   AreaErrPtg,
        RefNPtg.ptg:      RefNPtg,
        AreaNPtg.ptg:     AreaNPtg,
        NameXPtg.ptg:     NameXPtg,
        Ref3dPtg.ptg:     Ref3dPtg,
        Area3dPtg.ptg:    Area3dPtg,
        RefErr3dPtg.ptg:  RefErr3dPtg,
        AreaErr3dPtg.ptg: AreaErr3dPtg,

        # Control
        ExpPtg.ptg:       ExpPtg,
        TablePtg.ptg:     TablePtg,
        ParenPtg.ptg:     ParenPtg,
        AttrPtg.ptg:      AttrPtg,
        MemNoMemPtg.ptg:  MemNoMemPtg,
        MemFuncPtg.ptg:   MemFuncPtg,
        MemAreaNPtg.ptg:  MemAreaNPtg,
        MemNoMemNPtg.ptg: MemNoMemNPtg,

        # Func operators
        FuncPtg.ptg:    FuncPtg,
        FuncVarPtg.ptg: FuncVarPtg
    }

    FUNCTION_NAMES = {
        # https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/00b5dd7d-51ca-4938-b7b7-483fe0e5933b
        0x0000: ('COUNT',),
        0x0001: ('IF',),
        0x0002: ('ISNA', 1),
        0x0003: ('ISERROR', 1),
        0x0004: ('SUM',),
        0x0005: ('AVERAGE',),
        0x0006: ('MIN',),
        0x0007: ('MAX',),
        0x0008: ('ROW',),
        0x0009: ('COLUMN',),
        0x000A: ('NA',),
        0x000B: ('NPV',),
        0x000C: ('STDEV',),
        0x000D: ('DOLLAR',),
        0x000E: ('FIXED',),
        0x000F: ('SIN', 1),
        0x0010: ('COS', 1),
        0x0011: ('TAN', 1),
        0x0012: ('ATAN', 1),
        0x0013: ('PI',),
        0x0014: ('SQRT', 1),
        0x0015: ('EXP', 1),
        0x0016: ('LN', 1),
        0x0017: ('LOG10', 1),
        0x0018: ('ABS', 1),
        0x0019: ('INT', 1),
        0x001A: ('SIGN', 1),
        0x001B: ('ROUND', 2),
        0x001C: ('LOOKUP',),
        0x001D: ('INDEX',),
        0x001E: ('REPT', 2),
        0x001F: ('MID', 3),
        0x0020: ('LEN', 1),
        0x0021: ('VALUE', 1),
        0x0022: ('TRUE',),
        0x0023: ('FALSE',),
        0x0024: ('AND',),
        0x0025: ('OR',),
        0x0026: ('NOT', 1),
        0x0027: ('MOD', 2),
        0x0028: ('DCOUNT', 3),
        0x0029: ('DSUM', 3),
        0x002A: ('DAVERAGE', 3),
        0x002B: ('DMIN', 3),
        0x002C: ('DMAX', 3),
        0x002D: ('DSTDEV', 3),
        0x002E: ('VAR',),
        0x002F: ('DVAR', 3),
        0x0030: ('TEXT', 2),
        0x0031: ('LINEST',),
        0x0032: ('TREND',),
        0x0033: ('LOGEST',),
        0x0034: ('GROWTH',),
        0x0035: ('GOTO', 1),
        0x0036: ('HALT',),
        0x0037: ('RETURN',),
        0x0038: ('PV',),
        0x0039: ('FV',),
        0x003A: ('NPER',),
        0x003B: ('PMT',),
        0x003C: ('RATE',),
        0x003D: ('MIRR', 3),
        0x003E: ('IRR',),
        0x003F: ('RAND',),
        0x0040: ('MATCH',),
        0x0041: ('DATE', 3),
        0x0042: ('TIME', 3),
        0x0043: ('DAY', 1),
        0x0044: ('MONTH', 1),
        0x0045: ('YEAR', 1),
        0x0046: ('WEEKDAY',),
        0x0047: ('HOUR', 1),
        0x0048: ('MINUTE', 1),
        0x0049: ('SECOND', 1),
        0x004A: ('NOW',),
        0x004B: ('AREAS', 1),
        0x004C: ('ROWS', 1),
        0x004D: ('COLUMNS', 1),
        0x004E: ('OFFSET',),
        0x004F: ('ABSREF', 2),
        0x0050: ('RELREF', 2),
        0x0051: ('ARGUMENT',),
        0x0052: ('SEARCH',),
        0x0053: ('TRANSPOSE', 1),
        0x0054: ('ERROR',),
        0x0055: ('STEP',),
        0x0056: ('TYPE', 1),
        0x0057: ('ECHO',),
        0x0058: ('SET.NAME',),
        0x0059: ('CALLER',),
        0x005A: ('DEREF', 1),
        0x005B: ('WINDOWS',),
        0x005C: ('SERIES',),
        0x005D: ('DOCUMENTS',),
        0x005E: ('ACTIVE.CELL',),
        0x005F: ('SELECTION',),
        0x0060: ('RESULT',),
        0x0061: ('ATAN2', 2),
        0x0062: ('ASIN', 1),
        0x0063: ('ACOS', 1),
        0x0064: ('CHOOSE',),
        0x0065: ('HLOOKUP',),
        0x0066: ('VLOOKUP',),
        0x0067: ('LINKS',),
        0x0068: ('INPUT',),
        0x0069: ('ISREF', 1),
        0x006A: ('GET.FORMULA', 1),
        0x006B: ('GET.NAME',),
        0x006C: ('SET.VALUE', 2),
        0x006D: ('LOG',),
        0x006E: ('EXEC',),
        0x006F: ('CHAR', 1),
        0x0070: ('LOWER', 1),
        0x0071: ('UPPER', 1),
        0x0072: ('PROPER', 1),
        0x0073: ('LEFT',),
        0x0074: ('RIGHT',),
        0x0075: ('EXACT', 2),
        0x0076: ('TRIM', 1),
        0x0077: ('REPLACE', 4),
        0x0078: ('SUBSTITUTE',),
        0x0079: ('CODE', 1),
        0x007A: ('NAMES',),
        0x007B: ('DIRECTORY',),
        0x007C: ('FIND',),
        0x007D: ('CELL',),
        0x007E: ('ISERR', 1),
        0x007F: ('ISTEXT', 1),
        0x0080: ('ISNUMBER', 1),
        0x0081: ('ISBLANK', 1),
        0x0082: ('T', 1),
        0x0083: ('N', 1),
        0x0084: ('FOPEN',),
        0x0085: ('FCLOSE', 1),
        0x0086: ('FSIZE', 1),
        0x0087: ('FREADLN', 1),
        0x0088: ('FREAD', 2),
        0x0089: ('FWRITELN', 2),
        0x008A: ('FWRITE', 2),
        0x008B: ('FPOS',),
        0x008C: ('DATEVALUE', 1),
        0x008D: ('TIMEVALUE', 1),
        0x008E: ('SLN', 3),
        0x008F: ('SYD', 4),
        0x0090: ('DDB',),
        0x0091: ('GET.DEF',),
        0x0092: ('REFTEXT',),
        0x0093: ('TEXTREF',),
        0x0094: ('INDIRECT',),
        0x0095: ('REGISTER',),
        0x0096: ('CALL',),
        0x0097: ('ADD.BAR',),
        0x0098: ('ADD.MENU',),
        0x0099: ('ADD.COMMAND',),
        0x009A: ('ENABLE.COMMAND',),
        0x009B: ('CHECK.COMMAND',),
        0x009C: ('RENAME.COMMAND',),
        0x009D: ('SHOW.BAR',),
        0x009E: ('DELETE.MENU',),
        0x009F: ('DELETE.COMMAND',),
        0x00A0: ('GET.CHART.ITEM',),
        0x00A1: ('DIALOG.BOX', 1),
        0x00A2: ('CLEAN', 1),
        0x00A3: ('MDETERM', 1),
        0x00A4: ('MINVERSE', 1),
        0x00A5: ('MMULT', 2),
        0x00A6: ('FILES',),
        0x00A7: ('IPMT',),
        0x00A8: ('PPMT',),
        0x00A9: ('COUNTA',),
        0x00AA: ('CANCEL.KEY',),
        0x00AB: ('FOR',),
        0x00AC: ('WHILE', 1),
        0x00AD: ('BREAK',),
        0x00AE: ('NEXT',),
        0x00AF: ('INITIATE', 2),
        0x00B0: ('REQUEST', 2),
        0x00B1: ('POKE', 3),
        0x00B2: ('EXECUTE', 2),
        0x00B3: ('TERMINATE', 1),
        0x00B4: ('RESTART',),
        0x00B5: ('HELP',),
        0x00B6: ('GET.BAR',),
        0x00B7: ('PRODUCT',),
        0x00B8: ('FACT', 1),
        0x00B9: ('GET.CELL',),
        0x00BA: ('GET.WORKSPACE', 1),
        0x00BB: ('GET.WINDOW',),
        0x00BC: ('GET.DOCUMENT',),
        0x00BD: ('DPRODUCT', 3),
        0x00BE: ('ISNONTEXT', 1),
        0x00BF: ('GET.NOTE',),
        0x00C0: ('NOTE',),
        0x00C1: ('STDEVP',),
        0x00C2: ('VARP',),
        0x00C3: ('DSTDEVP', 3),
        0x00C4: ('DVARP', 3),
        0x00C5: ('TRUNC',),
        0x00C6: ('ISLOGICAL', 1),
        0x00C7: ('DCOUNTA', 3),
        0x00C8: ('DELETE.BAR', 1),
        0x00C9: ('UNREGISTER', 1),
        0x00CC: ('USDOLLAR',),
        0x00CD: ('FINDB',),
        0x00CE: ('SEARCHB',),
        0x00CF: ('REPLACEB', 4),
        0x00D0: ('LEFTB',),
        0x00D1: ('RIGHTB',),
        0x00D2: ('MIDB', 3),
        0x00D3: ('LENB', 1),
        0x00D4: ('ROUNDUP', 2),
        0x00D5: ('ROUNDDOWN', 2),
        0x00D6: ('ASC', 1),
        0x00D7: ('DBCS', 1),
        0x00D8: ('RANK',),
        0x00DB: ('ADDRESS',),
        0x00DC: ('DAYS360',),
        0x00DD: ('TODAY',),
        0x00DE: ('VDB',),
        0x00DF: ('ELSE',),
        0x00E0: ('ELSE.IF', 1),
        0x00E1: ('END.IF',),
        0x00E2: ('FOR.CELL',),
        0x00E3: ('MEDIAN',),
        0x00E4: ('SUMPRODUCT',),
        0x00E5: ('SINH', 1),
        0x00E6: ('COSH', 1),
        0x00E7: ('TANH', 1),
        0x00E8: ('ASINH', 1),
        0x00E9: ('ACOSH', 1),
        0x00EA: ('ATANH', 1),
        0x00EB: ('DGET', 3),
        0x00EC: ('CREATE.OBJECT',),
        0x00ED: ('VOLATILE',),
        0x00EE: ('LAST.ERROR',),
        0x00EF: ('CUSTOM.UNDO',),
        0x00F0: ('CUSTOM.REPEAT',),
        0x00F1: ('FORMULA.CONVERT',),
        0x00F2: ('GET.LINK.INFO',),
        0x00F3: ('TEXT.BOX',),
        0x00F4: ('INFO', 1),
        0x00F5: ('GROUP',),
        0x00F6: ('GET.OBJECT',),
        0x00F7: ('DB',),
        0x00F8: ('PAUSE',),
        0x00FB: ('RESUME',),
        0x00FC: ('FREQUENCY', 2),
        0x00FD: ('ADD.TOOLBAR',),
        0x00FE: ('DELETE.TOOLBAR', 1),
        0x00FF: ('UserDefinedFunction',),
        0x0100: ('RESET.TOOLBAR', 1),
        0x0101: ('EVALUATE', 1),
        0x0102: ('GET.TOOLBAR',),
        0x0103: ('GET.TOOL',),
        0x0104: ('SPELLING.CHECK',),
        0x0105: ('ERROR.TYPE', 1),
        0x0106: ('APP.TITLE',),
        0x0107: ('WINDOW.TITLE',),
        0x0108: ('SAVE.TOOLBAR',),
        0x0109: ('ENABLE.TOOL', 3),
        0x010A: ('PRESS.TOOL', 3),
        0x010B: ('REGISTER.ID',),
        0x010C: ('GET.WORKBOOK',),
        0x010D: ('AVEDEV',),
        0x010E: ('BETADIST',),
        0x010F: ('GAMMALN', 1),
        0x0110: ('BETAINV',),
        0x0111: ('BINOMDIST', 4),
        0x0112: ('CHIDIST', 2),
        0x0113: ('CHIINV', 2),
        0x0114: ('COMBIN', 2),
        0x0115: ('CONFIDENCE', 3),
        0x0116: ('CRITBINOM', 3),
        0x0117: ('EVEN', 1),
        0x0118: ('EXPONDIST', 3),
        0x0119: ('FDIST', 3),
        0x011A: ('FINV', 3),
        0x011B: ('FISHER', 1),
        0x011C: ('FISHERINV', 1),
        0x011D: ('FLOOR', 2),
        0x011E: ('GAMMADIST', 4),
        0x011F: ('GAMMAINV', 3),
        0x0120: ('CEILING', 2),
        0x0121: ('HYPGEOMDIST', 4),
        0x0122: ('LOGNORMDIST', 3),
        0x0123: ('LOGINV', 3),
        0x0124: ('NEGBINOMDIST', 3),
        0x0125: ('NORMDIST', 4),
        0x0126: ('NORMSDIST', 1),
        0x0127: ('NORMINV', 3),
        0x0128: ('NORMSINV', 1),
        0x0129: ('STANDARDIZE', 3),
        0x012A: ('ODD', 1),
        0x012B: ('PERMUT', 2),
        0x012C: ('POISSON', 3),
        0x012D: ('TDIST', 3),
        0x012E: ('WEIBULL', 4),
        0x012F: ('SUMXMY2', 2),
        0x0130: ('SUMX2MY2', 2),
        0x0131: ('SUMX2PY2', 2),
        0x0132: ('CHITEST', 2),
        0x0133: ('CORREL', 2),
        0x0134: ('COVAR', 2),
        0x0135: ('FORECAST', 3),
        0x0136: ('FTEST', 2),
        0x0137: ('INTERCEPT', 2),
        0x0138: ('PEARSON', 2),
        0x0139: ('RSQ', 2),
        0x013A: ('STEYX', 2),
        0x013B: ('SLOPE', 2),
        0x013C: ('TTEST', 4),
        0x013D: ('PROB',),
        0x013E: ('DEVSQ',),
        0x013F: ('GEOMEAN',),
        0x0140: ('HARMEAN',),
        0x0141: ('SUMSQ',),
        0x0142: ('KURT',),
        0x0143: ('SKEW',),
        0x0144: ('ZTEST',),
        0x0145: ('LARGE', 2),
        0x0146: ('SMALL', 2),
        0x0147: ('QUARTILE', 2),
        0x0148: ('PERCENTILE', 2),
        0x0149: ('PERCENTRANK',),
        0x014A: ('MODE',),
        0x014B: ('TRIMMEAN', 2),
        0x014C: ('TINV', 2),
        0x014E: ('MOVIE.COMMAND',),
        0x014F: ('GET.MOVIE',),
        0x0150: ('CONCATENATE',),
        0x0151: ('POWER', 2),
        0x0152: ('PIVOT.ADD.DATA',),
        0x0153: ('GET.PIVOT.TABLE',),
        0x0154: ('GET.PIVOT.FIELD',),
        0x0155: ('GET.PIVOT.ITEM',),
        0x0156: ('RADIANS', 1),
        0x0157: ('DEGREES', 1),
        0x0158: ('SUBTOTAL',),
        0x0159: ('SUMIF',),
        0x015A: ('COUNTIF', 2),
        0x015B: ('COUNTBLANK', 1),
        0x015C: ('SCENARIO.GET',),
        0x015D: ('OPTIONS.LISTS.GET', 1),
        0x015E: ('ISPMT', 4),
        0x015F: ('DATEDIF', 3),
        0x0160: ('DATESTRING', 1),
        0x0161: ('NUMBERSTRING', 2),
        0x0162: ('ROMAN',),
        0x0163: ('OPEN.DIALOG',),
        0x0164: ('SAVE.DIALOG',),
        0x0165: ('VIEW.GET',),
        0x0166: ('GETPIVOTDATA',),
        0x0167: ('HYPERLINK',),
        0x0168: ('PHONETIC', 1),
        0x0169: ('AVERAGEA',),
        0x016A: ('MAXA',),
        0x016B: ('MINA',),
        0x016C: ('STDEVPA',),
        0x016D: ('VARPA',),
        0x016E: ('STDEVA',),
        0x016F: ('VARA',),
        0x0170: ('BAHTTEXT', 1),
        0x0171: ('THAIDAYOFWEEK', 1),
        0x0172: ('THAIDIGIT', 1),
        0x0173: ('THAIMONTHOFYEAR', 1),
        0x0174: ('THAINUMSOUND', 1),
        0x0175: ('THAINUMSTRING', 1),
        0x0176: ('THAISTRINGLENGTH', 1),
        0x0177: ('ISTHAIDIGIT', 1),
        0x0178: ('ROUNDBAHTDOWN', 1),
        0x0179: ('ROUNDBAHTUP', 1),
        0x017A: ('THAIYEAR', 1),
        0x017B: ('RTD',),
        0x01C2: ('EOMONTH', 2),
        0x01D1: ('WEEKNUM', 2),
        0x01E0: ('IFERROR', 2),
        0x01E1: ('COUNTIFS', ),
        0x01E2: ('SUMIFS', ),

        # https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/0b8acba5-86d2-4854-836e-0afaee743d44
        0x8000: ('BEEP',),
        0x8001: ('OPEN',),
        0x8002: ('OPEN.LINKS',),
        0x8003: ('CLOSE.ALL',),
        0x8004: ('SAVE',),
        0x8005: ('SAVE.AS',),
        0x8006: ('FILE.DELETE',),
        0x8007: ('PAGE.SETUP',),
        0x8008: ('PRINT',),
        0x8009: ('PRINTER.SETUP',),
        0x800A: ('QUIT',),
        0x800B: ('NEW.WINDOW',),
        0x800C: ('ARRANGE.ALL',),
        0x800D: ('WINDOW.SIZE',),
        0x800E: ('WINDOW.MOVE',),
        0x800F: ('FULL',),
        0x8010: ('CLOSE',),
        0x8011: ('RUN',),
        0x8016: ('SET.PRINT.AREA',),
        0x8017: ('SET.PRINT.TITLES',),
        0x8018: ('SET.PAGE.BREAK',),
        0x8019: ('REMOVE.PAGE.BREAK',),
        0x801A: ('FONT',),
        0x801B: ('DISPLAY',),
        0x801C: ('PROTECT.DOCUMENT',),
        0x801D: ('PRECISION',),
        0x801E: ('A1.R1C1',),
        0x801F: ('CALCULATE.NOW',),
        0x8020: ('CALCULATION',),
        0x8022: ('DATA.FIND',),
        0x8023: ('EXTRACT',),
        0x8024: ('DATA.DELETE',),
        0x8025: ('SET.DATABASE',),
        0x8026: ('SET.CRITERIA',),
        0x8027: ('SORT',),
        0x8028: ('DATA.SERIES',),
        0x8029: ('TABLE',),
        0x802A: ('FORMAT.NUMBER',),
        0x802B: ('ALIGNMENT',),
        0x802C: ('STYLE',),
        0x802D: ('BORDER',),
        0x802E: ('CELL.PROTECTION',),
        0x802F: ('COLUMN.WIDTH',),
        0x8030: ('UNDO',),
        0x8031: ('CUT',),
        0x8032: ('COPY',),
        0x8033: ('PASTE',),
        0x8034: ('CLEAR',),
        0x8035: ('PASTE.SPECIAL',),
        0x8036: ('EDIT.DELETE',),
        0x8037: ('INSERT',),
        0x8038: ('FILL.RIGHT',),
        0x8039: ('FILL.DOWN',),
        0x803D: ('DEFINE.NAME',),
        0x803E: ('CREATE.NAMES',),
        0x803F: ('FORMULA.GOTO',),
        0x8040: ('FORMULA.FIND',),
        0x8041: ('SELECT.LAST.CELL',),
        0x8042: ('SHOW.ACTIVE.CELL',),
        0x8043: ('GALLERY.AREA',),
        0x8044: ('GALLERY.BAR',),
        0x8045: ('GALLERY.COLUMN',),
        0x8046: ('GALLERY.LINE',),
        0x8047: ('GALLERY.PIE',),
        0x8048: ('GALLERY.SCATTER',),
        0x8049: ('COMBINATION',),
        0x804A: ('PREFERRED',),
        0x804B: ('ADD.OVERLAY',),
        0x804C: ('GRIDLINES',),
        0x804D: ('SET.PREFERRED',),
        0x804E: ('AXES',),
        0x804F: ('LEGEND',),
        0x8050: ('ATTACH.TEXT',),
        0x8051: ('ADD.ARROW',),
        0x8052: ('SELECT.CHART',),
        0x8053: ('SELECT.PLOT.AREA',),
        0x8054: ('PATTERNS',),
        0x8055: ('MAIN.CHART',),
        0x8056: ('OVERLAY',),
        0x8057: ('SCALE',),
        0x8058: ('FORMAT.LEGEND',),
        0x8059: ('FORMAT.TEXT',),
        0x805A: ('EDIT.REPEAT',),
        0x805B: ('PARSE',),
        0x805C: ('JUSTIFY',),
        0x805D: ('HIDE',),
        0x805E: ('UNHIDE',),
        0x805F: ('WORKSPACE',),
        0x8060: ('FORMULA',),
        0x8061: ('FORMULA.FILL',),
        0x8062: ('FORMULA.ARRAY',),
        0x8063: ('DATA.FIND.NEXT',),
        0x8064: ('DATA.FIND.PREV',),
        0x8065: ('FORMULA.FIND.NEXT',),
        0x8066: ('FORMULA.FIND.PREV',),
        0x8067: ('ACTIVATE',),
        0x8068: ('ACTIVATE.NEXT',),
        0x8069: ('ACTIVATE.PREV',),
        0x806A: ('UNLOCKED.NEXT',),
        0x806B: ('UNLOCKED.PREV',),
        0x806C: ('COPY.PICTURE',),
        0x806D: ('SELECT',),
        0x806E: ('DELETE.NAME',),
        0x806F: ('DELETE.FORMAT',),
        0x8070: ('VLINE',),
        0x8071: ('HLINE',),
        0x8072: ('VPAGE',),
        0x8073: ('HPAGE',),
        0x8074: ('VSCROLL',),
        0x8075: ('HSCROLL',),
        0x8076: ('ALERT',),
        0x8077: ('NEW',),
        0x8078: ('CANCEL.COPY',),
        0x8079: ('SHOW.CLIPBOARD',),
        0x807A: ('MESSAGE',),
        0x807C: ('PASTE.LINK',),
        0x807D: ('APP.ACTIVATE',),
        0x807E: ('DELETE.ARROW',),
        0x807F: ('ROW.HEIGHT',),
        0x8080: ('FORMAT.MOVE',),
        0x8081: ('FORMAT.SIZE',),
        0x8082: ('FORMULA.REPLACE',),
        0x8083: ('SEND.KEYS',),
        0x8084: ('SELECT.SPECIAL',),
        0x8085: ('APPLY.NAMES',),
        0x8086: ('REPLACE.FONT',),
        0x8087: ('FREEZE.PANES',),
        0x8088: ('SHOW.INFO',),
        0x8089: ('SPLIT',),
        0x808A: ('ON.WINDOW',),
        0x808B: ('ON.DATA',),
        0x808C: ('DISABLE.INPUT',),
        0x808E: ('OUTLINE',),
        0x808F: ('LIST.NAMES',),
        0x8090: ('FILE.CLOSE',),
        0x8091: ('SAVE.WORKBOOK',),
        0x8092: ('DATA.FORM',),
        0x8093: ('COPY.CHART',),
        0x8094: ('ON.TIME',),
        0x8095: ('WAIT',),
        0x8096: ('FORMAT.FONT',),
        0x8097: ('FILL.UP',),
        0x8098: ('FILL.LEFT',),
        0x8099: ('DELETE.OVERLAY',),
        0x809B: ('SHORT.MENUS',),
        0x809F: ('SET.UPDATE.STATUS',),
        0x80A1: ('COLOR.PALETTE',),
        0x80A2: ('DELETE.STYLE',),
        0x80A3: ('WINDOW.RESTORE',),
        0x80A4: ('WINDOW.MAXIMIZE',),
        0x80A6: ('CHANGE.LINK',),
        0x80A7: ('CALCULATE.DOCUMENT',),
        0x80A8: ('ON.KEY',),
        0x80A9: ('APP.RESTORE',),
        0x80AA: ('APP.MOVE',),
        0x80AB: ('APP.SIZE',),
        0x80AC: ('APP.MINIMIZE',),
        0x80AD: ('APP.MAXIMIZE',),
        0x80AE: ('BRING.TO.FRONT',),
        0x80AF: ('SEND.TO.BACK',),
        0x80B9: ('MAIN.CHART.TYPE',),
        0x80BA: ('OVERLAY.CHART.TYPE',),
        0x80BB: ('SELECT.END',),
        0x80BC: ('OPEN.MAIL',),
        0x80BD: ('SEND.MAIL',),
        0x80BE: ('STANDARD.FONT',),
        0x80BF: ('CONSOLIDATE',),
        0x80C0: ('SORT.SPECIAL',),
        0x80C1: ('GALLERY.3D.AREA',),
        0x80C2: ('GALLERY.3D.COLUMN',),
        0x80C3: ('GALLERY.3D.LINE',),
        0x80C4: ('GALLERY.3D.PIE',),
        0x80C5: ('VIEW.3D',),
        0x80C6: ('GOAL.SEEK',),
        0x80C7: ('WORKGROUP',),
        0x80C8: ('FILL.GROUP',),
        0x80C9: ('UPDATE.LINK',),
        0x80CA: ('PROMOTE',),
        0x80CB: ('DEMOTE',),
        0x80CC: ('SHOW.DETAIL',),
        0x80CE: ('UNGROUP',),
        0x80CF: ('OBJECT.PROPERTIES',),
        0x80D0: ('SAVE.NEW.OBJECT',),
        0x80D1: ('SHARE',),
        0x80D2: ('SHARE.NAME',),
        0x80D3: ('DUPLICATE',),
        0x80D4: ('APPLY.STYLE',),
        0x80D5: ('ASSIGN.TO.OBJECT',),
        0x80D6: ('OBJECT.PROTECTION',),
        0x80D7: ('HIDE.OBJECT',),
        0x80D8: ('SET.EXTRACT',),
        0x80D9: ('CREATE.PUBLISHER',),
        0x80DA: ('SUBSCRIBE.TO',),
        0x80DB: ('ATTRIBUTES',),
        0x80DC: ('SHOW.TOOLBAR',),
        0x80DE: ('PRINT.PREVIEW',),
        0x80DF: ('EDIT.COLOR',),
        0x80E0: ('SHOW.LEVELS',),
        0x80E1: ('FORMAT.MAIN',),
        0x80E2: ('FORMAT.OVERLAY',),
        0x80E3: ('ON.RECALC',),
        0x80E4: ('EDIT.SERIES',),
        0x80E5: ('DEFINE.STYLE',),
        0x80F0: ('LINE.PRINT',),
        0x80F3: ('ENTER.DATA',),
        0x80F9: ('GALLERY.RADAR',),
        0x80FA: ('MERGE.STYLES',),
        0x80FB: ('EDITION.OPTIONS',),
        0x80FC: ('PASTE.PICTURE',),
        0x80FD: ('PASTE.PICTURE.LINK',),
        0x80FE: ('SPELLING',),
        0x8100: ('ZOOM',),
        0x8103: ('INSERT.OBJECT',),
        0x8104: ('WINDOW.MINIMIZE',),
        0x8109: ('SOUND.NOTE',),
        0x810A: ('SOUND.PLAY',),
        0x810B: ('FORMAT.SHAPE',),
        0x810C: ('EXTEND.POLYGON',),
        0x810D: ('FORMAT.AUTO',),
        0x8110: ('GALLERY.3D.BAR',),
        0x8111: ('GALLERY.3D.SURFACE',),
        0x8112: ('FILL.AUTO',),
        0x8114: ('CUSTOMIZE.TOOLBAR',),
        0x8115: ('ADD.TOOL',),
        0x8116: ('EDIT.OBJECT',),
        0x8117: ('ON.DOUBLECLICK',),
        0x8118: ('ON.ENTRY',),
        0x8119: ('WORKBOOK.ADD',),
        0x811A: ('WORKBOOK.MOVE',),
        0x811B: ('WORKBOOK.COPY',),
        0x811C: ('WORKBOOK.OPTIONS',),
        0x811D: ('SAVE.WORKSPACE',),
        0x8120: ('CHART.WIZARD',),
        0x8121: ('DELETE.TOOL',),
        0x8122: ('MOVE.TOOL',),
        0x8123: ('WORKBOOK.SELECT',),
        0x8124: ('WORKBOOK.ACTIVATE',),
        0x8125: ('ASSIGN.TO.TOOL',),
        0x8127: ('COPY.TOOL',),
        0x8128: ('RESET.TOOL',),
        0x8129: ('CONSTRAIN.NUMERIC',),
        0x812A: ('PASTE.TOOL',),
        0x812E: ('WORKBOOK.NEW',),
        0x8131: ('SCENARIO.CELLS',),
        0x8132: ('SCENARIO.DELETE',),
        0x8133: ('SCENARIO.ADD',),
        0x8134: ('SCENARIO.EDIT',),
        0x8135: ('SCENARIO.SHOW',),
        0x8136: ('SCENARIO.SHOW.NEXT',),
        0x8137: ('SCENARIO.SUMMARY',),
        0x8138: ('PIVOT.TABLE.WIZARD',),
        0x8139: ('PIVOT.FIELD.PROPERTIES',),
        0x813A: ('PIVOT.FIELD',),
        0x813B: ('PIVOT.ITEM',),
        0x813C: ('PIVOT.ADD.FIELDS',),
        0x813E: ('OPTIONS.CALCULATION',),
        0x813F: ('OPTIONS.EDIT',),
        0x8140: ('OPTIONS.VIEW',),
        0x8141: ('ADDIN.MANAGER',),
        0x8142: ('MENU.EDITOR',),
        0x8143: ('ATTACH.TOOLBARS',),
        0x8144: ('VBAActivate',),
        0x8145: ('OPTIONS.CHART',),
        0x8148: ('VBA.INSERT.FILE',),
        0x814A: ('VBA.PROCEDURE.DEFINITION',),
        0x8150: ('ROUTING.SLIP',),
        0x8152: ('ROUTE.DOCUMENT',),
        0x8153: ('MAIL.LOGON',),
        0x8156: ('INSERT.PICTURE',),
        0x8157: ('EDIT.TOOL',),
        0x8158: ('GALLERY.DOUGHNUT',),
        0x815E: ('CHART.TREND',),
        0x8160: ('PIVOT.ITEM.PROPERTIES',),
        0x8162: ('WORKBOOK.INSERT',),
        0x8163: ('OPTIONS.TRANSITION',),
        0x8164: ('OPTIONS.GENERAL',),
        0x8172: ('FILTER.ADVANCED',),
        0x8175: ('MAIL.ADD.MAILER',),
        0x8176: ('MAIL.DELETE.MAILER',),
        0x8177: ('MAIL.REPLY',),
        0x8178: ('MAIL.REPLY.ALL',),
        0x8179: ('MAIL.FORWARD',),
        0x817A: ('MAIL.NEXT.LETTER',),
        0x817B: ('DATA.LABEL',),
        0x817C: ('INSERT.TITLE',),
        0x817D: ('FONT.PROPERTIES',),
        0x817E: ('MACRO.OPTIONS',),
        0x817F: ('WORKBOOK.HIDE',),
        0x8180: ('WORKBOOK.UNHIDE',),
        0x8181: ('WORKBOOK.DELETE',),
        0x8182: ('WORKBOOK.NAME',),
        0x8184: ('GALLERY.CUSTOM',),
        0x8186: ('ADD.CHART.AUTOFORMAT',),
        0x8187: ('DELETE.CHART.AUTOFORMAT',),
        0x8188: ('CHART.ADD.DATA',),
        0x8189: ('AUTO.OUTLINE',),
        0x818A: ('TAB.ORDER',),
        0x818B: ('SHOW.DIALOG',),
        0x818C: ('SELECT.ALL',),
        0x818D: ('UNGROUP.SHEETS',),
        0x818E: ('SUBTOTAL.CREATE',),
        0x818F: ('SUBTOTAL.REMOVE',),
        0x8190: ('RENAME.OBJECT',),
        0x819C: ('WORKBOOK.SCROLL',),
        0x819D: ('WORKBOOK.NEXT',),
        0x819E: ('WORKBOOK.PREV',),
        0x819F: ('WORKBOOK.TAB.SPLIT',),
        0x81A0: ('FULL.SCREEN',),
        0x81A1: ('WORKBOOK.PROTECT',),
        0x81A4: ('SCROLLBAR.PROPERTIES',),
        0x81A5: ('PIVOT.SHOW.PAGES',),
        0x81A6: ('TEXT.TO.COLUMNS',),
        0x81A7: ('FORMAT.CHARTTYPE',),
        0x81A8: ('LINK.FORMAT',),
        0x81A9: ('TRACER.DISPLAY',),
        0x81AE: ('TRACER.NAVIGATE',),
        0x81AF: ('TRACER.CLEAR',),
        0x81B0: ('TRACER.ERROR',),
        0x81B1: ('PIVOT.FIELD.GROUP',),
        0x81B2: ('PIVOT.FIELD.UNGROUP',),
        0x81B3: ('CHECKBOX.PROPERTIES',),
        0x81B4: ('LABEL.PROPERTIES',),
        0x81B5: ('LISTBOX.PROPERTIES',),
        0x81B6: ('EDITBOX.PROPERTIES',),
        0x81B7: ('PIVOT.REFRESH',),
        0x81B8: ('LINK.COMBO',),
        0x81B9: ('OPEN.TEXT',),
        0x81BA: ('HIDE.DIALOG',),
        0x81BB: ('SET.DIALOG.FOCUS',),
        0x81BC: ('ENABLE.OBJECT',),
        0x81BD: ('PUSHBUTTON.PROPERTIES',),
        0x81BE: ('SET.DIALOG.DEFAULT',),
        0x81BF: ('FILTER',),
        0x81C0: ('FILTER.SHOW.ALL',),
        0x81C1: ('CLEAR.OUTLINE',),
        0x81C2: ('FUNCTION.WIZARD',),
        0x81C3: ('ADD.LIST.ITEM',),
        0x81C4: ('SET.LIST.ITEM',),
        0x81C5: ('REMOVE.LIST.ITEM',),
        0x81C6: ('SELECT.LIST.ITEM',),
        0x81C7: ('SET.CONTROL.VALUE',),
        0x81C8: ('SAVE.COPY.AS',),
        0x81CA: ('OPTIONS.LISTS.ADD',),
        0x81CB: ('OPTIONS.LISTS.DELETE',),
        0x81CC: ('SERIES.AXES',),
        0x81CD: ('SERIES.X',),
        0x81CE: ('SERIES.Y',),
        0x81CF: ('ERRORBAR.X',),
        0x81D0: ('ERRORBAR.Y',),
        0x81D1: ('FORMAT.CHART',),
        0x81D2: ('SERIES.ORDER',),
        0x81D3: ('MAIL.LOGOFF',),
        0x81D4: ('CLEAR.ROUTING.SLIP',),
        0x81D5: ('APP.ACTIVATE.MICROSOFT',),
        0x81D6: ('MAIL.EDIT.MAILER',),
        0x81D7: ('ON.SHEET',),
        0x81D8: ('STANDARD.WIDTH',),
        0x81D9: ('SCENARIO.MERGE',),
        0x81DA: ('SUMMARY.INFO',),
        0x81DB: ('FIND.FILE',),
        0x81DC: ('ACTIVE.CELL.FONT',),
        0x81DD: ('ENABLE.TIPWIZARD',),
        0x81DE: ('VBA.MAKE.ADDIN',),
        0x81E0: ('INSERTDATATABLE',),
        0x81E1: ('WORKGROUP.OPTIONS',),
        0x81E2: ('MAIL.SEND.MAILER',),
        0x81E5: ('AUTOCORRECT',),
        0x81E9: ('POST.DOCUMENT',),
        0x81EB: ('PICKLIST',),
        0x81ED: ('VIEW.SHOW',),
        0x81EE: ('VIEW.DEFINE',),
        0x81EF: ('VIEW.DELETE',),
        0x81FD: ('SHEET.BACKGROUND',),
        0x81FE: ('INSERT.MAP.OBJECT',),
        0x81FF: ('OPTIONS.MENONO',),
        0x8205: ('MSOCHECKS',),
        0x8206: ('NORMAL',),
        0x8207: ('LAYOUT',),
        0x8208: ('RM.PRINT.AREA',),
        0x8209: ('CLEAR.PRINT.AREA',),
        0x820A: ('ADD.PRINT.AREA',),
        0x820B: ('MOVE.BRK',),
        0x8221: ('HIDECURR.NOTE',),
        0x8222: ('HIDEALL.NOTES',),
        0x8223: ('DELETE.NOTE',),
        0x8224: ('TRAVERSE.NOTES',),
        0x8225: ('ACTIVATE.NOTES',),
        0x826C: ('PROTECT.REVISIONS',),
        0x826D: ('UNPROTECT.REVISIONS',),
        0x8287: ('OPTIONS.ME',),
        0x828D: ('WEB.PUBLISH',),
        0x829B: ('NEWWEBQUERY',),
        0x82A1: ('PIVOT.TABLE.CHART',),
        0x82F1: ('OPTIONS.SAVE',),
        0x82F3: ('OPTIONS.SPELL',),
        0x8328: ('HIDEALL.INKANNOTS',),
    }




############################################################################################################
# taken from pyxlsb2


class BasePtg(object):
    def __repr__(self):
        args = ('{}={}'.format(str(k), repr(v)) for k, v in self.__dict__.items())
        return '{}({})'.format(self.__class__.__name__, ', '.join(args))

    def is_classified(self):
        return False

    def stringify(self, tokens, workbook):
        return '#PTG{}!'.format(self.ptg)

    @classmethod
    def read(cls, reader, ptg):
        return cls()

    def write(self, writer):
        # TODO Eventually, some day
        pass





class ClassifiedPtg(BasePtg):
    def __init__(self, ptg, *args, **kwargs):
        super(ClassifiedPtg, self).__init__(*args, **kwargs)
        self.ptg = ptg

    @property
    def base_ptg(self):
        return ((self.ptg | 0x20) if self.ptg & 0x40 == 0x40 else self.ptg) & 0x3F

    def is_classified(self):
        return True

    def is_reference(self):
        return self.ptg & 0x20 == 0x20 and self.ptg & 0x40 == 0

    def is_value(self):
        return self.ptg & 0x20 == 0 and self.ptg & 0x40 == 0x40

    def is_array(self):
        return self.ptg & 0x60 == 0x60

    @classmethod
    def read(cls, reader, ptg):
        return cls(ptg)

    @staticmethod
    def cell_address(col, row, col_rel, row_rel):
        # A1 addressing
        col_name = ClassifiedPtg.convert_to_column_name(col+1)
        col_name = '$'+col_name if col_rel else col_name
        row_name = str(row+1)
        row_name = '$'+row_name if row_rel else row_name

        return col_name+row_name

    @staticmethod
    def convert_to_column_name(n):
        string = ""
        while n > 0:
            n, remainder = divmod(n - 1, 26)
            string = chr(65 + remainder) + string
        return string


class UnknownPtg(BasePtg):
    ptg = 0xFF

    def __init__(self, ptg, *args, **kwargs):
        super(UnknownPtg, self).__init__(*args, **kwargs)
        self.ptg = ptg

    def stringify(self, tokens, workbook):
        return '#UNK{}!'.format(self.ptg)

    @classmethod
    def read(cls, reader, ptg):
        return cls(ptg)


# Unary operators


class UPlusPtg(BasePtg):
    ptg = 0x12

    def stringify(self, tokens, workbook):
        return '+' + tokens.pop().stringify(tokens, workbook)


class UMinusPtg(BasePtg):
    ptg = 0x13

    def stringify(self, tokens, workbook):
        return '-' + tokens.pop().stringify(tokens, workbook)


class PercentPtg(BasePtg):
    ptg = 0x14

    def stringify(self, tokens, workbook):
        return tokens.pop().stringify(tokens, workbook) + '%'


# Binary operators


class AddPtg(BasePtg):
    ptg = 0x03

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '+' + b


class SubstractPtg(BasePtg):
    ptg = 0x04

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '-' + b


class MultiplyPtg(BasePtg):
    ptg = 0x05

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '*' + b


class DividePtg(BasePtg):
    ptg = 0x06

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '/' + b


class PowerPtg(BasePtg):
    ptg = 0x07

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '^' + b


class ConcatPtg(BasePtg):
    ptg = 0x08

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '&' + b


class LessPtg(BasePtg):
    ptg = 0x09

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '<' + b


class LessEqualPtg(BasePtg):
    ptg = 0x0A

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '<=' + b


class EqualPtg(BasePtg):
    ptg = 0x0B

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '=' + b


class GreaterEqualPtg(BasePtg):
    ptg = 0x0C

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '>=' + b


class GreaterPtg(BasePtg):
    ptg = 0x0D

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '>' + b


class NotEqualPtg(BasePtg):
    ptg = 0x0E

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + '<>' + b


class IntersectionPtg(BasePtg):
    ptg = 0x0F

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + ' ' + b


class UnionPtg(BasePtg):
    ptg = 0x10

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + ',' + b


class RangePtg(BasePtg):
    ptg = 0x11

    def stringify(self, tokens, workbook):
        b = tokens.pop().stringify(tokens, workbook)
        a = tokens.pop().stringify(tokens, workbook)
        return a + ':' + b


# Operands


class MissArgPtg(BasePtg):
    ptg = 0x16

    def stringify(self, tokens, workbook):
        return ''


class StringPtg(BasePtg):
    ptg = 0x17

    def __init__(self, value, *args, **kwargs):
        super(StringPtg, self).__init__(*args, **kwargs)
        self.value = value

    def stringify(self, tokens, workbook):
        return '"' + self.value.replace('"', '""') + '"'

    @classmethod
    def read(cls, reader, ptg):
        size = reader.read_short()
        value = reader.read_string(size=size)
        return cls(value)


class ErrorPtg(BasePtg):
    ptg = 0x1C

    def __init__(self, value, *args, **kwargs):
        super(ErrorPtg, self).__init__(*args, **kwargs)
        self.value = value

    def stringify(self, tokens, workbook):
        if self.value == 0x00:
            return '#NULL!'
        elif self.value == 0x07:
            return '#DIV/0!'
        elif self.value == 0x0F:
            return '#VALUE!'
        elif self.value == 0x17:
            return '#REF!'
        elif self.value == 0x1D:
            return '#NAME?'
        elif self.value == 0x24:
            return '#NUM!'
        elif self.value == 0x2A:
            return '#N/A'
        else:
            return '#ERR!'

    @classmethod
    def read(cls, reader, ptg):
        value = reader.read_byte()
        return cls(value)


class BooleanPtg(BasePtg):
    ptg = 0x1D

    def __init__(self, value, *args, **kwargs):
        super(BooleanPtg, self).__init__(*args, **kwargs)
        self.value = value

    def stringify(self, tokens, workbook):
        return 'TRUE' if self.value else 'FALSE'

    @classmethod
    def read(cls, reader, ptg):
        value = reader.read_bool()
        return cls(value)


class IntegerPtg(BasePtg):
    ptg = 0x1E

    def __init__(self, value, *args, **kwargs):
        super(IntegerPtg, self).__init__(*args, **kwargs)
        self.value = value

    def stringify(self, tokens, workbook):
        return str(self.value)

    @classmethod
    def read(cls, reader, ptg):
        value = reader.read_short()
        return cls(value)


class NumberPtg(BasePtg):
    ptg = 0x1F

    def __init__(self, value, *args, **kwargs):
        super(NumberPtg, self).__init__(*args, **kwargs)
        self.value = value

    def stringify(self, tokens, workbook):
        return str(self.value)

    @classmethod
    def read(cls, reader, ptg):
        value = reader.read_double()
        return cls(value)


class ArrayPtg(ClassifiedPtg):
    ptg = 0x20

    def __init__(self, cols, rows, values, *args, **kwargs):
        super(ArrayPtg, self).__init__(*args, **kwargs)
        self.cols = cols
        self.rows = rows
        self.values = values

    @classmethod
    def read(cls, reader, ptg):
        cols = reader.read_byte()
        if cols == 0:
            cols = 256
        rows = reader.read_short()
        values = list()
        for i in range(cols * rows):
            flag = reader.read_byte()
            value = None
            if flag == 0x01:
                value = reader.read_double()
            elif flag == 0x02:
                size = reader.read_short()
                value = reader.read_string(size=size)
            values.append(value)
        return cls(cols, rows, values, ptg)


class NamePtg(ClassifiedPtg):
    ptg = 0x23

    def __init__(self, idx, reserved, *args, **kwargs):
        super(NamePtg, self).__init__(*args, **kwargs)
        self.idx = idx
        self._reserved = reserved

    def stringify(self, tokens, workbook):
        if len(workbook.names) >= self.idx:
            return "#" + workbook.names[self.idx - 1]["Name"]["Value"]
        return "NAME#{}".format(self.idx)

    @classmethod
    def read(cls, reader, ptg):
        idx = reader.read_short()
        res = reader.read(2)  # Reserved
        return cls(idx, res, ptg)


class RefPtg(ClassifiedPtg):
    ptg = 0x24

    def __init__(self, row, col, row_rel, col_rel, *args, **kwargs):
        super(RefPtg, self).__init__(*args, **kwargs)
        self.row = row
        self.col = col
        self.row_rel = row_rel
        self.col_rel = col_rel


    def stringify(self, tokens, workbook):
        return self.cell_address(self.col, self.row, self.col_rel, self.row_rel)

    @classmethod
    def read(cls, reader, ptg):
        row = reader.read_int()
        col = reader.read_short()
        row_rel = col & 0x8000 == 0x8000
        col_rel = col & 0x4000 == 0x4000
        return cls(row, col & 0x3FFF, not row_rel, not col_rel, ptg)


class AreaPtg(ClassifiedPtg):
    ptg = 0x25

    def __init__(self, first_row, last_row, first_col, last_col, first_row_rel, last_row_rel, first_col_rel,
                 last_col_rel, *args, **kwargs):
        super(AreaPtg, self).__init__(*args, **kwargs)
        self.first_row = first_row
        self.last_row = last_row
        self.first_col = first_col
        self.last_col = last_col
        self.first_row_rel = first_row_rel
        self.last_row_rel = last_row_rel
        self.first_col_rel = first_col_rel
        self.last_col_rel = last_col_rel

    def stringify(self, tokens, workbook):
        first = self.cell_address(self.first_col, self.first_row, self.first_col_rel
                                  ,self.first_row_rel)
        last = self.cell_address(self.last_col, self.last_row, self.last_col_rel
                                  ,self.last_row_rel)
        return first + ':' + last

    @classmethod
    def read(cls, reader, ptg):
        r1 = reader.read_int()
        r2 = reader.read_int()
        c1 = reader.read_short()
        c2 = reader.read_short()
        r1rel = c1 & 0x8000 == 0x8000
        r2rel = c2 & 0x8000 == 0x8000
        c1rel = c1 & 0x4000 == 0x4000
        c2rel = c2 & 0x4000 == 0x4000
        return cls(r1, r2, c1 & 0x3FFF, c2 & 0x3FFF, not r1rel, not r2rel, not c1rel, not c2rel, ptg)


class MemAreaPtg(ClassifiedPtg):
    ptg = 0x26

    def __init__(self, reserved, rects, *args, **kwargs):
        super(ClassifiedPtg, self).__init__(*args, **kwargs)
        self._reserved = reserved
        self.rects = rects

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(4)  # Reserved
        subex_len = reader.read_short()
        rects = list()
        if subex_len:
            rect_count = reader.read_short()
            for i in range(rect_count):
                r1 = reader.read_int()
                r2 = reader.read_int()
                c1 = reader.read_short()
                c2 = reader.read_short()
                rects.append((r1, r2, c1, c2))
        return cls(res, rects, ptg)


class MemErrPtg(ClassifiedPtg):
    ptg = 0x27

    def __init__(self, reserved, subex, *args, **kwargs):
        super(MemErrPtg, self).__init__(*args, **kwargs)
        self._reserved = reserved
        self._subex = subex

    def stringify(self, tokens, workbook):
        return '#ERR!'

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(4)  # Reserved
        subex_len = reader.read_short()
        subex = reader.read(subex_len)
        return cls(res, subex, ptg)


class RefErrPtg(ClassifiedPtg):
    ptg = 0x2A

    def __init__(self, reserved, *args, **kwargs):
        super(RefErrPtg, self).__init__(*args, **kwargs)
        self._reserved = reserved

    def stringify(self, tokens, workbook):
        return '#REF!'

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(6)  # Reserved
        return cls(res, ptg)


class AreaErrPtg(ClassifiedPtg):
    ptg = 0x2B

    def __init__(self, reserved, *args, **kwargs):
        super(AreaErrPtg, self).__init__(*args, **kwargs)
        self._reserved = reserved

    def stringify(self, tokens, workbook):
        return '#REF!'

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(12)  # Reserved
        return cls(res, ptg)


class RefNPtg(ClassifiedPtg):
    ptg = 0x2C

    def __init__(self, row, col, row_rel, col_rel, *args, **kwargs):
        super(RefNPtg, self).__init__(*args, **kwargs)
        self.row = row
        self.col = col
        self.row_rel = row_rel
        self.col_rel = col_rel

    def stringify(self, tokens, workbook):
        return self.cell_address(self.col, self.row, self.col_rel, self.row_rel)

    @classmethod
    def read(cls, reader, ptg):
        row = reader.read_int()
        col = reader.read_short()
        row_rel = col & 0x8000 == 0x8000
        col_rel = col & 0x4000 == 0x4000
        return cls(row, col & 0x3FFF, not row_rel, not col_rel, ptg)


class AreaNPtg(ClassifiedPtg):
    ptg = 0x2D

    def __init__(self, first_row, last_row, first_col, last_col, first_row_rel, last_row_rel, first_col_rel,
                 last_col_rel, *args, **kwargs):
        super(AreaNPtg, self).__init__(*args, **kwargs)
        self.first_row = first_row
        self.last_row = last_row
        self.first_col = first_col
        self.last_col = last_col
        self.first_row_rel = first_row_rel
        self.last_row_rel = last_row_rel
        self.first_col_rel = first_col_rel
        self.last_col_rel = last_col_rel

    def stringify(self, tokens, workbook):
        first = self.cell_address(self.first_col, self.first_row, self.first_col_rel
                                  , self.first_row_rel)
        last = self.cell_address(self.last_col, self.last_row, self.last_col_rel
                                 , self.last_row_rel)
        return first + ':' + last

    @classmethod
    def read(cls, reader, ptg):
        r1 = reader.read_int()
        r2 = reader.read_int()
        c1 = reader.read_short()
        c2 = reader.read_short()
        r1_rel = c1 & 0x8000 == 0x8000
        r2_rel = c2 & 0x8000 == 0x8000
        c1_rel = c1 & 0x4000 == 0x4000
        c2_rel = c2 & 0x4000 == 0x4000
        return cls(r1, r2, c1 & 0x3FFF, c2 & 0x3FFF, not r1_rel, not r2_rel, not c1_rel, not c2_rel, ptg)


class NameXPtg(ClassifiedPtg):
    ptg = 0x39

    def __init__(self, sheet_idx, name_idx, reserved, *args, **kwargs):
        super(NameXPtg, self).__init__(*args, **kwargs)
        self.sheet_idx = sheet_idx
        self.name_idx = name_idx
        self._reserved = reserved

    # FIXME: We need to read names to stringify this

    @classmethod
    def read(cls, reader, ptg):
        sheet_idx = reader.read_short()
        name_idx = reader.read_short()
        res = reader.read(2)  # Reserved
        return cls(sheet_idx, name_idx, res, ptg)


class Ref3dPtg(ClassifiedPtg):
    ptg = 0x3A

    def __init__(self, extern_sheet_id, row, col, row_rel, col_rel, *args, **kwargs):
        super(Ref3dPtg, self).__init__(*args, **kwargs)
        self.extern_sheet_idx = extern_sheet_id
        self.row = row
        self.col = col
        self.row_rel = row_rel
        self.col_rel = col_rel

    def stringify(self, tokens, workbook):
        if (not self.col_rel) and (self.col & 0x2000 == 0x2000):
            self.col -= 16384
        if (not self.row_rel) and (self.row & 0x80000 == 0x80000):
            self.row -= 1048576
        cell_add = self.cell_address(self.col, self.row, self.col_rel, self.row_rel)

        sheet_name = "EXTSHEET[{:d}]".format(self.extern_sheet_idx)
        if self.extern_sheet_idx < len(workbook.externals):
            extern_obj = workbook.externals[self.extern_sheet_idx]
            sheet_id = None
            if extern_obj["FirstSheetId"] == extern_obj["LastSheetId"] and extern_obj["FirstSheetId"] >= 0:
                sheet_id = extern_obj["FirstSheetId"]
            elif extern_obj["FirstSheetId"] == -1:
                sheet_id = extern_obj["LastSheetId"]
            else:
                sheet_id = -2
            if sheet_id == -2:
                sheet_name = ""
            elif sheet_id is not None and sheet_id >= 0 and sheet_id < len(workbook.sheets):
                sheet_name = workbook.sheets[sheet_id]["Name"]["Value"]

        return "{}!{}".format(sheet_name, cell_add)

    @classmethod
    def read(cls, reader, ptg):
        sheet_extern_idx = reader.read_short()
        row = reader.read_int()
        col = reader.read_short()
        row_rel = col & 0x8000 == 0x8000
        col_rel = col & 0x4000 == 0x4000
        return cls(sheet_extern_idx, row, col & 0x3FFF, not row_rel, not col_rel, ptg)

    def cell_address(self, col, row, col_rel, row_rel):
        col_name = '$' + self.convert_to_column_name(col + 1) if col_rel else self.convert_to_column_name(col + 1)
        row_name = '$' + str(row + 1) if row_rel else str(row + 1)
        res = col_name + row_name
        return res


class Area3dPtg(ClassifiedPtg):
    ptg = 0x3B

    def __init__(self, extern_sheet_idx, first_row, last_row, first_col, last_col, first_row_rel, last_row_rel, first_col_rel,
                 last_col_rel, *args, **kwargs):
        super(Area3dPtg, self).__init__(*args, **kwargs)
        self.extern_sheet_idx = extern_sheet_idx
        self.first_row = first_row
        self.last_row = last_row
        self.first_col = first_col
        self.last_col = last_col
        self.first_row_rel = first_row_rel
        self.last_row_rel = last_row_rel
        self.first_col_rel = first_col_rel
        self.last_col_rel = last_col_rel

    def stringify(self, tokens, workbook):
        first = self.cell_address(self.first_col, self.first_row, self.first_col_rel
                                  ,self.first_row_rel)
        last = self.cell_address(self.last_col, self.last_row, self.last_col_rel
                                  ,self.last_row_rel)
        sheet_name = "EXTSHEET[{:d}]".format(self.extern_sheet_idx)
        if self.extern_sheet_idx < len(workbook.externals):
            extern_obj = workbook.externals[self.extern_sheet_idx]
            sheet_id = None
            if extern_obj["FirstSheetId"] == extern_obj["LastSheetId"] and extern_obj["FirstSheetId"] >= 0:
                sheet_id = extern_obj["FirstSheetId"]
            elif extern_obj["FirstSheetId"] == -1:
                sheet_id = extern_obj["LastSheetId"]
            else:
                sheet_id = -2
            if sheet_id == -2:
                sheet_name = ""
            elif sheet_id is not None and sheet_id >= 0 and sheet_id < len(workbook.sheets):
                sheet_name = workbook.sheets[sheet_id]["Name"]["Value"]
        return "{}!{}:{}".format(sheet_name, first, last)

    @classmethod
    def read(cls, reader, ptg):
        XtiIndex = reader.read_short()
        r1 = reader.read_int()
        r2 = reader.read_int()
        c1 = reader.read_short()
        c2 = reader.read_short()
        r1_rel = c1 & 0x8000 == 0x8000
        r2_rel = c2 & 0x8000 == 0x8000
        c1_rel = c1 & 0x4000 == 0x4000
        c2_rel = c2 & 0x4000 == 0x4000
        return cls(XtiIndex, r1, r2, c1 & 0x3FFF, c2 & 0x3FFF, not r1_rel, not r2_rel, not c1_rel, not c2_rel, ptg)


class RefErr3dPtg(ClassifiedPtg):
    ptg = 0x3C

    def __init__(self, reserved, *args, **kwargs):
        super(RefErr3dPtg, self).__init__(*args, **kwargs)
        self._reserved = reserved

    def stringify(self, tokens, workbook):
        return '#REF!'

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(8)  # Reserved
        return cls(res, ptg)


class AreaErr3dPtg(ClassifiedPtg):
    ptg = 0x3D

    def __init__(self, reserved, *args, **kwargs):
        super(AreaErr3dPtg, self).__init__(*args, **kwargs)

    def stringify(self, tokens, workbook):
        return '#REF!'

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(14)  # Reserved
        return cls(res, ptg)


# Control


class ExpPtg(BasePtg):
    ptg = 0x01

    def __init__(self, row, col, *args, **kwargs):
        super(ExpPtg, self).__init__(*args, **kwargs)
        self.row = row
        self.col = col

    # FIXME: We need a workbook that supports direct cell referencing to stringify this
    def stringify(self, tokens, workbook):
        return "#EXP!"

    @classmethod
    def read(cls, reader, ptg):
        row = reader.read_int()
        col = reader.read_short()
        return cls(row, col)


class TablePtg(BasePtg):
    ptg = 0x02

    def __init__(self, row, col, *args, **kwargs):
        super(TablePtg, self).__init__(*args, **kwargs)
        self.row = row
        self.col = col

    # FIXME: We need a workbook that supports tables to stringify this
    def stringify(self, tokens, workbook):
        return "#TABLE!!"

    @classmethod
    def read(cls, reader, ptg):
        row = reader.read_int()
        col = reader.read_short()
        return cls(row, col)


class ParenPtg(BasePtg):
    ptg = 0x15

    def stringify(self, tokens, workbook):
        return '(' + tokens.pop().stringify(tokens, workbook) + ')'


class AttrPtg(BasePtg):
    ptg = 0x19

    def __init__(self, flags, data, dests, *args, **kwargs):
        super(AttrPtg, self).__init__(*args, **kwargs)
        self.flags = flags
        self.data = data
        self.dests = dests

    @property
    def attr_semi(self):
        return self.flags & 0x01 == 0x01

    @property
    def attr_if(self):
        return self.flags & 0x02 == 0x02

    @property
    def attr_choose(self):
        return self.flags & 0x04 == 0x04

    @property
    def attr_goto(self):
        return self.flags & 0x08 == 0x08

    @property
    def attr_sum(self):
        return self.flags & 0x10 == 0x10

    @property
    def attr_baxcel(self):
        return self.flags & 0x20 == 0x20

    @property
    def attr_space(self):
        return self.flags & 0x40 == 0x40

    def stringify(self, tokens, workbook):
        spaces = ''
        if self.attr_space:
            if self.data & 0x00FF == 0x00 or self.data & 0x00FF == 0x06:
                spaces = ' ' * (self.data >> 1)
            elif self.data & 0x00FF == 0x01:
                spaces = '\n' * (self.data >> 1)
        elif self.attr_choose:
            spaces += "CHOOSE({})".format(",".join(["{:x}".format(x) for x in self.dests]))
        elif self.attr_goto:
            spaces += "GOTO({:x})".format(self.data)
        elif self.attr_sum:
            spaces += "SUM({:x})".format(self.data)
        elif self.attr_if:
            spaces += "IF({:x})".format(self.data)
        if tokens:
            spaces += tokens.pop().stringify(tokens, workbook)
        return spaces

    @classmethod
    def read(cls, reader, ptg):
        flags = reader.read_byte()
        data = reader.read_short()
        dests = []
        if flags == 4:
            # Choose
            for i in range(data + 1):
                dests.append(reader.read_short())
        return cls(flags, data, dests)


class MemNoMemPtg(ClassifiedPtg):
    ptg = 0x28

    def __init__(self, reserved, subex, *args, **kwargs):
        super(MemNoMemPtg, self).__init__(*args, **kwargs)
        self._reserved = reserved
        self._subex = subex

    @classmethod
    def read(cls, reader, ptg):
        res = reader.read(4)  # Reserved
        subex_len = reader.read_short()
        subex = reader.read(subex_len)
        return cls(res, subex, ptg)


class MemFuncPtg(ClassifiedPtg):
    ptg = 0x29

    def __init__(self, subex, *args, **kwargs):
        super(MemFuncPtg, self).__init__(*args, **kwargs)
        self._subex = subex

    @classmethod
    def read(cls, reader, ptg):
        subex_len = reader.read_short()
        subex = reader.read(subex_len)
        return cls(subex, ptg)


class MemAreaNPtg(ClassifiedPtg):
    ptg = 0x2E

    def __init__(self, subex, *args, **kwargs):
        super(MemAreaNPtg, self).__init__(*args, **kwargs)
        self._subex = subex

    @classmethod
    def read(cls, reader, ptg):
        subex_len = reader.read_short()
        subex = reader.skip(subex_len)
        return cls(subex, ptg)


class MemNoMemNPtg(ClassifiedPtg):
    ptg = 0x2F

    def __init__(self, subex, *args, **kwargs):
        super(MemNoMemNPtg, self).__init__(*args, **kwargs)
        self._subex = subex

    @classmethod
    def read(cls, reader, ptg):
        subex_len = reader.read_short()
        subex = reader.read(subex_len)
        return cls(subex, ptg)


# Func operators


class FuncPtg(ClassifiedPtg):
    ptg = 0x21

    def __init__(self, idx, *args, **kwargs):
        super(FuncPtg, self).__init__(*args, **kwargs)
        self.idx = idx

    # FIXME: We need a workbook to stringify this (most likely)

    @classmethod
    def read(cls, reader, ptg):
        idx = reader.read_short()
        return cls(idx, ptg)

    def stringify(self, tokens, workbook):
        args = list()

        if len(FUNCTION_NAMES[self.idx])>1:
            args_no = FUNCTION_NAMES[self.idx][1]
            for i in range(args_no):
                arg = tokens.pop().stringify(tokens, workbook)
                args.append(arg)

        return '{}({})'.format(FUNCTION_NAMES[self.idx][0], ', '.join(reversed(args)))


class FuncVarPtg(ClassifiedPtg):
    ptg = 0x22

    def __init__(self, idx, argc, prompt, ce, *args, **kwargs):
        super(FuncVarPtg, self).__init__(*args, **kwargs)
        self.idx = idx
        self.argc = argc
        self.prompt = prompt
        self.ce = ce

    def stringify(self, tokens, workbook):
        if self.idx == 255:  # UserDefinedFunction
            function_name = tokens[-self.argc].stringify(tokens, workbook).strip()
            del tokens[-1*self.argc]
            self.argc -= 1
        else:
            function_name = FUNCTION_NAMES[self.idx][0]

        args = list()
        for i in range(self.argc):
            if tokens:
                arg = tokens.pop().stringify(tokens, workbook).strip()
            else:
                arg = "#MISSING_ARGUMENT"
            args.append(arg)

        return '{}({})'.format(function_name, ', '.join(reversed(args)))

    @classmethod
    def read(cls, reader, ptg):
        argc = reader.read_byte()
        idx = reader.read_short()
        return cls(idx, argc & 0x7F, argc & 0x80 == 0x80, idx & 0x8000 == 0x8000, ptg)





_uint8_t = struct.Struct('<B')
_uint16_t = struct.Struct('<H')
_int32_t = struct.Struct('<i')
_uint32_t = struct.Struct('<I')
_float_t = struct.Struct('<f')
_double_t = struct.Struct('<d')


class DataReader(object):
    def __init__(self, buf, enc=None):
        import io
        self._buf = io.BytesIO(buf)
        self._enc = enc if enc is not None else 'utf-16'

    def skip(self, size):
        self._buf.seek(size, 1)

    def read(self, size):
        return self._buf.read(size)

    def read_bool(self):
        buf = self.read(1)
        if not buf:
            return None
        return buf != b'\x00'

    def read_byte(self):
        buf = self.read(1)
        if not buf:
            return None
        return _uint8_t.unpack(buf)[0]

    def read_short(self):
        buf = self.read(2)
        if len(buf) < 2:
            return None
        return _uint16_t.unpack(buf)[0]

    def read_int(self):
        buf = self.read(4)
        if len(buf) < 4:
            return None
        return _uint32_t.unpack(buf)[0]

    def read_signed_int(self):
        buf = self.read(4)
        if len(buf) < 4:
            return None
        return _int32_t.unpack(buf)[0]

    def read_float(self):
        buf = self.read(4)
        if len(buf) < 4:
            return None
        return _float_t.unpack(buf)[0]

    def read_double(self):
        buf = self.read(8)
        if len(buf) < 8:
            return None
        return _double_t.unpack(buf)[0]

    def read_rk(self):
        buf = self.read(4)
        if len(buf) < 4:
            return None

        value = 0.0
        intval = _int32_t.unpack(buf)[0]
        if intval & 0x02 == 0x02:
            value = float(intval >> 2)
        else:
            value = _double_t.unpack(b'\x00\x00\x00\x00' + _uint32_t.pack(intval & 0xFFFFFFFC))[0]

        if intval & 0x01 == 0x01:
            value /= 100

        return value

    def read_string(self, size=None, enc=None):
        if size is None:
            size = self.read_int()
            if size is None:
                return None

        size *= 2
        buf = self.read(size)
        if len(buf) != size:
            return None

        return buf.decode(enc or self._enc, errors='replace')
############################################################################################################

class Sheet(Struct):

    def __init__(self, document, *args, **kwargs):
        Struct.__init__(self, *args, **kwargs)
        self.document = document

    def parse(self):
        current_row = 0
        while self.remaining():
            opcode, _ = VarUInt64.parse(self.parser, self.parser.tell())
            name, comment, class_ = EXCEL_OPCODES.get(opcode, ["???", "", BiffRecord])
            obj = yield class_(name=name, comment=comment)
            if name in ("END_SHEET", "END_BOOK", "END_SST", "END_STYLE_SHEET"):
                break
            elif name == "ROW_HDR":
                current_row = obj["Row"]
            elif name == "BUNDLE_SH":
                self.document.sheets.append(obj)
            elif name == "EXTERN_SHEET":
                self.document.externals.extend([x for x in obj["Externals"]])
            elif name in ("NAME", ):
                label = obj["Name"]["Value"]
                if "Formula" in obj:
                    self.document.formulas[label] = obj["Formula"]
                self.document.names.append(obj)
            elif name in ("FMLA_BOOL", "FMLA_NUM", "FMLA_STRING", "FMLA_ERROR"):
                cell = ClassifiedPtg.cell_address(obj["Column"], current_row, False, False)
                if "Formula" in obj:
                    self.document.formulas[cell] = obj["Formula"]
                if name == "FMLA_BOOL":
                    self.document.values[cell] = bool(obj["Content"])
                elif name == "FMLA_NUM":
                    self.document.values[cell] = obj["Content"]
                elif name == "FMLA_STRING":
                    self.document.values[cell] = obj["Content"]["Value"]
            elif name in ("CELL_RK", "CELL_BOOL", "CELL_REAL", "CELL_ST") and "Content" in obj:
                cell = ClassifiedPtg.cell_address(obj["Column"], current_row, False, False)
                val = None
                if name == "CELL_RK":
                    val = CellRecord.read_rk(obj["Content"])
                elif name == "CELL_ST":
                    val = obj["Content"]["Value"]
                elif name == "CELL_BOOL":
                    val = bool(obj["Content"])
                if val is not None:
                    self.document.values[cell] = val
        

        

class WorkbookAnalyzer12(FileTypeAnalyzer):
    category = malcat.FileType.DOCUMENT
    name = "Office.Workbook12"
    regexp = r"\x81\x01\x00\x93\x01|\x83\x01\x00\x80\x01|\x9f\x01\x08........\x13|\x96\x02\x00\xe3\x04" 


    def decompile_formula(self, f):
        reader = DataReader(f["FormulaData"])
        tokens = []
        while True:
            ptg = reader.read_byte()
            if ptg is None:
                break
            base = ((ptg | 0x20) if ptg & 0x40 == 0x40 else ptg) & 0x3F
            ptg = PTG_DICT.get(base, UnknownPtg).read(reader, ptg)
            tokens.append(ptg)
        if not tokens:
            return ""
        else:
            return tokens.pop().stringify(tokens, self)


    def decompile(self):
        import traceback
        res = ""
        res += "#### CELL VALUES\n"
        for cell, val in self.values.items():
            res += f"● {cell}: {repr(val)}\n"
        res += "\n#### CELL FORMULAS\n"
        for cell, f in self.formulas.items():
            try:
                res += f"● {cell}: {self.decompile_formula(f)}"
            except BaseException as e:
                res += f"● {cell}: {traceback.format_exc()}"
            res += "\n"
        res += "\n\n"
        return res

    def parse(self, hint):
        delayed_globals()
        self.sst = []
        self.names = []
        self.formulas = {}
        self.values = {}
        self.version = 0
        self.sheets = []
        self.externals = []
        self.set_architecture(malcat.Architecture.BIFF)
        
        while self.remaining():
            opcode, _ = VarUInt64.parse(self, self.tell())
            name, comment, class_ = EXCEL_OPCODES.get(opcode, ["???", "", BiffRecord])
            if name not in ("BEGIN_SHEET", "BEGIN_BOOK", "BEGIN_SST", "BEGIN_STYLE_SHEET"):
                raise FatalError("Document does not start with BEGIN_ record")
            yield Sheet(self, category=Type.DATA)
            self.confirm()

