1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmlhelp.hxx" 30 31 #define WORKAROUND_98119 32 33 #ifdef WORKAROUND_98119 34 #include "bufferedinputstream.hxx" 35 #endif 36 37 #include <string.h> 38 #ifndef _VOS_DIAGNOSE_HXX_ 39 #include <vos/diagnose.hxx> 40 #endif 41 #include <osl/thread.h> 42 #include <rtl/memory.h> 43 #include <osl/file.hxx> 44 #include <cppuhelper/weak.hxx> 45 #include <cppuhelper/queryinterface.hxx> 46 #include <comphelper/processfactory.hxx> 47 #include <rtl/uri.hxx> 48 #include <rtl/ustrbuf.hxx> 49 #include <libxslt/xslt.h> 50 #include <libxslt/transform.h> 51 #include <libxslt/xsltutils.h> 52 #include "db.hxx" 53 #include <com/sun/star/io/XActiveDataSink.hpp> 54 #include <com/sun/star/io/XInputStream.hpp> 55 #include <com/sun/star/io/XSeekable.hpp> 56 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 57 #include <com/sun/star/ucb/OpenMode.hpp> 58 #include <com/sun/star/ucb/XCommandProcessor.hpp> 59 #include <com/sun/star/ucb/XCommandEnvironment.hpp> 60 #include <com/sun/star/ucb/XContentIdentifier.hpp> 61 #include <com/sun/star/ucb/XContentProvider.hpp> 62 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp> 63 #include <com/sun/star/container/XHierarchicalNameAccess.hpp> 64 #include <com/sun/star/beans/XPropertySet.hpp> 65 66 #include "urlparameter.hxx" 67 #include "databases.hxx" 68 69 namespace chelp { 70 71 inline bool ascii_isDigit( sal_Unicode ch ) 72 { 73 return ((ch >= 0x0030) && (ch <= 0x0039)); 74 } 75 76 inline bool ascii_isLetter( sal_Unicode ch ) 77 { 78 return ( ( (ch >= 0x0041) && (ch <= 0x005A) ) || 79 ( (ch >= 0x0061) && (ch <= 0x007A) ) ); 80 } 81 82 inline bool isLetterOrDigit( sal_Unicode ch ) 83 { 84 return ascii_isLetter( ch ) || ascii_isDigit( ch ); 85 } 86 87 } 88 89 using namespace cppu; 90 using namespace com::sun::star::io; 91 using namespace com::sun::star::uno; 92 using namespace com::sun::star::lang; 93 using namespace com::sun::star::ucb; 94 using namespace com::sun::star::beans; 95 using namespace com::sun::star::container; 96 using namespace berkeleydbproxy; 97 using namespace chelp; 98 99 100 URLParameter::URLParameter( const rtl::OUString& aURL, 101 Databases* pDatabases ) 102 throw( com::sun::star::ucb::IllegalIdentifierException ) 103 : m_pDatabases( pDatabases ), 104 m_aURL( aURL ) 105 { 106 init( false ); 107 parse(); 108 } 109 110 111 bool URLParameter::isErrorDocument() 112 { 113 bool bErrorDoc = false; 114 115 if( isFile() ) 116 { 117 Reference< XHierarchicalNameAccess > xNA = 118 m_pDatabases->findJarFileForPath( get_jar(), get_language(), get_path() ); 119 bErrorDoc = !xNA.is(); 120 } 121 122 return bErrorDoc; 123 } 124 125 126 rtl::OString URLParameter::getByName( const char* par ) 127 { 128 rtl::OUString val; 129 130 if( strcmp( par,"Program" ) == 0 ) 131 val = get_program(); 132 else if( strcmp( par,"Database" ) == 0 ) 133 val = get_module(); 134 else if( strcmp( par,"DatabasePar" ) == 0 ) 135 val = get_dbpar(); 136 else if( strcmp( par,"Id" ) == 0 ) 137 val = get_id(); 138 else if( strcmp( par,"Path" ) == 0 ) 139 val = get_path(); 140 else if( strcmp( par,"Language" ) == 0 ) 141 val = get_language(); 142 else if( strcmp( par,"System" ) == 0 ) 143 val = get_system(); 144 else if( strcmp( par,"HelpPrefix" ) == 0 ) 145 val = get_prefix(); 146 147 return rtl::OString( val.getStr(),val.getLength(),RTL_TEXTENCODING_UTF8 ); 148 } 149 150 151 rtl::OUString URLParameter::get_id() 152 { 153 if( m_aId.compareToAscii("start") == 0 ) 154 { // module is set 155 StaticModuleInformation* inf = 156 m_pDatabases->getStaticInformationForModule( get_module(), 157 get_language() ); 158 if( inf ) 159 m_aId = inf->get_id(); 160 161 m_bStart = true; 162 } 163 164 return m_aId; 165 } 166 167 rtl::OUString URLParameter::get_tag() 168 { 169 if( isFile() ) 170 return get_the_tag(); 171 else 172 return m_aTag; 173 } 174 175 176 rtl::OUString URLParameter::get_title() 177 { 178 if( isFile() ) 179 return get_the_title(); 180 else if( m_aModule.compareToAscii("") != 0 ) 181 { 182 StaticModuleInformation* inf = 183 m_pDatabases->getStaticInformationForModule( get_module(), 184 get_language() ); 185 if( inf ) 186 m_aTitle = inf->get_title(); 187 } 188 else // This must be the root 189 m_aTitle = rtl::OUString::createFromAscii("root"); 190 191 return m_aTitle; 192 } 193 194 195 rtl::OUString URLParameter::get_language() 196 { 197 if( m_aLanguage.getLength() == 0 ) 198 return m_aDefaultLanguage; 199 200 return m_aLanguage; 201 } 202 203 204 rtl::OUString URLParameter::get_program() 205 { 206 if( ! m_aProgram.getLength() ) 207 { 208 StaticModuleInformation* inf = 209 m_pDatabases->getStaticInformationForModule( get_module(), 210 get_language() ); 211 if( inf ) 212 m_aProgram = inf->get_program(); 213 } 214 return m_aProgram; 215 } 216 217 218 void URLParameter::init( bool bDefaultLanguageIsInitialized ) 219 { 220 (void)bDefaultLanguageIsInitialized; 221 222 m_bBerkeleyRead = false; 223 m_bStart = false; 224 m_bUseDB = true; 225 m_nHitCount = 100; // The default maximum hitcount 226 } 227 228 229 rtl::OUString URLParameter::get_the_tag() 230 { 231 if(m_bUseDB) { 232 if( ! m_bBerkeleyRead ) 233 readBerkeley(); 234 235 m_bBerkeleyRead = true; 236 237 return m_aTag; 238 } 239 else 240 return rtl::OUString(); 241 } 242 243 244 245 rtl::OUString URLParameter::get_the_path() 246 { 247 if(m_bUseDB) { 248 if( ! m_bBerkeleyRead ) 249 readBerkeley(); 250 m_bBerkeleyRead = true; 251 252 return m_aPath; 253 } 254 else 255 return get_id(); 256 } 257 258 259 260 rtl::OUString URLParameter::get_the_title() 261 { 262 if(m_bUseDB) { 263 if( ! m_bBerkeleyRead ) 264 readBerkeley(); 265 m_bBerkeleyRead = true; 266 267 return m_aTitle; 268 } 269 else 270 return rtl::OUString(); 271 } 272 273 274 rtl::OUString URLParameter::get_the_jar() 275 { 276 if(m_bUseDB) { 277 if( ! m_bBerkeleyRead ) 278 readBerkeley(); 279 m_bBerkeleyRead = true; 280 281 return m_aJar; 282 } 283 else 284 return get_module() + rtl::OUString::createFromAscii(".jar"); 285 } 286 287 288 289 290 void URLParameter::readBerkeley() 291 { 292 static rtl::OUString aQuestionMark( rtl::OUString::createFromAscii( "?" ) ); 293 294 if( get_id().compareToAscii("") == 0 ) 295 return; 296 297 rtl::OUString aModule = get_module(); 298 rtl::OUString aLanguage = get_language(); 299 300 DataBaseIterator aDbIt( *m_pDatabases, aModule, aLanguage, false ); 301 bool bSuccess = false; 302 303 int nSize = 0; 304 const sal_Char* pData = NULL; 305 306 Dbt data; 307 DBData aDBData; 308 rtl::OUString aExtensionPath; 309 rtl::OUString aExtensionRegistryPath; 310 while( true ) 311 { 312 Db* db = aDbIt.nextDb( &aExtensionPath, &aExtensionRegistryPath ); 313 if( !db ) 314 break; 315 316 rtl::OString keyStr( m_aId.getStr(),m_aId.getLength(),RTL_TEXTENCODING_UTF8 ); 317 318 DBHelp* pDBHelp = db->getDBHelp(); 319 if( pDBHelp != NULL ) 320 { 321 bSuccess = pDBHelp->getValueForKey( keyStr, aDBData ); 322 if( bSuccess ) 323 { 324 nSize = aDBData.getSize(); 325 pData = aDBData.getData(); 326 break; 327 } 328 } 329 else 330 { 331 Dbt key( static_cast< void* >( const_cast< sal_Char* >( keyStr.getStr() ) ), 332 keyStr.getLength() ); 333 int err = db->get( 0,&key,&data,0 ); 334 if( err == 0 ) 335 { 336 bSuccess = true; 337 nSize = data.get_size(); 338 pData = static_cast<sal_Char*>( data.get_data() ); 339 break; 340 } 341 } 342 } 343 344 if( bSuccess ) 345 { 346 DbtToStringConverter converter( pData, nSize ); 347 m_aTitle = converter.getTitle(); 348 m_pDatabases->replaceName( m_aTitle ); 349 m_aPath = converter.getFile(); 350 m_aJar = converter.getDatabase(); 351 if( aExtensionPath.getLength() > 0 ) 352 { 353 rtl::OUStringBuffer aExtendedJarStrBuf; 354 aExtendedJarStrBuf.append( aQuestionMark ); 355 aExtendedJarStrBuf.append( aExtensionPath ); 356 aExtendedJarStrBuf.append( aQuestionMark ); 357 aExtendedJarStrBuf.append( m_aJar ); 358 m_aJar = aExtendedJarStrBuf.makeStringAndClear(); 359 m_aExtensionRegistryPath = aExtensionRegistryPath; 360 } 361 m_aTag = converter.getHash(); 362 } 363 } 364 365 366 367 // Class encapsulating the transformation of the XInputStream to XHTML 368 369 370 class InputStreamTransformer 371 : public OWeakObject, 372 public XInputStream, 373 public XSeekable 374 { 375 public: 376 377 InputStreamTransformer( URLParameter* urlParam, 378 Databases* pDatatabases, 379 bool isRoot = false ); 380 381 ~InputStreamTransformer(); 382 383 virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException ); 384 virtual void SAL_CALL acquire( void ) throw(); 385 virtual void SAL_CALL release( void ) throw(); 386 387 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead ) 388 throw( NotConnectedException, 389 BufferSizeExceededException, 390 IOException, 391 RuntimeException); 392 393 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead ) 394 throw( NotConnectedException, 395 BufferSizeExceededException, 396 IOException, 397 RuntimeException); 398 399 virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException, 400 BufferSizeExceededException, 401 IOException, 402 RuntimeException ); 403 404 virtual sal_Int32 SAL_CALL available( void ) throw( NotConnectedException, 405 IOException, 406 RuntimeException ); 407 408 virtual void SAL_CALL closeInput( void ) throw( NotConnectedException, 409 IOException, 410 RuntimeException ); 411 412 virtual void SAL_CALL seek( sal_Int64 location ) throw( IllegalArgumentException, 413 IOException, 414 RuntimeException ); 415 416 virtual sal_Int64 SAL_CALL getPosition( void ) throw( IOException,RuntimeException ); 417 418 virtual sal_Int64 SAL_CALL getLength( void ) throw( IOException,RuntimeException ); 419 420 void addToBuffer( const char* buffer,int len ); 421 422 sal_Int8* getData() const { return (sal_Int8*) buffer; } 423 424 sal_Int32 getLen() const { return sal_Int32( len ); } 425 426 private: 427 428 osl::Mutex m_aMutex; 429 430 int len,pos; 431 char *buffer; 432 }; 433 434 435 436 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr, 437 const Command& aCommand, 438 sal_Int32 CommandId, 439 const Reference< XCommandEnvironment >& Environment, 440 const Reference< XOutputStream >& xDataSink ) 441 { 442 (void)rxSMgr; 443 (void)aCommand; 444 (void)CommandId; 445 (void)Environment; 446 447 if( ! xDataSink.is() ) 448 return; 449 450 if( isPicture() ) 451 { 452 Reference< XInputStream > xStream; 453 Reference< XHierarchicalNameAccess > xNA = 454 m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ), 455 get_language() ); 456 457 rtl::OUString path = get_path(); 458 if( xNA.is() ) 459 { 460 try 461 { 462 Any aEntry = xNA->getByHierarchicalName( path ); 463 Reference< XActiveDataSink > xSink; 464 if( ( aEntry >>= xSink ) && xSink.is() ) 465 xStream = xSink->getInputStream(); 466 } 467 catch ( NoSuchElementException & ) 468 { 469 } 470 } 471 if( xStream.is() ) 472 { 473 sal_Int32 ret; 474 Sequence< sal_Int8 > aSeq( 4096 ); 475 while( true ) 476 { 477 try 478 { 479 ret = xStream->readBytes( aSeq,4096 ); 480 xDataSink->writeBytes( aSeq ); 481 if( ret < 4096 ) 482 break; 483 } 484 catch( const Exception& ) 485 { 486 break; 487 } 488 } 489 } 490 } 491 else 492 { 493 // a standard document or else an active help text, plug in the new input stream 494 InputStreamTransformer* p = new InputStreamTransformer( this,m_pDatabases,isRoot() ); 495 try 496 { 497 xDataSink->writeBytes( Sequence< sal_Int8 >( p->getData(),p->getLen() ) ); 498 } 499 catch( const Exception& ) 500 { 501 } 502 delete p; 503 } 504 xDataSink->closeOutput(); 505 } 506 507 508 509 void URLParameter::open( const Reference< XMultiServiceFactory >& rxSMgr, 510 const Command& aCommand, 511 sal_Int32 CommandId, 512 const Reference< XCommandEnvironment >& Environment, 513 const Reference< XActiveDataSink >& xDataSink ) 514 { 515 (void)rxSMgr; 516 (void)aCommand; 517 (void)CommandId; 518 (void)Environment; 519 520 if( isPicture() ) 521 { 522 Reference< XInputStream > xStream; 523 Reference< XHierarchicalNameAccess > xNA = 524 m_pDatabases->jarFile( rtl::OUString::createFromAscii( "picture.jar" ), 525 get_language() ); 526 527 rtl::OUString path = get_path(); 528 if( xNA.is() ) 529 { 530 try 531 { 532 Any aEntry = xNA->getByHierarchicalName( path ); 533 Reference< XActiveDataSink > xSink; 534 if( ( aEntry >>= xSink ) && xSink.is() ) 535 xStream = xSink->getInputStream(); 536 } 537 catch ( NoSuchElementException & ) 538 { 539 } 540 } 541 #ifdef WORKAROUND_98119 542 xDataSink->setInputStream( turnToSeekable(xStream) ); 543 #else 544 xDataSink->setInputStream( xStream ); 545 #endif 546 } 547 else 548 // a standard document or else an active help text, plug in the new input stream 549 xDataSink->setInputStream( new InputStreamTransformer( this,m_pDatabases,isRoot() ) ); 550 } 551 552 553 // #include <stdio.h> 554 555 void URLParameter::parse() throw( com::sun::star::ucb::IllegalIdentifierException ) 556 { 557 // fprintf(stdout,"url send to xmlhelp: %s\n",(rtl::OUStringToOString(m_aURL,RTL_TEXTENCODING_UTF8).getStr())); 558 m_aExpr = m_aURL; 559 560 sal_Int32 lstIdx = m_aExpr.lastIndexOf( sal_Unicode( '#' ) ); 561 if( lstIdx != -1 ) 562 m_aExpr = m_aExpr.copy( 0,lstIdx ); 563 564 if( ! scheme() || 565 ! name( module() ) || 566 ! query() || 567 ! m_aLanguage.getLength() || 568 ! m_aSystem.getLength() ) 569 throw com::sun::star::ucb::IllegalIdentifierException(); 570 } 571 572 573 bool URLParameter::scheme() 574 { 575 // Correct extension help links as sometimes the 576 // module is missing resulting in a misformed URL 577 if( m_aExpr.compareToAscii( "vnd.sun.star.help:///", 21 ) == 0 ) 578 { 579 sal_Int32 nLen = m_aExpr.getLength(); 580 rtl::OUString aLastStr = m_aExpr.copy( nLen - 6 ); 581 if( aLastStr.compareToAscii( "DbPAR=" ) == 0 ) 582 { 583 rtl::OUString aNewExpr = m_aExpr.copy( 0, 20 ); 584 rtl::OUString aSharedStr = rtl::OUString::createFromAscii( "shared" ); 585 aNewExpr += aSharedStr; 586 aNewExpr += m_aExpr.copy( 20 ); 587 aNewExpr += aSharedStr; 588 m_aExpr = aNewExpr; 589 } 590 } 591 592 for( sal_Int32 nPrefixLen = 20 ; nPrefixLen >= 18 ; --nPrefixLen ) 593 { 594 if( m_aExpr.compareToAscii( "vnd.sun.star.help://", nPrefixLen ) == 0 ) 595 { 596 m_aExpr = m_aExpr.copy( nPrefixLen ); 597 return true; 598 } 599 } 600 return false; 601 } 602 603 604 bool URLParameter::module() 605 { 606 sal_Int32 idx = 0,length = m_aExpr.getLength(); 607 608 while( idx < length && isLetterOrDigit( (m_aExpr.getStr())[idx] ) ) 609 ++idx; 610 611 if( idx != 0 ) 612 { 613 m_aModule = m_aExpr.copy( 0,idx ); 614 m_aExpr = m_aExpr.copy( idx ); 615 return true; 616 } 617 else 618 return false; 619 } 620 621 622 623 bool URLParameter::name( bool modulePresent ) 624 { 625 // if modulepresent, a name may be present, but must not 626 627 sal_Int32 length = m_aExpr.getLength(); 628 629 if( length != 0 && (m_aExpr.getStr())[0] == sal_Unicode( '/' ) ) 630 { 631 sal_Int32 idx = 1; 632 while( idx < length && (m_aExpr.getStr())[idx] != '?' ) 633 // ( isLetterOrDigit( (m_aExpr.getStr())[idx] ) 634 // || (m_aExpr.getStr())[idx] == '/' 635 // || (m_aExpr.getStr())[idx] == '.' )) 636 ++idx; 637 638 if( idx != 1 && ! modulePresent ) 639 return false; 640 else 641 { 642 m_aId = m_aExpr.copy( 1,idx-1 ); 643 m_aExpr = m_aExpr.copy( idx ); 644 } 645 } 646 647 // fprintf(stdout,"id %s\n",(rtl::OUStringToOString(m_aId,RTL_TEXTENCODING_UTF8).getStr())); 648 return true; 649 } 650 651 652 bool URLParameter::query() 653 { 654 rtl::OUString query_; 655 656 if( ! m_aExpr.getLength() ) 657 return true; 658 else if( (m_aExpr.getStr())[0] == sal_Unicode( '?' ) ) 659 query_ = m_aExpr.copy( 1 ).trim(); 660 else 661 return false; 662 663 664 bool ret = true; 665 sal_Int32 delimIdx,equalIdx; 666 rtl::OUString parameter,value; 667 668 while( query_.getLength() != 0 ) 669 { 670 delimIdx = query_.indexOf( sal_Unicode( '&' ) ); 671 equalIdx = query_.indexOf( sal_Unicode( '=' ) ); 672 parameter = query_.copy( 0,equalIdx ).trim(); 673 if( delimIdx == -1 ) 674 { 675 value = query_.copy( equalIdx + 1 ).trim(); 676 query_ = rtl::OUString(); 677 } 678 else 679 { 680 value = query_.copy( equalIdx+1,delimIdx - equalIdx - 1 ).trim(); 681 query_ = query_.copy( delimIdx+1 ).trim(); 682 } 683 684 if( parameter.compareToAscii( "Language" ) == 0 ) 685 m_aLanguage = value; 686 else if( parameter.compareToAscii( "Device" ) == 0 ) 687 m_aDevice = value; 688 else if( parameter.compareToAscii( "Program" ) == 0 ) 689 m_aProgram = value; 690 else if( parameter.compareToAscii( "Eid" ) == 0 ) 691 m_aEid = value; 692 else if( parameter.compareToAscii( "UseDB" ) == 0 ) 693 m_bUseDB = ! ( value.compareToAscii("no") == 0 ); 694 else if( parameter.compareToAscii( "DbPAR" ) == 0 ) 695 m_aDbPar = value; 696 else if( parameter.compareToAscii( "Query" ) == 0 ) 697 { 698 if( ! m_aQuery.getLength() ) 699 m_aQuery = value; 700 else 701 m_aQuery += ( rtl::OUString::createFromAscii( " " ) + value ); 702 } 703 else if( parameter.compareToAscii( "Scope" ) == 0 ) 704 m_aScope = value; 705 else if( parameter.compareToAscii( "System" ) == 0 ) 706 m_aSystem = value; 707 else if( parameter.compareToAscii( "HelpPrefix" ) == 0 ) 708 m_aPrefix = rtl::Uri::decode( 709 value, 710 rtl_UriDecodeWithCharset, 711 RTL_TEXTENCODING_UTF8 ); 712 else if( parameter.compareToAscii( "HitCount" ) == 0 ) 713 m_nHitCount = value.toInt32(); 714 else if( parameter.compareToAscii( "Active" ) == 0 ) 715 m_aActive = value; 716 else 717 ret = false; 718 } 719 720 return ret; 721 } 722 723 struct UserData { 724 725 UserData( InputStreamTransformer* pTransformer, 726 URLParameter* pInitial, 727 Databases* pDatabases ) 728 : m_pTransformer( pTransformer ), 729 m_pDatabases( pDatabases ), 730 m_pInitial( pInitial ) 731 { 732 } 733 734 InputStreamTransformer* m_pTransformer; 735 Databases* m_pDatabases; 736 URLParameter* m_pInitial; 737 }; 738 739 UserData *ugblData = 0; 740 741 extern "C" { 742 743 static int 744 fileMatch(const char * URI) { 745 if ((URI != NULL) && !strncmp(URI, "file:/", 6)) 746 return 1; 747 return 0; 748 } 749 750 static int 751 zipMatch(const char * URI) { 752 if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.zip:/", 18)) 753 return 1; 754 return 0; 755 } 756 757 static int 758 helpMatch(const char * URI) { 759 if ((URI != NULL) && !strncmp(URI, "vnd.sun.star.help:/", 19)) 760 return 1; 761 return 0; 762 } 763 764 static void * 765 fileOpen(const char *URI) { 766 osl::File *pRet = new osl::File(rtl::OUString(URI, strlen(URI), RTL_TEXTENCODING_UTF8)); 767 pRet->open(OpenFlag_Read); 768 return pRet; 769 } 770 771 static void * 772 zipOpen(const char * /*URI*/) { 773 rtl::OUString language,jar,path; 774 775 if( ugblData->m_pInitial->get_eid().getLength() ) 776 return (void*)(new Reference< XHierarchicalNameAccess >); 777 else 778 { 779 jar = ugblData->m_pInitial->get_jar(); 780 language = ugblData->m_pInitial->get_language(); 781 path = ugblData->m_pInitial->get_path(); 782 } 783 784 Reference< XHierarchicalNameAccess > xNA = 785 ugblData->m_pDatabases->findJarFileForPath( jar, language, path ); 786 787 Reference< XInputStream > xInputStream; 788 789 if( xNA.is() ) 790 { 791 try 792 { 793 Any aEntry = xNA->getByHierarchicalName( path ); 794 Reference< XActiveDataSink > xSink; 795 if( ( aEntry >>= xSink ) && xSink.is() ) 796 xInputStream = xSink->getInputStream(); 797 } 798 catch ( NoSuchElementException & ) 799 { 800 } 801 } 802 803 if( xInputStream.is() ) 804 { 805 return new Reference<XInputStream>(xInputStream); 806 } 807 return 0; 808 } 809 810 static void * 811 helpOpen(const char * URI) { 812 rtl::OUString language,jar,path; 813 814 URLParameter urlpar( rtl::OUString::createFromAscii( URI ), 815 ugblData->m_pDatabases ); 816 817 jar = urlpar.get_jar(); 818 language = urlpar.get_language(); 819 path = urlpar.get_path(); 820 821 Reference< XHierarchicalNameAccess > xNA = 822 ugblData->m_pDatabases->findJarFileForPath( jar, language, path ); 823 824 Reference< XInputStream > xInputStream; 825 826 if( xNA.is() ) 827 { 828 try 829 { 830 Any aEntry = xNA->getByHierarchicalName( path ); 831 Reference< XActiveDataSink > xSink; 832 if( ( aEntry >>= xSink ) && xSink.is() ) 833 xInputStream = xSink->getInputStream(); 834 } 835 catch ( NoSuchElementException & ) 836 { 837 } 838 } 839 840 if( xInputStream.is() ) 841 return new Reference<XInputStream>(xInputStream); 842 return 0; 843 } 844 845 static int 846 helpRead(void * context, char * buffer, int len) { 847 Reference< XInputStream > *pRef = (Reference< XInputStream >*)context; 848 849 Sequence< sal_Int8 > aSeq; 850 len = (*pRef)->readBytes( aSeq,len); 851 memcpy(buffer, aSeq.getConstArray(), len); 852 853 return len; 854 } 855 856 static int 857 zipRead(void * context, char * buffer, int len) { 858 if( ugblData->m_pInitial->get_eid().getLength() ) 859 { 860 ugblData->m_pDatabases->popupDocument( ugblData->m_pInitial,&buffer,&len); 861 return len; 862 } 863 else 864 return helpRead(context, buffer, len); 865 } 866 867 static int 868 fileRead(void * context, char * buffer, int len) { 869 int nRead = 0; 870 osl::File *pFile = (osl::File*)context; 871 if (pFile) 872 { 873 sal_uInt64 uRead = 0; 874 if (osl::FileBase::E_None == pFile->read(buffer, len, uRead)) 875 nRead = static_cast<int>(uRead); 876 } 877 return nRead; 878 } 879 880 static int 881 uriClose(void * context) { 882 Reference< XInputStream > *pRef = (Reference< XInputStream >*)context; 883 delete pRef; 884 return 0; 885 } 886 887 static int 888 fileClose(void * context) { 889 osl::File *pFile = (osl::File*)context; 890 if (pFile) 891 { 892 pFile->close(); 893 delete pFile; 894 } 895 return 0; 896 } 897 898 } // extern "C" 899 900 /* 901 // For debugging only 902 extern "C" void StructuredXMLErrorFunction(void *userData, xmlErrorPtr error) 903 { 904 (void)userData; 905 (void)error; 906 907 // Reset error handler 908 xmlSetStructuredErrorFunc( NULL, NULL ); 909 } 910 */ 911 912 InputStreamTransformer::InputStreamTransformer( URLParameter* urlParam, 913 Databases* pDatabases, 914 bool isRoot ) 915 : len( 0 ), 916 pos( 0 ), 917 buffer( new char[1] ) // Initializing with one element to avoid gcc compiler warning 918 { 919 if( isRoot ) 920 { 921 delete[] buffer; 922 pDatabases->cascadingStylesheet( urlParam->get_language(), 923 &buffer, 924 &len ); 925 } 926 else if( urlParam->isActive() ) 927 { 928 delete[] buffer; 929 pDatabases->setActiveText( urlParam->get_module(), 930 urlParam->get_language(), 931 urlParam->get_id(), 932 &buffer, 933 &len ); 934 } 935 else 936 { 937 UserData userData( this,urlParam,pDatabases ); 938 939 // Uses the implementation detail, that rtl::OString::getStr returns a zero terminated character-array 940 941 const char* parameter[47]; 942 rtl::OString parString[46]; 943 int last = 0; 944 945 parString[last++] = "Program"; 946 rtl::OString aPureProgramm( urlParam->getByName( "Program" ) ); 947 parString[last++] = rtl::OString('\'') + aPureProgramm + rtl::OString('\''); 948 parString[last++] = "Database"; 949 parString[last++] = rtl::OString('\'') + urlParam->getByName( "DatabasePar" ) + rtl::OString('\''); 950 parString[last++] = "Id"; 951 parString[last++] = rtl::OString('\'') + urlParam->getByName( "Id" ) + rtl::OString('\''); 952 parString[last++] = "Path"; 953 rtl::OString aPath( urlParam->getByName( "Path" ) ); 954 parString[last++] = rtl::OString('\'') + aPath + rtl::OString('\''); 955 956 rtl::OString aPureLanguage = urlParam->getByName( "Language" ); 957 parString[last++] = "Language"; 958 parString[last++] = rtl::OString('\'') + aPureLanguage + rtl::OString('\''); 959 parString[last++] = "System"; 960 parString[last++] = rtl::OString('\'') + urlParam->getByName( "System" ) + rtl::OString('\''); 961 parString[last++] = "productname"; 962 parString[last++] = rtl::OString('\'') + rtl::OString( 963 pDatabases->getProductName().getStr(), 964 pDatabases->getProductName().getLength(), 965 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\''); 966 parString[last++] = "productversion"; 967 parString[last++] = rtl::OString('\'') + 968 rtl::OString( pDatabases->getProductVersion().getStr(), 969 pDatabases->getProductVersion().getLength(), 970 RTL_TEXTENCODING_UTF8 ) + rtl::OString('\''); 971 972 parString[last++] = "imgrepos"; 973 parString[last++] = rtl::OString('\'') + pDatabases->getImagesZipFileURL() + rtl::OString('\''); 974 parString[last++] = "hp"; 975 parString[last++] = rtl::OString('\'') + urlParam->getByName( "HelpPrefix" ) + rtl::OString('\''); 976 977 if( parString[last-1].getLength() ) 978 { 979 parString[last++] = "sm"; 980 parString[last++] = "'vnd.sun.star.help%3A%2F%2F'"; 981 parString[last++] = "qm"; 982 parString[last++] = "'%3F'"; 983 parString[last++] = "es"; 984 parString[last++] = "'%3D'"; 985 parString[last++] = "am"; 986 parString[last++] = "'%26'"; 987 parString[last++] = "cl"; 988 parString[last++] = "'%3A'"; 989 parString[last++] = "sl"; 990 parString[last++] = "'%2F'"; 991 parString[last++] = "hm"; 992 parString[last++] = "'%23'"; 993 parString[last++] = "cs"; 994 parString[last++] = "'css'"; 995 996 parString[last++] = "vendorname"; 997 parString[last++] = rtl::OString("''"); 998 parString[last++] = "vendorversion"; 999 parString[last++] = rtl::OString("''"); 1000 parString[last++] = "vendorshort"; 1001 parString[last++] = rtl::OString("''"); 1002 } 1003 1004 // Do we need to add extension path? 1005 ::rtl::OUString aExtensionPath; 1006 rtl::OUString aJar = urlParam->get_jar(); 1007 1008 bool bAddExtensionPath = false; 1009 rtl::OUString aExtensionRegistryPath; 1010 sal_Int32 nQuestionMark1 = aJar.indexOf( sal_Unicode('?') ); 1011 sal_Int32 nQuestionMark2 = aJar.lastIndexOf( sal_Unicode('?') ); 1012 if( nQuestionMark1 != -1 && nQuestionMark2 != -1 && nQuestionMark1 != nQuestionMark2 ) 1013 { 1014 aExtensionPath = aJar.copy( nQuestionMark1 + 1, nQuestionMark2 - nQuestionMark1 - 1 ); 1015 aExtensionRegistryPath = urlParam->get_ExtensionRegistryPath(); 1016 bAddExtensionPath = true; 1017 } 1018 else 1019 { 1020 // Path not yet specified, search directly 1021 Reference< XHierarchicalNameAccess > xNA = pDatabases->findJarFileForPath 1022 ( aJar, urlParam->get_language(), urlParam->get_path(), &aExtensionPath, &aExtensionRegistryPath ); 1023 if( xNA.is() && aExtensionPath.getLength() ) 1024 bAddExtensionPath = true; 1025 } 1026 1027 if( bAddExtensionPath ) 1028 { 1029 Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); 1030 Reference< XPropertySet > xProps( xFactory, UNO_QUERY ); 1031 OSL_ASSERT( xProps.is() ); 1032 Reference< XComponentContext > xContext; 1033 if (xProps.is()) 1034 { 1035 xProps->getPropertyValue( 1036 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext; 1037 } 1038 if( !xContext.is() ) 1039 { 1040 throw RuntimeException( 1041 ::rtl::OUString::createFromAscii( "InputStreamTransformer::InputStreamTransformer(), no XComponentContext" ), 1042 Reference< XInterface >() ); 1043 } 1044 1045 rtl::OUString aOUExpandedExtensionPath = Databases::expandURL( aExtensionRegistryPath, xContext ); 1046 rtl::OString aExpandedExtensionPath = rtl::OUStringToOString( aOUExpandedExtensionPath, osl_getThreadTextEncoding() ); 1047 1048 parString[last++] = "ExtensionPath"; 1049 parString[last++] = rtl::OString('\'') + aExpandedExtensionPath + rtl::OString('\''); 1050 1051 // ExtensionId 1052 rtl::OString aPureExtensionId; 1053 sal_Int32 iSlash = aPath.indexOf( '/' ); 1054 if( iSlash != -1 ) 1055 aPureExtensionId = aPath.copy( 0, iSlash ); 1056 1057 parString[last++] = "ExtensionId"; 1058 parString[last++] = rtl::OString('\'') + aPureExtensionId + rtl::OString('\''); 1059 } 1060 1061 for( int i = 0; i < last; ++i ) 1062 parameter[i] = parString[i].getStr(); 1063 parameter[last] = 0; 1064 1065 rtl::OUString xslURL = pDatabases->getInstallPathAsURL(); 1066 1067 rtl::OString xslURLascii( 1068 xslURL.getStr(), 1069 xslURL.getLength(), 1070 RTL_TEXTENCODING_UTF8); 1071 xslURLascii += "main_transform.xsl"; 1072 1073 ugblData = &userData; 1074 1075 xmlInitParser(); 1076 xmlRegisterInputCallbacks(zipMatch, zipOpen, zipRead, uriClose); 1077 xmlRegisterInputCallbacks(helpMatch, helpOpen, helpRead, uriClose); 1078 xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose); 1079 //xmlSetStructuredErrorFunc( NULL, (xmlStructuredErrorFunc)StructuredXMLErrorFunction ); 1080 1081 xsltStylesheetPtr cur = 1082 xsltParseStylesheetFile((const xmlChar *)xslURLascii.getStr()); 1083 1084 xmlDocPtr doc = xmlParseFile("vnd.sun.star.zip:/"); 1085 1086 xmlDocPtr res = xsltApplyStylesheet(cur, doc, parameter); 1087 if (res) 1088 { 1089 xmlChar *doc_txt_ptr=0; 1090 int doc_txt_len; 1091 xsltSaveResultToString(&doc_txt_ptr, &doc_txt_len, res, cur); 1092 addToBuffer((const char*)doc_txt_ptr, doc_txt_len); 1093 xmlFree(doc_txt_ptr); 1094 } 1095 xmlPopInputCallbacks(); //filePatch 1096 xmlPopInputCallbacks(); //helpPatch 1097 xmlPopInputCallbacks(); //zipMatch 1098 xmlFreeDoc(res); 1099 xmlFreeDoc(doc); 1100 xsltFreeStylesheet(cur); 1101 } 1102 } 1103 1104 1105 InputStreamTransformer::~InputStreamTransformer() 1106 { 1107 delete[] buffer; 1108 } 1109 1110 1111 Any SAL_CALL InputStreamTransformer::queryInterface( const Type& rType ) throw( RuntimeException ) 1112 { 1113 Any aRet = ::cppu::queryInterface( rType, 1114 SAL_STATIC_CAST( XInputStream*,this ), 1115 SAL_STATIC_CAST( XSeekable*,this ) ); 1116 1117 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); 1118 } 1119 1120 1121 1122 void SAL_CALL InputStreamTransformer::acquire( void ) throw() 1123 { 1124 OWeakObject::acquire(); 1125 } 1126 1127 1128 1129 void SAL_CALL InputStreamTransformer::release( void ) throw() 1130 { 1131 OWeakObject::release(); 1132 } 1133 1134 1135 1136 sal_Int32 SAL_CALL InputStreamTransformer::readBytes( Sequence< sal_Int8 >& aData,sal_Int32 nBytesToRead ) 1137 throw( NotConnectedException, 1138 BufferSizeExceededException, 1139 IOException, 1140 RuntimeException) 1141 { 1142 osl::MutexGuard aGuard( m_aMutex ); 1143 1144 int curr,available_ = len-pos; 1145 if( nBytesToRead <= available_ ) 1146 curr = nBytesToRead; 1147 else 1148 curr = available_; 1149 1150 if( 0 <= curr && aData.getLength() < curr ) 1151 aData.realloc( curr ); 1152 1153 for( int k = 0; k < curr; ++k ) 1154 aData[k] = buffer[pos++]; 1155 1156 return curr > 0 ? curr : 0; 1157 } 1158 1159 1160 sal_Int32 SAL_CALL InputStreamTransformer::readSomeBytes( Sequence< sal_Int8 >& aData,sal_Int32 nMaxBytesToRead ) 1161 throw( NotConnectedException, 1162 BufferSizeExceededException, 1163 IOException, 1164 RuntimeException) 1165 { 1166 return readBytes( aData,nMaxBytesToRead ); 1167 } 1168 1169 1170 1171 void SAL_CALL InputStreamTransformer::skipBytes( sal_Int32 nBytesToSkip ) throw( NotConnectedException, 1172 BufferSizeExceededException, 1173 IOException, 1174 RuntimeException ) 1175 { 1176 osl::MutexGuard aGuard( m_aMutex ); 1177 while( nBytesToSkip-- ) ++pos; 1178 } 1179 1180 1181 1182 sal_Int32 SAL_CALL InputStreamTransformer::available( void ) throw( NotConnectedException, 1183 IOException, 1184 RuntimeException ) 1185 { 1186 osl::MutexGuard aGuard( m_aMutex ); 1187 return len-pos > 0 ? len - pos : 0 ; 1188 } 1189 1190 1191 1192 void SAL_CALL InputStreamTransformer::closeInput( void ) throw( NotConnectedException, 1193 IOException, 1194 RuntimeException ) 1195 { 1196 } 1197 1198 1199 1200 void SAL_CALL InputStreamTransformer::seek( sal_Int64 location ) throw( IllegalArgumentException, 1201 IOException, 1202 RuntimeException ) 1203 { 1204 osl::MutexGuard aGuard( m_aMutex ); 1205 if( location < 0 ) 1206 throw IllegalArgumentException(); 1207 else 1208 pos = sal::static_int_cast<sal_Int32>( location ); 1209 1210 if( pos > len ) 1211 pos = len; 1212 } 1213 1214 1215 1216 sal_Int64 SAL_CALL InputStreamTransformer::getPosition( void ) throw( IOException, 1217 RuntimeException ) 1218 { 1219 osl::MutexGuard aGuard( m_aMutex ); 1220 return sal_Int64( pos ); 1221 } 1222 1223 1224 1225 sal_Int64 SAL_CALL InputStreamTransformer::getLength( void ) throw( IOException,RuntimeException ) 1226 { 1227 osl::MutexGuard aGuard( m_aMutex ); 1228 1229 return len; 1230 } 1231 1232 1233 void InputStreamTransformer::addToBuffer( const char* buffer_,int len_ ) 1234 { 1235 osl::MutexGuard aGuard( m_aMutex ); 1236 1237 char* tmp = buffer; 1238 buffer = new char[ len+len_ ]; 1239 rtl_copyMemory( (void*)(buffer),(void*)(tmp),sal_uInt32( len ) ); 1240 rtl_copyMemory( (void*)(buffer+len),(void*)(buffer_),sal_uInt32( len_ ) ); 1241 delete[] tmp; 1242 len += len_; 1243 } 1244