- import the old tags parser, backup some devel files
authorDuncan Mac-Vicar P <dmacvicar@suse.de>
Mon, 12 Mar 2007 14:18:56 +0000 (14:18 +0000)
committerDuncan Mac-Vicar P <dmacvicar@suse.de>
Mon, 12 Mar 2007 14:18:56 +0000 (14:18 +0000)
19 files changed:
devel/devel.dmacvicar/CMakeLists.txt
devel/devel.dmacvicar/ScanSource.cc [new file with mode: 0644]
devel/devel.dmacvicar/TIMING.txt [new file with mode: 0644]
doc/downloaders-mediaset.txt [new file with mode: 0644]
zypp/CMakeLists.txt
zypp/parser/taggedfile/Rep.cc [new file with mode: 0644]
zypp/parser/taggedfile/Rep.h [new file with mode: 0644]
zypp/parser/taggedfile/RepDef.h [new file with mode: 0644]
zypp/parser/taggedfile/TagCacheRetrieval.cc [new file with mode: 0644]
zypp/parser/taggedfile/TagCacheRetrieval.h [new file with mode: 0644]
zypp/parser/taggedfile/TagCacheRetrievalPtr.h [new file with mode: 0644]
zypp/parser/taggedfile/TagParser.cc [new file with mode: 0644]
zypp/parser/taggedfile/TagParser.h [new file with mode: 0644]
zypp/parser/taggedfile/TagRetrievalPos.cc [new file with mode: 0644]
zypp/parser/taggedfile/TagRetrievalPos.h [new file with mode: 0644]
zypp/parser/taggedfile/TaggedFile.cc [new file with mode: 0644]
zypp/parser/taggedfile/TaggedFile.h [new file with mode: 0644]
zypp/parser/taggedfile/TaggedParser.cc [new file with mode: 0644]
zypp/parser/taggedfile/TaggedParser.h [new file with mode: 0644]

index 588bb50..8284325 100644 (file)
@@ -67,5 +67,10 @@ mediaaccess.cc
 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 )
+
+
diff --git a/devel/devel.dmacvicar/ScanSource.cc b/devel/devel.dmacvicar/ScanSource.cc
new file mode 100644 (file)
index 0000000..0a517de
--- /dev/null
@@ -0,0 +1,181 @@
+#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;
+}
+
diff --git a/devel/devel.dmacvicar/TIMING.txt b/devel/devel.dmacvicar/TIMING.txt
new file mode 100644 (file)
index 0000000..9cd4e66
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/doc/downloaders-mediaset.txt b/doc/downloaders-mediaset.txt
new file mode 100644 (file)
index 0000000..e69de29
index ae039c6..48289a9 100644 (file)
@@ -441,6 +441,32 @@ INSTALL(  FILES
   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
@@ -954,6 +980,7 @@ ${zypp_detail_SRCS}
 ${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}
@@ -986,6 +1013,7 @@ SET( zypp_lib_HEADERS
 ${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}
diff --git a/zypp/parser/taggedfile/Rep.cc b/zypp/parser/taggedfile/Rep.cc
new file mode 100644 (file)
index 0000000..d4ccbef
--- /dev/null
@@ -0,0 +1,69 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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();
+}
diff --git a/zypp/parser/taggedfile/Rep.h b/zypp/parser/taggedfile/Rep.h
new file mode 100644 (file)
index 0000000..fb97c78
--- /dev/null
@@ -0,0 +1,826 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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&lt;_Rep> constructed from ptr.
+ **/
+template<typename _Rep>
+  inline VarPtr<_Rep>
+  makeVarPtr( _Rep * ptr )
+  { return VarPtr<_Rep>( ptr ); }
+
+///////////////////////////////////////////////////////////////////
+
+#endif // Rep_h
diff --git a/zypp/parser/taggedfile/RepDef.h b/zypp/parser/taggedfile/RepDef.h
new file mode 100644 (file)
index 0000000..0757076
--- /dev/null
@@ -0,0 +1,105 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TagCacheRetrieval.cc b/zypp/parser/taggedfile/TagCacheRetrieval.cc
new file mode 100644 (file)
index 0000000..9317572
--- /dev/null
@@ -0,0 +1,145 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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;
+}
+
diff --git a/zypp/parser/taggedfile/TagCacheRetrieval.h b/zypp/parser/taggedfile/TagCacheRetrieval.h
new file mode 100644 (file)
index 0000000..67fc390
--- /dev/null
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TagCacheRetrievalPtr.h b/zypp/parser/taggedfile/TagCacheRetrievalPtr.h
new file mode 100644 (file)
index 0000000..b2f3939
--- /dev/null
@@ -0,0 +1,30 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TagParser.cc b/zypp/parser/taggedfile/TagParser.cc
new file mode 100644 (file)
index 0000000..94efb16
--- /dev/null
@@ -0,0 +1,476 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TagParser.h b/zypp/parser/taggedfile/TagParser.h
new file mode 100644 (file)
index 0000000..e1e3c84
--- /dev/null
@@ -0,0 +1,151 @@
+/*---------------------------------------------------------------------\
+ |                                                                      |
+ |                      __   __    ____ _____ ____                      |
+ |                      \ \ / /_ _/ ___|_   _|___ \                     |
+ |                       \ 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
diff --git a/zypp/parser/taggedfile/TagRetrievalPos.cc b/zypp/parser/taggedfile/TagRetrievalPos.cc
new file mode 100644 (file)
index 0000000..8d215a6
--- /dev/null
@@ -0,0 +1,150 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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;
+}
+
diff --git a/zypp/parser/taggedfile/TagRetrievalPos.h b/zypp/parser/taggedfile/TagRetrievalPos.h
new file mode 100644 (file)
index 0000000..9c4a5c0
--- /dev/null
@@ -0,0 +1,82 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TaggedFile.cc b/zypp/parser/taggedfile/TaggedFile.cc
new file mode 100644 (file)
index 0000000..2f2997c
--- /dev/null
@@ -0,0 +1,354 @@
+ /*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TaggedFile.h b/zypp/parser/taggedfile/TaggedFile.h
new file mode 100644 (file)
index 0000000..e60b0d5
--- /dev/null
@@ -0,0 +1,319 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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
diff --git a/zypp/parser/taggedfile/TaggedParser.cc b/zypp/parser/taggedfile/TaggedParser.cc
new file mode 100644 (file)
index 0000000..50de242
--- /dev/null
@@ -0,0 +1,473 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ 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;
+}
diff --git a/zypp/parser/taggedfile/TaggedParser.h b/zypp/parser/taggedfile/TaggedParser.h
new file mode 100644 (file)
index 0000000..b696984
--- /dev/null
@@ -0,0 +1,157 @@
+/*---------------------------------------------------------------------\
+ |                                                                      |
+ |                      __   __    ____ _____ ____                      |
+ |                      \ \ / /_ _/ ___|_   _|___ \                     |
+ |                       \ 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