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