1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: externallinkfragment.cxx,v $
10 * $Revision: 1.4.20.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/externallinkfragment.hxx"
32 #include <com/sun/star/sheet/XExternalSheetCache.hpp>
33 #include "oox/helper/attributelist.hxx"
34 #include "oox/xls/biffinputstream.hxx"
35 #include "oox/xls/defnamesbuffer.hxx"
36 #include "oox/xls/sheetdatacontext.hxx"
37 #include "oox/xls/unitconverter.hxx"
39 using ::rtl::OUString
;
40 using ::com::sun::star::uno::Any
;
41 using ::com::sun::star::uno::Reference
;
42 using ::com::sun::star::uno::Exception
;
43 using ::com::sun::star::table::CellAddress
;
44 using ::com::sun::star::sheet::XExternalSheetCache
;
45 using ::oox::core::ContextHandlerRef
;
46 using ::oox::core::RecordInfo
;
47 using ::oox::core::Relation
;
52 // ============================================================================
54 OoxExternalSheetDataContext::OoxExternalSheetDataContext(
55 OoxWorkbookFragmentBase
& rFragment
, const Reference
< XExternalSheetCache
>& rxSheetCache
) :
56 OoxWorkbookContextBase( rFragment
),
57 mxSheetCache( rxSheetCache
)
59 OSL_ENSURE( mxSheetCache
.is(), "OoxExternalSheetDataContext::OoxExternalSheetDataContext - missing sheet cache" );
62 // oox.core.ContextHandler2Helper interface -----------------------------------
64 ContextHandlerRef
OoxExternalSheetDataContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
66 switch( getCurrentElement() )
68 case XLS_TOKEN( sheetData
):
69 if( nElement
== XLS_TOKEN( row
) ) return this;
71 case XLS_TOKEN( row
):
72 if( nElement
== XLS_TOKEN( cell
) ) { importCell( rAttribs
); return this; }
74 case XLS_TOKEN( cell
):
75 if( nElement
== XLS_TOKEN( v
) ) return this; // collect characters in onEndElement()
81 void OoxExternalSheetDataContext::onEndElement( const OUString
& rChars
)
83 switch( getCurrentElement() )
90 setCellValue( Any( rChars
.toDouble() ) );
93 setCellValue( Any( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( rChars
) ) ) );
96 setCellValue( Any( rChars
) );
99 mnCurrType
= XML_TOKEN_INVALID
;
104 ContextHandlerRef
OoxExternalSheetDataContext::onCreateRecordContext( sal_Int32 nRecId
, RecordInputStream
& rStrm
)
106 switch( getCurrentElement() )
108 case OOBIN_ID_EXTSHEETDATA
:
109 if( nRecId
== OOBIN_ID_EXTROW
) { maCurrPos
.Row
= rStrm
.readInt32(); return this; }
111 case OOBIN_ID_EXTROW
:
114 case OOBIN_ID_EXTCELL_BLANK
: importExtCellBlank( rStrm
); break;
115 case OOBIN_ID_EXTCELL_BOOL
: importExtCellBool( rStrm
); break;
116 case OOBIN_ID_EXTCELL_DOUBLE
: importExtCellDouble( rStrm
); break;
117 case OOBIN_ID_EXTCELL_ERROR
: importExtCellError( rStrm
); break;
118 case OOBIN_ID_EXTCELL_STRING
: importExtCellString( rStrm
); break;
125 // private --------------------------------------------------------------------
127 void OoxExternalSheetDataContext::importCell( const AttributeList
& rAttribs
)
129 if( getAddressConverter().convertToCellAddress( maCurrPos
, rAttribs
.getString( XML_r
, OUString() ), 0, false ) )
130 mnCurrType
= rAttribs
.getToken( XML_t
, XML_n
);
132 mnCurrType
= XML_TOKEN_INVALID
;
135 void OoxExternalSheetDataContext::importExtCellBlank( RecordInputStream
& rStrm
)
137 maCurrPos
.Column
= rStrm
.readInt32();
138 setCellValue( Any( OUString() ) );
141 void OoxExternalSheetDataContext::importExtCellBool( RecordInputStream
& rStrm
)
143 maCurrPos
.Column
= rStrm
.readInt32();
144 double fValue
= (rStrm
.readuInt8() == 0) ? 0.0 : 1.0;
145 setCellValue( Any( fValue
) );
148 void OoxExternalSheetDataContext::importExtCellDouble( RecordInputStream
& rStrm
)
150 maCurrPos
.Column
= rStrm
.readInt32();
151 setCellValue( Any( rStrm
.readDouble() ) );
154 void OoxExternalSheetDataContext::importExtCellError( RecordInputStream
& rStrm
)
156 maCurrPos
.Column
= rStrm
.readInt32();
157 setCellValue( Any( BiffHelper::calcDoubleFromError( rStrm
.readuInt8() ) ) );
160 void OoxExternalSheetDataContext::importExtCellString( RecordInputStream
& rStrm
)
162 maCurrPos
.Column
= rStrm
.readInt32();
163 setCellValue( Any( rStrm
.readString() ) );
166 void OoxExternalSheetDataContext::setCellValue( const Any
& rValue
)
168 if( mxSheetCache
.is() && getAddressConverter().checkCellAddress( maCurrPos
, false ) ) try
170 mxSheetCache
->setCellValue( maCurrPos
.Column
, maCurrPos
.Row
, rValue
);
177 // ============================================================================
179 OoxExternalLinkFragment::OoxExternalLinkFragment( const WorkbookHelper
& rHelper
,
180 const OUString
& rFragmentPath
, ExternalLink
& rExtLink
) :
181 OoxWorkbookFragmentBase( rHelper
, rFragmentPath
),
182 mrExtLink( rExtLink
),
183 mnResultType( XML_TOKEN_INVALID
)
187 // oox.core.ContextHandler2Helper interface -----------------------------------
189 ContextHandlerRef
OoxExternalLinkFragment::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
191 switch( getCurrentElement() )
193 case XML_ROOT_CONTEXT
:
194 if( nElement
== XLS_TOKEN( externalLink
) ) return this;
197 case XLS_TOKEN( externalLink
):
200 case XLS_TOKEN( externalBook
): mrExtLink
.importExternalBook( getRelations(), rAttribs
); return this;
201 case XLS_TOKEN( ddeLink
): mrExtLink
.importDdeLink( rAttribs
); return this;
202 case XLS_TOKEN( oleLink
): mrExtLink
.importOleLink( getRelations(), rAttribs
); return this;
206 case XLS_TOKEN( externalBook
):
209 case XLS_TOKEN( sheetNames
):
210 case XLS_TOKEN( definedNames
):
211 case XLS_TOKEN( sheetDataSet
): return this;
215 case XLS_TOKEN( sheetNames
):
216 if( nElement
== XLS_TOKEN( sheetName
) ) mrExtLink
.importSheetName( rAttribs
);
218 case XLS_TOKEN( definedNames
):
219 if( nElement
== XLS_TOKEN( definedName
) ) mrExtLink
.importDefinedName( rAttribs
);
221 case XLS_TOKEN( sheetDataSet
):
222 if( (nElement
== XLS_TOKEN( sheetData
)) && (mrExtLink
.getLinkType() == LINKTYPE_EXTERNAL
) )
223 return createSheetDataContext( rAttribs
.getInteger( XML_sheetId
, -1 ) );
226 case XLS_TOKEN( ddeLink
):
227 if( nElement
== XLS_TOKEN( ddeItems
) ) return this;
229 case XLS_TOKEN( ddeItems
):
230 if( nElement
== XLS_TOKEN( ddeItem
) )
232 mxExtName
= mrExtLink
.importDdeItem( rAttribs
);
236 case XLS_TOKEN( ddeItem
):
237 if( nElement
== XLS_TOKEN( values
) )
239 if( mxExtName
.get() ) mxExtName
->importValues( rAttribs
);
243 case XLS_TOKEN( values
):
244 if( nElement
== XLS_TOKEN( value
) )
246 mnResultType
= rAttribs
.getToken( XML_t
, XML_n
);
250 case XLS_TOKEN( value
):
251 if( nElement
== XLS_TOKEN( val
) ) return this; // collect value in onEndElement()
254 case XLS_TOKEN( oleLink
):
255 if( nElement
== XLS_TOKEN( oleItems
) ) return this;
257 case XLS_TOKEN( oleItems
):
258 if( nElement
== XLS_TOKEN( oleItem
) ) mxExtName
= mrExtLink
.importOleItem( rAttribs
);
264 void OoxExternalLinkFragment::onEndElement( const OUString
& rChars
)
266 switch( getCurrentElement() )
268 case XLS_TOKEN( val
):
269 maResultValue
= rChars
;
271 case XLS_TOKEN( value
):
272 if( mxExtName
.get() ) switch( mnResultType
)
275 mxExtName
->appendResultValue( maResultValue
.toDouble() );
278 mxExtName
->appendResultValue( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( maResultValue
) ) );
281 mxExtName
->appendResultValue( maResultValue
.toDouble() );
284 mxExtName
->appendResultValue( maResultValue
);
287 mxExtName
->appendResultValue( BiffHelper::calcDoubleFromError( BIFF_ERR_NA
) );
293 ContextHandlerRef
OoxExternalLinkFragment::onCreateRecordContext( sal_Int32 nRecId
, RecordInputStream
& rStrm
)
295 switch( getCurrentElement() )
297 case XML_ROOT_CONTEXT
:
298 if( nRecId
== OOBIN_ID_EXTERNALBOOK
)
300 mrExtLink
.importExternalBook( getRelations(), rStrm
);
305 case OOBIN_ID_EXTERNALBOOK
:
308 case OOBIN_ID_EXTSHEETDATA
:
309 if( mrExtLink
.getLinkType() == LINKTYPE_EXTERNAL
)
310 return createSheetDataContext( rStrm
.readInt32() );
313 case OOBIN_ID_EXTSHEETNAMES
: mrExtLink
.importExtSheetNames( rStrm
); break;
314 case OOBIN_ID_EXTERNALNAME
: mxExtName
= mrExtLink
.importExternalName( rStrm
); return this;
318 case OOBIN_ID_EXTERNALNAME
:
321 case OOBIN_ID_EXTERNALNAMEFLAGS
: if( mxExtName
.get() ) mxExtName
->importExternalNameFlags( rStrm
); break;
322 case OOBIN_ID_DDEITEMVALUES
: if( mxExtName
.get() ) mxExtName
->importDdeItemValues( rStrm
); return this;
326 case OOBIN_ID_DDEITEMVALUES
:
329 case OOBIN_ID_DDEITEM_BOOL
: if( mxExtName
.get() ) mxExtName
->importDdeItemBool( rStrm
); break;
330 case OOBIN_ID_DDEITEM_DOUBLE
: if( mxExtName
.get() ) mxExtName
->importDdeItemDouble( rStrm
); break;
331 case OOBIN_ID_DDEITEM_ERROR
: if( mxExtName
.get() ) mxExtName
->importDdeItemError( rStrm
); break;
332 case OOBIN_ID_DDEITEM_STRING
: if( mxExtName
.get() ) mxExtName
->importDdeItemString( rStrm
); break;
339 ContextHandlerRef
OoxExternalLinkFragment::createSheetDataContext( sal_Int32 nSheetId
)
341 return new OoxExternalSheetDataContext( *this, mrExtLink
.getSheetCache( nSheetId
) );
344 // oox.core.FragmentHandler2 interface ----------------------------------------
346 const RecordInfo
* OoxExternalLinkFragment::getRecordInfos() const
348 static const RecordInfo spRecInfos
[] =
350 { OOBIN_ID_DDEITEMVALUES
, OOBIN_ID_DDEITEMVALUES
+ 1 },
351 { OOBIN_ID_EXTERNALBOOK
, OOBIN_ID_EXTERNALBOOK
+ 228 },
352 { OOBIN_ID_EXTERNALNAME
, OOBIN_ID_EXTERNALNAME
+ 10 },
353 { OOBIN_ID_EXTROW
, -1 },
354 { OOBIN_ID_EXTSHEETDATA
, OOBIN_ID_EXTSHEETDATA
+ 1 },
360 // ============================================================================
362 BiffExternalLinkFragment::BiffExternalLinkFragment( const BiffWorkbookFragmentBase
& rParent
, bool bImportDefNames
) :
363 BiffWorkbookFragmentBase( rParent
),
364 mbImportDefNames( bImportDefNames
)
368 BiffExternalLinkFragment::~BiffExternalLinkFragment()
372 bool BiffExternalLinkFragment::importFragment()
374 // process all record in this sheet fragment
375 while( mrStrm
.startNextRecord() && (mrStrm
.getRecId() != BIFF_ID_EOF
) )
378 skipFragment(); // skip unknown embedded fragments
382 return !mrStrm
.isEof() && (mrStrm
.getRecId() == BIFF_ID_EOF
);
385 void BiffExternalLinkFragment::importRecord()
387 sal_uInt16 nRecId
= mrStrm
.getRecId();
390 case BIFF2
: switch( nRecId
)
392 case BIFF2_ID_EXTERNALNAME
: importExternalName(); break;
393 case BIFF_ID_EXTERNSHEET
: importExternSheet(); break;
394 case BIFF2_ID_DEFINEDNAME
: importDefinedName(); break;
397 case BIFF3
: switch( nRecId
)
399 case BIFF_ID_CRN
: importCrn(); break;
400 case BIFF3_ID_EXTERNALNAME
: importExternalName(); break;
401 case BIFF_ID_EXTERNSHEET
: importExternSheet(); break;
402 case BIFF3_ID_DEFINEDNAME
: importDefinedName(); break;
403 case BIFF_ID_XCT
: importXct(); break;
406 case BIFF4
: switch( nRecId
)
408 case BIFF_ID_CRN
: importCrn(); break;
409 case BIFF3_ID_EXTERNALNAME
: importExternalName(); break;
410 case BIFF_ID_EXTERNSHEET
: importExternSheet(); break;
411 case BIFF3_ID_DEFINEDNAME
: importDefinedName(); break;
412 case BIFF_ID_XCT
: importXct(); break;
415 case BIFF5
: switch( nRecId
)
417 case BIFF_ID_CRN
: importCrn(); break;
418 case BIFF5_ID_EXTERNALNAME
: importExternalName(); break;
419 case BIFF_ID_EXTERNSHEET
: importExternSheet(); break;
420 case BIFF5_ID_DEFINEDNAME
: importDefinedName(); break;
421 case BIFF_ID_XCT
: importXct(); break;
424 case BIFF8
: switch( nRecId
)
426 case BIFF_ID_CRN
: importCrn(); break;
427 case BIFF_ID_EXTERNALBOOK
: importExternalBook(); break;
428 case BIFF5_ID_EXTERNALNAME
: importExternalName(); break;
429 case BIFF_ID_EXTERNSHEET
: importExternSheet(); break;
430 case BIFF5_ID_DEFINEDNAME
: importDefinedName(); break;
431 case BIFF_ID_XCT
: importXct(); break;
434 case BIFF_UNKNOWN
: break;
438 void BiffExternalLinkFragment::finalizeImport()
440 getDefinedNames().finalizeImport();
443 // private --------------------------------------------------------------------
445 void BiffExternalLinkFragment::importExternSheet()
447 mxSheetCache
.clear();
448 if( getBiff() == BIFF8
)
449 getExternalLinks().importExternSheet8( mrStrm
);
451 mxExtLink
= getExternalLinks().importExternSheet( mrStrm
);
454 void BiffExternalLinkFragment::importExternalBook()
456 mxSheetCache
.clear();
457 mxExtLink
= getExternalLinks().importExternalBook( mrStrm
);
460 void BiffExternalLinkFragment::importExternalName()
462 if( mxExtLink
.get() )
463 mxExtLink
->importExternalName( mrStrm
);
466 void BiffExternalLinkFragment::importXct()
468 mxSheetCache
.clear();
469 if( mxExtLink
.get() && (mxExtLink
->getLinkType() == LINKTYPE_EXTERNAL
) )
478 mxSheetCache
= mxExtLink
->getSheetCache( 0 );
482 mxSheetCache
= mxExtLink
->getSheetCache( mrStrm
.readInt16() );
484 case BIFF_UNKNOWN
: break;
489 void BiffExternalLinkFragment::importCrn()
491 if( !mxSheetCache
.is() ) return;
493 sal_uInt8 nCol2
, nCol1
;
495 mrStrm
>> nCol2
>> nCol1
>> nRow
;
497 for( BinAddress
aBinAddr( nCol1
, nRow
); bLoop
&& !mrStrm
.isEof() && (aBinAddr
.mnCol
<= nCol2
); ++aBinAddr
.mnCol
)
499 switch( mrStrm
.readuInt8() )
501 case BIFF_DATATYPE_EMPTY
:
503 setCellValue( aBinAddr
, Any( OUString() ) );
505 case BIFF_DATATYPE_DOUBLE
:
506 setCellValue( aBinAddr
, Any( mrStrm
.readDouble() ) );
508 case BIFF_DATATYPE_STRING
:
510 OUString aText
= (getBiff() == BIFF8
) ? mrStrm
.readUniString() : mrStrm
.readByteStringUC( false, getTextEncoding() );
511 setCellValue( aBinAddr
, Any( aText
) );
514 case BIFF_DATATYPE_BOOL
:
516 double fValue
= (mrStrm
.readuInt8() == 0) ? 0.0 : 1.0;
517 setCellValue( aBinAddr
, Any( fValue
) );
521 case BIFF_DATATYPE_ERROR
:
522 setCellValue( aBinAddr
, Any( BiffHelper::calcDoubleFromError( mrStrm
.readuInt8() ) ) );
526 OSL_ENSURE( false, "BiffExternalLinkFragment::importCrn - unknown data type" );
532 void BiffExternalLinkFragment::importDefinedName()
534 if( mbImportDefNames
)
535 getDefinedNames().importDefinedName( mrStrm
);
538 void BiffExternalLinkFragment::setCellValue( const BinAddress
& rBinAddr
, const Any
& rValue
)
540 CellAddress aCellPos
;
541 if( mxSheetCache
.is() && getAddressConverter().convertToCellAddress( aCellPos
, rBinAddr
, 0, false ) ) try
543 mxSheetCache
->setCellValue( aCellPos
.Column
, aCellPos
.Row
, rValue
);
550 // ============================================================================