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