Update ooo320-m1
[ooovba.git] / oox / source / xls / externallinkfragment.cxx
blob39686ae7cb64cd1c379b5dda3bdcace192e9269c
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;
49 namespace oox {
50 namespace xls {
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;
70 break;
71 case XLS_TOKEN( row ):
72 if( nElement == XLS_TOKEN( cell ) ) { importCell( rAttribs ); return this; }
73 break;
74 case XLS_TOKEN( cell ):
75 if( nElement == XLS_TOKEN( v ) ) return this; // collect characters in onEndElement()
76 break;
78 return 0;
81 void OoxExternalSheetDataContext::onEndElement( const OUString& rChars )
83 switch( getCurrentElement() )
85 case XLS_TOKEN( v ):
86 switch( mnCurrType )
88 case XML_b:
89 case XML_n:
90 setCellValue( Any( rChars.toDouble() ) );
91 break;
92 case XML_e:
93 setCellValue( Any( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( rChars ) ) ) );
94 break;
95 case XML_str:
96 setCellValue( Any( rChars ) );
97 break;
99 mnCurrType = XML_TOKEN_INVALID;
100 break;
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; }
110 break;
111 case OOBIN_ID_EXTROW:
112 switch( nRecId )
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;
120 break;
122 return 0;
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 );
131 else
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 );
172 catch( Exception& )
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;
195 break;
197 case XLS_TOKEN( externalLink ):
198 switch( nElement )
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;
204 break;
206 case XLS_TOKEN( externalBook ):
207 switch( nElement )
209 case XLS_TOKEN( sheetNames ):
210 case XLS_TOKEN( definedNames ):
211 case XLS_TOKEN( sheetDataSet ): return this;
213 break;
215 case XLS_TOKEN( sheetNames ):
216 if( nElement == XLS_TOKEN( sheetName ) ) mrExtLink.importSheetName( rAttribs );
217 break;
218 case XLS_TOKEN( definedNames ):
219 if( nElement == XLS_TOKEN( definedName ) ) mrExtLink.importDefinedName( rAttribs );
220 break;
221 case XLS_TOKEN( sheetDataSet ):
222 if( (nElement == XLS_TOKEN( sheetData )) && (mrExtLink.getLinkType() == LINKTYPE_EXTERNAL) )
223 return createSheetDataContext( rAttribs.getInteger( XML_sheetId, -1 ) );
224 break;
226 case XLS_TOKEN( ddeLink ):
227 if( nElement == XLS_TOKEN( ddeItems ) ) return this;
228 break;
229 case XLS_TOKEN( ddeItems ):
230 if( nElement == XLS_TOKEN( ddeItem ) )
232 mxExtName = mrExtLink.importDdeItem( rAttribs );
233 return this;
235 break;
236 case XLS_TOKEN( ddeItem ):
237 if( nElement == XLS_TOKEN( values ) )
239 if( mxExtName.get() ) mxExtName->importValues( rAttribs );
240 return this;
242 break;
243 case XLS_TOKEN( values ):
244 if( nElement == XLS_TOKEN( value ) )
246 mnResultType = rAttribs.getToken( XML_t, XML_n );
247 return this;
249 break;
250 case XLS_TOKEN( value ):
251 if( nElement == XLS_TOKEN( val ) ) return this; // collect value in onEndElement()
252 break;
254 case XLS_TOKEN( oleLink ):
255 if( nElement == XLS_TOKEN( oleItems ) ) return this;
256 break;
257 case XLS_TOKEN( oleItems ):
258 if( nElement == XLS_TOKEN( oleItem ) ) mxExtName = mrExtLink.importOleItem( rAttribs );
259 break;
261 return false;
264 void OoxExternalLinkFragment::onEndElement( const OUString& rChars )
266 switch( getCurrentElement() )
268 case XLS_TOKEN( val ):
269 maResultValue = rChars;
270 break;
271 case XLS_TOKEN( value ):
272 if( mxExtName.get() ) switch( mnResultType )
274 case XML_b:
275 mxExtName->appendResultValue( maResultValue.toDouble() );
276 break;
277 case XML_e:
278 mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( maResultValue ) ) );
279 break;
280 case XML_n:
281 mxExtName->appendResultValue( maResultValue.toDouble() );
282 break;
283 case XML_str:
284 mxExtName->appendResultValue( maResultValue );
285 break;
286 default:
287 mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) );
289 break;
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 );
301 return this;
303 break;
305 case OOBIN_ID_EXTERNALBOOK:
306 switch( nRecId )
308 case OOBIN_ID_EXTSHEETDATA:
309 if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL )
310 return createSheetDataContext( rStrm.readInt32() );
311 break;
313 case OOBIN_ID_EXTSHEETNAMES: mrExtLink.importExtSheetNames( rStrm ); break;
314 case OOBIN_ID_EXTERNALNAME: mxExtName = mrExtLink.importExternalName( rStrm ); return this;
316 break;
318 case OOBIN_ID_EXTERNALNAME:
319 switch( nRecId )
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;
324 break;
326 case OOBIN_ID_DDEITEMVALUES:
327 switch( nRecId )
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;
334 break;
336 return 0;
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 },
355 { -1, -1 }
357 return spRecInfos;
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) )
377 if( isBofRecord() )
378 skipFragment(); // skip unknown embedded fragments
379 else
380 importRecord();
382 return !mrStrm.isEof() && (mrStrm.getRecId() == BIFF_ID_EOF);
385 void BiffExternalLinkFragment::importRecord()
387 sal_uInt16 nRecId = mrStrm.getRecId();
388 switch( getBiff() )
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;
396 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;
405 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;
414 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;
423 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;
433 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 );
450 else
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) )
471 switch( getBiff() )
473 case BIFF2:
474 break;
475 case BIFF3:
476 case BIFF4:
477 case BIFF5:
478 mxSheetCache = mxExtLink->getSheetCache( 0 );
479 break;
480 case BIFF8:
481 mrStrm.skip( 2 );
482 mxSheetCache = mxExtLink->getSheetCache( mrStrm.readInt16() );
483 break;
484 case BIFF_UNKNOWN: break;
489 void BiffExternalLinkFragment::importCrn()
491 if( !mxSheetCache.is() ) return;
493 sal_uInt8 nCol2, nCol1;
494 sal_uInt16 nRow;
495 mrStrm >> nCol2 >> nCol1 >> nRow;
496 bool bLoop = true;
497 for( BinAddress aBinAddr( nCol1, nRow ); bLoop && !mrStrm.isEof() && (aBinAddr.mnCol <= nCol2); ++aBinAddr.mnCol )
499 switch( mrStrm.readuInt8() )
501 case BIFF_DATATYPE_EMPTY:
502 mrStrm.skip( 8 );
503 setCellValue( aBinAddr, Any( OUString() ) );
504 break;
505 case BIFF_DATATYPE_DOUBLE:
506 setCellValue( aBinAddr, Any( mrStrm.readDouble() ) );
507 break;
508 case BIFF_DATATYPE_STRING:
510 OUString aText = (getBiff() == BIFF8) ? mrStrm.readUniString() : mrStrm.readByteStringUC( false, getTextEncoding() );
511 setCellValue( aBinAddr, Any( aText ) );
513 break;
514 case BIFF_DATATYPE_BOOL:
516 double fValue = (mrStrm.readuInt8() == 0) ? 0.0 : 1.0;
517 setCellValue( aBinAddr, Any( fValue ) );
518 mrStrm.skip( 7 );
520 break;
521 case BIFF_DATATYPE_ERROR:
522 setCellValue( aBinAddr, Any( BiffHelper::calcDoubleFromError( mrStrm.readuInt8() ) ) );
523 mrStrm.skip( 7 );
524 break;
525 default:
526 OSL_ENSURE( false, "BiffExternalLinkFragment::importCrn - unknown data type" );
527 bLoop = false;
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 );
545 catch( Exception& )
550 // ============================================================================
552 } // namespace xls
553 } // namespace oox