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