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