private void CheckFutureFunction(TParsedTokenListBuilder TokenBuilder, ref int np, TNameRecordList Names, ref TCellFunctionData fd2, TTokenOffset TokenOffset, ref bool HasAggregate) { //We need to recursively read parameters in back order to find out the name, which is stored as far as possible from the function :( TParsedTokenList ParsedList = TokenBuilder.ToParsedTokenList(); ParsedList.ResetPositionToLast(); for (int i = 0; i < np; i++) //np is +1. But we will move below the name, then inc 1, so we know there isn't a "neutral" token like parent or memarea, intead of the real thing. { ParsedList.Flush(); } ParsedList.MoveBack(); TNameToken bp = ParsedList.ForwardPop() as TNameToken; if (bp is TNameXToken) { return; //This name isn't an internal 2007 name. } if (bp == null) { return; } if (bp.NameIndex <= 0 || bp.NameIndex > Names.Count) { return; } string FunctionName = Names[bp.NameIndex - 1].Name; if (FunctionName.StartsWith("_xlfn.", StringComparison.InvariantCultureIgnoreCase)) { TCellFunctionData fn = TXlsFunction.GetData(FunctionName.Substring("_xlfn.".Length)); if (fn != null) { if (fn.Index == (int)TFutureFunctions.Aggregate) { HasAggregate = true; } fd2 = fn; int tPos = ParsedList.SavePosition(); TokenBuilder.RemoveAt(tPos); TokenOffset.RemoveToken(tPos); np--; } } }
private static string GetFuncName(TBaseFunctionToken Token, out int ArgCount, bool WritingXlsx, out bool IsAddin) { TCellFunctionData fd = Token.GetFunctionData(); ArgCount = Token.ArgumentCount; IsAddin = Token is TUserDefinedToken; if (IsAddin) { ArgCount--; return(String.Empty); } if (WritingXlsx && fd.FutureInXlsx) { return(fd.FutureName); } return(fd.Name); }
private bool Evaluate(TParsedTokenListBuilder TokenBuilder, TTokenOffset TokenOffset, TNameRecordList Names, ptg BaseToken, ptg RealToken, byte[] RPN, ref int tPos, ref int ArrayPos, ref TUnsupportedFormulaErrorType ErrType, ref string ErrName, ref bool HasSubtotal, ref bool HasAggregate) { switch (BaseToken) { case ptg.Exp: AddParsedExp(TokenBuilder, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 3)); tPos += 4; break; case ptg.Tbl: AddParsedTable(TokenBuilder, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 3)); tPos += 4; break; case ptg.Add: case ptg.Sub: case ptg.Mul: case ptg.Div: case ptg.Power: case ptg.Concat: case ptg.LT: case ptg.LE: case ptg.EQ: case ptg.GE: case ptg.GT: case ptg.NE: case ptg.Uminus: case ptg.Percent: case ptg.Uplus: AddParsedOp(TokenBuilder, (TOperator)BaseToken); break; case ptg.MissArg: AddMissingArg(TokenBuilder); break; case ptg.Isect: AddParsedSep(TokenBuilder, BaseToken); break; case ptg.Union: AddParsedSep(TokenBuilder, BaseToken); break; case ptg.Range: AddParsedSep(TokenBuilder, BaseToken); break; case ptg.Paren: Push(TokenBuilder, TParenToken.Instance); break; case ptg.Str: long sl = 0; string Result = null; StrOps.GetSimpleString(false, RPN, tPos + 1, false, 0, ref Result, ref sl); AddParsed(TokenBuilder, Result); tPos += (int)sl; break; case ptg.Attr: int AttrLen = 0; if (!ProcessAttr(TokenBuilder, RPN, tPos + 1, ref AttrLen)) { return(false); } tPos += AttrLen; break; case ptg.Sheet: return(false); case ptg.EndSheet: return(false); case ptg.Err: AddParsed(TokenBuilder, (TFlxFormulaErrorValue)RPN[tPos + 1]); tPos++; break; case ptg.Bool: AddParsed(TokenBuilder, RPN[tPos + 1] == 1); tPos++; break; case ptg.Int: AddParsed16(TokenBuilder, BitOps.GetWord(RPN, tPos + 1)); tPos += 2; break; case ptg.Num: AddParsed(TokenBuilder, BitConverter.ToDouble(RPN, tPos + 1)); tPos += 8; break; case ptg.Array: Push(TokenBuilder, GetArrayDataToken(RealToken, RPN, ref ArrayPos)); tPos += 7; break; case ptg.Func: bool Result1; int index = BitOps.GetWord(RPN, tPos + 1); TCellFunctionData fd = TXlsFunction.GetData(index, out Result1); if (!Result1) { return(false); } Debug.Assert(fd.MinArgCount == fd.MaxArgCount, "On a fixed formula the min count of arguments should be the same as the max"); AddParsedFormula(TokenBuilder, RealToken, fd, (byte)fd.MinArgCount); tPos += 2; break; case ptg.FuncVar: bool Result2; int index2 = BitOps.GetWord(RPN, tPos + 2); TCellFunctionData fd2 = TXlsFunction.GetData(index2, out Result2); if (!Result2) { return(false); } if (fd2.Index == 344) // SubTotal { HasSubtotal = true; } int np = RPN[tPos + 1] & 0x7F; if (fd2.Index == 255) { CheckFutureFunction(TokenBuilder, ref np, Names, ref fd2, TokenOffset, ref HasAggregate); } AddParsedFormula(TokenBuilder, RealToken, fd2, (byte)np); tPos += 3; break; case ptg.Name: Push(TokenBuilder, new TNameToken(RealToken, BitOps.GetWord(RPN, tPos + 1))); tPos += 4; break; case ptg.NameX: Push(TokenBuilder, new TNameXToken(RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 3))); tPos += 6; break; case ptg.RefErr: case ptg.Ref: AddParsedRef(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1)); tPos += 4; break; case ptg.RefN: AddParsedRefN(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1)); tPos += 4; break; case ptg.AreaErr: case ptg.Area: AddParsedArea(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1), BitOps.GetWord(RPN, tPos + 4 + 1), BitOps.GetWord(RPN, tPos + 6 + 1)); tPos += 8; break; case ptg.AreaN: AddParsedAreaN(TokenBuilder, RealToken, BitOps.GetWord(RPN, tPos + 1), BitOps.GetWord(RPN, tPos + 2 + 1), BitOps.GetWord(RPN, tPos + 4 + 1), BitOps.GetWord(RPN, tPos + 6 + 1)); tPos += 8; break; case ptg.MemArea: { int ArrayLen; Push(TokenBuilder, new TMemAreaToken(RealToken, GetMemControl(RPN, ArrayPos, out ArrayLen), tPos + 1 + 6 + BitOps.GetWord(RPN, tPos + 1 + 4))); ArrayPos += ArrayLen; tPos += 6; break; //this is an optimization, but we don't need it. } case ptg.MemErr: { Push(TokenBuilder, new TMemErrToken(RealToken, (TFlxFormulaErrorValue)RPN[tPos + 1], tPos + 1 + 6 + BitOps.GetWord(RPN, tPos + 1 + 4))); tPos += 6; break; //this is an optimization, but we don't need it. } case ptg.MemNoMem: { Push(TokenBuilder, new TMemNoMemToken(RealToken, tPos + 1 + 6 + BitOps.GetWord(RPN, tPos + 1 + 4))); tPos += 6; break; //this is an optimization, but we don't need it. } case ptg.MemFunc: { Push(TokenBuilder, new TMemFuncToken(RealToken, tPos + 1 + 2 + BitOps.GetWord(RPN, tPos + 1))); tPos += 2; break; //this is an optimization, but we don't need it. } case ptg.MemAreaN: { Push(TokenBuilder, new TMemAreaNToken(RealToken, tPos + 1 + 2 + BitOps.GetWord(RPN, tPos + 1))); tPos += 2; break; //this is an optimization, but we don't need it. } case ptg.MemNoMemN: { Push(TokenBuilder, new TMemNoMemNToken(RealToken, tPos + 1 + 2 + BitOps.GetWord(RPN, tPos + 1))); tPos += 2; break; //this is an optimization, but we don't need it. } case ptg.Ref3dErr: case ptg.Ref3d: { int grBit1 = BitOps.GetWord(RPN, tPos + 4 + 1); int ExternSheet = BitOps.GetWord(RPN, tPos + 1); int Row1 = BitOps.GetWord(RPN, tPos + 2 + 1); AddParsed3dRef(TokenBuilder, RealToken, ExternSheet, Row1, grBit1); tPos += 6; break; } case ptg.Area3dErr: case ptg.Area3d: { int ExternSheet = BitOps.GetWord(RPN, tPos + 1); int Row1 = BitOps.GetWord(RPN, tPos + 2 + 1); int Row2 = BitOps.GetWord(RPN, tPos + 4 + 1); int grBit1 = BitOps.GetWord(RPN, tPos + 6 + 1); int grBit2 = BitOps.GetWord(RPN, tPos + 8 + 1); AddParsed3dArea(TokenBuilder, RealToken, ExternSheet, Row1, Row2, grBit1, grBit2); tPos += 10; break; } default: return(false); } return(true); }
protected static void AddParsedFormula(TParsedTokenListBuilder TokenBuilder, ptg FmlaPtg, TCellFunctionData Func, byte ArgCount) { TBaseParsedToken FmlaToken = TParsedTokenListBuilder.GetParsedFormula(FmlaPtg, Func, ArgCount); Push(TokenBuilder, FmlaToken); //Always push unsupported. }
private static bool BackFromFutureToUserDef(Stream Data, TParsedTokenList Tokens, Int32List FuturePos, TBaseFunctionToken ft, TCellFunctionData fd) { string FutureName = fd.FutureName; if (FutureName != null) { Data.WriteByte((byte)(ft.ArgumentCount + 1)); WriteWord(Data, 0xFF); //User def... FuturePos.Add(Tokens.SavePosition()); return(true); } return(false); }
private static void Add(Stream Data, Stream ArrayData, TBaseParsedToken Token, ptg BaseToken, TParsedTokenList Tokens, TTokenOffset StreamPos, TFormulaType FmlaType, Int32List FuturePos) { if (IsError(BaseToken, FmlaType)) { Data.WriteByte(0x1C); //PtgErr Data.WriteByte(0x2A); return; } Data.WriteByte((byte)Token.GetId); switch (BaseToken) { case ptg.Exp: TExp_Token exp = (TExp_Token)Token; Biff8Utils.CheckRow(exp.Row); Biff8Utils.CheckCol(exp.Col); WriteWord(Data, exp.Row); WriteWord(Data, exp.Col); break; case ptg.Tbl: TTableObjToken tblo = Token as TTableObjToken; if (tblo != null) { //no biff8 checks here. This numbers might be anything. WriteWord(Data, tblo.Row); WriteWord(Data, tblo.Col); } else { TTableToken tbl = (TTableToken)Token; Biff8Utils.CheckRow(tbl.Row); Biff8Utils.CheckCol(tbl.Col); WriteWord(Data, tbl.Row); WriteWord(Data, tbl.Col); } break; case ptg.Add: case ptg.Sub: case ptg.Mul: case ptg.Div: case ptg.Power: case ptg.Concat: case ptg.LT: case ptg.LE: case ptg.EQ: case ptg.GE: case ptg.GT: case ptg.NE: case ptg.Isect: case ptg.Union: case ptg.Range: case ptg.Uplus: case ptg.Uminus: case ptg.Percent: case ptg.Paren: case ptg.MissArg: break; case ptg.Str: { TStrDataToken tkd = Token as TStrDataToken; string s = tkd.GetData(); if (s.Length > FlxConsts.Max_FormulaStringConstant) { FlxMessages.ThrowException(FlxErr.ErrStringConstantInFormulaTooLong, s, String.Empty); } TExcelString Xs = new TExcelString(TStrLenLength.is8bits, s, null, false); byte[] b = new byte[Xs.TotalSize()]; Xs.CopyToPtr(b, 0); Data.Write(b, 0, b.Length); break; } case ptg.Attr: WriteAttr(Data, Token, StreamPos, Tokens.SavePosition()); break; /* * case ptg.Sheet: //Can't happen, ConvertBiff8ToInternal skips them. * case ptg.EndSheet: //Can't happen, ConvertBiff8ToInternal skips them. * break;*/ case ptg.Err: { Data.WriteByte((byte)((TErrDataToken)Token).GetData()); break; } case ptg.Bool: { if (((TBoolDataToken)Token).GetData()) { Data.WriteByte(1); } else { Data.WriteByte(0); } break; } case ptg.Int: { UInt16 a = (UInt16)((TIntDataToken)Token).GetData(); WriteWord(Data, a); break; } case ptg.Num: { double d = ((TNumDataToken)Token).GetData(); Data.Write(BitConverter.GetBytes(d), 0, 8); break; } case ptg.Array: { Data.Write(new byte[7], 0, 7); TArrayDataToken tk = (TArrayDataToken)Token; object[,] Arr = tk.GetData; int ColCount = Arr.GetLength(1) - 1; if (ColCount < 0 || ColCount > FlxConsts.Max_Columns97_2003) { FlxMessages.ThrowException(FlxErr.ErrInvalidCols, ColCount, FlxConsts.Max_Columns97_2003 + 1); } ArrayData.WriteByte((byte)(ColCount)); int RowCount = Arr.GetLength(0) - 1; if (RowCount < 0 || RowCount > FlxConsts.Max_Rows) { FlxMessages.ThrowException(FlxErr.ErrInvalidRows, RowCount, FlxConsts.Max_Rows + 1); } WriteWord(ArrayData, RowCount); for (int r = 0; r <= RowCount; r++) { for (int c = 0; c <= ColCount; c++) { WriteArrayObject(ArrayData, Arr[r, c]); } } break; } case ptg.Func: { TBaseFunctionToken ft = (TBaseFunctionToken)Token; TCellFunctionData fd = ft.GetFunctionData(); WriteWord(Data, fd.Index); break; } case ptg.FuncVar: { TBaseFunctionToken ft = (TBaseFunctionToken)Token; TCellFunctionData fd = ft.GetFunctionData(); if (!BackFromFutureToUserDef(Data, Tokens, FuturePos, ft, fd)) { Data.WriteByte((byte)ft.ArgumentCount); WriteWord(Data, fd.Index); } break; } case ptg.Name: WriteWord(Data, ((TNameToken)Token).NameIndex); WriteWord(Data, 0); break; case ptg.Ref: case ptg.RefN: case ptg.RefErr: { TRefToken reft = (TRefToken)Token; WriteRef(Data, reft.CanHaveRelativeOffsets, reft.Row, reft.RowAbs, reft.Col, reft.ColAbs); break; } case ptg.Area: case ptg.AreaN: case ptg.AreaErr: { TAreaToken areat = (TAreaToken)Token; WriteArea(Data, areat.CanHaveRelativeOffsets, areat.Row1, areat.RowAbs1, areat.Col1, areat.ColAbs1, areat.Row2, areat.RowAbs2, areat.Col2, areat.ColAbs2); break; } case ptg.MemArea: { WriteWord(Data, 0); WriteWord(Data, 0); StreamPos.Add((int)Data.Position, Tokens.SavePosition()); WriteWord(Data, 0); TRefRange[] Range = ((TMemAreaToken)Token).Data; WriteWord(ArrayData, Range.Length); foreach (TRefRange OneRef in Range) { int r1 = Biff8Utils.CheckAndContractBiff8Row(OneRef.FirstRow); int r2 = Biff8Utils.CheckAndContractBiff8Row(OneRef.LastRow); int c1 = Biff8Utils.CheckAndContractBiff8Col(OneRef.FirstCol); int c2 = Biff8Utils.CheckAndContractBiff8Col(OneRef.LastCol); WriteWord(ArrayData, r1); WriteWord(ArrayData, r2); WriteWord(ArrayData, c1); WriteWord(ArrayData, c2); } break; } case ptg.MemErr: case ptg.MemNoMem: WriteWord(Data, 0); WriteWord(Data, 0); StreamPos.Add((int)Data.Position, Tokens.SavePosition()); WriteWord(Data, 0); break; case ptg.MemFunc: case ptg.MemAreaN: case ptg.MemNoMemN: StreamPos.Add((int)Data.Position, Tokens.SavePosition()); WriteWord(Data, 0); break; case ptg.NameX: TNameXToken NameX = (TNameXToken)Token; WriteWord(Data, NameX.FExternSheet); WriteWord(Data, NameX.NameIndex); WriteWord(Data, 0); break; case ptg.Ref3dErr: case ptg.Ref3d: TRef3dToken reft3d = (TRef3dToken)Token; WriteWord(Data, reft3d.FExternSheet); WriteRef(Data, reft3d.CanHaveRelativeOffsets, reft3d.Row, reft3d.RowAbs, reft3d.Col, reft3d.ColAbs); break; case ptg.Area3d: case ptg.Area3dErr: TArea3dToken areat3d = (TArea3dToken)Token; WriteWord(Data, areat3d.FExternSheet); WriteArea(Data, areat3d.CanHaveRelativeOffsets, areat3d.Row1, areat3d.RowAbs1, areat3d.Col1, areat3d.ColAbs1, areat3d.Row2, areat3d.RowAbs2, areat3d.Col2, areat3d.ColAbs2); break; default: XlsMessages.ThrowException(XlsErr.ErrInternal); //All tokens here should exist break; } }