bump product version to 4.1.6.2
[LibreOffice.git] / package / source / xstor / ocompinstream.cxx
blob55a731281a43ff5e9398695506d5df3e206266b3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "ocompinstream.hxx"
22 #include <com/sun/star/embed/StorageFormats.hpp>
23 #include <com/sun/star/lang/DisposedException.hpp>
24 #include <osl/diagnose.h>
26 #include "owriteablestream.hxx"
27 #include "xstorage.hxx"
29 using namespace ::com::sun::star;
31 //-----------------------------------------------
32 OInputCompStream::OInputCompStream( OWriteStream_Impl& aImpl,
33 uno::Reference < io::XInputStream > xStream,
34 const uno::Sequence< beans::PropertyValue >& aProps,
35 sal_Int32 nStorageType )
36 : m_pImpl( &aImpl )
37 , m_rMutexRef( m_pImpl->m_rMutexRef )
38 , m_xStream( xStream )
39 , m_pInterfaceContainer( NULL )
40 , m_aProperties( aProps )
41 , m_bDisposed( sal_False )
42 , m_nStorageType( nStorageType )
44 OSL_ENSURE( m_pImpl->m_rMutexRef.Is(), "No mutex is provided!\n" );
45 if ( !m_pImpl->m_rMutexRef.Is() )
46 throw uno::RuntimeException(); // just a disaster
48 OSL_ENSURE( xStream.is(), "No stream is provided!\n" );
51 //-----------------------------------------------
52 OInputCompStream::OInputCompStream( uno::Reference < io::XInputStream > xStream,
53 const uno::Sequence< beans::PropertyValue >& aProps,
54 sal_Int32 nStorageType )
55 : m_pImpl( NULL )
56 , m_rMutexRef( new SotMutexHolder )
57 , m_xStream( xStream )
58 , m_pInterfaceContainer( NULL )
59 , m_aProperties( aProps )
60 , m_bDisposed( sal_False )
61 , m_nStorageType( nStorageType )
63 OSL_ENSURE( xStream.is(), "No stream is provided!\n" );
66 //-----------------------------------------------
67 OInputCompStream::~OInputCompStream()
70 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
72 if ( !m_bDisposed )
74 m_refCount++;
75 dispose();
78 if ( m_pInterfaceContainer )
79 delete m_pInterfaceContainer;
83 //-----------------------------------------------
84 uno::Any SAL_CALL OInputCompStream::queryInterface( const uno::Type& rType )
85 throw( uno::RuntimeException )
87 uno::Any aReturn;
89 // common interfaces
90 aReturn <<= ::cppu::queryInterface
91 ( rType
92 , static_cast<io::XInputStream*> ( this )
93 , static_cast<io::XStream*> ( this )
94 , static_cast<lang::XComponent*> ( this )
95 , static_cast<beans::XPropertySet*> ( this )
96 , static_cast<embed::XExtendedStorageStream*> ( this ) );
98 if ( aReturn.hasValue() == sal_True )
99 return aReturn ;
101 if ( m_nStorageType == embed::StorageFormats::OFOPXML )
103 aReturn <<= ::cppu::queryInterface
104 ( rType
105 , static_cast<embed::XRelationshipAccess*> ( this ) );
107 if ( aReturn.hasValue() == sal_True )
108 return aReturn ;
111 return OWeakObject::queryInterface( rType );
114 //-----------------------------------------------
115 sal_Int32 SAL_CALL OInputCompStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
116 throw ( io::NotConnectedException,
117 io::BufferSizeExceededException,
118 io::IOException,
119 uno::RuntimeException )
121 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
122 if ( m_bDisposed )
124 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
125 throw lang::DisposedException();
128 if ( !m_xStream.is() )
130 ::package::StaticAddLog( OSL_LOG_PREFIX "No stream!" );
131 throw uno::RuntimeException();
134 return m_xStream->readBytes( aData, nBytesToRead );
137 //-----------------------------------------------
138 sal_Int32 SAL_CALL OInputCompStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
139 throw ( io::NotConnectedException,
140 io::BufferSizeExceededException,
141 io::IOException,
142 uno::RuntimeException )
144 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
145 if ( m_bDisposed )
147 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
148 throw lang::DisposedException();
151 if ( !m_xStream.is() )
153 ::package::StaticAddLog( OSL_LOG_PREFIX "No stream!" );
154 throw uno::RuntimeException();
157 return m_xStream->readSomeBytes( aData, nMaxBytesToRead );
161 //-----------------------------------------------
162 void SAL_CALL OInputCompStream::skipBytes( sal_Int32 nBytesToSkip )
163 throw ( io::NotConnectedException,
164 io::BufferSizeExceededException,
165 io::IOException,
166 uno::RuntimeException )
168 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
169 if ( m_bDisposed )
171 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
172 throw lang::DisposedException();
175 if ( !m_xStream.is() )
177 ::package::StaticAddLog( OSL_LOG_PREFIX "No stream!" );
178 throw uno::RuntimeException();
181 m_xStream->skipBytes( nBytesToSkip );
185 //-----------------------------------------------
186 sal_Int32 SAL_CALL OInputCompStream::available( )
187 throw ( io::NotConnectedException,
188 io::IOException,
189 uno::RuntimeException )
191 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
192 if ( m_bDisposed )
194 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
195 throw lang::DisposedException();
198 if ( !m_xStream.is() )
200 ::package::StaticAddLog( OSL_LOG_PREFIX "No stream!" );
201 throw uno::RuntimeException();
204 return m_xStream->available();
208 //-----------------------------------------------
209 void SAL_CALL OInputCompStream::closeInput( )
210 throw ( io::NotConnectedException,
211 io::IOException,
212 uno::RuntimeException )
214 dispose();
217 //-----------------------------------------------
218 uno::Reference< io::XInputStream > SAL_CALL OInputCompStream::getInputStream()
219 throw ( uno::RuntimeException )
221 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
222 if ( m_bDisposed )
224 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
225 throw lang::DisposedException();
228 if ( !m_xStream.is() )
229 return uno::Reference< io::XInputStream >();
231 return uno::Reference< io::XInputStream >( static_cast< io::XInputStream* >( this ), uno::UNO_QUERY );
234 //-----------------------------------------------
235 uno::Reference< io::XOutputStream > SAL_CALL OInputCompStream::getOutputStream()
236 throw ( uno::RuntimeException )
238 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
239 if ( m_bDisposed )
241 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
242 throw lang::DisposedException();
245 return uno::Reference< io::XOutputStream >();
248 //-----------------------------------------------
249 void OInputCompStream::InternalDispose()
251 // can be called only by OWriteStream_Impl
252 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
253 if ( m_bDisposed )
255 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
256 throw lang::DisposedException();
259 // the source object is also a kind of locker for the current object
260 // since the listeners could dispose the object while being notified
261 lang::EventObject aSource( static_cast< ::cppu::OWeakObject*>( this ) );
263 if ( m_pInterfaceContainer )
264 m_pInterfaceContainer->disposeAndClear( aSource );
268 m_xStream->closeInput();
270 catch( uno::Exception& )
273 m_pImpl = NULL;
274 m_bDisposed = sal_True;
277 //-----------------------------------------------
278 void SAL_CALL OInputCompStream::dispose( )
279 throw ( uno::RuntimeException )
281 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
282 if ( m_bDisposed )
284 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
285 throw lang::DisposedException();
288 if ( m_pInterfaceContainer )
290 lang::EventObject aSource( static_cast< ::cppu::OWeakObject*>( this ) );
291 m_pInterfaceContainer->disposeAndClear( aSource );
294 m_xStream->closeInput();
296 if ( m_pImpl )
298 m_pImpl->InputStreamDisposed( this );
299 m_pImpl = NULL;
302 m_bDisposed = sal_True;
305 //-----------------------------------------------
306 void SAL_CALL OInputCompStream::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
307 throw ( uno::RuntimeException )
309 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
310 if ( m_bDisposed )
312 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
313 throw lang::DisposedException();
316 if ( !m_pInterfaceContainer )
317 m_pInterfaceContainer = new ::cppu::OInterfaceContainerHelper( m_rMutexRef->GetMutex() );
319 m_pInterfaceContainer->addInterface( xListener );
322 //-----------------------------------------------
323 void SAL_CALL OInputCompStream::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
324 throw ( uno::RuntimeException )
326 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
327 if ( m_bDisposed )
329 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
330 throw lang::DisposedException();
333 if ( m_pInterfaceContainer )
334 m_pInterfaceContainer->removeInterface( xListener );
337 //-----------------------------------------------
338 sal_Bool SAL_CALL OInputCompStream::hasByID( const OUString& sID )
339 throw ( io::IOException,
340 uno::RuntimeException )
342 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
344 if ( m_bDisposed )
346 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
347 throw lang::DisposedException();
350 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
351 throw uno::RuntimeException();
355 getRelationshipByID( sID );
356 return sal_True;
358 catch( container::NoSuchElementException& )
361 return sal_False;
364 //-----------------------------------------------
365 OUString SAL_CALL OInputCompStream::getTargetByID( const OUString& sID )
366 throw ( container::NoSuchElementException,
367 io::IOException,
368 uno::RuntimeException )
370 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
372 if ( m_bDisposed )
374 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
375 throw lang::DisposedException();
378 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
379 throw uno::RuntimeException();
381 uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID );
382 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
383 if ( aSeq[nInd].First == "Target" )
384 return aSeq[nInd].Second;
386 return OUString();
389 //-----------------------------------------------
390 OUString SAL_CALL OInputCompStream::getTypeByID( const OUString& sID )
391 throw ( container::NoSuchElementException,
392 io::IOException,
393 uno::RuntimeException )
395 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
397 if ( m_bDisposed )
399 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
400 throw lang::DisposedException();
403 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
404 throw uno::RuntimeException();
406 uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID );
407 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
408 if ( aSeq[nInd].First == "Type" )
409 return aSeq[nInd].Second;
411 return OUString();
414 //-----------------------------------------------
415 uno::Sequence< beans::StringPair > SAL_CALL OInputCompStream::getRelationshipByID( const OUString& sID )
416 throw ( container::NoSuchElementException,
417 io::IOException,
418 uno::RuntimeException )
420 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
422 if ( m_bDisposed )
424 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
425 throw lang::DisposedException();
428 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
429 throw uno::RuntimeException();
431 // TODO/LATER: in future the unification of the ID could be checked
432 uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
433 for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ )
434 for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ )
435 if ( aSeq[nInd1][nInd2].First == "Id" )
437 if ( aSeq[nInd1][nInd2].Second.equals( sID ) )
438 return aSeq[nInd1];
439 break;
442 throw container::NoSuchElementException();
445 //-----------------------------------------------
446 uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OInputCompStream::getRelationshipsByType( const OUString& sType )
447 throw ( io::IOException,
448 uno::RuntimeException )
450 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
452 if ( m_bDisposed )
454 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
455 throw lang::DisposedException();
458 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
459 throw uno::RuntimeException();
461 uno::Sequence< uno::Sequence< beans::StringPair > > aResult;
462 sal_Int32 nEntriesNum = 0;
464 // TODO/LATER: in future the unification of the ID could be checked
465 uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
466 for ( sal_Int32 nInd1 = 0; nInd1 < aSeq.getLength(); nInd1++ )
467 for ( sal_Int32 nInd2 = 0; nInd2 < aSeq[nInd1].getLength(); nInd2++ )
468 if ( aSeq[nInd1][nInd2].First == "Type" )
470 if ( aSeq[nInd1][nInd2].Second.equals( sType ) )
472 aResult.realloc( nEntriesNum );
473 aResult[nEntriesNum-1] = aSeq[nInd1];
475 break;
478 return aResult;
481 //-----------------------------------------------
482 uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OInputCompStream::getAllRelationships()
483 throw (io::IOException, uno::RuntimeException)
485 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
487 if ( m_bDisposed )
489 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
490 throw lang::DisposedException();
493 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
494 throw uno::RuntimeException();
496 // TODO/LATER: in future the information could be taken directly from m_pImpl when possible
497 uno::Sequence< uno::Sequence< beans::StringPair > > aResult;
498 for ( sal_Int32 aInd = 0; aInd < m_aProperties.getLength(); aInd++ )
499 if ( m_aProperties[aInd].Name == "RelationsInfo" )
501 if ( m_aProperties[aInd].Value >>= aResult )
502 return aResult;
504 break;
507 throw io::IOException(); // the relations info could not be read
510 //-----------------------------------------------
511 void SAL_CALL OInputCompStream::insertRelationshipByID( const OUString& /*sID*/, const uno::Sequence< beans::StringPair >& /*aEntry*/, ::sal_Bool /*bReplace*/ )
512 throw ( container::ElementExistException,
513 io::IOException,
514 uno::RuntimeException )
516 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
518 if ( m_bDisposed )
520 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
521 throw lang::DisposedException();
524 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
525 throw uno::RuntimeException();
527 throw io::IOException(); // TODO: Access denied
530 //-----------------------------------------------
531 void SAL_CALL OInputCompStream::removeRelationshipByID( const OUString& /*sID*/ )
532 throw ( container::NoSuchElementException,
533 io::IOException,
534 uno::RuntimeException )
536 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
538 if ( m_bDisposed )
540 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
541 throw lang::DisposedException();
544 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
545 throw uno::RuntimeException();
547 throw io::IOException(); // TODO: Access denied
550 //-----------------------------------------------
551 void SAL_CALL OInputCompStream::insertRelationships( const uno::Sequence< uno::Sequence< beans::StringPair > >& /*aEntries*/, ::sal_Bool /*bReplace*/ )
552 throw ( container::ElementExistException,
553 io::IOException,
554 uno::RuntimeException )
556 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
558 if ( m_bDisposed )
560 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
561 throw lang::DisposedException();
564 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
565 throw uno::RuntimeException();
567 throw io::IOException(); // TODO: Access denied
570 //-----------------------------------------------
571 void SAL_CALL OInputCompStream::clearRelationships()
572 throw ( io::IOException,
573 uno::RuntimeException )
575 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
577 if ( m_bDisposed )
579 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
580 throw lang::DisposedException();
583 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
584 throw uno::RuntimeException();
586 throw io::IOException(); // TODO: Access denied
589 //-----------------------------------------------
590 uno::Reference< beans::XPropertySetInfo > SAL_CALL OInputCompStream::getPropertySetInfo()
591 throw ( uno::RuntimeException )
593 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
595 if ( m_bDisposed )
597 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
598 throw lang::DisposedException();
601 //TODO:
602 return uno::Reference< beans::XPropertySetInfo >();
605 //-----------------------------------------------
606 void SAL_CALL OInputCompStream::setPropertyValue( const OUString& aPropertyName, const uno::Any& /*aValue*/ )
607 throw ( beans::UnknownPropertyException,
608 beans::PropertyVetoException,
609 lang::IllegalArgumentException,
610 lang::WrappedTargetException,
611 uno::RuntimeException )
613 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
615 if ( m_bDisposed )
617 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
618 throw lang::DisposedException();
621 // all the provided properties are accessible
622 for ( sal_Int32 aInd = 0; aInd < m_aProperties.getLength(); aInd++ )
624 if ( m_aProperties[aInd].Name.equals( aPropertyName ) )
626 throw beans::PropertyVetoException(); // TODO
630 throw beans::UnknownPropertyException(); // TODO
634 //-----------------------------------------------
635 uno::Any SAL_CALL OInputCompStream::getPropertyValue( const OUString& aProp )
636 throw ( beans::UnknownPropertyException,
637 lang::WrappedTargetException,
638 uno::RuntimeException )
640 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
642 if ( m_bDisposed )
644 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
645 throw lang::DisposedException();
648 OUString aPropertyName;
649 if ( aProp == "IsEncrypted" )
650 aPropertyName = "Encrypted";
651 else
652 aPropertyName = aProp;
654 if ( aPropertyName == "RelationsInfo" )
655 throw beans::UnknownPropertyException(); // TODO
657 // all the provided properties are accessible
658 for ( sal_Int32 aInd = 0; aInd < m_aProperties.getLength(); aInd++ )
660 if ( m_aProperties[aInd].Name.equals( aPropertyName ) )
662 return m_aProperties[aInd].Value;
666 throw beans::UnknownPropertyException(); // TODO
670 //-----------------------------------------------
671 void SAL_CALL OInputCompStream::addPropertyChangeListener(
672 const OUString& /*aPropertyName*/,
673 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
674 throw ( beans::UnknownPropertyException,
675 lang::WrappedTargetException,
676 uno::RuntimeException )
678 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
680 if ( m_bDisposed )
682 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
683 throw lang::DisposedException();
686 //TODO:
690 //-----------------------------------------------
691 void SAL_CALL OInputCompStream::removePropertyChangeListener(
692 const OUString& /*aPropertyName*/,
693 const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ )
694 throw ( beans::UnknownPropertyException,
695 lang::WrappedTargetException,
696 uno::RuntimeException )
698 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
700 if ( m_bDisposed )
702 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
703 throw lang::DisposedException();
706 //TODO:
710 //-----------------------------------------------
711 void SAL_CALL OInputCompStream::addVetoableChangeListener(
712 const OUString& /*PropertyName*/,
713 const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
714 throw ( beans::UnknownPropertyException,
715 lang::WrappedTargetException,
716 uno::RuntimeException )
718 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
720 if ( m_bDisposed )
722 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
723 throw lang::DisposedException();
726 //TODO:
730 //-----------------------------------------------
731 void SAL_CALL OInputCompStream::removeVetoableChangeListener(
732 const OUString& /*PropertyName*/,
733 const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
734 throw ( beans::UnknownPropertyException,
735 lang::WrappedTargetException,
736 uno::RuntimeException )
738 ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() );
740 if ( m_bDisposed )
742 ::package::StaticAddLog( OSL_LOG_PREFIX "Disposed!" );
743 throw lang::DisposedException();
746 //TODO:
750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */