public NumberEval(Ptg ptg) { if (ptg is IntPtg) { this._value = ((IntPtg)ptg).Value; } else if (ptg is NumberPtg) { this._value = ((NumberPtg)ptg).Value; } }
public ParseNode(Ptg token, ParseNode[] children) { _token = token; _children = children; _isIf = IsIf(token); int tokenCount = 1; for (int i = 0; i < children.Length; i++) { tokenCount += children[i].GetTokenCount(); } if (_isIf) { // there will be 2 or 3 extra tAttr tokens according to whether the false param is present tokenCount += children.Length; } _tokenCount = tokenCount; }
/** * Used to calculate value that should be encoded at the start of the encoded Ptg token array; * @return the size of the encoded Ptg tokens not including any trailing array data. */ public static int GetEncodedSizeWithoutArrayData(Ptg[] ptgs) { int result = 0; for (int i = 0; i < ptgs.Length; i++) { Ptg ptg = ptgs[i]; if (ptg is ArrayPtg) { result += ArrayPtg.PLAIN_TOKEN_SIZE; } else { result += ptg.Size; } } return(result); }
private static bool IsDeletedCellRef(Ptg ptg) { if (ptg == ErrPtg.REF_INVALID) { return(true); } if (ptg is DeletedArea3DPtg) { return(true); } if (ptg is DeletedRef3DPtg) { return(true); } if (ptg is AreaErrPtg) { return(true); } if (ptg is RefErrorPtg) { return(true); } return(false); }
public static bool DoesFormulaReferToDeletedCell(Ptg[] ptgs) { for (int i = 0; i < ptgs.Length; i++) { if (IsDeletedCellRef(ptgs[i])) { return true; } } return false; }
private static bool IsIf(Ptg token) { if (token is FuncVarPtg) { FuncVarPtg func = (FuncVarPtg)token; if (FunctionMetadataRegistry.FUNCTION_NAME_IF.Equals(func.Name)) { return true; } } return false; }
/** * Static method To convert an array of {@link Ptg}s in RPN order * To a human readable string format in infix mode. * @param book used for defined names and 3D references * @param ptgs must not be <c>null</c> * @return a human readable String */ public static String ToFormulaString(IFormulaRenderingWorkbook book, Ptg[] ptgs) { if (ptgs == null || ptgs.Length == 0) { throw new ArgumentException("ptgs must not be null"); } Stack stack = new Stack(); for (int i = 0; i < ptgs.Length; i++) { Ptg ptg = ptgs[i]; // TODO - what about MemNoMemPtg? if (ptg is MemAreaPtg || ptg is MemFuncPtg || ptg is MemErrPtg) { // marks the start of a list of area expressions which will be naturally combined // by their trailing operators (e.g. UnionPtg) // TODO - Put comment and throw exception in ToFormulaString() of these classes continue; } if (ptg is ParenthesisPtg) { String contents = (String)stack.Pop(); stack.Push("(" + contents + ")"); continue; } if (ptg is AttrPtg) { AttrPtg attrPtg = ((AttrPtg)ptg); if (attrPtg.IsOptimizedIf || attrPtg.IsOptimizedChoose || attrPtg.IsSkip) { continue; } if (attrPtg.IsSpace) { // POI currently doesn't render spaces in formulas continue; // but if it ever did, care must be taken: // tAttrSpace comes *before* the operand it applies To, which may be consistent // with how the formula text appears but is against the RPN ordering assumed here } if (attrPtg.IsSemiVolatile) { // similar To tAttrSpace - RPN is violated continue; } if (attrPtg.IsSum) { String[] operands = GetOperands(stack, attrPtg.NumberOfOperands); stack.Push(attrPtg.ToFormulaString(operands)); continue; } throw new Exception("Unexpected tAttr: " + attrPtg.ToString()); } if (ptg is WorkbookDependentFormula) { WorkbookDependentFormula optg = (WorkbookDependentFormula)ptg; stack.Push(optg.ToFormulaString(book)); continue; } if (!(ptg is OperationPtg)) { stack.Push(ptg.ToFormulaString()); continue; } OperationPtg o = (OperationPtg)ptg; String[] operands1 = GetOperands(stack, o.NumberOfOperands); stack.Push(o.ToFormulaString(operands1)); } if (stack.Count == 0) { // inspection of the code above reveals that every stack.pop() is followed by a // stack.push(). So this is either an internal error or impossible. throw new InvalidOperationException("Stack underflow"); } String result = (String)stack.Pop(); if (stack.Count != 0) { // Might be caused by some Tokens like AttrPtg and Mem*Ptg, which really shouldn't // Put anything on the stack throw new InvalidOperationException("too much stuff left on the stack"); } return result; }
private Ptg AdjustPtgDueToShiftMove(Ptg ptg) { Ptg updatedPtg = null; if (ptg is Ref3DPtg) { Ref3DPtg ref1 = (Ref3DPtg)ptg; if (ref1.ExternSheetIndex == _srcSheetIndex) { ref1.ExternSheetIndex = (_dstSheetIndex); updatedPtg = ref1; } else if (ref1.ExternSheetIndex == _dstSheetIndex) { ref1.ExternSheetIndex = (_srcSheetIndex); updatedPtg = ref1; } } return updatedPtg; }
/** * @param in the stream to read data from * @param cbFContinued the seconf short in the record header * @param cmoOt the Containing Obj's {@link CommonObjectDataSubRecord#field_1_objectType} */ public LbsDataSubRecord(ILittleEndianInput in1, int cbFContinued, int cmoOt) { _cbFContinued = cbFContinued; int encodedTokenLen = in1.ReadUShort(); if (encodedTokenLen > 0) { int formulaSize = in1.ReadUShort(); _unknownPreFormulaInt = in1.ReadInt(); Ptg[] ptgs = Ptg.ReadTokens(formulaSize, in1); if (ptgs.Length != 1) { throw new RecordFormatException("Read " + ptgs.Length + " tokens but expected exactly 1"); } _linkPtg = ptgs[0]; switch (encodedTokenLen - formulaSize - 6) { case 1: _unknownPostFormulaByte = (byte)in1.ReadByte(); break; case 0: _unknownPostFormulaByte = null; break; default: throw new RecordFormatException("Unexpected leftover bytes"); } } _cLines = in1.ReadUShort(); _iSel = in1.ReadUShort(); _flags = in1.ReadUShort(); _idEdit = in1.ReadUShort(); // From [MS-XLS].pdf 2.5.147 FtLbsData: // This field MUST exist if and only if the Containing Obj?s cmo.ot is equal to 0x14. if (cmoOt == 0x14) { _dropData = new LbsDropData(in1); } // From [MS-XLS].pdf 2.5.147 FtLbsData: // This array MUST exist if and only if the fValidPlex flag (0x2) is set if ((_flags & 0x2) != 0) { _rgLines = new String[_cLines]; for (int i = 0; i < _cLines; i++) { _rgLines[i] = StringUtil.ReadUnicodeString(in1); } } // bits 5-6 in the _flags specify the type // of selection behavior this list control is expected to support // From [MS-XLS].pdf 2.5.147 FtLbsData: // This array MUST exist if and only if the wListType field is not equal to 0. if (((_flags >> 4) & 0x2) != 0) { _bsels = new bool[_cLines]; for (int i = 0; i < _cLines; i++) { _bsels[i] = in1.ReadByte() == 1; } } }
public DVRecord(int validationType, int operator1, int errorStyle, bool emptyCellAllowed, bool suppressDropDownArrow, bool isExplicitList, bool showPromptBox, String promptTitle, String promptText, bool showErrorBox, String errorTitle, String errorText, Ptg[] formula1, Ptg[] formula2, CellRangeAddressList regions) { int flags = 0; flags = opt_data_type.SetValue(flags, validationType); flags = opt_condition_operator.SetValue(flags, operator1); flags = opt_error_style.SetValue(flags, errorStyle); flags = opt_empty_cell_allowed.SetBoolean(flags, emptyCellAllowed); flags = opt_suppress_dropdown_arrow.SetBoolean(flags, suppressDropDownArrow); flags = opt_string_list_formula.SetBoolean(flags, isExplicitList); flags = opt_show_prompt_on_cell_selected.SetBoolean(flags, showPromptBox); flags = opt_show_error_on_invalid_value.SetBoolean(flags, showErrorBox); _option_flags = flags; _promptTitle = ResolveTitleText(promptTitle); _promptText = ResolveTitleText(promptText); _errorTitle = ResolveTitleText(errorTitle); _errorText = ResolveTitleText(errorText); _formula1 = Zephyr.Utils.NPOI.SS.Formula.Formula.Create(formula1); _formula2 = Zephyr.Utils.NPOI.SS.Formula.Formula.Create(formula2); _regions = regions; }
private Ptg AdjustPtg(Ptg ptg, int currentExternSheetIx) { //return AdjustPtgDueToRowMove(ptg, currentExternSheetIx); switch (_mode) { case ShiftMode.Row: return AdjustPtgDueToRowMove(ptg, currentExternSheetIx); case ShiftMode.Sheet: return AdjustPtgDueToShiftMove(ptg); default: throw new InvalidOperationException("Unsupported shift mode: " + _mode); } }
public void SetArrayFormula(CellRangeAddress r, Ptg[] ptgs) { ArrayRecord arr = new ArrayRecord(Zephyr.Utils.NPOI.SS.Formula.Formula.Create(ptgs), new CellRangeAddress8Bit(r.FirstRow, r.LastRow, r.FirstColumn, r.LastColumn)); _sharedValueManager.AddArrayRecord(arr); }
private static bool IsDeletedCellRef(Ptg ptg) { if (ptg == ErrPtg.REF_INVALID) { return true; } if (ptg is DeletedArea3DPtg) { return true; } if (ptg is DeletedRef3DPtg) { return true; } if (ptg is AreaErrPtg) { return true; } if (ptg is RefErrorPtg) { return true; } return false; }
/** * Also checks for a related shared formula and unlinks it if found */ public void SetParsedExpression(Ptg[] ptgs) { NotifyFormulaChanging(); _formulaRecord.ParsedExpression=(ptgs); }
public ParseNode(Ptg token, ParseNode child0, ParseNode child1): this(token, new ParseNode[] { child0, child1, }) { }
public ParseNode(Ptg token):this(token, EMPTY_ARRAY) { }
public void Add(Ptg token) { if (token == null) { throw new ArgumentException("token must not be null"); } _ptgs[_offset] = token; _offset++; }
public void SetPlaceholder(int index, Ptg token) { if (_ptgs[index] != null) { throw new InvalidOperationException("Invalid placeholder index (" + index + ")"); } _ptgs[index] = token; }
/** * Creates a {@link Formula} object from a supplied {@link Ptg} array. * Handles <code>null</code>s OK. * @param ptgs may be <code>null</code> * @return Never <code>null</code> (Possibly empty if the supplied <c>ptgs</c> is <code>null</code>) */ public static Formula Create(Ptg[] ptgs) { if (ptgs == null || ptgs.Length < 1) { return EMPTY; } int totalSize = Ptg.GetEncodedSize(ptgs); byte[] encodedData = new byte[totalSize]; Ptg.SerializePtgs(ptgs, encodedData, 0); int encodedTokenLen = Ptg.GetEncodedSizeWithoutArrayData(ptgs); return new Formula(encodedData, encodedTokenLen); }
/** * Generates the variable Function ptg for the formula. * * For IF Formulas, Additional PTGs are Added To the Tokens * @param name a {@link NamePtg} or {@link NameXPtg} or <code>null</code> * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this Function */ private ParseNode GetFunction(String name, Ptg namePtg, ParseNode[] args) { FunctionMetadata fm = FunctionMetadataRegistry.GetFunctionByName(name.ToUpper()); int numArgs = args.Length; if (fm == null) { if (namePtg == null) { throw new InvalidOperationException("NamePtg must be supplied for external Functions"); } // must be external Function ParseNode[] allArgs = new ParseNode[numArgs + 1]; allArgs[0] = new ParseNode(namePtg); System.Array.Copy(args, 0, allArgs, 1, numArgs); return new ParseNode(FuncVarPtg.Create(name, (byte)(numArgs + 1)), allArgs); } if (namePtg != null) { throw new InvalidOperationException("NamePtg no applicable To internal Functions"); } bool IsVarArgs = !fm.HasFixedArgsLength; int funcIx = fm.Index; if (funcIx == FunctionMetadataRegistry.FUNCTION_INDEX_SUM && args.Length == 1) { // Excel encodes the sum of a single argument as tAttrSum // POI does the same for consistency, but this is not critical return new ParseNode(AttrPtg.GetSumSingle(), args); // The code below would encode tFuncVar(SUM) which seems to do no harm } ValidateNumArgs(args.Length, fm); AbstractFunctionPtg retval; if (IsVarArgs) { retval = FuncVarPtg.Create(name, (byte)numArgs); } else { retval = FuncPtg.Create(funcIx); } return new ParseNode(retval, args); }
/** * @param ptgs - if necessary, will get modified by this method * @param currentExternSheetIx - the extern sheet index of the sheet that contains the formula being adjusted * @return <c>true</c> if a change was made to the formula tokens */ public bool AdjustFormula(Ptg[] ptgs, int currentExternSheetIx) { bool refsWereChanged = false; for (int i = 0; i < ptgs.Length; i++) { Ptg newPtg = AdjustPtg(ptgs[i], currentExternSheetIx); if (newPtg != null) { refsWereChanged = true; ptgs[i] = newPtg; } } return refsWereChanged; }
private static Double ConvertArrayNumber(Ptg ptg, bool isPositive) { double value; if (ptg is IntPtg) { value = ((IntPtg)ptg).Value; } else if (ptg is NumberPtg) { value = ((NumberPtg)ptg).Value; } else { throw new Exception("Unexpected ptg (" + ptg.GetType().Name + ")"); } if (!isPositive) { value = -value; } return value; }
/** * @return <c>true</c> if this Ptg needed to be changed */ private Ptg AdjustPtgDueToRowMove(Ptg ptg, int currentExternSheetIx) { if (ptg is RefPtg) { if (currentExternSheetIx != _externSheetIndex) { // local refs on other sheets are unaffected return null; } RefPtg rptg = (RefPtg)ptg; return RowMoveRefPtg(rptg); } if (ptg is Ref3DPtg) { Ref3DPtg rptg = (Ref3DPtg)ptg; if (_externSheetIndex != rptg.ExternSheetIndex) { // only move 3D refs that refer to the sheet with cells being moved // (currentExternSheetIx is irrelevant) return null; } return RowMoveRefPtg(rptg); } if (ptg is Area2DPtgBase) { if (currentExternSheetIx != _externSheetIndex) { // local refs on other sheets are unaffected return ptg; } return RowMoveAreaPtg((Area2DPtgBase)ptg); } if (ptg is Area3DPtg) { Area3DPtg aptg = (Area3DPtg)ptg; if (_externSheetIndex != aptg.ExternSheetIndex) { // only move 3D refs that refer to the sheet with cells being moved // (currentExternSheetIx is irrelevant) return null; } return RowMoveAreaPtg(aptg); } return null; }
/** * * "A1", "B3" -> "A1:B3" * "sheet1!A1", "B3" -> "sheet1!A1:B3" * * @return <c>null</c> if the range expression cannot / shouldn't be reduced. */ private static Ptg ReduceRangeExpression(Ptg ptgA, Ptg ptgB) { if (!(ptgB is RefPtg)) { // only when second ref is simple 2-D ref can the range // expression be converted To an area ref return null; } RefPtg refB = (RefPtg)ptgB; if (ptgA is RefPtg) { RefPtg refA = (RefPtg)ptgA; return new AreaPtg(refA.Row, refB.Row, refA.Column, refB.Column, refA.IsRowRelative, refB.IsRowRelative, refA.IsColRelative, refB.IsColRelative); } if (ptgA is Ref3DPtg) { Ref3DPtg refA = (Ref3DPtg)ptgA; return new Area3DPtg(refA.Row, refB.Row, refA.Column, refB.Column, refA.IsRowRelative, refB.IsRowRelative, refA.IsColRelative, refB.IsColRelative, refA.ExternSheetIndex); } // Note - other operand types (like AreaPtg) which probably can't evaluate // do not cause validation errors at Parse time return null; }
private static Ptg CreateDeletedRef(Ptg ptg) { if (ptg is RefPtg) { return new RefErrorPtg(); } if (ptg is Ref3DPtg) { Ref3DPtg rptg = (Ref3DPtg)ptg; return new DeletedRef3DPtg(rptg.ExternSheetIndex); } if (ptg is AreaPtg) { return new AreaErrPtg(); } if (ptg is Area3DPtg) { Area3DPtg area3DPtg = (Area3DPtg)ptg; return new DeletedArea3DPtg(area3DPtg.ExternSheetIndex); } throw new ArgumentException("Unexpected ref ptg class (" + ptg.GetType().Name + ")"); }
/** * This method will return the same result as {@link #getEncodedSizeWithoutArrayData(Ptg[])} * if there are no array tokens present. * @return the full size taken to encode the specified <c>Ptg</c>s */ public static int GetEncodedSize(Ptg[] ptgs) { int result = 0; for (int i = 0; i < ptgs.Length; i++) { result += ptgs[i].Size; } return result; }
public FormulaPair(Ptg[] formula1, Ptg[] formula2) { _formula1 = formula1; _formula2 = formula2; }
/** * Used to calculate value that should be encoded at the start of the encoded Ptg token array; * @return the size of the encoded Ptg tokens not including any trailing array data. */ public static int GetEncodedSizeWithoutArrayData(Ptg[] ptgs) { int result = 0; for (int i = 0; i < ptgs.Length; i++) { Ptg ptg = ptgs[i]; if (ptg is ArrayPtg) { result += ArrayPtg.PLAIN_TOKEN_SIZE; } else { result += ptg.Size; } } return result; }
public void SetParsedExpression(Ptg[] ptgs) { field_5_name_definition = Formula.Create(ptgs); }
/** * Writes the ptgs to the data buffer, starting at the specified offset. * * <br/> * The 2 byte encode Length field is <b>not</b> written by this method. * @return number of bytes written */ public static int SerializePtgs(Ptg[] ptgs, byte[] array, int offset) { int size = ptgs.Length; LittleEndianByteArrayOutputStream out1 = new LittleEndianByteArrayOutputStream(array, offset); ArrayList arrayPtgs = null; for (int k = 0; k < size; k++) { Ptg ptg = ptgs[k]; ptg.Write(out1); if (ptg is ArrayPtg) { if (arrayPtgs == null) { arrayPtgs = new ArrayList(5); } arrayPtgs.Add(ptg); } } if (arrayPtgs != null) { for (int i = 0; i < arrayPtgs.Count; i++) { ArrayPtg p = (ArrayPtg)arrayPtgs[i]; p.WriteTokenValueBytes(out1); } } return out1.WriteIndex - offset; ; }
public void SetParsedExpression(Ptg[] ptgs) { field_8_parsed_expr = Zephyr.Utils.NPOI.SS.Formula.Formula.Create(ptgs); }
/** * Constructs an EmbeddedObjectRef record and Sets its fields appropriately. * * @param in the record input stream. */ public EmbeddedObjectRefSubRecord(ILittleEndianInput in1, int size) { // Much guess-work going on here due to lack of any documentation. // See similar source code in OOO: // http://lxr.go-oo.org/source/sc/sc/source/filter/excel/xiescher.cxx // 1223 void XclImpOleObj::ReadPictFmla( XclImpStream& rStrm, sal_uInt16 nRecSize ) int streamIdOffset = in1.ReadShort(); // OOO calls this 'nFmlaLen' int remaining = size - LittleEndianConsts.SHORT_SIZE; int dataLenAfterFormula = remaining - streamIdOffset; int formulaSize = in1.ReadUShort(); remaining -= LittleEndianConsts.SHORT_SIZE; field_1_unknown_int = in1.ReadInt(); remaining -= LittleEndianConsts.INT_SIZE; byte[] formulaRawBytes = ReadRawData(in1, formulaSize); remaining -= formulaSize; field_2_refPtg = ReadRefPtg(formulaRawBytes); if (field_2_refPtg == null) { // common case // field_2_n16 seems to be 5 here // The formula almost looks like tTbl but the row/column values seem like garbage. field_2_unknownFormulaData = formulaRawBytes; } else { field_2_unknownFormulaData = null; } int stringByteCount; if (remaining >= dataLenAfterFormula + 3) { int tag = in1.ReadByte(); stringByteCount = LittleEndianConsts.BYTE_SIZE; if (tag != 0x03) { throw new RecordFormatException("Expected byte 0x03 here"); } int nChars = in1.ReadUShort(); stringByteCount += LittleEndianConsts.SHORT_SIZE; if (nChars > 0) { // OOO: the 4th way Xcl stores a unicode string: not even a Grbit byte present if Length 0 field_3_unicode_flag = (in1.ReadByte() & 0x01) != 0; stringByteCount += LittleEndianConsts.BYTE_SIZE; if (field_3_unicode_flag) { field_4_ole_classname = StringUtil.ReadUnicodeLE(in1,nChars); stringByteCount += nChars * 2; } else { field_4_ole_classname = StringUtil.ReadCompressedUnicode(in1,nChars); stringByteCount += nChars; } } else { field_4_ole_classname = ""; } } else { field_4_ole_classname = null; stringByteCount = 0; } remaining -= stringByteCount; // Pad to next 2-byte boundary if (((stringByteCount + formulaSize) % 2) != 0) { int b = in1.ReadByte(); remaining -= LittleEndianConsts.BYTE_SIZE; if (field_2_refPtg != null && field_4_ole_classname == null) { field_4_unknownByte = (byte)b; } } int nUnexpectedPadding = remaining - dataLenAfterFormula; if (nUnexpectedPadding > 0) { Console.WriteLine("Discarding " + nUnexpectedPadding + " unexpected padding bytes "); ReadRawData(in1, nUnexpectedPadding); remaining -= nUnexpectedPadding; } // Fetch the stream ID if (dataLenAfterFormula >= 4) { field_5_stream_id = in1.ReadInt(); remaining -= LittleEndianConsts.INT_SIZE; } else { field_5_stream_id = null; } field_6_unknown = ReadRawData(in1, remaining); }