diff -pudr sc/inc/compiler.hrc sc/inc/compiler.hrc --- sc/inc/compiler.hrc 2007-03-11 06:44:27.000000000 -0400 +++ sc/inc/compiler.hrc 2007-03-11 13:15:50.000000000 -0400 @@ -58,44 +58,47 @@ #define SC_OPCODE_MACRO 15 #define SC_OPCODE_COL_ROW_NAME 16 #define SC_OPCODE_COL_ROW_NAME_AUTO 17 -#define SC_OPCODE_PERCENT_SIGN 18 /* operator _follows_ value */ -#define SC_OPCODE_END_DIV 20 +#define SC_OPCODE_PERCENT_SIGN 18 /* operator _follows_ value */ +#define SC_OPCODE_ARRAY_OPEN 19 +#define SC_OPCODE_ARRAY_CLOSE 20 +#define SC_OPCODE_ARRAY_ROW_SEP 21 +#define SC_OPCODE_END_DIV 22 /*** Binaere Operatoren ***/ -#define SC_OPCODE_ADD 21 -#define SC_OPCODE_SUB 22 -#define SC_OPCODE_MUL 23 -#define SC_OPCODE_DIV 24 -#define SC_OPCODE_AMPERSAND 25 -#define SC_OPCODE_POW 26 -#define SC_OPCODE_EQUAL 27 -#define SC_OPCODE_NOT_EQUAL 28 -#define SC_OPCODE_LESS 29 -#define SC_OPCODE_GREATER 30 -#define SC_OPCODE_LESS_EQUAL 31 -#define SC_OPCODE_GREATER_EQUAL 32 -#define SC_OPCODE_AND 33 -#define SC_OPCODE_OR 34 -#define SC_OPCODE_INTERSECT 35 -#define SC_OPCODE_UNION 36 -#define SC_OPCODE_RANGE 37 -#define SC_OPCODE_END_BIN_OP 40 +#define SC_OPCODE_ADD 25 +#define SC_OPCODE_SUB 26 +#define SC_OPCODE_MUL 27 +#define SC_OPCODE_DIV 28 +#define SC_OPCODE_AMPERSAND 29 +#define SC_OPCODE_POW 30 +#define SC_OPCODE_EQUAL 31 +#define SC_OPCODE_NOT_EQUAL 32 +#define SC_OPCODE_LESS 33 +#define SC_OPCODE_GREATER 34 +#define SC_OPCODE_LESS_EQUAL 35 +#define SC_OPCODE_GREATER_EQUAL 36 +#define SC_OPCODE_AND 37 +#define SC_OPCODE_OR 38 +#define SC_OPCODE_INTERSECT 39 +#define SC_OPCODE_UNION 40 +#define SC_OPCODE_RANGE 41 +#define SC_OPCODE_END_BIN_OP 44 /*** Unaere Operatoren ***/ -#define SC_OPCODE_NOT 41 -#define SC_OPCODE_NEG 42 -#define SC_OPCODE_NEG_SUB 43 -#define SC_OPCODE_END_UN_OP 45 +#define SC_OPCODE_NOT 45 +#define SC_OPCODE_NEG 46 +#define SC_OPCODE_NEG_SUB 47 +#define SC_OPCODE_END_UN_OP 48 /*** Funktionen ohne Parameter ***/ -#define SC_OPCODE_PI 46 -#define SC_OPCODE_RANDOM 47 -#define SC_OPCODE_TRUE 48 -#define SC_OPCODE_FALSE 49 -#define SC_OPCODE_GET_ACT_DATE 50 -#define SC_OPCODE_GET_ACT_TIME 51 -#define SC_OPCODE_NO_VALUE 52 -#define SC_OPCODE_CURRENT 53 +#define SC_OPCODE_PI 50 +#define SC_OPCODE_RANDOM 51 +#define SC_OPCODE_TRUE 52 +#define SC_OPCODE_FALSE 53 +#define SC_OPCODE_GET_ACT_DATE 54 +#define SC_OPCODE_GET_ACT_TIME 55 +#define SC_OPCODE_NO_VALUE 56 +#define SC_OPCODE_CURRENT 57 #define SC_OPCODE_END_NO_PAR 60 /*** Funktionen mit einem Parameter ***/ diff -pudr sc/inc/compiler.hxx sc/inc/compiler.hxx --- sc/inc/compiler.hxx 2007-03-11 06:44:27.000000000 -0400 +++ sc/inc/compiler.hxx 2007-03-11 13:15:50.000000000 -0400 @@ -319,6 +319,7 @@ private: void PushTokenArray( ScTokenArray*, BOOL = FALSE ); void PopTokenArray(); void SetRelNameReference(); + void CreateStringFromScMatrix( rtl::OUStringBuffer& rBuffer, const ScMatrix* pMatrix ); public: ScCompiler(ScDocument* pDocument, const ScAddress& ); diff -pudr sc/inc/errorcodes.hxx sc/inc/errorcodes.hxx --- sc/inc/errorcodes.hxx 2007-03-11 06:44:27.000000000 -0400 +++ sc/inc/errorcodes.hxx 2007-03-11 13:15:50.000000000 -0400 @@ -83,6 +83,7 @@ const USHORT errNoAddin = 5 // Interpreter: needed Macro not found const USHORT errNoMacro = 531; const USHORT errDivisionByZero = 532; // #DIV/0! +const USHORT errNestedArray = 533; // Interpreter: NA() not available condition, not a real error const USHORT NOVALUE = 0x7fff; diff -pudr sc/inc/globstr.hrc sc/inc/globstr.hrc --- sc/inc/globstr.hrc 2007-03-11 06:44:27.000000000 -0400 +++ sc/inc/globstr.hrc 2007-03-11 13:15:50.000000000 -0400 @@ -561,7 +561,9 @@ #define STR_UNDO_TAB_R1C1 418 -#define STR_COUNT 419 +#define STR_ERR_NESTED_ARRAY 419 + +#define STR_COUNT 420 #endif diff -pudr sc/inc/opcode.hxx sc/inc/opcode.hxx --- sc/inc/opcode.hxx 2007-03-11 06:44:27.000000000 -0400 +++ sc/inc/opcode.hxx 2007-03-11 13:15:50.000000000 -0400 @@ -58,6 +58,10 @@ enum OpCodeEnum ocOpen = SC_OPCODE_OPEN, ocClose = SC_OPCODE_CLOSE, ocSep = SC_OPCODE_SEP, + ocArrayOpen = SC_OPCODE_ARRAY_OPEN, + ocArrayClose = SC_OPCODE_ARRAY_CLOSE, + ocArrayRowSep = SC_OPCODE_ARRAY_ROW_SEP, + // Spezial-Opcodes ocMissing = SC_OPCODE_MISSING, ocBad = SC_OPCODE_BAD, diff -pudr sc/inc/tokenarray.hxx sc/inc/tokenarray.hxx --- sc/inc/tokenarray.hxx 2007-03-11 06:44:27.000000000 -0400 +++ sc/inc/tokenarray.hxx 2007-03-11 13:15:50.000000000 -0400 @@ -224,6 +224,7 @@ public: ScToken* AddColRowName( const SingleRefData& rRef ); ScToken* AddBad( const sal_Unicode* pStr ); /// ocBad with String ScToken* AddBad( const String& rStr ); /// ocBad with String + ScToken* MergeArray( ); /// Assignment with references to ScToken entries (not copied!) ScTokenArray& operator=( const ScTokenArray& ); diff -pudr sc/source/core/data/global.cxx sc/source/core/data/global.cxx --- sc/source/core/data/global.cxx 2007-03-11 06:44:27.000000000 -0400 +++ sc/source/core/data/global.cxx 2007-03-11 13:15:50.000000000 -0400 @@ -488,6 +488,9 @@ String ScGlobal::GetLongErrorString(USHO case errDivisionByZero: nErrNumber = STR_LONG_ERR_DIV_ZERO; break; + case errNestedArray: + nErrNumber = STR_ERR_NESTED_ARRAY; + break; case errNoValue: nErrNumber = STR_LONG_ERR_NO_VALUE; break; diff -pudr sc/source/core/src/compiler.src sc/source/core/src/compiler.src --- sc/source/core/src/compiler.src 2007-03-11 06:44:27.000000000 -0400 +++ sc/source/core/src/compiler.src 2007-03-11 13:15:50.000000000 -0400 @@ -51,6 +51,9 @@ Resource RID_SC_FUNCTION_NAMES }; String SC_OPCODE_OPEN { Text = "(" ; }; String SC_OPCODE_CLOSE { Text = ")" ; }; + String SC_OPCODE_ARRAY_OPEN { Text = "{" ; }; + String SC_OPCODE_ARRAY_CLOSE { Text = "}" ; }; + String SC_OPCODE_ARRAY_ROW_SEP { Text = "|" ; }; String SC_OPCODE_SEP { Text = ";" ; }; String SC_OPCODE_PERCENT_SIGN { Text = "%" ; }; String SC_OPCODE_ADD { Text = "+" ; }; @@ -1700,6 +1703,9 @@ Resource RID_SC_FUNCTION_NAMES_ENGLISH String SC_OPCODE_CHOSE { Text = "CHOOSE" ; }; String SC_OPCODE_OPEN { Text = "(" ; }; String SC_OPCODE_CLOSE { Text = ")" ; }; + String SC_OPCODE_ARRAY_OPEN { Text = "{" ; }; + String SC_OPCODE_ARRAY_CLOSE { Text = "}" ; }; + String SC_OPCODE_ARRAY_ROW_SEP { Text = "|" ; }; String SC_OPCODE_SEP { Text = ";" ; }; String SC_OPCODE_PERCENT_SIGN { Text = "%" ; }; String SC_OPCODE_ADD { Text = "+" ; }; diff -pudr sc/source/core/tool/compiler.cxx sc/source/core/tool/compiler.cxx --- sc/source/core/tool/compiler.cxx 2007-03-11 06:45:24.000000000 -0400 +++ sc/source/core/tool/compiler.cxx 2007-03-11 13:15:50.000000000 -0400 @@ -351,9 +351,9 @@ for (i = 65; i < 91; i++) /* ` */ // FREI for (i = 97; i < 123; i++) /* a-z */ t[i] = SC_COMPILER_C_CHAR_WORD | SC_COMPILER_C_WORD | SC_COMPILER_C_CHAR_IDENT | SC_COMPILER_C_IDENT; -/* { */ // FREI -/* | */ // FREI -/* } */ // FREI +/* { */ t[123] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array open +/* | */ t[124] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array row sep (Should be OOo specific) +/* } */ t[125] = SC_COMPILER_C_CHAR | SC_COMPILER_C_WORD_SEP | SC_COMPILER_C_VALUE_SEP; // array close /* ~ */ // FREI /* 127 */ // FREI if( ScAddress::CONV_XL_A1 == meConv || ScAddress::CONV_XL_R1C1 == meConv ) @@ -1369,7 +1369,8 @@ BOOL ScCompiler::IsOpCode( const String& } } if ( bFound && pRawToken->GetOpCode() == ocSub && - (eLastOp == ocOpen || eLastOp == ocSep || eLastOp == ocNegSub || + (eLastOp == ocOpen || eLastOp == ocArrayOpen || + eLastOp == ocSep || eLastOp == ocNegSub || (eLastOp > ocEndDiv && eLastOp < ocEndBinOp))) pRawToken->NewOpCode( ocNegSub ); //! if ocNegSub had ForceArray we'd have to set it here @@ -2098,8 +2099,10 @@ BOOL ScCompiler::NextNewToken() { xub_StrLen nSpaces = NextSymbol(); -// fprintf( stderr, "NextNewToken '%s' (?) ", -// rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr() ); +#if 0 + fprintf( stderr, "NextNewToken '%s' (spaces = %d)\n", + rtl::OUStringToOString( cSymbol, RTL_TEXTENCODING_UTF8 ).getStr(), nSpaces ); +#endif ScRawToken aToken; if( cSymbol[0] ) @@ -2181,8 +2184,11 @@ BOOL ScCompiler::NextNewToken() ScTokenArray* ScCompiler::CompileString( const String& rFormula, ScAddress::Convention eConv ) { -// fprintf( stderr, "CompileString '%s'\n", -// rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); +#if 0 + fprintf( stderr, "CompileString '%s'\n", + rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); +#endif + ScTokenArray aArr; pArr = &aArr; aFormula = rFormula; @@ -2214,6 +2220,7 @@ ScTokenArray* ScCompiler::CompileString( aCorrectedFormula += '='; } short nBrackets = 0; + bool bInArray = false; eLastOp = ocOpen; while( NextNewToken() ) { @@ -2233,6 +2240,29 @@ ScTokenArray* ScCompiler::CompileString( } else nBrackets--; } + else if( pRawToken->GetOpCode() == ocArrayOpen ) + { + if( bInArray ) + SetError( errNestedArray ); + else + bInArray = true; + } + else if( pRawToken->GetOpCode() == ocArrayClose ) + { + if( bInArray ) + { + bInArray = false; + } + else + { + SetError( errPairExpected ); + if ( bAutoCorrect ) + { + bCorrected = TRUE; + aCorrectedSymbol.Erase(); + } + } + } if( eLastOp == ocSep && pRawToken->GetOpCode() == ocSep ) { @@ -2254,6 +2284,15 @@ ScTokenArray* ScCompiler::CompileString( } if ( eLastOp != ocBad ) { + if (bInArray) { + ScByteToken aToken( ocArrayClose ); + if( !pArr->AddToken( aToken ) ) + { + SetError(errCodeOverflow); + } else if ( bAutoCorrect ) + aCorrectedFormula += pSymbolTable[ocArrayClose]; + } + // With ocBad the remaining formula is a string, too many parentheses // would be shown. ScByteToken aToken( ocClose ); @@ -4396,6 +4435,10 @@ ScToken* ScCompiler::CreateStringFromTok case svDoubleRef: pConv->MakeRefStr( rBuffer, *this, t->GetDoubleRef(), FALSE ); break; + case svMatrix: + CreateStringFromScMatrix( rBuffer, t->GetMatrix() ); + break; + case svIndex: { rtl::OUStringBuffer aBuffer; @@ -4459,6 +4502,76 @@ ScToken* ScCompiler::CreateStringFromTok return pTokenP; } +void ScCompiler::CreateStringFromScMatrix( rtl::OUStringBuffer& rBuffer, + const ScMatrix* pMatrix ) +{ + SCSIZE nC, nMaxC, nR, nMaxR; + + pMatrix->GetDimensions( nMaxC, nMaxR); + + rBuffer.append( pSymbolTable[ocArrayOpen] ); + for( nR = 0 ; nR < nMaxR ; nR++) + { + if( nR > 0) + { + rBuffer.append( pSymbolTable[ocArrayRowSep] ); + } + + for( nC = 0 ; nC < nMaxC ; nC++) + { + if( nC > 0) + { + rBuffer.append( pSymbolTable[ocSep] ); + } + + if( pMatrix->IsValue( nC, nR ) ) + { + const double v = pMatrix->GetDouble( nC, nR ); + if ( pSymbolTable == pSymbolTableEnglish ) + { + ::rtl::math::doubleToUStringBuffer( rBuffer, v, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', TRUE ); + } + else + { + ::rtl::math::doubleToUStringBuffer( rBuffer, v, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, + ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0), + TRUE ); + } + } + else if( pMatrix->IsString( nC, nR ) ) + { + const String & v = pMatrix->GetString( nC, nR ); + if (bImportXML) + rBuffer.append( v ); + else + { + rBuffer.append(sal_Unicode('"')); + if ( ScGlobal::UnicodeStrChr( v.GetBuffer(), '"' ) == NULL ) + rBuffer.append( v ); + else + { + String aStr( v ); + xub_StrLen nPos = 0; + while ( (nPos = aStr.Search( '"', nPos)) != STRING_NOTFOUND ) + { + aStr.Insert( '"', nPos ); + nPos += 2; + } + rBuffer.append(aStr); + } + rBuffer.append(sal_Unicode('"')); + } + } + // else if( pMatrix->IsEmpty( nC, nR ) ) { } + } + } + rBuffer.append( pSymbolTable[ocArrayClose] ); +} + void ScCompiler::CreateStringFromTokenArray( String& rFormula ) { rtl::OUStringBuffer aBuffer( pArr->GetLen() * 2 ); diff -pudr sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx --- sc/source/core/tool/token.cxx 2007-03-11 06:44:27.000000000 -0400 +++ sc/source/core/tool/token.cxx 2007-03-11 13:15:50.000000000 -0400 @@ -1437,6 +1437,150 @@ ScToken* ScTokenArray::AddToken( const S return Add( r.Clone() ); } +// Utility function to ensure that there is strict alternation of values and +// seperators. +static bool +checkArraySep( bool & bPrevWasSep, bool bNewVal ) +{ + bool bResult = (bPrevWasSep == bNewVal); + bPrevWasSep = bNewVal; + return bResult; +} + +ScToken* ScTokenArray::MergeArray( ) +{ + int nCol = -1, nRow = 0; + int i, nPrevRowSep = -1, nStart = 0; + bool bPrevWasSep = false; // top of stack is ocArrayClose + ScToken* t; + + // (1) Iterate from the end to the start to find matrix dims + // and do basic validation. + for ( i = nLen ; i-- > nStart ; ) + { + t = pCode[i]; + switch ( t->GetOpCode() ) + { + case ocPush : + if( checkArraySep( bPrevWasSep, false ) ) + { + return NULL; + } + + // no references or nested arrays + if ( t->GetType() != svDouble && t->GetType() != svString ) + { + return NULL; + } + break; + + case ocSep : + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + break; + + case ocArrayClose : + // not possible with the , but check just in case + // something changes in the future + if( i != (nLen-1)) + { + return NULL; + } + + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + + nPrevRowSep = i; + break; + + case ocArrayOpen : + nStart = i; // stop iteration + // fall through to ArrayRowSep + + case ocArrayRowSep : + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + + if( nPrevRowSep < 0 || // missing ocArrayClose + ((nPrevRowSep - i) % 2) == 1) // no complex elements + { + return NULL; + } + + if( nCol < 0 ) + { + nCol = (nPrevRowSep - i) / 2; + } + else if( (nPrevRowSep - i)/2 != nCol) // irregular array + { + return NULL; + } + + nPrevRowSep = i; + nRow++; + break; + + case ocMissing : + // Talk to ER : Do we want to expand past XL to support + // missing/null values in arrays ? + break; + + default : + // no functions or operators + return NULL; + } + } + if( nCol <= 0 || nRow <= 0 ) + return NULL; + + // fprintf (stderr, "Array (cols = %d, rows = %d)\n", nCol, nRow ); + + ScMatrix* pArray = new ScMatrix( nCol, nRow ); + for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ ) + { + t = pCode[i]; + + switch ( t->GetOpCode() ) + { + case ocMissing : + pArray->PutEmpty( nCol, nRow); + break; + + case ocPush : + if ( t->GetType() == svDouble ) + { + pArray->PutDouble( t->GetDouble(), nCol, nRow); + } + else if ( t->GetType() == svString ) + { + pArray->PutString( t->GetString(), nCol, nRow); + } + break; + + case ocSep : + nCol++; + break; + + case ocArrayRowSep : + nRow++; nCol = 0; + break; + + default : + break; + } + pCode[i] = NULL; + t->DecRef(); + } + nLen = nStart; + return AddMatrix( pArray ); +} + // Wird auch vom Compiler genutzt. Das Token ist per new angelegt! ScToken* ScTokenArray::Add( ScToken* t ) @@ -1450,6 +1594,8 @@ ScToken* ScTokenArray::Add( ScToken* t ) && ( t->GetType() == svSingleRef || t->GetType() == svDoubleRef ) ) nRefs++; t->IncRef(); + if( t->GetOpCode() == ocArrayClose ) + return MergeArray(); return t; } else diff -pudr sc/source/filter/excel/excform8.cxx sc/source/filter/excel/excform8.cxx --- sc/source/filter/excel/excform8.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/excform8.cxx 2007-03-11 20:03:45.000000000 -0400 @@ -81,8 +81,9 @@ BOOL ExcelToSc8::Read3DTabReference( Xcl } -// stream seeks to first byte after -ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, sal_Size nFormulaLen, const FORMULA_TYPE eFT ) +// if bAllowArrays is false stream seeks to first byte after +// otherwise it will seek to the first byte past additional content after +ConvErr ExcelToSc8::Convert( const ScTokenArray*& rpTokArray, XclImpStream& aIn, sal_Size nFormulaLen, bool bAllowArrays, const FORMULA_TYPE eFT ) { BYTE nOp, nLen, nByte; UINT16 nUINT16; @@ -94,10 +95,10 @@ ConvErr ExcelToSc8::Convert( const ScTok const BOOL bRangeName = eFT == FT_RangeName; const BOOL bSharedFormula = eFT == FT_SharedFormula; const BOOL bRNorSF = bRangeName || bSharedFormula; - UINT32 nExtCnt = 0; SingleRefData aSRD; ComplRefData aCRD; + ExtensionTypeVec aExtensions; if( eStatus != ConvOK ) { @@ -285,31 +286,28 @@ ConvErr ExcelToSc8::Convert( const ScTok aStack << aPool.StoreNlf( aSRD ); break; + case 0x0B: // RadicalS 13 x ref aIn.Ignore( 13 ); - nExtCnt++; + aExtensions.push_back( EXTENSION_NLR ); goto _ocbad; - break; case 0x0C: // RwS 4 x ref aIn.Ignore( 4 ); - nExtCnt++; + aExtensions.push_back( EXTENSION_NLR ); goto _ocbad; - break; case 0x0D: // ColS 4 x ref aIn.Ignore( 4 ); - nExtCnt++; + aExtensions.push_back( EXTENSION_NLR ); goto _ocbad; - break; case 0x0E: // RwSV 4 x val aIn.Ignore( 4 ); - nExtCnt++; + aExtensions.push_back( EXTENSION_NLR ); goto _ocbad; - break; case 0x0F: // ColSV 4 x val aIn.Ignore( 4 ); - nExtCnt++; + aExtensions.push_back( EXTENSION_NLR ); goto _ocbad; - break; + case 0x10: // RadicalLel 4 - err aIn.Ignore( 4 ); goto _ocbad; @@ -383,9 +381,23 @@ ConvErr ExcelToSc8::Convert( const ScTok case 0x40: case 0x60: case 0x20: // Array Constant [317 268] - aIn.Ignore( 7 ); - aPool << ocBad; - aPool >> aStack; + if( bAllowArrays ) + { + aIn >> nByte >> nUINT16; + aIn.Ignore( 4 ); + + SCSIZE nC = nByte + 1; + SCSIZE nR = nUINT16 + 1; + + aStack << aPool.StoreMatrix( nC, nR ); + aExtensions.push_back( EXTENSION_ARRAY ); + } + else + { + aIn.Ignore( 7 ); + aPool << ocBad; + aPool >> aStack; + } break; case 0x41: case 0x61: @@ -505,6 +517,7 @@ ConvErr ExcelToSc8::Convert( const ScTok case 0x46: case 0x66: case 0x26: // Constant Reference Subexpression [321 271] + aExtensions.push_back( EXTENSION_MEMAREA ); aIn.Ignore( 6 ); // mehr steht da nicht! break; case 0x47: @@ -800,6 +813,10 @@ ConvErr ExcelToSc8::Convert( const ScTok } aIn.Seek( nEndPos ); + + if( eRet == ConvOK) + ReadExtensions( aExtensions, aIn ); + return eRet; } diff -pudr sc/source/filter/excel/excform.cxx sc/source/filter/excel/excform.cxx --- sc/source/filter/excel/excform.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/excform.cxx 2007-03-11 06:42:48.000000000 -0400 @@ -152,7 +152,7 @@ void ImportExcel::Formula( const XclAddr bConvert = TRUE; if( bConvert ) - eErr = pFormConv->Convert( pErgebnis, maStrm, nFormLen ); + eErr = pFormConv->Convert( pErgebnis, maStrm, nFormLen, true, FT_CellFormula); ScFormulaCell* pZelle = NULL; @@ -210,8 +210,9 @@ void ExcelToSc::GetDummy( const ScTokenA } -// stream seeks to first byte after -ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, sal_Size nFormulaLen, const FORMULA_TYPE eFT ) +// if bAllowArrays is false stream seeks to first byte after +// oterhwise it will seek to the first byte after the additional content after +ConvErr ExcelToSc::Convert( const ScTokenArray*& pErgebnis, XclImpStream& aIn, sal_Size nFormulaLen, bool bAllowArrays, const FORMULA_TYPE eFT ) { RootData& rR = GetOldRoot(); BYTE nOp, nLen, nByte; @@ -226,8 +227,9 @@ ConvErr ExcelToSc::Convert( const ScToke const BOOL bSharedFormula = eFT == FT_SharedFormula; const BOOL bRNorSF = bRangeName || bSharedFormula; - SingleRefData aSRD; - ComplRefData aCRD; + SingleRefData aSRD; + ComplRefData aCRD; + ExtensionTypeVec aExtensions; bExternName = FALSE; @@ -474,9 +476,23 @@ ConvErr ExcelToSc::Convert( const ScToke case 0x40: case 0x60: case 0x20: // Array Constant [317 268] - aIn.Ignore( 7 ); - aPool << ocBad; - aPool >> aStack; + if( bAllowArrays ) + { + aIn >> nByte >> nUINT16; + aIn.Ignore( 4 ); + + SCSIZE nC = nByte + 1; + SCSIZE nR = nUINT16 + 1; + + aStack << aPool.StoreMatrix( nC, nR ); + aExtensions.push_back( EXTENSION_ARRAY ); + } + else + { + aIn.Ignore( 7 ); + aPool << ocBad; + aPool >> aStack; + } break; case 0x41: case 0x61: @@ -606,6 +622,9 @@ ConvErr ExcelToSc::Convert( const ScToke case 0x46: case 0x66: case 0x26: // Constant Reference Subexpression [321 271] + aExtensions.push_back( EXTENSION_MEMAREA ); + // fall through + case 0x47: case 0x67: case 0x27: // Erroneous Constant Reference Subexpr. [322 272] @@ -885,11 +904,16 @@ ConvErr ExcelToSc::Convert( const ScToke } aIn.Seek( nEndPos ); + + if( eRet == ConvOK) + ReadExtensions( aExtensions, aIn ); + return eRet; } -// stream seeks to first byte after +// if bAllowArrays is false stream seeks to first byte after +// otherwise it will seek to the first byte past additional content after ConvErr ExcelToSc::Convert( _ScRangeListTabs& rRangeList, XclImpStream& aIn, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT ) { @@ -1676,5 +1700,163 @@ void ExcelToSc::SetComplRow( ComplRefDat rSRD.nRow = MAXROW; } +void ExcelToSc::ReadExtensionArray( unsigned int n, XclImpStream& aIn ) +{ + // printf( "inline array;\n" ); + + BYTE nByte; + UINT16 nUINT16; + double fDouble; + String aString; + ScMatrix* pMatrix; + + aIn >> nByte >> nUINT16; + + SCSIZE nC, nCols; + SCSIZE nR, nRows; + if( GetBiff() == EXC_BIFF8 ) + { + nCols = nByte + 1; + nRows = nUINT16 + 1; + } + else + { + nCols = nByte ? nByte : 256; + nRows = nUINT16; + } + + pMatrix = aPool.GetMatrix( n ); + + if( NULL != pMatrix ) + { + pMatrix->GetDimensions( nC, nR); + if( nC != nCols || nR != nRows ) + { + DBG_ERRORFILE( "ExcelToSc::ReadExtensionArray - matrix size mismatch" ); + pMatrix = NULL; + } + } + else + { + DBG_ERRORFILE( "ExcelToSc::ReadExtensionArray - missing matrix" ); + } + + for( nR = 0 ; nR < nRows; nR++ ) + { + for( nC = 0 ; nC < nCols; nC++ ) + { + aIn >> nByte; + switch( nByte ) + { + case EXC_CACHEDVAL_EMPTY: + aIn.Ignore( 8 ); + if( NULL != pMatrix ) + { +#if 0 + // Empty is not permitted in a matrix + pMatrix->PutEmpty( nC, nR ); +#else + pMatrix->PutDouble( 0., nC, nR ); +#endif + } + break; + + case EXC_CACHEDVAL_DOUBLE: + aIn >> fDouble; + if( NULL != pMatrix ) + { + pMatrix->PutDouble( fDouble, nC, nR ); + } + break; + + case EXC_CACHEDVAL_STRING: + if( GetBiff() == EXC_BIFF8 ) + { + aIn >> nUINT16; + aString = aIn.ReadUniString( nUINT16 ); + } + else + { + aIn >> nByte; + aString = aIn.ReadRawByteString( nByte ); + } + if( NULL != pMatrix ) + { + pMatrix->PutString( aString, nC, nR ); + } + break; + + case EXC_CACHEDVAL_BOOL: + aIn >> nByte; + aIn.Ignore( 7 ); + if( NULL != pMatrix ) + { +#if 0 + // No boolean support yet + pMatrix->PutBoolean( nByte != 0, nC, nR ); +#else + pMatrix->PutDouble( nByte ? 1 : 0, nC, nR ); +#endif + } + break; + + case EXC_CACHEDVAL_ERROR: + aIn >> nByte; + aIn.Ignore( 7 ); + if( NULL != pMatrix ) + { + pMatrix->PutError( nByte, nC, nR ); + } + break; + } + } + } +} + +void ExcelToSc::ReadExtensionNlr( XclImpStream& aIn ) +{ + // printf( "natural lang fmla;\n" ); + + sal_uInt32 nFlags; + aIn >> nFlags; + + sal_uInt32 nCount = nFlags & EXC_TOK_NLR_ADDMASK; + aIn.Ignore( nCount * (4 + 2) ); // Drop the cell positions +} + +void ExcelToSc::ReadExtensionMemArea( XclImpStream& aIn ) +{ + // printf( "mem area;\n" ); + + sal_uInt16 nCount; + aIn >> nCount; + + aIn.Ignore( nCount * (4 + 4 + 2 + 2) ); // drop the ranges +} + +void ExcelToSc::ReadExtensions( const ExtensionTypeVec& rExtensions, + XclImpStream& aIn ) +{ + unsigned int nArray = 0; + for( unsigned int i = 0 ; i < rExtensions.size() ; i++ ) + { + ExtensionType eType = rExtensions[i]; + + switch( eType ) + { + case EXTENSION_ARRAY: + ReadExtensionArray( nArray++, aIn ); + break; + + case EXTENSION_NLR: + ReadExtensionNlr( aIn ); + break; + + case EXTENSION_MEMAREA: + ReadExtensionMemArea( aIn ); + break; + } + } +} diff -pudr sc/source/filter/excel/impop.cxx sc/source/filter/excel/impop.cxx --- sc/source/filter/excel/impop.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/impop.cxx 2007-03-11 13:57:52.000000000 -0400 @@ -538,7 +538,7 @@ void ImportExcel::Array25( void ) pFormConv->Reset( ScAddress( static_cast(nFirstCol), static_cast(nFirstRow), GetCurrScTab() ) ); - pFormConv->Convert( pErgebnis, maStrm, nFormLen ); + pFormConv->Convert( pErgebnis, maStrm, nFormLen, true, FT_CellFormula); DBG_ASSERT( pErgebnis, "*ImportExcel::Array25(): ScTokenArray ist NULL!" ); @@ -833,7 +833,7 @@ void ImportExcel::Shrfmla( void ) const ScTokenArray* pErgebnis; pFormConv->Reset(); - pFormConv->Convert( pErgebnis, maStrm, nLenExpr, FT_SharedFormula ); + pFormConv->Convert( pErgebnis, maStrm, nLenExpr, true, FT_SharedFormula ); DBG_ASSERT( pErgebnis, "+ImportExcel::Shrfmla(): ScTokenArray ist NULL!" ); @@ -1014,7 +1014,7 @@ void ImportExcel::Array34( void ) pFormConv->Reset( ScAddress( static_cast(nFirstCol), static_cast(nFirstRow), GetCurrScTab() ) ); - pFormConv->Convert( pErgebnis, maStrm, nFormLen ); + pFormConv->Convert( pErgebnis, maStrm, nFormLen, true, FT_CellFormula); DBG_ASSERT( pErgebnis, "+ImportExcel::Array34(): ScTokenArray ist NULL!" ); diff -pudr sc/source/filter/excel/tokstack.cxx sc/source/filter/excel/tokstack.cxx --- sc/source/filter/excel/tokstack.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/tokstack.cxx 2007-03-11 06:07:48.000000000 -0400 @@ -111,6 +111,10 @@ TokenPool::TokenPool( void ) ppP_Nlf = new NLFCONT*[ nP_Nlf ]; memset( ppP_Nlf, 0, sizeof( NLFCONT* ) * nP_Nlf ); + nP_Matrix = 16; + ppP_Matrix = new ScMatrix*[ nP_Matrix ]; + memset( ppP_Matrix, 0, sizeof( ScMatrix* ) * nP_Matrix ); + pScToken = new ScTokenArray; Reset(); @@ -155,6 +159,13 @@ TokenPool::~TokenPool() } delete[] ppP_Nlf; + for( n = 0 ; n < nP_Matrix ; n++ ) + { + if( ppP_Matrix[ n ] ) + ppP_Matrix[ n ]->DecRef( ); + } + delete[] ppP_Matrix; + delete pScToken; } @@ -285,6 +296,20 @@ void TokenPool::GrowNlf( void ) } +void TokenPool::GrowMatrix( void ) +{ + UINT16 nNewSize = nP_Matrix * 2; + + ScMatrix** ppNew = new ScMatrix*[ nNewSize ]; + + memset( ppNew, 0, sizeof( ScMatrix* ) * nNewSize ); + memcpy( ppNew, ppP_Matrix, sizeof( ScMatrix* ) * nP_Matrix ); + + delete[] ppP_Matrix; + ppP_Matrix = ppNew; + nP_Matrix = nNewSize; +} + void TokenPool::GetElement( const UINT16 nId ) { DBG_ASSERT( nId < nElementAkt, "*TokenPool::GetElement(): Id zu gross!?" ); @@ -341,6 +366,15 @@ void TokenPool::GetElement( const UINT16 pScToken->AddColRowName( p->aRef ); } break; + case T_Matrix: + { + UINT16 n = pElement[ nId ]; + ScMatrix* p = ( n < nP_Matrix )? ppP_Matrix[ n ] : NULL; + + if( p ) + pScToken->AddMatrix( p ); + } + break; default: DBG_ERROR("-TokenPool::GetElement(): Zustand undefiniert!?"); } @@ -412,6 +446,15 @@ void TokenPool::GetElementRek( const UIN pScToken->AddColRowName( p->aRef ); } break; + case T_Matrix: + { + UINT16 n = pElement[ *pAkt ]; + ScMatrix* p = ( n < nP_Matrix )? ppP_Matrix[ n ] : NULL; + + if( p ) + pScToken->AddMatrix( p ); + } + break; default: DBG_ERROR("-TokenPool::GetElementRek(): Zustand undefiniert!?"); } @@ -613,10 +656,33 @@ const TokenId TokenPool::StoreNlf( const return ( const TokenId ) nElementAkt; } +const TokenId TokenPool::StoreMatrix( SCSIZE nC, SCSIZE nR ) +{ + ScMatrix* pM; + + if( nElementAkt >= nElement ) + GrowElement(); + + if( nP_MatrixAkt >= nP_Matrix ) + GrowMatrix(); + + pElement[ nElementAkt ] = nP_MatrixAkt; + pType[ nElementAkt ] = T_Matrix; + + pM = new ScMatrix( nC, nR ); + pM->FillDouble( 0., 0,0, nC-1, nR-1 ); + pM->IncRef( ); + ppP_Matrix[ nP_MatrixAkt ] = pM; + + nElementAkt++; + nP_MatrixAkt++; + + return ( const TokenId ) nElementAkt; +} void TokenPool::Reset( void ) { - nP_IdAkt = nP_IdLast = nElementAkt = nP_StrAkt = nP_DblAkt = nP_RefTrAkt = nP_ExtAkt = nP_NlfAkt = 0; + nP_IdAkt = nP_IdLast = nElementAkt = nP_StrAkt = nP_DblAkt = nP_RefTrAkt = nP_ExtAkt = nP_NlfAkt = nP_MatrixAkt = 0; } @@ -672,3 +738,12 @@ const String* TokenPool::GetString( cons return p; } +ScMatrix* TokenPool::GetMatrix( unsigned int n ) const +{ + if( n < nP_MatrixAkt ) + return ppP_Matrix[ n ]; + else + printf ("GETMATRIX %d >= %d\n", n, nP_MatrixAkt); + return NULL; +} + diff -pudr sc/source/filter/excel/xeformula.cxx sc/source/filter/excel/xeformula.cxx --- sc/source/filter/excel/xeformula.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/xeformula.cxx 2007-03-11 06:27:10.000000000 -0400 @@ -106,6 +106,7 @@ struct XclExpCompConfig bool mbFromCell; /// True = Any kind of cell formula (cell, array, shared). bool mb3DRefOnly; /// True = Only 3D references allowed (e.g. names). bool mbStopAtSep; /// True = Stop compilation at ocSep in root level. + bool mbAllowArrays; /// True = Allow inline arrays }; // ---------------------------------------------------------------------------- @@ -113,6 +114,8 @@ struct XclExpCompConfig /** Working data of the formula compiler. Used to push onto a stack for recursive calls. */ struct XclExpCompData { + typedef ::std::list< const ScMatrix * > ScMatrixList; + typedef ScfRef< ScMatrixList > ScMatrixListRef; typedef ScfRef< ScTokenArray > ScTokenArrayRef; XclExpCompConfig maCfg; /// Configuration for current formula type. @@ -121,6 +124,8 @@ struct XclExpCompData XclTokenArrayIterator maTokArrIt; /// Iterator in Calc token array. XclExpLinkManager* mpLinkMgr; /// Link manager for current context (local/global). XclExpRefLog* mpRefLog; /// Log for external references. + ScMatrixListRef maInlineArr; /// List of inline arrays (in reverse order) + const ScAddress* mpScBasePos; /// Current cell position of the formula. // processing data during compilation @@ -281,8 +286,9 @@ private: const ScAddress* pScBasePos, XclExpRefLog* pRefLog ); void LeaveRecursive(); - void FinalizeFormula(); - XclTokenArrayRef CreateTokenArray(); + void FinalizeFormula( ScfUInt8Vec & rExtensionTokens ); + void AppendInlineArrays( ScfUInt8Vec & rExtensionTokens ); + XclTokenArrayRef CreateTokenArray( ScfUInt8Vec* pExtensionTokens = NULL ); // compiler --------------------------------------------------------------- // XclExpTokenData: pass-by-value and return-by-value is intended @@ -347,6 +353,7 @@ private: XclExpRefLogEntry* GetNewRefLogEntry(); void ProcessCellRef( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); void ProcessRangeRef( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); + void ProcessMatrix (const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); void ProcessDefinedName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); void ProcessDatabaseArea( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ); @@ -375,6 +382,7 @@ private: void AppendAddress( const XclAddress& rXclPos ); void AppendRange( const XclRange& rXclRange ); + void AppendMatrixPlaceHolder( const ScMatrix* rMatrix ); void AppendSpaceToken( sal_uInt8 nType, sal_uInt8 nCount ); void AppendIntToken( sal_uInt16 nValue, sal_uInt8 nSpaces = 0 ); @@ -423,17 +431,17 @@ namespace { /** The table containing configuration data for all formula types. */ static const XclExpCompConfig spConfigTable[] = { - // formula type token class type link manager type inCell 3dOnly StopAtSep - { EXC_FMLATYPE_CELL, EXC_CLASSTYPE_CELL, EXC_LINKMGRTYPE_LOCAL, true, false, true }, - { EXC_FMLATYPE_SHARED, EXC_CLASSTYPE_CELL, EXC_LINKMGRTYPE_LOCAL, true, false, true }, - { EXC_FMLATYPE_MATRIX, EXC_CLASSTYPE_ARRAY, EXC_LINKMGRTYPE_LOCAL, true, false, true }, - { EXC_FMLATYPE_CONDFMT, EXC_CLASSTYPE_ARRAY, EXC_LINKMGRTYPE_NONE, false, false, true }, - { EXC_FMLATYPE_DATAVAL, EXC_CLASSTYPE_ARRAY, EXC_LINKMGRTYPE_NONE, false, false, true }, - { EXC_FMLATYPE_NAME, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_GLOBAL, false, true, false }, - { EXC_FMLATYPE_CHART, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_LOCAL, false, true, false }, - { EXC_FMLATYPE_CONTROL, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_LOCAL, false, false, true }, - { EXC_FMLATYPE_WQUERY, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_LOCAL, false, true, false }, - { EXC_FMLATYPE_LISTVAL, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_NONE, false, false, true } + // formula type token class type link manager type inCell 3dOnly StopAtSep allowArray + { EXC_FMLATYPE_CELL, EXC_CLASSTYPE_CELL, EXC_LINKMGRTYPE_LOCAL, true, false, true, true }, + { EXC_FMLATYPE_SHARED, EXC_CLASSTYPE_CELL, EXC_LINKMGRTYPE_LOCAL, true, false, true, true }, + { EXC_FMLATYPE_MATRIX, EXC_CLASSTYPE_ARRAY, EXC_LINKMGRTYPE_LOCAL, true, false, true, true }, + { EXC_FMLATYPE_CONDFMT, EXC_CLASSTYPE_ARRAY, EXC_LINKMGRTYPE_NONE, false, false, true, false }, + { EXC_FMLATYPE_DATAVAL, EXC_CLASSTYPE_ARRAY, EXC_LINKMGRTYPE_NONE, false, false, true, false }, + { EXC_FMLATYPE_NAME, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_GLOBAL, false, true, false, true }, + { EXC_FMLATYPE_CHART, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_LOCAL, false, true, false, true }, + { EXC_FMLATYPE_CONTROL, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_LOCAL, false, false, true, false }, + { EXC_FMLATYPE_WQUERY, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_LOCAL, false, true, false, false }, + { EXC_FMLATYPE_LISTVAL, EXC_CLASSTYPE_NAME, EXC_LINKMGRTYPE_NONE, false, false, true, false } }; } // namespace @@ -497,10 +505,11 @@ XclTokenArrayRef XclExpFmlaCompImpl::Cre } } - // finalizing, e.g. add tAttr-volatile token - FinalizeFormula(); + // finalizing, e.g. add tAttr-volatile token, and storing any inline arrays + ScfUInt8Vec aExtensionTokens; + FinalizeFormula( aExtensionTokens ); - return CreateTokenArray(); + return CreateTokenArray( &aExtensionTokens ); } XclTokenArrayRef XclExpFmlaCompImpl::CreateErrorFormula( sal_uInt8 nErrCode ) @@ -570,6 +579,9 @@ void XclExpFmlaCompImpl::Init( XclFormul maTokArrIt.Init(); mpLinkMgr = 0; mpRefLog = 0; + + maInlineArr.reset( NULL ); + mpScBasePos = 0; // init processing data used during compilation @@ -605,6 +617,9 @@ void XclExpFmlaCompImpl::Init( XclFormul ScCompiler::MoveRelWrap( *mxOwnScTokArr, GetDocPtr(), *pScBasePos ); // don't remember pScBasePos in mpScBasePos, shared formulas use real relative refs break; + + default : + break; } if( mbOk ) @@ -634,39 +649,130 @@ void XclExpFmlaCompImpl::LeaveRecursive( } } -void XclExpFmlaCompImpl::FinalizeFormula() +void XclExpFmlaCompImpl::AppendInlineArrays( ScfUInt8Vec & rExtensionTokens ) +{ + const ScMatrixList::const_reverse_iterator end = maInlineArr->rend(); + ScMatrixList::const_reverse_iterator i = maInlineArr->rbegin(); + for( ; i != end ; i++ ) + { + const ScMatrix *pMatrix = *i; + SCSIZE nC, nMaxC, nR, nMaxR; + + pMatrix->GetDimensions( nMaxC, nMaxR); + + if( meBiff == EXC_BIFF8 ) + { + rExtensionTokens.push_back( nMaxC - 1 ); + rExtensionTokens.resize( rExtensionTokens.size() + 2 ); + ShortToSVBT16( nMaxR - 1, &*(rExtensionTokens.end() - 2) ); + } + else + { + rExtensionTokens.push_back( nMaxC == 256 ? 0 : nMaxC ); + rExtensionTokens.resize( rExtensionTokens.size() + 2 ); + ShortToSVBT16( nMaxR, &*(rExtensionTokens.end() - 2) ); + } + + for( nR = 0 ; nR < nMaxR ; nR++) + { + for( nC = 0 ; nC < nMaxC ; nC++) + { + if( pMatrix->IsValue( nC, nR ) ) + { + rExtensionTokens.push_back( EXC_CACHEDVAL_DOUBLE ); + + const double nVal = pMatrix->GetDouble( nC, nR ); + rExtensionTokens.resize( rExtensionTokens.size() + 8 ); + DoubleToSVBT64( nVal, &*(rExtensionTokens.end() - 8) ); + } + else if( pMatrix->IsString( nC, nR ) ) + { + rExtensionTokens.push_back( EXC_CACHEDVAL_STRING ); + + const String & rString = pMatrix->GetString( nC, nR ); + XclExpStringRef xXclStr = XclExpStringHelper::CreateString( + GetRoot(), rString, + ((meBiff == EXC_BIFF8) ? EXC_STR_DEFAULT : EXC_STR_8BITLENGTH), + EXC_TOK_STR_MAXLEN ); + size_t nSize = rExtensionTokens.size(); + rExtensionTokens.resize( nSize + xXclStr->GetSize() ); + xXclStr->WriteToMem( &rExtensionTokens[ nSize ] ); + } + else if( pMatrix->IsEmpty( nC, nR ) ) + { + rExtensionTokens.push_back( EXC_CACHEDVAL_EMPTY ); + + UInt32ToSVBT32( 0, &*(rExtensionTokens.end() - 8) ); + UInt32ToSVBT32( 0, &*(rExtensionTokens.end() - 4) ); + } + +#if 0 + // If we every get a native boolean type enable this + else if( pMatrix->IsBoolean( nC, nR ) ) + { + rExtensionTokens.push_back( EXC_CACHEDVAL_BOOL ); + + const bool nVal = pMatrix->GetBoolean( nC, nR ); + UInt32ToSVBT32( nVal ? 1 : 0, &*(rExtensionTokens.end() - 8) ); + UInt32ToSVBT32( 0, &*(rExtensionTokens.end() - 4) ); + } + + // Check the semantics of errors in ScMatrix + else if( pMatrix->IsError( nC, nR ) ) + { + rExtensionTokens.push_back( EXC_CACHEDVAL_ERROR ); + + rExtensionTokens.resize( rExtensionTokens..size() + 8 ); + UInt32ToSVBT32( XclTools::GetXclErrorCode ( nErr ), + &*(rExtensionTokens.end() - 8) ); + UInt32ToSVBT32( 0, &*(rExtensionTokens.end() - 4) ); + } +#endif + } + } + } +} + +void XclExpFmlaCompImpl::FinalizeFormula( ScfUInt8Vec & rExtensionTokens ) { if( mbOk ) { - // Volatile? Add a tAttr-volatile token at the beginning of the token array. - if( mbVolatile ) - { - // tAttr-space token can be extended with volatile flag - if( !IsSpaceToken( 0 ) ) - { - Insert( 0, 4 ); - maTokVec[ 0 ] = EXC_TOKID_ATTR; - } - maTokVec[ 1 ] |= EXC_TOK_ATTR_VOLATILE; - } + // Volatile? Add a tAttr-volatile token at the beginning of the token array. + if( mbVolatile ) + { + // tAttr-space token can be extended with volatile flag + if( !IsSpaceToken( 0 ) ) + { + Insert( 0, 4 ); + maTokVec[ 0 ] = EXC_TOKID_ATTR; + } + maTokVec[ 1 ] |= EXC_TOK_ATTR_VOLATILE; + } - // Token array too long? -> error - mbOk = maTokVec.size() <= EXC_TOKARR_MAXLEN; + // Token array too long? -> error + mbOk = maTokVec.size() <= EXC_TOKARR_MAXLEN; + + // Store any inline arrays + if( maInlineArr.is() ) + { + AppendInlineArrays( rExtensionTokens ); + } } if( !mbOk ) { - // Any unrecoverable error? -> Create a =#NA formula. - maTokVec.clear(); - mbVolatile = false; - AppendErrorToken( EXC_ERR_NA ); + // Any unrecoverable error? -> Create a =#NA formula. + maTokVec.clear(); + rExtensionTokens.clear(); + mbVolatile = false; + AppendErrorToken( EXC_ERR_NA ); } } -XclTokenArrayRef XclExpFmlaCompImpl::CreateTokenArray() +XclTokenArrayRef XclExpFmlaCompImpl::CreateTokenArray( ScfUInt8Vec* pExtensionTokens ) { // create the Excel token array object before calling LeaveRecursive() - XclTokenArrayRef xTokArr( new XclTokenArray( maTokVec, mbVolatile ) ); + XclTokenArrayRef xTokArr( new XclTokenArray( maTokVec, mbVolatile, pExtensionTokens ) ); // compiler invoked recursively? - restore old working data LeaveRecursive(); @@ -1041,6 +1147,7 @@ XclExpTokenData XclExpFmlaCompImpl::Fact case svString: ProcessString( aTokData ); break; case svSingleRef: ProcessCellRef( aTokData, nExpClass ); break; case svDoubleRef: ProcessRangeRef( aTokData, nExpClass ); break; + case svMatrix: ProcessMatrix (aTokData, nExpClass ); break; case svExternal: ProcessExternal( aTokData, nExpClass ); break; default: @@ -1760,6 +1867,20 @@ void XclExpFmlaCompImpl::ProcessRangeRef AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces ); } } +void XclExpFmlaCompImpl::ProcessMatrix ( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ) +{ + if( maCfg.mbAllowArrays ) + { + AppendOpTokenId( GetTokenId( EXC_TOKID_ARRAY, EXC_TOKCLASS_VAL ), + nExpClass, rTokData.mnSpaces ); + AppendMatrixPlaceHolder( rTokData.mpScToken->GetMatrix() ); + } + else + { + // Array in places that do not allow it (cond fmts, data validation) + AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces ); + } +} void XclExpFmlaCompImpl::ProcessDefinedName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass ) { @@ -2004,6 +2125,19 @@ void XclExpFmlaCompImpl::AppendRange( co Append( rXclRange.maLast.mnCol ); } } +void XclExpFmlaCompImpl::AppendMatrixPlaceHolder( const ScMatrix* pMatrix ) +{ + SCSIZE cols, rows; + + if( !maInlineArr ) + maInlineArr.reset( new ScMatrixList ); + maInlineArr->push_front( pMatrix ); // save it for later + + pMatrix->GetDimensions( cols, rows); + Append( static_cast< sal_uInt8 >( cols-1 ) ); + Append( static_cast< sal_uInt16 >( rows-1 ) ); + Append( static_cast< sal_uInt32 >( 0 ) ); // unknown +} void XclExpFmlaCompImpl::AppendSpaceToken( sal_uInt8 nType, sal_uInt8 nCount ) { diff -pudr sc/source/filter/excel/xichart.cxx sc/source/filter/excel/xichart.cxx --- sc/source/filter/excel/xichart.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/xichart.cxx 2007-03-11 13:57:52.000000000 -0400 @@ -1033,7 +1033,7 @@ void XclImpChSourceLink::ReadChSourceLin rStrm >> aXclTokArr; // convert token array to range list ScRangeList aScRanges; - GetFormulaCompiler().CreateRangeList( aScRanges, EXC_FMLATYPE_CHART, aXclTokArr, rStrm ); + GetFormulaCompiler().CreateRangeList( aScRanges, EXC_FMLATYPE_CHART, aXclTokArr, rStrm ); // JEG : This is wrong. It should be a formula // process range list CalcOrientation( aScRanges ); } diff -pudr sc/source/filter/excel/xicontent.cxx sc/source/filter/excel/xicontent.cxx --- sc/source/filter/excel/xicontent.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/xicontent.cxx 2007-03-11 13:57:52.000000000 -0400 @@ -607,7 +607,7 @@ void XclImpCondFormat::ReadCF( XclImpStr { const ScTokenArray* pTokArr = 0; rFmlaConv.Reset( rPos ); - rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, FT_RangeName ); + rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_RangeName ); // JEF // formula converter owns pTokArr -> create a copy of the token array if( pTokArr ) xTokArr1.reset( pTokArr->Clone() ); @@ -618,7 +618,7 @@ void XclImpCondFormat::ReadCF( XclImpStr { const ScTokenArray* pTokArr = 0; rFmlaConv.Reset( rPos ); - rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, FT_RangeName ); + rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_RangeName ); // JEF // formula converter owns pTokArr -> create a copy of the token array if( pTokArr ) pTokArr2.reset( pTokArr->Clone() ); @@ -741,7 +741,7 @@ void XclImpValidation::ReadDV( XclImpStr { const ScTokenArray* pTokArr = 0; rFmlaConv.Reset(); - rFmlaConv.Convert( pTokArr, rStrm, nLen, FT_RangeName ); + rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName ); // formula converter owns pTokArr -> create a copy of the token array if( pTokArr ) xTokArr1.reset( pTokArr->Clone() ); @@ -756,7 +756,7 @@ void XclImpValidation::ReadDV( XclImpStr { const ScTokenArray* pTokArr = 0; rFmlaConv.Reset(); - rFmlaConv.Convert( pTokArr, rStrm, nLen, FT_RangeName ); + rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName ); // formula converter owns pTokArr -> create a copy of the token array if( pTokArr ) xTokArr2.reset( pTokArr->Clone() ); diff -pudr sc/source/filter/excel/xiname.cxx sc/source/filter/excel/xiname.cxx --- sc/source/filter/excel/xiname.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/xiname.cxx 2007-03-11 09:33:57.000000000 -0400 @@ -192,7 +192,9 @@ XclImpName::XclImpName( XclImpStream& rS rStrm.PopPosition(); // --- name formula --- - rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, FT_RangeName ); + // JEG : double check this. It is clearly false for normal names + // but some of the builtins (sheettitle?) might be able to handle arrays + rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, false, FT_RangeName ); // --- auto or advanced filter --- if( (GetBiff() == EXC_BIFF8) && pTokArr && bBuiltIn ) @@ -220,7 +222,7 @@ XclImpName::XclImpName( XclImpStream& rS else if( nFmlaSize > 0 ) { // regular defined name - rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, FT_RangeName ); + rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize, true, FT_RangeName ); } // 4) *** create a defined name in the Calc document *** ------------------ diff -pudr sc/source/filter/excel/xldumper.cxx sc/source/filter/excel/xldumper.cxx --- sc/source/filter/excel/xldumper.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/xldumper.cxx 2007-03-11 13:57:52.000000000 -0400 @@ -92,7 +92,8 @@ const sal_Unicode SCF_DUMP_LISTSEP const sal_Unicode SCF_DUMP_ADDRABS = '$'; const sal_Unicode SCF_DUMP_RANGESEP = ':'; const sal_Unicode SCF_DUMP_TABSEP = '!'; -const sal_Unicode SCF_DUMP_ARRAYSEP = ';'; +const sal_Unicode SCF_DUMP_ARRAY_COL = ';'; +const sal_Unicode SCF_DUMP_ARRAY_ROW = '|'; const sal_Unicode SCF_DUMP_EMPTYVALUE = '~'; const sal_Unicode SCF_DUMP_CMDPROMPT = '?'; const sal_Unicode SCF_DUMP_PLACEHOLDER = '\x01'; @@ -1605,8 +1606,8 @@ void FormulaObject::DumpAddDataArray( si { String aArrayLine; for( sal_uInt32 nCol = 0; nCol < nCols; ++nCol ) - StringHelper::AppendToken( aArrayLine, DumpConstValue(), SCF_DUMP_LISTSEP ); - StringHelper::AppendToken( aOp, aArrayLine, SCF_DUMP_ARRAYSEP ); + StringHelper::AppendToken( aArrayLine, DumpConstValue(), SCF_DUMP_ARRAY_COL ); + StringHelper::AppendToken( aOp, aArrayLine, SCF_DUMP_ARRAY_ROW ); } StringHelper::Enclose( aOp, '{', '}' ); mxStack->ReplaceOnTop( CreatePlaceHolder( nIdx ), aOp ); diff -pudr sc/source/filter/excel/xlformula.cxx sc/source/filter/excel/xlformula.cxx --- sc/source/filter/excel/xlformula.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/excel/xlformula.cxx 2007-03-11 13:57:52.000000000 -0400 @@ -454,10 +454,16 @@ XclTokenArray::XclTokenArray( bool bVola { } -XclTokenArray::XclTokenArray( ScfUInt8Vec& rTokVec, bool bVolatile ) : +XclTokenArray::XclTokenArray( ScfUInt8Vec& rTokVec, bool bVolatile, + ScfUInt8Vec* pExtensionTokens) : mbVolatile( bVolatile ) { maTokVec.swap( rTokVec ); + if( NULL != pExtensionTokens) + { + DBG_ASSERT( maTokVec.size() <= 0xFFFF, "XclTokenArray::XclTokenArray - extension array too long" ); + maExtensions.swap( *pExtensionTokens ); + } } sal_uInt16 XclTokenArray::GetSize() const @@ -494,6 +500,8 @@ void XclTokenArray::WriteArray( XclExpSt { if( !maTokVec.empty() ) rStrm.Write( &maTokVec.front(), GetSize() ); + if( !maExtensions.empty() ) + rStrm.Write( &maExtensions.front(), limit_cast< sal_uInt16 >(maExtensions.size() ) ); } void XclTokenArray::Write( XclExpStream& rStrm ) const diff -pudr sc/source/filter/inc/excform.hxx sc/source/filter/inc/excform.hxx --- sc/source/filter/inc/excform.hxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/inc/excform.hxx 2007-03-11 06:37:43.000000000 -0400 @@ -55,6 +55,9 @@ class ScRangeList; class ExcelToSc : public ExcelConverterBase, protected XclImpRoot { protected: + enum ExtensionType { EXTENSION_ARRAY, EXTENSION_NLR, EXTENSION_MEMAREA }; + typedef ::std::vector< ExtensionType > ExtensionTypeVec; + BOOL bExternName; // wenn External Name gefunden wurde static const UINT16 nRowMask; static const UINT16 nLastInd; // letzter Index fuer Excel->SC- @@ -73,7 +76,7 @@ public: ExcelToSc( const XclImpRoot& rRoot ); virtual ~ExcelToSc(); - virtual ConvErr Convert( const ScTokenArray*&, XclImpStream& rStrm, sal_Size nFormulaLen, const FORMULA_TYPE eFT = FT_CellFormula ); + virtual ConvErr Convert( const ScTokenArray*&, XclImpStream& rStrm, sal_Size nFormulaLen, bool bAllowArrays, const FORMULA_TYPE eFT = FT_CellFormula ); virtual ConvErr Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula ); virtual BOOL GetAbsRefs( ScRangeList& rRangeList, XclImpStream& rStrm, sal_Size nLen ); @@ -91,6 +94,13 @@ public: void SetComplCol( ComplRefData& ); void SetComplRow( ComplRefData& ); + + void ReadExtensions( const ExtensionTypeVec& rExtensions, + XclImpStream& aIn ); + void ReadExtensionArray( unsigned int n, + XclImpStream& aIn ); + void ReadExtensionNlr( XclImpStream& aIn ); + void ReadExtensionMemArea( XclImpStream& aIn ); }; @@ -123,7 +133,7 @@ public: ExcelToSc8( const XclImpRoot& rRoot ); virtual ~ExcelToSc8(); - virtual ConvErr Convert( const ScTokenArray*& rpTokArray, XclImpStream& rStrm, sal_Size nFormulaLen, const FORMULA_TYPE eFT = FT_CellFormula ); + virtual ConvErr Convert( const ScTokenArray*& rpTokArray, XclImpStream& rStrm, sal_Size nFormulaLen, bool bAllowArrays, const FORMULA_TYPE eFT = FT_CellFormula ); virtual ConvErr Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula ); diff -pudr sc/source/filter/inc/formel.hxx sc/source/filter/inc/formel.hxx --- sc/source/filter/inc/formel.hxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/inc/formel.hxx 2007-03-11 16:13:45.000000000 -0400 @@ -237,7 +237,7 @@ public: void Reset( ScAddress aEingPos ); virtual ConvErr Convert( const ScTokenArray*& rpErg, XclImpStream& rStrm, sal_Size nFormulaLen, - const FORMULA_TYPE eFT = FT_CellFormula ) = 0; + bool bAllowArrays, const FORMULA_TYPE eFT = FT_CellFormula ) = 0; virtual ConvErr Convert( _ScRangeListTabs&, XclImpStream& rStrm, sal_Size nFormulaLen, SCsTAB nTab, const FORMULA_TYPE eFT = FT_CellFormula ) = 0; }; diff -pudr sc/source/filter/inc/tokstack.hxx sc/source/filter/inc/tokstack.hxx --- sc/source/filter/inc/tokstack.hxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/inc/tokstack.hxx 2007-03-11 20:55:58.000000000 -0400 @@ -81,15 +81,16 @@ class ScToken; enum E_TYPE { - T_Id, // Id-Folge - T_Str, // String - T_D, // Double - T_RefC, // Cell Reference - T_RefA, // Area Reference - T_RN, // Range Name - T_Ext, // irgendwas Unbekanntes mit Funktionsnamen - T_Nlf, // token for natural language formula - T_Error // fuer Abfrage im Fehlerfall + T_Id, // Id-Folge + T_Str, // String + T_D, // Double + T_RefC, // Cell Reference + T_RefA, // Area Reference + T_RN, // Range Name + T_Ext, // irgendwas Unbekanntes mit Funktionsnamen + T_Nlf, // token for natural language formula + T_Matrix, // token for inline arrays + T_Error // fuer Abfrage im Fehlerfall }; @@ -137,6 +138,10 @@ class TokenPool UINT16 nP_Nlf; UINT16 nP_NlfAkt; + ScMatrix** ppP_Matrix; // Pool fuer Matricies + UINT16 nP_Matrix; + UINT16 nP_MatrixAkt; + UINT16* pElement; // Array mit Indizes fuer Elemente E_TYPE* pType; // ...mit Typ-Info UINT16* pSize; // ...mit Laengenangabe (Anz. UINT16) @@ -156,6 +161,7 @@ class TokenPool void GrowElement( void ); void GrowExt( void ); void GrowNlf( void ); + void GrowMatrix( void ); void GetElement( const UINT16 nId ); void GetElementRek( const UINT16 nId ); public: @@ -179,6 +185,8 @@ class TokenPool const TokenId Store( const DefTokenId eId, const String& rName ); // 4 externals (e.g. AddIns, Makros...) const TokenId StoreNlf( const SingleRefData& rTr ); + const TokenId StoreMatrix( SCSIZE nC, SCSIZE nR ); + inline const TokenId LastId( void ) const; inline const ScTokenArray* operator []( const TokenId nId ); void Reset( void ); @@ -186,7 +194,8 @@ class TokenPool inline const SingleRefData* GetSRD( const TokenId& nId ) const; BOOL IsSingleOp( const TokenId& nId, const DefTokenId eId ) const; const String* GetExternal( const TokenId& nId ) const; - const String* GetString( const TokenId& nId ) const; + const String* GetString( const TokenId& nId ) const; + ScMatrix* GetMatrix( unsigned int n ) const; }; diff -pudr sc/source/filter/inc/xlformula.hxx sc/source/filter/inc/xlformula.hxx --- sc/source/filter/inc/xlformula.hxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/inc/xlformula.hxx 2007-03-11 13:57:52.000000000 -0400 @@ -291,7 +291,8 @@ public: /** Creates an empty token array. */ explicit XclTokenArray( bool bVolatile = false ); /** Creates a token array, swaps passed token vector into own data. */ - explicit XclTokenArray( ScfUInt8Vec& rTokVec, bool bVolatile = false ); + explicit XclTokenArray( ScfUInt8Vec& rTokVec, bool bVolatile = false, + ScfUInt8Vec* pExtensionTokens = NULL); /** Returns true, if the token array is empty. */ inline bool Empty() const { return maTokVec.empty(); } @@ -302,9 +303,6 @@ public: /** Returns true, if the formula contains a volatile function. */ inline bool IsVolatile() const { return mbVolatile; } - /** Swaps own token vector with passed token vector. */ - inline void SwapTokenVec( ScfUInt8Vec& rTokVec ) { maTokVec.swap( rTokVec ); } - /** Reads the size field of the token array. */ void ReadSize( XclImpStream& rStrm ); /** Reads the tokens of the token array (without size field). */ @@ -324,6 +322,7 @@ public: private: ScfUInt8Vec maTokVec; /// Byte vector containing token data. + ScfUInt8Vec maExtensions; /// Byte vector of extensions (eg inline arrays) bool mbVolatile; /// True = Formula contains volatile function. }; diff -pudr sc/source/filter/xcl97/XclImpChangeTrack.cxx sc/source/filter/xcl97/XclImpChangeTrack.cxx --- sc/source/filter/xcl97/XclImpChangeTrack.cxx 2007-03-11 13:53:03.000000000 -0400 +++ sc/source/filter/xcl97/XclImpChangeTrack.cxx 2007-03-11 13:57:52.000000000 -0400 @@ -232,7 +232,7 @@ void XclImpChangeTrack::ReadFormula( ScT // read the formula, 3D tab refs from extended data const ScTokenArray* pArray = NULL; aFmlConv.Reset( rPosition ); - BOOL bOK = (aFmlConv.Convert( pArray, aFmlaStrm, nFmlSize ) == ConvOK); + BOOL bOK = (aFmlConv.Convert( pArray, aFmlaStrm, nFmlSize, false, FT_CellFormula) == ConvOK); // JEG : Check This rpTokenArray = (bOK && pArray) ? new ScTokenArray( *pArray ) : NULL; pStrm->Ignore( 1 ); } diff -pudr sc/source/ui/src/globstr.src sc/source/ui/src/globstr.src --- sc/source/ui/src/globstr.src 2007-03-11 06:44:27.000000000 -0400 +++ sc/source/ui/src/globstr.src 2007-03-11 13:15:50.000000000 -0400 @@ -2605,6 +2605,12 @@ Resource RID_GLOBSTR Text [ en-US ] = "#NULL!" ; Text [ x-comment ] = " "; }; + String STR_ERR_NESTED_ARRAY + { + Text [ de ] = "Nested arrays are not supported." ; + Text [ en-US ] = "Nested arrays are not supported." ; + Text [ x-comment ] = " "; + }; String STR_RECALC_MANUAL { Text [ de ] = "Manuell";