ADD_EXECUTABLE(mediaaccess ${mediaaccess_SRCS})
TARGET_LINK_LIBRARIES(mediaaccess zypp )
+ADD_EXECUTABLE(scansource ScanSource.cc)
+TARGET_LINK_LIBRARIES(scansource zypp )
+
ADD_EXECUTABLE(susetags-downloader SUSETagsDownloader.cc)
-TARGET_LINK_LIBRARIES(susetags-downloader zypp )
\ No newline at end of file
+TARGET_LINK_LIBRARIES(susetags-downloader zypp )
+
+
--- /dev/null
+#include <iostream>
+
+#include <zypp/base/LogControl.h>
+#include <zypp/base/LogTools.h>
+#include <zypp/base/Measure.h>
+#include <zypp/SourceFactory.h>
+#include <zypp/Source.h>
+#include <zypp/ResStore.h>
+#include <zypp/ResObject.h>
+#include <zypp/pool/PoolStats.h>
+#include <zypp/KeyRing.h>
+#include <zypp/Date.h>
+#include <zypp/SourceManager.h>
+
+using namespace std;
+using namespace zypp;
+
+static bool verbose = false;
+static bool debug_flag = false;
+
+#define LOG (debug_flag ? USR : cout)
+
+struct KeyRingReceiver : public callback::ReceiveReport<KeyRingReport>
+{
+ KeyRingReceiver()
+ {
+ connect();
+ }
+
+ virtual bool askUserToAcceptUnsignedFile( const std::string & file )
+ {
+ LOG << "===[UnsignedFile " << file << "]" << endl;
+ return true;
+ }
+ virtual bool askUserToAcceptUnknownKey( const std::string &file,
+ const std::string &id )
+ {
+ LOG << "===[UnknownKey " << id << "]" << endl;
+ return true;
+ }
+ virtual bool askUserToTrustKey( const PublicKey &key)
+ {
+ LOG << "===[TrustKey" << key << "]" << endl;
+ return true;
+ }
+ virtual bool askUserToImportKey( const PublicKey &key)
+ {
+ LOG << "===[ImportKey " << key << "]" << endl;
+ return true;
+ }
+ virtual bool askUserToAcceptVerificationFailed( const std::string &file,
+ const PublicKey &key )
+ {
+ LOG << "===[VerificationFailed " << file << " " << key << "]" << endl;
+ return true;
+ }
+};
+
+struct ResStoreStats : public pool::PoolStats
+{
+ void operator()( const ResObject::constPtr & obj )
+ {
+ if ( isKind<Product>( obj ) )
+ {
+ LOG << obj << endl;
+ }
+ pool::PoolStats::operator()( obj );
+ }
+};
+
+/******************************************************************
+**
+** FUNCTION NAME : main
+** FUNCTION TYPE : int
+*/
+int main( int argc, char * argv[] )
+{
+ //zypp::base::LogControl::instance().logfile( "" );
+ INT << "===[START]==========================================" << endl;
+ --argc;
+ ++argv;
+
+ if ( ! argc )
+ {
+ LOG << "Usage: ScanSource [options] url [[options] url...]" << endl;
+ LOG << " Display summary of Sources found at 'url'. " << endl;
+ LOG << " " << endl;
+ LOG << " " << endl;
+ LOG << " options:" << endl;
+ LOG << " +/-l enable/disable detailed listing of Source content" << endl;
+ LOG << " +/-d enable/disable debug output" << endl;
+ return 0;
+ }
+
+ KeyRingReceiver accept;
+
+ for ( ; argc; --argc, ++argv )
+ {
+ if ( *argv == string("+l") )
+ {
+ verbose = true;
+ continue;
+ }
+ if ( *argv == string("-l") )
+ {
+ verbose = false;
+ continue;
+ }
+ if ( *argv == string("+d") )
+ {
+ zypp::base::LogControl::instance().logfile( "-" );
+ debug_flag = true;
+ continue;
+ }
+ if ( *argv == string("-d") )
+ {
+ zypp::base::LogControl::instance().logfile( "" );
+ debug_flag = false;
+ continue;
+ }
+
+ LOG << "====================================================" << endl;
+ LOG << "===Search Source at Url(" << *argv << ")..." << endl;
+ Source_Ref src;
+ try
+ {
+ debug::Measure m( "Create" );
+ Url url(*argv);
+ try
+ {
+ src = SourceFactory().createFrom( url, "/", Date::now().asSeconds() );
+ }
+ catch ( const source::SourceUnknownTypeException & )
+ {
+ src = SourceFactory().createFrom( "Plaindir", url, "/", Date::now().asSeconds(), "", false, true );
+ }
+ m.elapsed();
+ //LOG << m.asString() << endl;
+ }
+ catch ( const Exception & except_r )
+ {
+ LOG << "***Failed: " << except_r << endl;
+ continue;
+ }
+ LOG << "type: " << src.type() << endl;
+ LOG << "numberOfMedia: " << src.numberOfMedia() << endl;
+ LOG << "alias: " << src.alias() << endl;
+ LOG << "vendor: " << src.vendor() << endl;
+ LOG << "unique_id: " << src.unique_id() << endl;
+ LOG << "baseSource: " << src.baseSource() << endl;
+ LOG << "autorefresh: " << src.autorefresh() << endl;
+ LOG << "publicKeys: " << src.publicKeys() << endl;
+
+ LOG << "===Parse content..." << endl;
+ try
+ {
+ debug::Measure m( "Parse" );
+ src.resolvables();
+ m.elapsed();
+ //LOG << m.asString() << endl;
+ }
+ catch ( const Exception & except_r )
+ {
+ LOG << "***Failed: " << except_r << endl;
+ continue;
+ }
+ LOG << for_each( src.resolvables().begin(), src.resolvables().end(),
+ ResStoreStats() ) << endl;
+ if ( verbose )
+ {
+ dumpRange( LOG, src.resolvables().begin(), src.resolvables().end() ) << endl;
+ }
+
+ //SourceManager::sourceManager()->addSource( src );
+ //SourceManager::sourceManager()->store( "/", true );
+ }
+
+ INT << "===[END]============================================" << endl << endl;
+ return 0;
+}
+
--- /dev/null
+2007-03-08 16:24:30 <5> piscola(19785) [Measure] /space/sources/zypp/trunk/libzypp/zypp/base/Measure.cc(~Impl):160 MEASURE(Parse) 42 (u 41.17 s 0.44 c 0.00) [0 (u 0.00 s 0.00 c 0.00)]
+
+2007-03-09 12:09:41 <5> piscola(15522) [Measure] /space/sources/zypp/trunk/libzypp/zypp/base/Measure.cc(~Impl):160 MEASURE(Parse) 45 (u 43.69 s 0.28 c 0.00) [0 (u 0.00 s 0.00 c 0.00)]
+
+2007-03-09 14:19:21 <5> piscola(12400) [Measure] /space/sources/zypp/trunk/libzypp/zypp/base/Measure.cc(~Impl):160 MEASURE(Parse) 43 (u 43.04 s 0.23 c 0.00) [0 (u 0.00 s 0.00 c 0.00)]
+
+
+after change 1
+
+
+2007-03-09 16:49:03 <5> piscola(19367) [Measure] /space/sources/zypp/trunk/libzypp/zypp/base/Measure.cc(~Impl):160 MEASURE(Parse) 36 (u 29.82 s 5.51 c 0.00) [0 (u 0.00 s 0.00 c 0.00)]
\ No newline at end of file
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/tagfile
)
+SET( zypp_parser_taggedfile_SRCS
+ parser/taggedfile/Rep.cc
+ parser/taggedfile/TagCacheRetrieval.cc
+ parser/taggedfile/TaggedFile.cc
+ parser/taggedfile/TaggedParser.cc
+ parser/taggedfile/TagParser.cc
+ parser/taggedfile/TagRetrievalPos.cc
+)
+
+SET( zypp_parser_taggedfile_HEADERS
+ parser/taggedfile/RepDef.h
+ parser/taggedfile/TagCacheRetrieval.h
+ parser/taggedfile/TaggedFile.h
+ parser/taggedfile/TagParser.h
+ parser/taggedfile/Rep.h
+ parser/taggedfile/TagCacheRetrievalPtr.h
+ parser/taggedfile/TaggedParser.h
+ parser/taggedfile/TagRetrievalPos.h
+)
+
+INSTALL( FILES
+ ${zypp_parser_taggedfile_HEADERS}
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/parser/taggedfile
+)
+
+
SET( zypp_parser_xml_SRCS
parser/xml/Node.cc
parser/xml/ParseDef.cc
${zypp_capability_SRCS}
${zypp_pool_SRCS}
${zypp_parser_tagfile_SRCS}
+${zypp_parser_taggedfile_SRCS}
${zypp_parser_yum2_SRCS}
${zypp_parser_xmlstore_SRCS}
${zypp_parser_xml_SRCS}
${zypp_source_plaindir_HEADERS}
${zypp_target_store_xml_HEADERS}
${zypp_parser_tagfile_HEADERS}
+${zypp_parser_taggedfile_HEADERS}
${zypp_target_rpm_HEADERS}
${zypp_parser_yum2_HEADERS}
${zypp_capability_HEADERS}
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: Rep.cc
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+ Purpose: Base class for reference counted objects and counted pointer templates.
+
+/-*/
+
+#include <iostream>
+
+#include "zypp/parser/taggedfile/Rep.h"
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : Rep
+//
+///////////////////////////////////////////////////////////////////
+
+ostream & Rep::dumpOn( ostream & str ) const {
+ return str << repName() << "(<-" << refCount() << ')';
+}
+
+ostream & operator<<( ostream & str, const Rep & obj ) {
+ return obj.dumpOn( str );
+}
+
+ostream & operator<<( ostream & str, const Rep * obj ) {
+ if ( ! obj )
+ return str << "(NULL)";
+ return str << *obj;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : CountedRep
+//
+///////////////////////////////////////////////////////////////////
+
+unsigned CountedRep::_objectCount = 0;
+unsigned CountedRep::_objectIds = 0;
+
+ostream & CountedRep::dumpOn( ostream & str ) const {
+ return str << repName() << "[" << objectId() << "(<-" << refCount() << ")]";
+}
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : RepPtrBase
+//
+///////////////////////////////////////////////////////////////////
+
+ostream & operator<<( ostream & str, const RepPtrBase & obj ) {
+ return str << obj.refbase();
+}
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: Rep.h
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+ Purpose: Base class for reference counted objects and counted pointer templates.
+
+/-*/
+#ifndef Rep_h
+#define Rep_h
+
+#include <iosfwd>
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : Rep
+/**
+ * @short Base class for reference counted objects.
+ *
+ * The initial reference count is zero. Calling @ref ref(),
+ * the reference counter is increased. Calling @ref unref(),
+ * the reference counter is decreased. If the reference count
+ * becomes zero, the object is deleted.
+ *
+ * Any attempt to delete an object with a non zero reference
+ * count will throw an exeption.
+ *
+ * Any attempt to @ref unref() an object with a zero reference
+ * count will throw an exeption.
+ *
+ * Stream output operator are provided for Rep and Rep*. Both use
+ * @ref dumpOn(), which might be overloaded by derived classes.
+ **/
+class Rep {
+ private:
+
+ /**
+ * The reference counter.
+ **/
+ mutable unsigned _counter;
+
+ protected:
+
+ /**
+ * Trigger derived classes after refCount was increased.
+ **/
+ virtual void ref_to( unsigned /* rep_cnt_r */ ) const {}
+ /**
+ * Trigger derived classes after refCount was decreased.
+ * No trigger is sent, if refCount got zero (i.e. the
+ * object is deleted).
+ **/
+ virtual void unref_to( unsigned /* rep_cnt_r */ ) const {}
+
+ public:
+
+ /**
+ * Constructor. Initial reference count is zero.
+ **/
+ Rep() : _counter( 0 ) {}
+ /**
+ * CopyConstructor. Initial reference count is zero.
+ **/
+ Rep( const Rep & /* rhs */ ) : _counter( 0 ) {}
+ /**
+ * Assignment. Reference count remains untouched.
+ **/
+ Rep & operator=( const Rep & /* rhs */ ) { return *this; }
+ /**
+ * Destructor. Throws exception if reference count is not zero.
+ **/
+ virtual ~Rep() { if ( _counter ) throw( this ); }
+
+ public:
+
+ /**
+ * Increment reference counter.
+ **/
+ void ref() const {
+ ref_to( ++_counter ); // trigger derived classes
+ }
+ /**
+ * Decrement reference counter and delete the object if reference
+ * count got zero. Throws exception if reference count already is
+ * zero.
+ **/
+ void unref() const {
+ if ( ! _counter )
+ throw( this );
+ if ( --_counter )
+ unref_to( _counter ); // trigger derived classes
+ else
+ delete this;
+ }
+
+ /**
+ * Safe increment reference counter. Ignore NULL object pointer
+ * passed as argument.
+ **/
+ static void ref( const Rep * obj_r ) {
+ if ( obj_r )
+ obj_r->ref();
+ }
+ /**
+ * Safe decrement reference counter. Ignore NULL object pointer
+ * passed as argument..
+ **/
+ static void unref( const Rep * obj_r ) {
+ if ( obj_r )
+ obj_r->unref();
+ }
+
+ public:
+
+ /**
+ * Current reference counter value.
+ **/
+ unsigned refCount() const { return _counter; }
+
+ public:
+
+ /**
+ * Objects name used in dumpOn().
+ **/
+ virtual const char * repName() const { return "Rep"; }
+ /**
+ * Derived classes may overload this to realize
+ * std::ostream & operator<< for object and pointer
+ * classes.
+ **/
+ virtual std::ostream & dumpOn( std::ostream & str ) const;
+};
+
+/**
+ * Stream output operator for reference counted objects.
+ **/
+std::ostream & operator<<( std::ostream & str, const Rep & obj );
+/**
+ * Stream output operator for reference counted object pointer.
+ **/
+std::ostream & operator<<( std::ostream & str, const Rep * obj );
+
+////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : CountedRep
+/**
+ * @short Base class for reference counted objects. Provides numerical object ids.
+ *
+ * Derived from @ref Rep, CountedRep provides a numerical object id and
+ *
+ * See class @ref Rep.
+ **/
+class CountedRep : public Rep {
+
+ private:
+
+ /**
+ * Counts total ammount of CountedRep instances in memeory.
+ **/
+ static unsigned _objectCount;
+ /**
+ * Provides numerical ids.
+ **/
+ static unsigned _objectIds;
+
+ /**
+ * This objects numerical id.
+ **/
+ const unsigned _objectId;
+
+ public:
+
+ /**
+ * Constructor.
+ **/
+ CountedRep() : _objectId( ++_objectIds ) { ++_objectCount; }
+ /**
+ * CopyConstructor.
+ **/
+ CountedRep( const CountedRep & rhs ) : Rep( rhs ), _objectId( ++_objectIds ) { ++_objectCount; }
+ /**
+ * Assignment. objectId remains untouched.
+ **/
+ CountedRep & operator=( const CountedRep & rhs ) {
+ Rep::operator=( rhs );
+ return *this;
+ }
+ /**
+ * Destructor.
+ **/
+ virtual ~CountedRep() { --_objectCount; }
+
+ public:
+
+ /**
+ * This objects numerical id.
+ **/
+ unsigned objectId() const { return _objectId; }
+
+ /**
+ * The total ammount of CountedRep instances in memeory.
+ **/
+ static unsigned objectCount() { return _objectCount; }
+
+ public:
+
+ /**
+ * Stream output
+ **/
+ virtual std::ostream & dumpOn( std::ostream & str ) const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Counted pointer
+//
+////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : RepPtrStore<typename _Tp, typename _Bt>
+/**
+ * @short A '_Tp*' with reference counting on construction and assign.
+ *
+ * Class _Tp must inherit class @ref Rep. @ref tryAssign() supports assignment from
+ * '_Bt *' via dynamic_cast. Thus _Bt must either be _Tp, or a baseclass of _Tp.
+ *
+ * The counted pointer template classes @ref Ptr and @ref constPtr use RepPtrStore
+ * to store the 'object *'. Intentionally all methods which require more than a
+ * forward declaration of classes _Tp and _Bt are defined within RepPtrStore and
+ * not inlined.
+ *
+ * To use an ordinary <code>_Tp*</code>, a forward declaration <code>class _Tp;</code>
+ * is sufficient, unless you actually access the '_Tp' object. Using a counted pointer,
+ * you'll have to pervent the implicit generation of RepPtrStore<_Tp> instances too.
+ * Otherwise the definition of class _Tp had to be provided.
+ *
+ * <PRE>
+ * #include <y2util/Rep.h> // template definition
+ * class Foo; // forward declare class Foo
+ * extern template class RepPtrStore<Foo>; // pervent implicit instanciation of RepPtrStore<Foo>
+ * </PRE>
+ *
+ * Then within some translation unit you'll have to explicitly instantiate RepPtrStore<Foo>.
+ *
+ * <PRE>
+ * #include <y2util/Rep.h> // template definition
+ * #include "Foo.h" // definition of class Foo
+ * template class RepPtrStore<Foo>; // explicit instantiation of RepPtrStore<Foo>
+ * </PRE>
+ *
+ **/
+template<typename _Tp, typename _Bt = _Tp>
+class RepPtrStore {
+
+ private:
+
+ /**
+ * The pointer.
+ **/
+ _Tp * _obj;
+
+ private:
+
+ /**
+ * Assign a new value to @ref _obj. Adjusts the objects reference counter
+ * according to the old and new pointer value.
+ **/
+ void _assign( _Tp * new_r );
+
+ public:
+
+ /**
+ * DefaultConstructor. NULL
+ **/
+ RepPtrStore() : _obj( 0 ) {}
+ /**
+ * Constructor. Uses @ref _assign.
+ **/
+ RepPtrStore( _Tp * ptr ) : _obj( 0 ) { _assign( ptr ); }
+ /**
+ * CopyConstructor. Uses @ref _assign.
+ **/
+ RepPtrStore( const RepPtrStore & rhs ) : _obj( 0 ) { _assign( rhs._obj ); }
+
+ /**
+ * Assign. Uses @ref _assign.
+ **/
+ RepPtrStore & operator=( _Tp * ptr ) { _assign( ptr ); return *this; }
+ /**
+ * Assign. Uses @ref _assign.
+ **/
+ RepPtrStore & operator=( const RepPtrStore & rhs ) { _assign( rhs._obj ); return *this; }
+
+ /**
+ * Destructor. Uses @ref _assign.
+ **/
+ ~RepPtrStore() { _assign( 0 ); }
+
+ /**
+ * Conversion to '_Tp *'
+ **/
+ operator _Tp *() const { return _obj; }
+
+ public:
+
+ /**
+ * Assign the result of dynamic_cast '_Bt *' to '_Tp *'. Uses @ref _assign.
+ **/
+ void tryAssign( _Bt * ptr );
+
+ public:
+
+ /**
+ * Explicit conversion to '_Bt *'
+ **/
+ _Bt * base() const;
+ /**
+ * Explicit conversion to 'const @ref Rep *'
+ **/
+ const Rep * refbase() const;
+};
+
+template<typename _Tp,typename _Bt>
+void RepPtrStore<_Tp,_Bt>::_assign( _Tp * new_r ) {
+ if ( new_r != _obj ) {
+ Rep::unref( _obj );
+ _obj = new_r;
+ Rep::ref( _obj );
+ }
+}
+
+template<typename _Tp,typename _Bt>
+void RepPtrStore<_Tp,_Bt>::tryAssign( _Bt * ptr ) {
+ _assign( dynamic_cast<_Tp*>(ptr) );
+ if ( !_obj && ptr && ! ptr->refCount() ) {
+ Rep::ref( ptr );
+ Rep::unref( ptr );
+ }
+}
+
+template<typename _Tp,typename _Bt>
+_Bt * RepPtrStore<_Tp,_Bt>::base() const { return _obj; }
+
+template<typename _Tp,typename _Bt>
+const Rep * RepPtrStore<_Tp,_Bt>::refbase() const { return _obj; }
+
+////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : RepPtrBase
+/**
+ * @short Common base class for all counted pointer classes
+ *
+ * Provides stream output operator and conversion to 'const void *'
+ * to allow pointer comparison and test for NULL.
+ *
+ * See @ref PtrBase and @ref constPtrBase
+ **/
+class RepPtrBase {
+ /**
+ * Stream output operator for all counted pointer classes.
+ **/
+ friend std::ostream & operator<<( std::ostream & str, const RepPtrBase & obj );
+
+ protected:
+
+ /**
+ * virtual destructor;
+ **/
+ virtual ~RepPtrBase() {}
+ /**
+ * Derived class must provide the objects '@ref Rep *'
+ **/
+ virtual const Rep * refbase() const = 0;
+
+ public:
+
+ /**
+ * Conversion to 'const void *' to allow pointer comparison
+ * and test for NULL.
+ **/
+ operator const void *() const { return refbase(); }
+};
+
+///////////////////////////////////////////////////////////////////
+
+template<typename _Bt> class constPtrBase;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : PtrBase<typename _Bt>
+/**
+ * @short Common base class for counted '_Bt *' (@ref Ptr)
+ *
+ * See also @ref constPtrBase and @ref RepPtrStore.
+ **/
+template<typename _Bt>
+class PtrBase : public RepPtrBase {
+
+ protected:
+
+ friend class constPtrBase<_Bt>;
+
+ /**
+ * Derived class must provide the objects '_Bt *'. See @ref RepPtrStore.
+ **/
+ virtual _Bt * base() const = 0;
+
+ /**
+ * Retrieve base() from another PtrBase<_Bt> object.
+ **/
+ _Bt * getBase( const PtrBase & rhs ) const {
+ return rhs.base();
+ }
+};
+
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : constPtrBase<typename _Bt>
+/**
+ * @short Common base class for counted 'const _Bt *' (@ref constPtr)
+ *
+ * See also @ref PtrBase and @ref RepPtrStore.
+ **/
+template<typename _Bt>
+class constPtrBase : public RepPtrBase {
+
+ protected:
+
+ /**
+ * Derived class must provide the objects 'const _Bt *'. See @ref RepPtrStore.
+ **/
+ virtual const _Bt * base() const = 0;
+
+ /**
+ * Retrieve base() from another constPtrBase<_Bt> object.
+ **/
+ const _Bt * getBase( const constPtrBase & rhs ) const {
+ return rhs.base();
+ }
+
+ /**
+ * Retrieve base() from a nonconst PtrBase<_Bt> object. Needed
+ * as it's ok to create a constPtr from a Ptr, but not vice versa.
+ **/
+ const _Bt * getBase( const PtrBase<_Bt> & rhs ) const {
+ return rhs.base();
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<typename _Tp,typename _Bt> class constPtr;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : Ptr<typename _Tp, typename _Bt>
+/**
+ * @short Counted '_Tp *'. Support construction/assignment via dynamic_cast from @ref PtrBase<_Bt>
+ **/
+template<typename _Tp, typename _Bt = _Tp>
+class Ptr : public PtrBase<_Bt> {
+
+ private:
+
+ /**
+ * The '_Tp*'.
+ **/
+ RepPtrStore<_Tp,_Bt> _ptr;
+
+ protected:
+
+ /**
+ * Required by inherited @ref RepPtrBase.
+ **/
+ virtual const Rep * refbase() const { return _ptr.refbase(); }
+ /**
+ * Required by inherited @ref PtrBase.
+ **/
+ virtual _Bt * base() const { return _ptr.base(); }
+
+ public:
+
+ /**
+ * Constructor. From '_Tp *'. Defaults to NULL.
+ **/
+ Ptr( _Tp * ptr = 0 ) : _ptr( ptr ) {}
+ /**
+ * CopyConstructor. From Ptr<_Tp,_Bt>.
+ **/
+ Ptr( const Ptr & rhs ) : PtrBase<_Bt>( rhs ), _ptr( rhs._ptr ) {}
+ /**
+ * Constructor. From Ptr<..,_Bt>, i.e. pointer to an object that inherits _Bt.
+ **/
+ Ptr( const PtrBase<_Bt> & rhs ) { _ptr.tryAssign( getBase( rhs ) ); }
+
+ public:
+
+ /**
+ * Assign from '_Tp *'.
+ **/
+ Ptr & operator=( _Tp * ptr ) { _ptr = ptr; return *this; }
+ /**
+ * Assign from Ptr<_Tp,_Bt>.
+ **/
+ Ptr & operator=( const Ptr & rhs ) { _ptr = rhs._ptr; return *this; }
+ /**
+ * Assign from Ptr<..,_Bt>, i.e. pointer to an object that inherits _Bt.
+ **/
+ Ptr & operator=( const PtrBase<_Bt> & rhs ) { _ptr.tryAssign( getBase( rhs ) ); return *this; }
+
+ public:
+
+ /**
+ * Access forwarded to the _Tp object (or SEGV if _ptr is NULL)
+ **/
+ _Tp * operator->() const { return _ptr; }
+
+ /**
+ * Access the _Tp object (or SEGV if _ptr is NULL)
+ **/
+ _Tp & operator*() const { return *_ptr; }
+
+ public:
+
+ /**
+ * ConstCast. Create a Ptr from constPtr ('_Tp*' from 'const _Tp*').
+ **/
+ static Ptr cast_away_const( constPtr<_Tp,_Bt> rhs ) {
+ return const_cast<_Tp*>(rhs.operator->());
+ }
+};
+
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : constPtr<typename _Tp, typename _Bt>
+/**
+ * @short Counted 'const _Tp *'. Support construction/assignment via dynamic_cast from @ref constPtrBase<_Bt>
+ **/
+template<typename _Tp, typename _Bt = _Tp>
+class constPtr : public constPtrBase<_Bt> {
+
+ private:
+
+ /**
+ * The 'const _Tp*'.
+ **/
+ RepPtrStore<const _Tp,const _Bt> _ptr;
+
+ protected:
+
+ /**
+ * Required by inherited @ref RepPtrBase.
+ **/
+ virtual const Rep * refbase() const { return _ptr.refbase(); }
+ /**
+ * Required by inherited @ref PtrBase.
+ **/
+ virtual const _Bt * base() const { return _ptr.base(); }
+
+ public:
+
+ /**
+ * Constructor. From 'const _Tp *'. Defaults to NULL.
+ **/
+ constPtr( const _Tp * ptr = 0 ) : _ptr( ptr ) {}
+ /**
+ * CopyConstructor. From constPtr<_Tp,_Bt>.
+ **/
+ constPtr( const constPtr & rhs ) : constPtrBase<_Bt>( rhs ), _ptr( rhs._ptr ) {}
+ /**
+ * Constructor. From constPtr<..,_Bt>, i.e. pointer to an object that inherits _Bt.
+ **/
+ constPtr( const constPtrBase<_Bt> & rhs ) { _ptr.tryAssign( getBase( rhs ) ); }
+
+ public:
+
+ /**
+ * Assign from 'const _Tp *'.
+ **/
+ constPtr & operator=( const _Tp * ptr ) { _ptr = ptr; return *this; }
+ /**
+ * Assign from constPtr<_Tp,_Bt>.
+ **/
+ constPtr & operator=( const constPtr & rhs ) { _ptr = rhs._ptr; return *this; }
+ /**
+ * Assign from constPtr<..,_Bt>, i.e. pointer to an object that inherits _Bt.
+ **/
+ constPtr & operator=( const constPtrBase<_Bt> & rhs ) { _ptr.tryAssign( getBase( rhs ) ); return *this; }
+
+ public:
+
+ /**
+ * Constructor. From nonconst Ptr<_Tp,_Bt>.
+ **/
+ constPtr( const Ptr<_Tp,_Bt> & rhs ) : _ptr( rhs.operator->() ) {}
+ /**
+ * Constructor. From nonconst Ptr<..,_Bt>, i.e. pointer to an object that inherits _Bt.
+ **/
+ constPtr( const PtrBase<_Bt> & rhs ) { _ptr.tryAssign( getBase( rhs ) ); }
+
+ public:
+
+ /**
+ * Assign from nonconst Ptr<_Tp,_Bt>.
+ **/
+ constPtr & operator=( const Ptr<_Tp,_Bt> & rhs ) { _ptr = rhs.operator->(); return *this; }
+ /**
+ * Assign from nonconst Ptr<..,_Bt>, i.e. pointer to an object that inherits _Bt.
+ **/
+ constPtr & operator=( const PtrBase<_Bt> & rhs ) { _ptr.tryAssign( getBase( rhs ) ); return *this; }
+
+ public:
+
+ /**
+ * Access forwarded to the _Tp object (or SEGV if _ptr is NULL)
+ **/
+ const _Tp * operator->() const { return _ptr; }
+ /**
+ * Access the _Tp object (or SEGV if _ptr is NULL)
+ **/
+ const _Tp & operator*() const { return *_ptr; }
+};
+
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : VarPtr
+//
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : BasicRepPtr
+/**
+ * @short Base class wraping a @ref Rep* and managing reference counting.
+ *
+ * A @ref BasicRepPtr is explicity constructed from a @ref Rep*. It
+ * references @ref Rep while it holds the pointer and adjusts the
+ * reference counter on copy and assignment.
+ *
+ * It may serve as base for template classes operating on data classes
+ * derived from @ref Rep. For example @ref VarPtr.
+ **/
+class BasicRepPtr
+{
+ /**
+ * Print out the @ref Rep object.
+ **/
+ friend std::ostream &
+ operator<<( std::ostream & str, const BasicRepPtr & obj )
+ { return str << obj._ptr; }
+
+ public:
+ /**
+ * Allow easy test for NULL.
+ **/
+ operator const void *() const
+ { return _ptr; }
+
+ protected:
+ /**
+ * Default ctor: NULL
+ **/
+ BasicRepPtr()
+ : _ptr( NULL )
+ {}
+
+ explicit
+ BasicRepPtr( Rep * ptr )
+ : _ptr( NULL )
+ { _assign( ptr ); }
+
+ BasicRepPtr( const BasicRepPtr & rhs )
+ : _ptr( NULL )
+ { _assign( rhs._ptr ); }
+
+ BasicRepPtr &
+ operator=( const BasicRepPtr & rhs )
+ { _assign( rhs._ptr ); return *this; }
+
+ ~BasicRepPtr()
+ { _assign( NULL ); }
+
+ /**
+ * @return The @ref Rep*.
+ **/
+ Rep *
+ repPtr() const
+ { return _ptr; }
+
+ private:
+ /**
+ * The @ref Rep*.
+ **/
+ Rep * _ptr;
+
+ /**
+ * Takes care of reference counter when assigning
+ * _ptr a new value.
+ **/
+ void
+ _assign( Rep * new_r )
+ {
+ // Don't miss this test
+ if ( new_r != _ptr )
+ {
+ Rep::unref( _ptr );
+ _ptr = new_r;
+ Rep::ref( _ptr );
+ }
+ }
+};
+///////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : VarPtr
+/**
+ * @short Simple counted pointer with variable like const access.
+ *
+ * On construction and assignment it behaves like a pointer. I.e.
+ * a <code>'const VarPtr<_Tp>'</code> is a <code>'_Tp *const'</code>.
+ *
+ * But accessing _Tp (via @ref operator-> or @ref operator*) its
+ * constness is propagated to _Tp. I.e. <code>'VarPtr<_Tp>'</code>
+ * behaves like a <code>'_Tp *'</code> while a <code>'const VarPtr<_Tp>'</code>
+ * behaves as a <code>'const _Tp *'</code>.
+ *
+ * Used in some classes to hide implementation data from the interface:
+ * <PRE>
+ * class Foo
+ * {
+ * class _Implementation;
+ * VarPtr<_Implementation> _impl;
+ * ...
+ * </PRE>
+ * All a @ref VarPtr does, is preventing accidential access to nonconst
+ * implementation data from const interface methods. If such access
+ * is intended is has to be expressed by using a cost_cast.
+ **/
+template<typename _Rep>
+ class VarPtr : public BasicRepPtr
+ {
+ public:
+
+ /**
+ * Default ctor: NULL
+ **/
+ VarPtr()
+ : BasicRepPtr()
+ {}
+
+ /**
+ * See @ref makeVarPtr for convenient construction.
+ **/
+ explicit
+ VarPtr( _Rep * ptr_r )
+ : BasicRepPtr( ptr_r )
+ {}
+
+ public:
+
+ _Rep *
+ operator->()
+ { return ptr(); }
+
+ const _Rep *
+ operator->() const
+ { return ptr(); }
+
+ _Rep &
+ operator*()
+ { return *ptr(); }
+
+ const _Rep &
+ operator*() const
+ { return *ptr(); }
+
+ private:
+
+ _Rep *
+ ptr() const
+ { return static_cast<_Rep *>( BasicRepPtr::repPtr() ); }
+ };
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+
+/**
+ * Convenience @return @ref VarPtr<_Rep> constructed from ptr.
+ **/
+template<typename _Rep>
+ inline VarPtr<_Rep>
+ makeVarPtr( _Rep * ptr )
+ { return VarPtr<_Rep>( ptr ); }
+
+///////////////////////////////////////////////////////////////////
+
+#endif // Rep_h
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: RepDef.h
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+ Purpose: Provides a set of macros to define data and pointer classes.
+ See class RepPtrStore in Rep.h.
+
+/-*/
+#ifndef RepDef_h
+#define RepDef_h
+
+#include "zypp/parser/taggedfile/Rep.h"
+
+///////////////////////////////////////////////////////////////////
+//
+// NOTE: Data classes must inherit class Rep:
+//
+// class CLNAME : public Rep {
+// REP_BODY(CLNAME);
+// ...
+// };
+//
+///////////////////////////////////////////////////////////////////
+
+#define REP_BODY(NAME) GEN_REP_BODY( NAME, #NAME )
+
+///////////////////////////////////////////////////////////////////
+
+#define GEN_REP_BODY(CLNAME,STRNAME) \
+ CLNAME( const CLNAME & ); /* no copy */ \
+ CLNAME & operator=(const CLNAME & ); /* no assign */ \
+ public: \
+ virtual const char * repName() const \
+ { return STRNAME; } \
+ virtual size_t mem_size () const { return sizeof (CLNAME); }\
+ private:
+
+///////////////////////////////////////////////////////////////////
+
+#define DEFINE_BASE_POINTER(NAME) \
+ class NAME; \
+ typedef Ptr<NAME> NAME##Ptr; \
+ typedef constPtr<NAME> const##NAME##Ptr; \
+ extern template class RepPtrStore<NAME>; \
+ extern template class RepPtrStore<const NAME>;
+
+#define DEFINE_BASE_POINTER_IN_NAMESPACE(NS,NAME) \
+ namespace NS { \
+ class NAME; \
+ typedef Ptr<NAME> NAME##Ptr; \
+ typedef constPtr<NAME> const##NAME##Ptr; \
+ } \
+ extern template class RepPtrStore<NS::NAME>; \
+ extern template class RepPtrStore<const NS::NAME>;
+
+#define DEFINE_DERIVED_POINTER(NAME,BASE) \
+ class NAME; \
+ typedef Ptr<NAME,BASE> NAME##Ptr; \
+ typedef constPtr<NAME,BASE> const##NAME##Ptr; \
+ extern template class RepPtrStore<NAME,BASE>; \
+ extern template class RepPtrStore<const NAME,const BASE>;
+
+#define DEFINE_DERIVED_POINTER_IN_NAMESPACE(NS,NAME,BASE) \
+ namespace NS { \
+ class NAME; \
+ typedef Ptr<NAME,BASE> NAME##Ptr; \
+ typedef constPtr<NAME,BASE> const##NAME##Ptr; \
+ } \
+ extern template class RepPtrStore<NS::NAME,BASE>; \
+ extern template class RepPtrStore<const NS::NAME,const BASE>;
+
+///////////////////////////////////////////////////////////////////
+
+#define IMPL_BASE_POINTER(NAME) \
+template class RepPtrStore<NAME>; \
+template class RepPtrStore<const NAME>;
+
+#define IMPL_BASE_POINTER_IN_NAMESPACE(NS,NAME) \
+template class RepPtrStore<NS::NAME>; \
+template class RepPtrStore<const NS::NAME>;
+
+#define IMPL_DERIVED_POINTER(NAME,BASE) \
+template class RepPtrStore<NAME,BASE>; \
+template class RepPtrStore<const NAME,const BASE>;
+
+#define IMPL_DERIVED_POINTER_IN_NAMESPACE(NS,NAME,BASE) \
+template class RepPtrStore<NS::NAME,BASE>; \
+template class RepPtrStore<const NS::NAME,const BASE>;
+
+///////////////////////////////////////////////////////////////////
+
+#endif // RepDef_h
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TagCacheRetrieval.cc
+
+ Author: Klaus Kaempf <kkaempf@suse.de>
+ Maintainer: Klaus Kaempf <kkaempf@suse.de>
+
+ Purpose: Realize PMCacheRetrieval
+
+/-*/
+
+#include <iostream>
+
+#include <zypp/base/Logger.h>
+#include <zypp/parser/taggedfile/TagCacheRetrieval.h>
+
+using namespace std;
+using namespace zypp;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagCacheRetrieval
+//
+///////////////////////////////////////////////////////////////////
+
+IMPL_BASE_POINTER(TagCacheRetrieval);
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagCacheRetrieval::TagCacheRetrieval
+// METHOD TYPE : Constructor
+//
+// DESCRIPTION : open file stream and keep pointer to tag parser
+// for later value retrieval on-demand
+//
+TagCacheRetrieval::TagCacheRetrieval(const Pathname& name)
+ : _name (name.asString())
+ , _keep_open (false)
+{
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagCacheRetrieval::~TagCacheRetrieval
+// METHOD TYPE : Destructor
+//
+// DESCRIPTION :
+//
+TagCacheRetrieval::~TagCacheRetrieval()
+{
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagCacheRetrieval::retrieveData
+// METHOD TYPE : bool
+//
+// DESCRIPTION : retrieves data at TagRetrievalPos pos and fills
+// data_r appropriately
+//
+bool
+TagCacheRetrieval::retrieveData(const TagRetrievalPos& pos, std::list<std::string> &data_r)
+{
+ data_r.clear();
+
+ if (!_stream.is_open())
+ {
+ _stream.open (_name.c_str());
+ if (_stream.fail())
+ {
+ ERR << "Open (" << _name << ") failed" << endl;
+ return false;
+ }
+ }
+ bool ret = pos.retrieveData (_stream, data_r);
+ if (!_keep_open)
+ {
+ _stream.close ();
+ }
+ return ret;
+}
+
+bool
+TagCacheRetrieval::retrieveData(const TagRetrievalPos& pos, std::string &data_r)
+{
+ data_r.erase();
+
+ if (pos.empty())
+ {
+ return true;
+ }
+ if (!_stream.is_open())
+ {
+ _stream.open (_name.c_str());
+ if (_stream.fail())
+ {
+ ERR << "Open (" << _name << ") failed";
+ return false;
+ }
+ }
+ std::list<std::string> listdata;
+ bool ret = false;
+ if (pos.retrieveData (_stream, listdata)
+ && !listdata.empty())
+ {
+ data_r = listdata.front();
+ ret = true;
+ }
+ if (!_keep_open)
+ {
+ _stream.close ();
+ }
+ return ret;
+}
+
+
+
+void
+TagCacheRetrieval::startRetrieval()
+{
+ _keep_open = true;
+}
+
+void
+TagCacheRetrieval::stopRetrieval()
+{
+ if (_stream.is_open())
+ _stream.close();
+ _keep_open = false;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TagCacheRetrieval.h
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+ Purpose: Keep data and provide functions for on-demand retrieval
+ of cache values
+
+/-*/
+#ifndef TagCacheRetrieval_h
+#define TagCacheRetrieval_h
+
+#include <iosfwd>
+#include <string>
+#include <fstream>
+
+#include <zypp/parser/taggedfile/TaggedParser.h>
+#include <zypp/parser/taggedfile/TagRetrievalPos.h>
+
+#include <zypp/parser/taggedfile/TagCacheRetrievalPtr.h>
+#include <zypp/Pathname.h>
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagCacheRetrieval
+//
+class TagCacheRetrieval : public CountedRep {
+ REP_BODY(TagCacheRetrieval);
+ private:
+ // the name of the file
+ std::string _name;
+
+ // hint to keep stream open
+ bool _keep_open;
+
+ // the stream to read data from
+ std::ifstream _stream;
+
+ public:
+
+ TagCacheRetrieval (const zypp::Pathname& filename);
+ ~TagCacheRetrieval();
+
+ void startRetrieval();
+ void stopRetrieval();
+
+ /**
+ * access to stream and parser
+ * these are non-const because the caller might clobber the values
+ */
+ std::string& getName (void) { return _name; }
+
+ /**
+ * access to values
+ */
+ bool retrieveData (const TagRetrievalPos& pos, std::list<std::string> &data_r);
+ bool retrieveData (const TagRetrievalPos& pos, std::string &data_r);
+};
+
+///////////////////////////////////////////////////////////////////
+
+#endif // TagCacheRetrieval_h
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TagCacheRetrievalPtr.h
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+/-*/
+#ifndef TagCacheRetrievalPtr_h
+#define TagCacheRetrievalPtr_h
+
+#include <zypp/parser/taggedfile/RepDef.h>
+
+///////////////////////////////////////////////////////////////////
+// CLASS NAME : TagCacheRetrievalPtr
+// CLASS NAME : constTagCacheRetrievalPtr
+///////////////////////////////////////////////////////////////////
+DEFINE_BASE_POINTER(TagCacheRetrieval);
+
+#endif // TagCacheRetrievalPtr_h
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TagParser.cc
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+/-*/
+
+#include <iostream>
+#include <zypp/base/Logger.h>
+#include <zypp/parser/taggedfile/TagParser.h>
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagParser
+//
+///////////////////////////////////////////////////////////////////
+
+const unsigned TagParser::bufferLen_i = 1024;
+char TagParser::buffer_ac[bufferLen_i];
+const streamoff TagParser::nopos = streamoff(-1);
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::_datareset
+// METHOD TYPE : void
+//
+// DESCRIPTION :
+//
+inline void TagParser::_datareset()
+{
+ startData_i = endData_i = endTag_i = nopos;
+ endTag_t.erase();
+ data_Vt.clear();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::_reset
+// METHOD TYPE : void
+//
+// DESCRIPTION :
+//
+inline void TagParser::_reset()
+{
+ lookupStart_i = startTag_i = nopos;
+ startTag_t.erase();
+ _datareset();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::TagParser
+// METHOD TYPE : Constructor
+//
+// DESCRIPTION :
+//
+TagParser::TagParser()
+{
+ _reset();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::~TagParser
+// METHOD TYPE : Destructor
+//
+// DESCRIPTION :
+//
+TagParser::~TagParser()
+{
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::readLine
+// METHOD TYPE : streamoff
+//
+// DESCRIPTION : read a line from an istream to a string
+// return streamoff of start of line
+//
+inline streamoff TagParser::readLine( istream & stream_fr, string & cline_tr )
+{
+ streamoff lineBegin_ii = streamoff( stream_fr.tellg() );
+ cline_tr.erase();
+
+ do {
+ stream_fr.clear();
+ stream_fr.getline( buffer_ac, bufferLen_i ); // always writes '\0' terminated
+ cline_tr += buffer_ac;
+ } while( stream_fr.rdstate() == ios::failbit );
+
+ return lineBegin_ii;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::tagOnLine
+// METHOD TYPE : bool
+//
+// DESCRIPTION : check if a tag exists on the line
+// return true (tag exists) or false
+// O: string tag_tr tag found
+// O: size_type delim_ir position following tag
+//
+inline bool TagParser::tagOnLine( const string & cline_tr, string & tag_tr, string::size_type & delim_ir )
+{
+ if ( !cline_tr.size() || cline_tr[0] == '#' ) {
+ delim_ir = string::npos;
+ tag_tr.erase();
+ return false; // empty or comment line
+ }
+
+ delim_ir = cline_tr.find_first_of( ": \t" );
+
+ if ( delim_ir == string::npos || delim_ir == 0 || cline_tr[delim_ir] != ':' ) {
+ delim_ir = string::npos;
+ tag_tr.erase();
+ return false; // no tag or empty tag or whitespace in tag
+ }
+
+ tag_tr = cline_tr.substr( 0, delim_ir );
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::lookupTag
+// METHOD TYPE : bool
+//
+// DESCRIPTION : read from istream until known tag is found
+// return true/false
+// O: string stag_tr tag found
+//
+bool TagParser::lookupTag( istream & stream_fr, const string & stag_tr )
+{
+ _reset();
+ if ( stream_fr.good() ) {
+ lookupStart_i = streamoff( stream_fr.tellg() );
+
+ streamoff lineBegin_ii = nopos;
+ string cline_ti;
+ string::size_type delim_ii = string::npos;
+ string maybe_ti;
+
+ do {
+ lineBegin_ii = readLine( stream_fr, cline_ti );
+
+ if ( !tagOnLine( cline_ti, maybe_ti, delim_ii ) )
+ continue; // no tag on cline
+
+ if ( stag_tr.size() && maybe_ti != stag_tr )
+ continue; // tag does not match given stag_tr
+
+ // here we've got a valid tag
+ startTag_i = lineBegin_ii;
+ startTag_t = maybe_ti;
+
+ // look for data on this line
+ delim_ii = cline_ti.find_first_not_of( " \t", delim_ii+1 );
+ if ( delim_ii == string::npos ) {
+ // no data on this line
+ startData_i = endData_i = startTag_i + cline_ti.size();
+ data_Vt.push_back( "" );
+ } else {
+ startData_i = startTag_i + delim_ii;
+ maybe_ti = cline_ti.substr( delim_ii, cline_ti.find_last_not_of( " \t" ) + 1 - delim_ii );
+ endData_i = startData_i + maybe_ti.size();
+ data_Vt.push_back( maybe_ti );
+ }
+
+ return true;
+
+ } while( stream_fr.good() );
+ }
+
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::parseData
+// METHOD TYPE : bool
+//
+// DESCRIPTION : read all data from istream until endtag
+//
+bool TagParser::parseData( istream & stream_fr, const string & etag_tr )
+{
+ _datareset();
+ if ( stream_fr.good() ) {
+ startData_i = streamoff( stream_fr.tellg() );
+
+ streamoff lineBegin_ii = nopos;
+ string cline_ti;
+ string::size_type delim_ii = string::npos;
+ string maybe_ti;
+
+ do {
+ lineBegin_ii = readLine( stream_fr, cline_ti );
+
+ if ( tagOnLine( cline_ti, maybe_ti, delim_ii ) && maybe_ti == etag_tr ) {
+ endData_i = endTag_i = lineBegin_ii;
+ endTag_t = maybe_ti;
+
+ if ( data_Vt.empty() )
+ data_Vt.push_back( "" );
+
+ return true;
+ }
+
+ // here we've got collect the line;
+ data_Vt.push_back( cline_ti );
+
+ } while( stream_fr.good() );
+
+ // here saw no endTag
+ _datareset();
+ }
+
+ return dataLines();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::retrieveData
+// METHOD TYPE : bool
+//
+// DESCRIPTION : retrieve data from istream between two offsets
+//
+bool TagParser::retrieveData( istream & stream_fr,
+ streamoff startData_ir, streamoff endData_ir,
+ string & data_tr )
+{
+ data_tr.erase();
+ if ( startData_ir == nopos || endData_ir == nopos || endData_ir < startData_ir ) {
+ ERR << "positions make no sense "<< stream_fr.rdstate() << "(" << startData_ir << ", " << endData_ir << ")" << endl;;
+ return false; // positions make no sense
+ }
+
+ stream_fr.clear();
+ stream_fr.seekg( startData_ir );
+
+ if ( !stream_fr.good() ) {
+ ERR << "seekg failed "<< stream_fr.rdstate() << "(" << startData_ir << ", " << endData_ir << ")" << endl;;
+ return false; // illegal startData position
+ }
+
+ unsigned expect_ii = endData_ir-startData_ir;
+
+ if ( !expect_ii ) {
+ return true; // startData position is valid, but we don't expect any data
+ }
+
+ for ( unsigned toread_ii = min( expect_ii, bufferLen_i );
+ toread_ii;
+ expect_ii -= toread_ii, toread_ii = min( expect_ii, bufferLen_i ) ) {
+ stream_fr.read( buffer_ac, toread_ii );
+ if ( stream_fr.gcount() != (int)toread_ii ) {
+ data_tr.erase();
+ ERR << "data missing "<< stream_fr.rdstate() << "(" << startData_ir << ", " << endData_ir << ")" << endl;;
+ return false; // not as many data available as expected
+ }
+ data_tr += string( buffer_ac, toread_ii );
+ }
+
+ // strip a trailing NL
+ if ( data_tr[data_tr.size()-1] == '\n' )
+ data_tr.erase( data_tr.size()-1 );
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::retrieveData
+// METHOD TYPE : bool
+//
+// DESCRIPTION : retrieve data from istream between two offsets
+//
+bool TagParser::retrieveData( istream & stream_fr,
+ streamoff startData_ir, streamoff endData_ir,
+ list<string> & data_Vtr )
+{
+ data_Vtr.clear();
+ string data_ti;
+ if ( !retrieveData( stream_fr, startData_ir, endData_ir, data_ti ) ) {
+ return false;
+ }
+
+ string::size_type subStart_ii = 0;
+ for ( string::size_type delim_ii = data_ti.find( '\n', subStart_ii );
+ delim_ii != string::npos;
+ subStart_ii = delim_ii+1, delim_ii = data_ti.find( '\n', subStart_ii ) ) {
+ data_Vtr.push_back( data_ti.substr( subStart_ii, delim_ii - subStart_ii ) );
+ }
+ data_Vtr.push_back( data_ti.substr( subStart_ii ) );
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::data2string
+// METHOD TYPE : string
+//
+// DESCRIPTION : concatenate list of strings to single string
+//
+string TagParser::data2string( const list<string> & data_Vtr )
+{
+ if ( data_Vtr.empty() )
+ return "";
+
+ string ret_ti;
+ for (list<string>::const_iterator pos = data_Vtr.begin();
+ pos != data_Vtr.end(); ++pos)
+ {
+ if (!ret_ti.empty())
+ ret_ti += '\n';
+ ret_ti += *pos;
+ }
+
+ return ret_ti;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagParser::split2words
+// METHOD TYPE : vector<string>
+//
+// DESCRIPTION :
+//
+vector<string> TagParser::split2words( const string & line_tr, const string & sepchars_tr )
+{
+ vector<string> Ret_Vti;
+
+ string::size_type wstart_ii = 0;
+ string::size_type wend_ii = string::npos;
+ do {
+ wstart_ii = line_tr.find_first_not_of( sepchars_tr, wstart_ii );
+ if ( wstart_ii != string::npos ) {
+ wend_ii = line_tr.find_first_of( sepchars_tr, wstart_ii );
+ if ( wend_ii != string::npos ) {
+ Ret_Vti.push_back( line_tr.substr( wstart_ii, wend_ii-wstart_ii ) );
+ } else {
+ Ret_Vti.push_back( line_tr.substr( wstart_ii ) );
+ }
+ wstart_ii = wend_ii;
+ }
+ } while ( wstart_ii != string::npos );
+
+ return Ret_Vti;
+}
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : operator<<
+** FUNCTION TYPE : ostream &
+**
+** DESCRIPTION :
+*/
+ostream & operator<<( ostream & str, const TagParser & obj )
+{
+ str << "TagParser{"
+ << obj.lookupStart()
+ << " [" << obj.posStartTag() << ":" << obj.startTag() << "]"
+ << " [" << obj.posEndTag() << ":" << obj.endTag() << "]"
+ << " [" << obj.posDataStart() << "-" << obj.posDataEnd() << "=" << obj.dataLength() << "]"
+ << " (" << obj.dataLines() << ")";
+ if ( obj.dataLines() )
+ str << " \"" << obj.data().front() << '"';
+
+ return str << '}';
+
+}
+
+#if 0
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagSet
+//
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagSet::addTag
+// METHOD TYPE : void
+//
+// DESCRIPTION : For sake of derived classes we always create a new
+// index entry in lookupEnd_V, even if the tag is alredy defined,
+// i.e. does not occurr in lookupStart_V.
+//
+void TagSet::addTag( const string & start_tr, const string & end_tr )
+{
+ map<string,unsigned>::value_type val_Ci( start_tr, lookupEnd_V.size() );
+
+ if ( !lookupStart_V.insert( val_Ci ).second ) {
+ WAR << "Duplicate definition for Tag(" << start_tr.c_str() << ", " << end_tr.c_str() << ")" << endl;
+ }
+
+ lookupEnd_V.push_back( end_tr );
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagSet::parseData
+// METHOD TYPE : unsigned
+//
+// DESCRIPTION :
+//
+unsigned TagSet::parseData( istream & in_Fr, TagParser & ctag_Cr ) const
+{
+ map<string,unsigned>::const_iterator i = lookupStart_V.find( ctag_Cr.startTag() );
+
+ if ( i == lookupStart_V.end() )
+ return unknowntag;
+
+ unsigned ret_ii = i->second;
+
+ if ( lookupEnd_V[ret_ii].size() )
+ ctag_Cr.parseData( in_Fr, lookupEnd_V[ret_ii] );
+
+ return ret_ii;
+}
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : operator<<
+** FUNCTION TYPE : ostream &
+**
+** DESCRIPTION :
+*/
+ostream & operator<<( ostream & str, const TagSet & obj )
+{
+ str << "TagSet(tags " << obj.lookupStart_V.size() << ", indices " << obj.lookupEnd_V.size();
+ if ( obj.lookupStart_V.size() ) {
+ str << endl;
+ for ( map<string,unsigned>::const_iterator i = obj.lookupStart_V.begin();
+ i != obj.lookupStart_V.end(); ++i ) {
+ str << " [" << i->first << "] [" << obj.lookupEnd_V[i->second] << "] (" << i->second << ") " << endl;
+ }
+ }
+ return str << ")" << endl;
+}
+
+#endif
--- /dev/null
+/*---------------------------------------------------------------------\
+ | |
+ | __ __ ____ _____ ____ |
+ | \ \ / /_ _/ ___|_ _|___ \ |
+ | \ V / _` \___ \ | | __) | |
+ | | | (_| |___) || | / __/ |
+ | |_|\__,_|____/ |_| |_____| |
+ | |
+ | core system |
+ | (C) SuSE GmbH |
+ \----------------------------------------------------------------------/
+
+ File: TagParser.h
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+ /-*/
+#ifndef TagParser_h
+#define TagParser_h
+
+#include <iosfwd>
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+
+using std::vector;
+using std::map;
+using std::streamoff;
+using std::istream;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagParser
+//
+//
+// DESCRIPTION :
+//
+class TagParser {
+
+ private:
+
+ static const unsigned bufferLen_i;
+ static char buffer_ac[];
+
+ private:
+
+ streamoff lookupStart_i;
+ streamoff startTag_i;
+ streamoff startData_i;
+ streamoff endData_i;
+ streamoff endTag_i;
+
+ std::string startTag_t;
+ std::string endTag_t;
+
+ std::list<std::string> data_Vt;
+
+ private:
+
+ void _reset();
+ void _datareset();
+
+ static streamoff readLine( istream & stream_fr, std::string & cline_tr );
+ static bool tagOnLine( const std::string & cline_tr, std::string & tag_tr, std::string::size_type & delim_ir );
+
+ public:
+
+ TagParser();
+ virtual ~TagParser();
+
+ static const streamoff nopos;
+
+ streamoff lookupStart() const { return lookupStart_i; }
+
+ streamoff posStartTag() const { return startTag_i; }
+ const std::string & startTag() const { return startTag_t; }
+
+ streamoff posEndTag() const { return endTag_i; }
+ const std::string & endTag() const { return endTag_t; }
+
+ public:
+
+ streamoff posDataStart()const { return startData_i; }
+ streamoff posDataEnd() const { return endData_i; }
+ unsigned dataLength() const { return endData_i - startData_i; }
+ unsigned dataLines() const { return data_Vt.size(); }
+
+ const std::list<std::string> & data() const { return data_Vt; }
+
+ public:
+
+ // parse until stag_tr, leave empty to parse until any tag. On succes
+ // posStartTag() and posEndTag() can be used
+ bool lookupTag( istream & stream_fr, const std::string & stag_tr = "" );
+ // continue parsing until end tag etag_tr is found since the above
+ // function sets posEndTag to the end of the line
+ bool parseData( istream & stream_fr, const std::string & etag_tr );
+
+ static bool retrieveData( istream & stream_fr,
+ streamoff startData_ir, streamoff endData_ir,
+ std::string & data_tr );
+ static bool retrieveData( istream & stream_fr,
+ streamoff startData_ir, streamoff endData_ir,
+ std::list<std::string> & data_Vtr );
+ static std::string data2string( const std::list<std::string> & data_Vtr );
+ static vector<std::string> split2words( const std::string & line_tr, const std::string & sepchars_tr = " \t\n" );
+};
+
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagSet
+//
+// DESCRIPTION :
+//
+#if 0
+class TagSet {
+
+ friend std::ostream & operator<<( std::ostream & str, const TagSet & obj );
+
+ private:
+
+ map<std::string,unsigned> lookupStart_V;
+ vector<std::string> lookupEnd_V;
+
+ public:
+
+ static const unsigned unknowntag = (unsigned)-1;
+
+ TagSet() {}
+ virtual ~TagSet() {}
+
+ void addTag( const std::string & start_tr, const std::string & end_tr = "" );
+
+ unsigned parseData( istream & in_Fr, TagParser & ctag_Cr ) const;
+};
+
+///////////////////////////////////////////////////////////////////
+
+extern std::ostream & operator<<( std::ostream & str, const TagParser & obj );
+extern std::ostream & operator<<( std::ostream & str, const TagSet & obj );
+
+///////////////////////////////////////////////////////////////////
+#endif // #if 0
+
+#endif // TagParser_h
+
+// vim:sw=2
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TagRetrievalPos.cc
+
+ Author: Klaus Kaempf <kkaempf@suse.de>
+ Maintainer: Klaus Kaempf <kkaempf@suse.de>
+
+ Purpose: Realize data access at position
+
+/-*/
+
+#include <iostream>
+
+#include <zypp/base/Logger.h>
+#include <zypp/parser/taggedfile/TagRetrievalPos.h>
+#include <zypp/base/String.h>
+
+using namespace std;
+using namespace zypp;
+
+// ------------------------------------------------------------------
+
+const unsigned TagRetrievalPos::bufferLen_i = 1024;
+char TagRetrievalPos::buffer_ac[bufferLen_i];
+const streamoff TagRetrievalPos::nopos = streamoff(-1);
+
+// ------------------------------------------------------------------
+
+/**
+ * position stream to _begin
+ *
+ * return _end - _begin ( == expected data size)
+ */
+int
+TagRetrievalPos::positionStream (istream & stream_fr) const
+{
+ if (empty())
+ return 0;
+
+ if (_begin == nopos
+ || _end == nopos
+ || _end < _begin)
+ {
+ ERR << "positions make no sense "<< stream_fr.rdstate() << "(" << _begin << ", " << _end << ")" << endl;;
+ return -1; // positions make no sense
+ }
+
+ stream_fr.clear();
+ stream_fr.seekg( _begin );
+
+ if ( !stream_fr.good() )
+ {
+ ERR << "seekg failed "<< stream_fr.rdstate() << "(" << _begin << ", " << _end << ")" << endl;;
+ return -1; // illegal startData position
+ }
+
+ return _end - _begin;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagRetrievalPos::retrieveData single-line
+// METHOD TYPE : bool
+//
+// DESCRIPTION : retrieve data from istream between two offsets
+// into a single string
+//
+bool
+TagRetrievalPos::retrieveData (istream & stream_fr, string & data_tr ) const
+{
+ data_tr.erase();
+
+ // position stream an calculate
+ int expect_ii = positionStream (stream_fr);
+ if ( expect_ii < 0)
+ return false; // error
+ if ( expect_ii == 0)
+ return true; // startData position is valid, but we don't expect any data
+
+ for ( unsigned toread_ii = min ((unsigned)expect_ii, bufferLen_i);
+ toread_ii;
+ expect_ii -= toread_ii, toread_ii = min( (unsigned)expect_ii, bufferLen_i ) )
+ {
+ stream_fr.read( buffer_ac, toread_ii );
+ if ( stream_fr.gcount() != (int)toread_ii )
+ {
+ data_tr.erase();
+ ERR << "data missing "<< stream_fr.rdstate() << "(" << _begin << ", " << _end << ")" << endl;;
+ return false; // not as many data available as expected
+ }
+ data_tr += string( buffer_ac, toread_ii );
+ }
+
+ // strip a trailing NL
+ if ( data_tr[data_tr.size()-1] == '\n' )
+ {
+ data_tr.erase( data_tr.size()-1 );
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TagRetrievalPos::retrieveData multi-line
+// METHOD TYPE : bool
+//
+// DESCRIPTION : retrieve data from istream between two offsets
+// into a list of strings
+//
+bool
+TagRetrievalPos::retrieveData (istream & stream_fr, list<string>& data_Vtr ) const
+{
+ data_Vtr.clear();
+
+ // position stream an calculate
+ int expect_ii = positionStream (stream_fr);
+ if ( expect_ii < 0)
+ return false; // error
+ if ( expect_ii == 0)
+ return true; // startData position is valid, but we don't expect any data
+
+ while ( streamoff( stream_fr.tellg() ) < _end)
+ {
+ string ln = str::getline( stream_fr );
+ if ( ! ( stream_fr.fail() || stream_fr.bad() ) )
+ {
+ data_Vtr.push_back( ln );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TagRetrievalPos.h
+
+ Author: Klaus Kaempf <kkaempf@suse.de>
+ Maintainer: Klaus Kaempf <kkaempf@suse.de>
+
+ Purpose: Keep data and provide functions for on-demand retrieval
+ of cache values
+
+/-*/
+#ifndef TagRetrievalPos_h
+#define TagRetrievalPos_h
+
+#include <iostream>
+#include <string>
+#include <list>
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TagRetrievalPos
+//
+class TagRetrievalPos {
+ private:
+ std::streamoff _begin;
+ std::streamoff _end;
+
+ // position stream and calculate expected characters
+ int positionStream (std::istream & stream_fr) const;
+
+ static const unsigned bufferLen_i;
+ static char buffer_ac[];
+
+ public:
+ static const std::streamoff nopos;
+ TagRetrievalPos () : _begin(nopos), _end (nopos) {}
+ TagRetrievalPos (std::streamoff begin, std::streamoff end) : _begin(begin), _end (end) {}
+ ~TagRetrievalPos() {}
+
+ /**
+ * test if empty
+ */
+ bool empty () const { return _end == nopos; }
+
+ /**
+ * access functions
+ */
+ const std::streamoff begin() const { return _begin; }
+ const std::streamoff end() const { return _end; }
+
+ /**
+ * set position
+ */
+ void set (std::streamoff begin, std::streamoff end) {
+ if ( begin < end ) {
+ _begin = begin;
+ _end = end;
+ }
+ }
+
+ /**
+ * retrieve single-line data
+ */
+ bool retrieveData (std::istream& input, std::string& data_r) const;
+
+ /**
+ * retrieve multi-line data
+ */
+ bool retrieveData (std::istream& input, std::list<std::string>& data_r) const;
+};
+
+#endif // TagRetrievalPos_h
--- /dev/null
+ /*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TaggedFile.cc
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+/-*/
+#include <ctype.h> // for toupper
+
+#include <zypp/parser/taggedfile/TaggedFile.h>
+#include <zypp/parser/taggedfile/TagRetrievalPos.h>
+#include <zypp/base/Logger.h>
+#include <iostream>
+
+using namespace zypp;
+
+namespace TaggedFile
+{
+
+///////////////////////////////////////////////////////////////////////
+// Tag
+//-------------------------------------------------------------------
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : Tag::Tag ()
+** FUNCTION TYPE : constructor
+**
+** DESCRIPTION set _name, _datatype, and _tagtype
+** it datatype == MULTIOLD, also send end
+*/
+
+Tag::Tag (const std::string& name, datatype dtype, tagtype ttype)
+ : _name(name)
+ , _datatype(dtype)
+ , _tagtype(ttype)
+{
+ if (_datatype == MULTIOLD || _datatype == MULTIYOU)
+ {
+ unsigned int namepos = _name.size();
+ if (namepos == 0)
+ return;
+ _end.reserve (namepos);
+ _end += toupper (_name[--namepos]);
+ for (;;)
+ {
+ namepos--;
+
+ if (namepos == 0)
+ {
+ _end += tolower (_name[namepos]);
+ break;
+ }
+ _end += _name[namepos];
+ }
+ while (namepos > 0);
+ }
+}
+
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : Tag::assign ()
+** FUNCTION TYPE : assignstatus
+**
+** DESCRIPTION assign a value/position to _this_ Tag
+//
+// in order to find _this_, the initial lookupTag must have already
+// taken place. So for single-line tags, we just have to check
+// the locale and assing start and end positions.
+//
+// For multi-line tags. this functions searches the matching end tag
+// and assigns start and end positions to the proper locale slot.
+*/
+
+assignstatus
+Tag::assign (const std::string& locale, TaggedParser& parser, std::istream& istr)
+{
+//std::cerr << "Tag::assign(" << _name << "." << locale << ")@" << parser.lineNumber() << std::endl;
+
+ if (locale.empty())
+ {
+ if (_tagtype == FORCELOCALE)
+ return REJECTED_NOLOCALE;
+ }
+ else // locale not empty
+ {
+ if (_tagtype == REJECTLOCALE)
+ return REJECTED_LOCALE;
+ }
+
+ // this tag _again_ ?
+
+ posmaptype::iterator it = _pos.find (locale);
+
+ if (it != _pos.end()) // we already had this one
+ {
+ if (_tagtype == START)
+ return ACCEPTED_FULL; // ok for start
+ else
+ return REJECTED_FULL; // not ok for others
+ }
+
+ switch (_datatype)
+ {
+ case SINGLE: // retrieve data
+ _data = parser.data();
+ break;
+ case SINGLEPOS: // skip data
+ break;
+ case MULTI: // for multi-line data, look for the matching end tag
+ if (parser.lookupEndTag (istr, _name, locale) != TaggedParser::END)
+ {
+ ERR << "Endtag not found" << std::endl;
+ return REJECTED_NOENDTAG;
+ }
+ break;
+ case MULTIOLD:
+ if (parser.lookupEndTag (istr, _end, locale) != TaggedParser::OLDMULTI)
+ {
+ ERR << "Endtag not found" << std::endl;
+ return REJECTED_NOENDTAG;
+ }
+ break;
+ case MULTIYOU:
+ if (parser.lookupEndTag (istr, _end, locale, true) != TaggedParser::OLDMULTI)
+ {
+ ERR << "Endtag not found" << std::endl;
+ return REJECTED_NOENDTAG;
+ }
+ break;
+ }
+ // remember positions
+ _pos[locale] = TagRetrievalPos (parser.dataStartPos (), parser.dataEndPos ());
+
+ return ACCEPTED;
+}
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : Pos
+** FUNCTION TYPE : TagRetrievalPos
+**
+** DESCRIPTION : return position matching locale
+** or TagRetrievalPos(nopos,nopos) if locale not defined
+*/
+const TagRetrievalPos
+Tag::Pos (const std::string& locale) const
+{
+ posmaptype::const_iterator it = _pos.find (locale);
+ if (it == _pos.end())
+ return TagRetrievalPos();
+ return it->second;
+}
+
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : operator<<
+** FUNCTION TYPE : ostream &
+**
+** DESCRIPTION : print Tag to stream
+*/
+std::ostream & operator<<( std::ostream & str, const TaggedFile::Tag & obj )
+{
+ str << "Tag: '" << obj._name << "' ";
+ switch (obj._tagtype) {
+ case TaggedFile::REJECTLOCALE: str << "REJECTLOCALE"; break;
+ case TaggedFile::START: str << "START"; break;
+ case TaggedFile::ALLOWLOCALE: str << "ALLOWLOCALE"; break;
+ case TaggedFile::FORCELOCALE: str << "FORCELOCALE"; break;
+ }
+ str << ", ";
+ switch (obj._datatype) {
+ case TaggedFile::SINGLE: str << "SINGLE"; break;
+ case TaggedFile::SINGLEPOS: str << "SINGLEPOS"; break;
+ case TaggedFile::MULTI: str << "MULTI"; break;
+ case TaggedFile::MULTIOLD: str << "MULTIOLD"; break;
+ case TaggedFile::MULTIYOU: str << "MULTIYOU"; break;
+ }
+ str << std::endl;
+ return str;
+}
+
+///////////////////////////////////////////////////////////////////////
+// TagSet
+//-------------------------------------------------------------------
+
+TagSet::TagSet()
+ : _allow_multiple_sets (false)
+ , _allow_unknown_tags (true)
+ , _reuse_previous_tag (false)
+{
+}
+
+TagSet::~TagSet()
+{
+ // delete tags from map, allocated in addTag()
+ tagmaptype::iterator it;
+ for (it = _tags.begin(); it != _tags.end(); ++it)
+ {
+ delete it->second;
+ }
+}
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : TagSet::assign ()
+** FUNCTION TYPE : assignstatus
+**
+** DESCRIPTION assign a single value/position to a single Tag
+*/
+assignstatus
+TagSet::assign (const std::string& starttag, const std::string& startlocale, TaggedParser& parser, std::istream& istr)
+{
+ // find given Tag in map
+
+ tagmaptype::iterator t = _tags.find (starttag);
+
+ if (t == _tags.end())
+ {
+ if (_allow_unknown_tags)
+ return ACCEPTED;
+ return REJECTED_NOMATCH;
+ }
+
+//std::cerr << "TagSet::assign(" << starttag << "." << startlocale << ")@" << parser.lineNumber() << std::endl;
+ // assign to found tag
+ return t->second->assign (startlocale, parser, istr);
+}
+
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : TagSet::assignSet ()
+** FUNCTION TYPE : assignstatus
+**
+** DESCRIPTION assign a complete TagSet from a stream
+*/
+assignstatus
+TagSet::assignSet (TaggedParser& parser, std::istream& istr)
+{
+//std::cerr << "TagSet::assignSet(-------------------)@" << parser.lineNumber() << std::endl;
+
+ // reset tag set
+
+ tagmaptype::iterator it;
+ for (it = _tags.begin(); it != _tags.end(); ++it)
+ {
+ it->second->clear();
+ }
+
+ int count = -1;
+
+ // fill tag set
+
+ assignstatus ret = ACCEPTED;
+ do
+ {
+ // only call parser if it isn't already set from a previous
+ // ACCEPTED_FULL
+
+ if (!_reuse_previous_tag)
+ {
+ TaggedParser::TagType tagtype = parser.lookupTag (istr);
+
+ if (tagtype == TaggedParser::NONE) // no tag found
+ {
+ if (istr.eof ())
+ {
+ if (count > 0)
+ ret = ACCEPTED_FULL;
+ else
+ ret = REJECTED_EOF;
+ }
+ else if (_allow_unknown_tags)
+ {
+ continue;
+ }
+ else
+ {
+ ret = REJECTED_NOMATCH;
+ }
+ break;
+ }
+ else
+ ret = ACCEPTED;
+ }
+ else
+ {
+ _reuse_previous_tag = false;
+ }
+
+ if (ret == ACCEPTED)
+ {
+ ret = assign (parser.currentTag(), parser.currentLocale(), parser, istr);
+ ++count;
+ }
+ }
+ while (ret == ACCEPTED);
+
+ if ((ret == ACCEPTED_FULL)
+ && _allow_multiple_sets)
+ {
+ // re use last scanned tag on next entry
+ _reuse_previous_tag = true;
+ }
+ return ret;
+}
+
+
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : operator<<
+** FUNCTION TYPE : ostream &
+**
+** DESCRIPTION : print every contained tag
+*/
+std::ostream & operator<<( std::ostream & str, const TagSet & obj )
+{
+ str << "TagSet {" << std::endl;
+ TaggedFile::TagSet::tagmaptype::const_iterator it;
+ for (it = obj._tags.begin(); it != obj._tags.end(); ++it)
+ {
+ str << *(it->second);
+ }
+ str << "}" << std::endl;
+ return str;
+}
+
+
+}
+
+
+// vim:sw=4
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) 2002 SuSE AG |
+\----------------------------------------------------------------------/
+
+ File: TaggedFile.h
+ Purpose: Declare Tag and TagSet as interface to the TaggedParser
+ Author: Ludwig Nussel <lnussel@suse.de>
+ Maintainer: Klaus Kaempf <kkaempf@suse.de>
+
+/-*/
+
+#ifndef TaggedFile_h
+#define TaggedFile_h
+#include <iostream>
+#include <string>
+#include <map>
+#include <list>
+#include <zypp/parser/taggedfile/TaggedParser.h>
+#include <zypp/parser/taggedfile/TagRetrievalPos.h>
+
+namespace TaggedFile
+{
+
+ /**
+ * START = explicit start tag, return ACCEPTED_FULL when
+ * this tag occurs a second time
+ * N.B.: in the current implementation, a start tag
+ * can't have a locale (START implies REJECTLOCALE)
+ * <br>
+ * ALLOWLOCALE = accept locale for this tag
+ * <br>
+ * FORCELOCALE = force locale for this tag
+ * <br>
+ * REJECTLOCALE = reject locale (default !)
+ */
+ enum tagtype {
+ REJECTLOCALE, START, ALLOWLOCALE, FORCELOCALE
+ };
+
+ /**
+ * data type allowed for this tag
+ * SINGLE = single line of data, retrieve data<br>
+ * SINGLEPOS = single line of data, just retrieve positions<br>
+ * MULTI = multiple lines of data<br>
+ * MULTIOLD = multiple lines of data<br>
+ * end tag is start tag reversed
+ */
+ enum datatype {
+ SINGLE, SINGLEPOS, MULTI, MULTIOLD, MULTIYOU
+ };
+
+ /**
+ * final assign status
+ * ACCEPTED = single tag accepted
+ * ACCEPTED_FULL = new start tag found
+ * <br>
+ * REJECTED_EOF = at end of file
+ * <br>
+ * REJECTED_NOMATCH = no matching tag found
+ * <br>
+ * REJECTED_LOCALE = matching tag found but locale not allowed
+ * <br>
+ * REJECTED_NOLOCALE = matching tag found but locale required
+ * <br>
+ * REJECTED_FULL = repeating non-start tag found
+ * <br>
+ * REJECTED_NOENDTAG = missing end tag
+ * <br>
+ */
+ enum assignstatus {
+ ACCEPTED, // 0
+ ACCEPTED_FULL, // 1
+ REJECTED_EOF, // 2
+ REJECTED_NOMATCH, // 3
+ REJECTED_LOCALE, // 4
+ REJECTED_NOLOCALE, // 5
+ REJECTED_FULL, // 6
+ REJECTED_NOENDTAG // 7
+ };
+
+ static const streamoff nopos = streamoff(-1);
+
+/**
+* A Tag has a starttag, probably and endtag as well as data and the start and end positions in the stream
+*/
+
+class Tag
+{
+ public:
+ typedef std::map<std::string, TagRetrievalPos> posmaptype;
+
+ private:
+ /** name of the tag */
+ std::string _name;
+
+ /** name of the end tag for datatype MULTIOLD */
+ std::string _end;
+
+ /**
+ * start and end position of data in stream
+ * indexed by locale
+ */
+ posmaptype _pos;
+
+ /**
+ * the actual data for a SINGLE, REJECTLOCALE datatype.
+ * for all other datatypes, only _pos is retrieved
+ */
+ std::string _data;
+
+ /**
+ * the type of data for this tag
+ */
+ datatype _datatype;
+
+ /**
+ * the type of tag
+ */
+ tagtype _tagtype;
+
+ public:
+ /** Constructor
+ * @param name Name of Tag
+ * @param type how to handle multiple assignments of the same tag
+ * */
+ Tag (const std::string& name, datatype dtype, tagtype ttype = REJECTLOCALE);
+
+ /**
+ * override old-style end tag
+ * (needed e.g. for update.inf parsing which reversed
+ * DefaultInstsrcFTP to PTFCrstsniTluafed
+ * which can _not_ be handle automagically :-}
+ */
+ void setEndTag (std::string end) { _end = end; }
+
+ /**
+ * assign data from stream to tag
+ *
+ * @param parser = TaggedParser to use
+ * @param locale = locale found at tag
+ * @param istr = stream to use
+ * @returns assignstatus
+ *
+ * if REJECTED_NOENDTAG is returned, stream and parser are in an
+ * undefined state
+ */
+ assignstatus assign (const std::string& locale, TaggedParser& parser, std::istream& istr);
+
+ /** clears only data, not behavior nor tag names
+ * */
+ void clear()
+ {
+ _pos.clear();
+ _data.erase();
+ }
+
+ /**
+ * Name()
+ * return name of this tag
+ */
+ const std::string& Name() const
+ {
+ return _name;
+ }
+
+ /**
+ * return single line data of current tag
+ */
+ const std::string& Data() const
+ {
+ return _data;
+ }
+
+ /**
+ * return start position of data in stream
+ */
+ const TagRetrievalPos Pos (const std::string& locale = "") const;
+
+ /**
+ * return complete positionmap
+ */
+ const posmaptype PosMap () const { return _pos; }
+
+ /**
+ * return start position of data in stream
+ */
+ std::streamoff posDataStart (const std::string& locale = "") const { return Pos(locale).begin(); }
+
+ /**
+ * return end position of data in stream
+ */
+ std::streamoff posDataEnd (const std::string& locale = "") const { return Pos(locale).end(); }
+
+ friend std::ostream & operator<<( std::ostream & str, const TaggedFile::Tag & obj );
+};
+
+/** TagSet manages all Tags contained in a file. It redirects
+ * assignments to the proper Tag
+ * */
+class TagSet
+{
+ private:
+ /** file contains multiple sets or single set */
+ bool _allow_multiple_sets;
+
+ /** allow unknown tags */
+ bool _allow_unknown_tags;
+
+ /** language dependant tags, needed for setting the encoding */
+ typedef std::map<std::string, Tag *> tagmaptype;
+
+ /** map of tags managed by this tagset */
+ tagmaptype _tags;
+
+ /**
+ * index <-> string mapping for access-by-index
+ * since this is faster and easier when handling the
+ * complete tagset
+ */
+ typedef std::vector<Tag*> tagvectortype;
+ tagvectortype _tagv;
+
+ /** assign number to Tag
+ *
+ * @param idx number
+ * @param t Tag*
+ * */
+ void setTagByIndex (int idx, Tag* t)
+ {
+ if (idx < 0)
+ return;
+ if (_tagv.size() <= (unsigned int)idx)
+ {
+ _tagv.resize ((unsigned int)idx+1);
+ }
+ _tagv[(unsigned int)idx] = t;
+ }
+
+ /**
+ * re-use previous tag
+ * (used in assignSet() to re-use last parser state from
+ * previous ACCEPTED_FULL)
+ */
+ bool _reuse_previous_tag;
+
+ /**
+ * lookup single Tag responsible for parsing starttag in map and
+ * call its assign function
+ *
+ * @param starttag Tag to assign
+ * @param istr stream to parse
+ * */
+ assignstatus assign (const std::string& starttag, const std::string& startlocale, TaggedParser& parser, std::istream& istr);
+
+ public:
+ TagSet();
+ virtual ~TagSet();
+
+ /**
+ * allow multiple sets
+ */
+ void setAllowMultipleSets (bool flag) { _allow_multiple_sets = flag; }
+
+ /**
+ * allow unknown tags
+ */
+ void setAllowUnknownTags (bool flag) { _allow_unknown_tags = flag; }
+
+ /** add Tag to TagSet
+ *
+ * @param name name of tag
+ * @param idx index for getTagByIndex, -1 for n/a
+ * @param dtype datatype for tag
+ * @param ttype tagtype for tag
+ * */
+ void addTag (const std::string& name, int idx, datatype dtype, tagtype ttype = REJECTLOCALE)
+ {
+ Tag *tag = new Tag (name, dtype, ttype);
+ _tags[name] = tag;
+ setTagByIndex (idx, tag);
+ }
+
+ /**
+ * assign complete TagSet from parser and stream
+ *
+ * @param parser parser to use
+ * @param istr stream to parse
+ */
+ assignstatus assignSet (TaggedParser& parser, std::istream& istr);
+
+ /** get Tag by number instead of string
+ *
+ * @param idx Tag number
+ * @return pointer to tag or NULL if idx doesn't exist
+ * */
+ Tag* getTagByIndex (unsigned int idx)
+ {
+ if (idx < _tagv.size ())
+ return _tagv[idx];
+ else
+ return NULL;
+ }
+
+ friend std::ostream & operator<<( std::ostream & str, const TaggedFile::TagSet & obj );
+};
+
+} // namespace TaggedFile
+
+#endif // TaggedFile_h
+
+// vim:sw=4
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ V / _` \___ \ | | __) | |
+| | | (_| |___) || | / __/ |
+| |_|\__,_|____/ |_| |_____| |
+| |
+| core system |
+| (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+ File: TaggedParser.cc
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Michael Andres <ma@suse.de>
+
+ Purpose: parse file in tagged format
+ ('<tag>: <data>\n')
+ Parser for tagged file format as used in SuSE/UnitedLinux
+ media data
+/-*/
+
+#include <iostream>
+#include <ctype.h>
+#include <string.h> // for strcasecmp
+#include <zypp/base/Logger.h>
+#include <zypp/parser/taggedfile/TaggedParser.h>
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TaggedParser
+//
+///////////////////////////////////////////////////////////////////
+
+const unsigned TaggedParser::bufferLen_i = 1024;
+char TaggedParser::buffer_ac[bufferLen_i];
+const streamoff TaggedParser::nopos = streamoff(-1);
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::_datareset
+// METHOD TYPE : void
+//
+// DESCRIPTION : reset position pointers to 'nopos'
+// erase all buffers
+//
+inline void TaggedParser::_datareset()
+{
+ _startPos = _endPos = nopos;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::_reset
+// METHOD TYPE : void
+//
+// DESCRIPTION :
+//
+inline void TaggedParser::_reset()
+{
+ _tagPos = nopos;
+ _currentTag.erase();
+ _currentLocale.erase();
+ _datareset();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::TaggedParser
+// METHOD TYPE : Constructor
+//
+// DESCRIPTION :
+//
+TaggedParser::TaggedParser()
+ : _lineNumber (0)
+ , _oldstyle (false)
+ , _offset (1)
+{
+ _reset();
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::~TaggedParser
+// METHOD TYPE : Destructor
+//
+// DESCRIPTION :
+//
+TaggedParser::~TaggedParser()
+{
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::readLine
+// METHOD TYPE : streamoff
+//
+// DESCRIPTION : read a line from an istream to a string
+// return streamoff of start of line
+//
+inline streamoff TaggedParser::readLine( istream & stream_fr, string & cline_tr )
+{
+ streamoff lineBegin_ii = streamoff( stream_fr.tellg() );
+ cline_tr.erase();
+
+ do
+ {
+ stream_fr.clear();
+ stream_fr.getline (buffer_ac, bufferLen_i); // always writes '\0' terminated
+ cline_tr += buffer_ac;
+ } while( stream_fr.rdstate() == ios::failbit );
+
+ return lineBegin_ii;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::tagOnLine
+// METHOD TYPE : TagType
+//
+// DESCRIPTION : check if a tag exists on the line
+// return != TagType::NONE if tag exists
+// O: string tag_tr tag found
+// O: size_type delim_ir position following tag
+// O: string lang_tr language code found
+//
+TaggedParser::TagType
+TaggedParser::tagOnLine (const string & cline_tr, string & tag_tr, string::size_type & delim_ir, string & lang_tr)
+{
+ TagType type = NONE;
+
+ // empty or comment line ?
+
+ if (cline_tr.size() != 0)
+ {
+ switch (cline_tr[0])
+ {
+ case '#':
+ case '\0':
+ case '\n':
+ break;
+ case '=':
+ type = SINGLE; break;
+ case '+':
+ type = START; break;
+ case '-':
+ type = END; break;
+ default:
+ if (_oldstyle
+ && isupper (cline_tr[0])) // check oldstyle
+ {
+ string::size_type colonpos = cline_tr.find (":"); // ":" + blank
+ if (colonpos != string::npos)
+ {
+ colonpos++;
+ if (cline_tr[colonpos] == ' ' || cline_tr[colonpos] == '\t')
+ type = OLDSINGLE;
+ else
+ type = OLDMULTI;
+ }
+ }
+ break;
+ }
+ }
+
+ if (type == NONE)
+ {
+ return type;
+ }
+
+ // find first separator
+
+ delim_ir = cline_tr.find_first_of (":. \t", _offset);
+
+ int taglen = delim_ir - _offset;
+
+ // no tag or empty tag or whitespace in tag ?
+
+ if (delim_ir == string::npos
+ || delim_ir < 2)
+ {
+ type = NONE; // no delimiter found
+ }
+ else if (cline_tr[delim_ir] == '.' ) // language found ?!
+ {
+ string::size_type langpos = delim_ir+1;
+ delim_ir = cline_tr.find_first_of (":", langpos);
+ if ((delim_ir == string::npos) // nope, ":" missing
+ || (delim_ir < langpos+1)) // language empty
+ {
+ type = NONE;
+ }
+ else
+ {
+ lang_tr = cline_tr.substr (langpos, delim_ir-langpos);
+ }
+ }
+ else
+ {
+ lang_tr.clear();
+ }
+
+ if (type == NONE)
+ {
+ return type;
+ }
+
+ tag_tr = cline_tr.substr (_offset, taglen);
+
+ return type;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::lookupTag
+// METHOD TYPE : TaggedParser::TagType
+//
+// DESCRIPTION : read from istream until known tag is found
+// return type of tag found
+// if stag_tr!="" slang_tr!="", the tag must match
+// the given values (used to find a matching end tag)
+//
+TaggedParser::TagType
+TaggedParser::lookupTag( istream & stream_fr, const string & stag_tr, const string & slang_tr)
+{
+ _reset();
+ if ( stream_fr.good() )
+ {
+ streamoff lineBegin_ii = nopos;
+ string::size_type delim_ii = string::npos;
+ string maybe_ti; // tag candidate
+ string lang_ti; // language
+ TagType type;
+
+ do
+ {
+ lineBegin_ii = readLine (stream_fr, currentLine);
+ _lineNumber++;
+
+ // find next tag
+ // return tag type
+ // set maybe_ti == tagname, lang_ti == taglang
+ // delim_ii = data position
+ type = tagOnLine (currentLine, maybe_ti, delim_ii, lang_ti);
+
+ if (type == NONE )
+ continue; // no tag on cline
+
+ if (!stag_tr.empty()
+ && (strcasecmp (maybe_ti.c_str(), stag_tr.c_str()) != 0) )
+ {
+ continue; // tag does not match given stag_tr
+ }
+
+ if (!slang_tr.empty()
+ && (strcasecmp (lang_ti.c_str(), slang_tr.c_str()) != 0) )
+ {
+ continue; // tag does not match given slang_tr
+ }
+
+ // here we've got a valid tag
+ _tagPos = lineBegin_ii;
+ _currentTag = maybe_ti;
+ _currentLocale = lang_ti;
+
+ // look for data on this line
+ delim_ii = currentLine.find_first_not_of( " \t", delim_ii+1 );
+
+ if ( delim_ii == string::npos )
+ {
+ // no data on this line
+
+ _startPos = _endPos = _tagPos + currentLine.size();
+ _bufferPos = 0;
+ _bufferLen = 0;
+ }
+ else
+ {
+ // delim_ii == first non-blank after tag ':'
+
+ _bufferPos = delim_ii;
+ _startPos = _tagPos + delim_ii;
+
+ _bufferLen = currentLine.find_last_not_of (" \t") + 1 - delim_ii;
+ if (_bufferLen == string::npos)
+ _bufferLen = 0;
+ _endPos = _startPos + _bufferLen;
+ }
+
+ return type;
+
+ } while( stream_fr.good() );
+ }
+
+ return NONE;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::lookupEndTag
+// METHOD TYPE : TaggedParser::TagType
+//
+// DESCRIPTION : skip all data from istream until endtag
+//
+TaggedParser::TagType
+TaggedParser::lookupEndTag (istream & stream_fr, const string & etag_tr,
+ const string & elang_tr, bool reverseLocale)
+{
+ _datareset();
+ if ( stream_fr.good() )
+ {
+ _startPos = streamoff( stream_fr.tellg() );
+
+ streamoff lineBegin_ii = nopos;
+ string::size_type delim_ii = string::npos;
+ string maybe_ti;
+ string lang_ti;
+ TagType type;
+
+ string revertedLocale;
+ if ( reverseLocale ) {
+ unsigned int namepos = elang_tr.size();
+ if (namepos != 0) {
+ revertedLocale.reserve (namepos);
+ revertedLocale += toupper (elang_tr[--namepos]);
+ for (;;)
+ {
+ namepos--;
+
+ if (namepos == 0)
+ {
+ revertedLocale += tolower (elang_tr[namepos]);
+ break;
+ }
+ revertedLocale += elang_tr[namepos];
+ }
+ while (namepos > 0);
+ }
+ }
+
+ do {
+ // read line
+ lineBegin_ii = readLine( stream_fr, currentLine );
+ _lineNumber++;
+
+ // find tag
+ if ( reverseLocale ) {
+ type = tagOnLine( currentLine, lang_ti, delim_ii, maybe_ti);
+ } else {
+ type = tagOnLine( currentLine, maybe_ti, delim_ii, lang_ti);
+ }
+
+ // check tag
+ if (_oldstyle)
+ {
+ if (type != OLDMULTI)
+ continue;
+ }
+ else if (type != END)
+ {
+ continue;
+ }
+
+ string locale = reverseLocale ? revertedLocale : elang_tr;
+
+ if ((strcasecmp (maybe_ti.c_str(), etag_tr.c_str()) == 0) // the one we're expecting
+ && ((elang_tr.size() == 0) // no lang given
+ || strcasecmp (lang_ti.c_str(), locale.c_str()) == 0 )) // correct lang found
+ {
+ _endPos = lineBegin_ii;
+
+ // end found, return
+ return type;
+ }
+
+ } while( stream_fr.good() );
+
+ // here saw no endTag
+ _datareset();
+ }
+
+ return NONE;
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::data2string
+// METHOD TYPE : string
+//
+// DESCRIPTION : concatenate list of strings to single string
+//
+string TaggedParser::data2string( const list<string> & data_Vtr )
+{
+ if ( data_Vtr.empty() )
+ return "";
+
+ string ret_ti;
+ for (list<string>::const_iterator pos = data_Vtr.begin();
+ pos != data_Vtr.end(); ++pos)
+ {
+ if (!ret_ti.empty())
+ ret_ti += '\n';
+ ret_ti += *pos;
+ }
+
+ return ret_ti;
+}
+
+///////////////////////////////////////////////////////////////////
+//
+//
+// METHOD NAME : TaggedParser::split2words
+// METHOD TYPE : vector<string>
+//
+// DESCRIPTION :
+//
+vector<string> TaggedParser::split2words( const string & line_tr, const string & sepchars_tr )
+{
+ vector<string> Ret_Vti;
+
+ string::size_type wstart_ii = 0;
+ string::size_type wend_ii = string::npos;
+ do {
+ wstart_ii = line_tr.find_first_not_of( sepchars_tr, wstart_ii );
+ if ( wstart_ii != string::npos )
+ {
+ wend_ii = line_tr.find_first_of( sepchars_tr, wstart_ii );
+ if ( wend_ii != string::npos )
+ {
+ Ret_Vti.push_back( line_tr.substr( wstart_ii, wend_ii-wstart_ii ) );
+ }
+ else
+ {
+ Ret_Vti.push_back( line_tr.substr( wstart_ii ) );
+ }
+ wstart_ii = wend_ii;
+ }
+ } while ( wstart_ii != string::npos );
+
+ return Ret_Vti;
+}
+
+/******************************************************************
+**
+**
+** FUNCTION NAME : operator<<
+** FUNCTION TYPE : ostream &
+**
+** DESCRIPTION :
+*/
+ostream & operator<<( ostream & str, const TaggedParser & obj )
+{
+ str << "TaggedParser{"
+ << obj.currentTag();
+ if (!obj.currentLocale().empty())
+ str << "." << obj.currentLocale();
+ str << " [" << obj.dataStartPos() << ":" << obj.dataEndPos() << "]";
+
+ return str << '}' << endl;
+}
--- /dev/null
+/*---------------------------------------------------------------------\
+ | |
+ | __ __ ____ _____ ____ |
+ | \ \ / /_ _/ ___|_ _|___ \ |
+ | \ V / _` \___ \ | | __) | |
+ | | | (_| |___) || | / __/ |
+ | |_|\__,_|____/ |_| |_____| |
+ | |
+ | core system |
+ | (C) SuSE GmbH |
+ \----------------------------------------------------------------------/
+
+ File: TaggedParser.h
+
+ Author: Michael Andres <ma@suse.de>
+ Maintainer: Klaus Kaempf <kkaempf@suse.de>
+
+ Parser for tagged file format as used in SuSE/UnitedLinux
+ media data
+
+ /-*/
+#ifndef TaggedParser_h
+#define TaggedParser_h
+
+#include <iosfwd>
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+
+using std::vector;
+using std::map;
+using std::streamoff;
+using std::istream;
+
+///////////////////////////////////////////////////////////////////
+//
+// CLASS NAME : TaggedParser
+//
+//
+// DESCRIPTION :
+// parses file in "tagged" format
+// a tag starts at the beginning of a line with
+// '=' (single line tag, tag_type SINGLE),
+// '+' (start of multi-line tag, tag_type START), or
+// '-' (end of multi line tag, tag_type END)
+// followed by an arbitrary string and a colon (':')
+//
+// The tag parser 'lookupTag()' searches through an open
+// stream for such a tag
+//
+// It also recognizes all other "<tag>:<blank>" lines as
+// tag_type OLDSTYLE. However, since this style requires
+// a full-line scan (opposed to a initial char check only),
+// the lookupTag() and lookupEndTag() have an extra oldstyle
+// parameter for this.
+//
+//
+class TaggedParser {
+ public:
+ enum tag_type {
+ NONE=0, // no tag
+ SINGLE, // single value
+ START, // start of multi value
+ END, // end of multi value
+ OLDSINGLE, // tag has no prefix but a value
+ OLDMULTI // tag has no prefix and no value
+ };
+ typedef tag_type TagType;
+
+ private:
+
+ static const unsigned bufferLen_i;
+ static char buffer_ac[];
+
+ std::string currentLine;
+
+ private:
+
+ streamoff _tagPos; // position of tag
+ streamoff _startPos; // start postition of data
+ streamoff _endPos; // end position of data
+
+ int _bufferPos; // position of data in buffer
+ unsigned int _bufferLen; // length of data in buffer (unsigned for string::npos comparison)
+
+ int _lineNumber;
+
+ std::string _currentTag;
+ std::string _currentLocale;
+ std::string _currentData; // substr of currentLine, set by data()
+
+ bool _oldstyle;
+
+ // set from start of line to start of tag
+ int _offset;
+
+ private:
+
+ void _reset();
+ void _datareset();
+
+ // read line from stream
+ static streamoff readLine (istream & stream_fr, std::string & cline_tr );
+
+ // check line for tag
+ TagType tagOnLine (const std::string & cline_tr, std::string & tag_tr,
+ std::string::size_type & delim_ir, std::string & lang_tr);
+
+ public:
+
+ TaggedParser();
+ virtual ~TaggedParser();
+
+ void asOldstyle (bool oldstyle) { _oldstyle = oldstyle; _offset = (oldstyle?0:1); }
+ static const streamoff nopos;
+
+ int lineNumber () const { return _lineNumber; }
+
+ streamoff tagPos() const { return _tagPos; }
+ const std::string & currentTag() const { return _currentTag; }
+ const std::string & currentLocale() const { return _currentLocale; }
+
+ public:
+
+ streamoff dataStartPos () const { return _startPos; }
+ streamoff dataEndPos () const { return _endPos; }
+ unsigned dataLength () const { return _endPos - _startPos; }
+
+ // valid after parseData()
+ const std::string& data() { return (_currentData = currentLine.substr (_bufferPos, _bufferLen)); }
+
+ public:
+
+ /**
+ * lookup a tag
+ * parse until stag_tr, leave empty to parse until any tag. On succes
+ * posStartTag() and posEndTag() can be used
+ * Usually used to lookup a single or a start tag
+ */
+ TagType lookupTag( istream & stream_fr, const std::string & stag_tr = "", const std::string & slang_tr = "");
+
+ /**
+ * lookup end tag
+ * set start and end retrieval positions
+ */
+ TagType lookupEndTag ( istream & stream_fr, const std::string & etag_tr,
+ const std::string & elang_tr = "", bool reverseLocale = false );
+
+ // helper functions
+ static std::string data2string( const std::list<std::string> & data_Vtr );
+ static vector<std::string> split2words( const std::string & line_tr, const std::string & sepchars_tr = " \t\n" );
+};
+
+#endif // TaggedParser_h
+
+// vim:sw=2