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