Add seek() method to archive and compressed file isostream classes
(which can only rewind to the start).

Also clean up some cruft in archive class.

This still needs testing on a .gz archive (slightly involved as there
aren't any currently!)
---
 archive.cc       | 52 --------------------------------------
 archive.h        | 14 +++--------
 archive_tar.cc   | 14 +++++++----
 compress_bz.cc   | 12 +++++++++
 compress_bz.h    |  1 +
 compress_gz.cc   | 65 +++++++++++++++++++++++++++++-------------------
 compress_gz.h    |  3 ++-
 compress_xz.cc   | 34 ++++++++++++++++++-------
 compress_xz.h    |  3 ++-
 compress_zstd.cc | 19 +++++++++++---
 compress_zstd.h  |  3 ++-
 11 files changed, 111 insertions(+), 109 deletions(-)

diff --git a/archive.cc b/archive.cc
index 1ceb355..448ea0e 100644
--- a/archive.cc
+++ b/archive.cc
@@ -45,7 +45,6 @@
  * offset 257     string  ustar\040\040\0
  */
 
-
 #define longest_magic 265
 
 archive *
@@ -65,15 +64,6 @@ archive::extract (io_stream * original)
            return rv;
          return NULL;
        }
-#if 0
-      else if (memcmp (magic, "BZh", 3) == 0)
-       {
-         archive_bz *rv = new archive_bz (original);
-         if (!rv->error ())
-           return rv;
-         return NULL;
-       }
-#endif
     }
   return NULL;
 }
@@ -194,45 +184,3 @@ out:
 }
 
 archive::~archive () {};
-
-#if 0
-ssize_t archive::read (void *buffer, size_t len)
-{
-  Log (LOG_TIMESTAMP, "archive::read called");
-  return 0;
-}
-
-ssize_t archive::write (void *buffer, size_t len)
-{
-  Log (LOG_TIMESTAMP, "archive::write called");
-  return 0;
-}
-
-ssize_t archive::peek (void *buffer, size_t len)
-{
-  Log (LOG_TIMESTAMP, "archive::peek called");
-  return 0;
-}
-
-long
-archive::tell ()
-{
-  Log (LOG_TIMESTAMP, "bz::tell called");
-  return 0;
-}
-
-int
-archive::error ()
-{
-  Log (LOG_TIMESTAMP, "archive::error called");
-  return 0;
-}
-
-const char *
-archive::next_file_name ()
-{
-  Log (LOG_TIMESTAMP, "archive::next_file_name called");
-  return NULL;
-}
-
-#endif
diff --git a/archive.h b/archive.h
index d3c795a..adab9f0 100644
--- a/archive.h
+++ b/archive.h
@@ -69,14 +69,9 @@ public:
   /* read data - not valid for archives (duh!) 
    * Could be made valid via the read-child-directly model 
    */
-//  virtual ssize_t read(void *buffer, size_t len) {return -1;};
-  /* provide data to (double duh!) */
-//  virtual ssize_t write(void *buffer, size_t len) { return -1;};
-  /* read data without removing it from the class's internal buffer */
-//  virtual ssize_t peek(void *buffer, size_t len);
-//  virtual long tell ();
-  /* try guessing this one */
-//  virtual int error ();
+
+  virtual int seek (long offset, io_stream_seek_t whence) = 0;
+
   /* Find out the next stream name -
    * ie for foo.tar.gz, at offset 0, next_file_name = foo.tar
    * for foobar that is an compress, next_file_name is the next
@@ -88,14 +83,11 @@ public:
   virtual archive_file_t next_file_type () = 0;
   virtual const std::string linktarget () = 0;
   virtual int skip_file () = 0;
-  /* if you are still needing these hints... give up now! */
   virtual ~archive() = 0;
 protected:
   void operator= (const archive &);
   archive () {};
   archive (const archive &);
-private:
-//  archive () {};
 };
 
 #endif /* SETUP_ARCHIVE_H */
diff --git a/archive_tar.cc b/archive_tar.cc
index c359238..5b2a771 100644
--- a/archive_tar.cc
+++ b/archive_tar.cc
@@ -100,11 +100,15 @@ archive_tar::tell ()
 int
 archive_tar::seek (long where, io_stream_seek_t whence)
 {
-  /* seeking in the parent archive doesn't make sense. although we could
-     map to files ? 
-     Also, seeking might make sense for rewing..?? 
-     */
-  return -1; 
+  /* Because the parent stream is compressed, we can only easily support
+     seek()-ing to rewind to the start */
+  if ((whence == IO_SEEK_SET) && (where == 0))
+    {
+      state.header_read = 0;
+      return state.parent->seek(where, whence);
+    }
+
+  return -1;
 }
 
 int
diff --git a/compress_bz.cc b/compress_bz.cc
index 18773d4..e4792d6 100644
--- a/compress_bz.cc
+++ b/compress_bz.cc
@@ -35,7 +35,12 @@ compress_bz::compress_bz (io_stream * parent) : peeklen (0), 
position (0)
     }
   original = parent;
   owns_original = true;
+  init_state();
+}
 
+void
+compress_bz::init_state(void)
+{
   initialisedOk = 0;
   endReached = 0;
   writing = 0;
@@ -194,6 +199,13 @@ compress_bz::tell ()
 int
 compress_bz::seek (long where, io_stream_seek_t whence)
 {
+  if ((whence == IO_SEEK_SET) && (where == 0))
+    {
+      int result = original->seek(where, whence);
+      init_state();
+      return result;
+    }
+
   throw new std::logic_error ("compress_bz::seek is not implemented");
 }
 
diff --git a/compress_bz.h b/compress_bz.h
index 39a0d5b..a7e865a 100644
--- a/compress_bz.h
+++ b/compress_bz.h
@@ -67,6 +67,7 @@ private:
   char buf[4096];
   int writing;
   size_t position;
+  void init_state(void);
 };
 
 #endif /* SETUP_COMPRESS_BZ_H */
diff --git a/compress_gz.cc b/compress_gz.cc
index 55a015e..e73ccd3 100644
--- a/compress_gz.cc
+++ b/compress_gz.cc
@@ -41,19 +41,23 @@ static int gz_magic[2] = { 0x1f, 0x8b };    /* gzip magic 
header */
  */
 compress_gz::compress_gz (io_stream * parent)
 {
-  construct (parent, "r");
+  original = parent;
+  owns_original = true;
+  openmode = "r";
+  construct ();
 }
 
-compress_gz::compress_gz (io_stream * parent, const char *openmode)
+compress_gz::compress_gz (io_stream * parent, const char *_openmode)
 {
-  construct (parent, openmode);
+  original = parent;
+  owns_original = true;
+  openmode = _openmode;
+  construct ();
 }
 
 void
-compress_gz::construct (io_stream * parent, const char *openmode)
+compress_gz::construct ()
 {
-  original = parent;
-  owns_original = true;
   peeklen = 0;
   int err;
   int level = Z_DEFAULT_COMPRESSION;   /* compression level */
@@ -76,7 +80,7 @@ compress_gz::construct (io_stream * parent, const char 
*openmode)
 
   mode = '\0';
 
-  if (!parent)
+  if (!original)
     {
       z_err = Z_STREAM_ERROR;
       return;
@@ -413,6 +417,14 @@ compress_gz::tell ()
 int
 compress_gz::seek (long where, io_stream_seek_t whence)
 {
+  if ((whence == IO_SEEK_SET) && (where == 0))
+    {
+      int result = original->seek(where, whence);
+      destroy();
+      construct();
+      return result;
+    }
+
   throw new std::logic_error("compress_gz::seek is not implemented");
 }
 
@@ -458,7 +470,11 @@ void
 compress_gz::destroy ()
 {
   if (msg)
-    free (msg);
+    {
+      free (msg);
+      msg = NULL;
+    }
+
   if (stream.state != NULL)
     {
       if (mode == 'w')
@@ -472,12 +488,15 @@ compress_gz::destroy ()
     }
 
   if (inbuf)
-
-    free (inbuf);
+    {
+      free (inbuf);
+      inbuf = NULL;
+    }
   if (outbuf)
-    free (outbuf);
-  if (original && owns_original)
-    delete original;
+    {
+      free (outbuf);
+      outbuf = NULL;
+    }
 }
 
 compress_gz::~compress_gz ()
@@ -485,16 +504,15 @@ compress_gz::~compress_gz ()
   if (mode == 'w')
     {
       z_err = do_flush (Z_FINISH);
-      if (z_err != Z_OK)
-       {
-         destroy ();
-         return;
-       }
-
-      putLong (crc);
-      putLong (stream.total_in);
+      if (z_err == Z_OK)
+        {
+          putLong (crc);
+          putLong (stream.total_in);
+        }
     }
   destroy ();
+  if (original && owns_original)
+    delete original;
 }
 
 int
@@ -534,11 +552,6 @@ compress_gz::do_flush (int flush)
   return z_err == Z_STREAM_END ? Z_OK : z_err;
 }
 
-
-#if 0
-
-gzclose (lst);
-#endif
 /* ===========================================================================
  *  Read a byte from a gz_stream; update next_in and avail_in. Return EOF
  *  for end of file.
diff --git a/compress_gz.h b/compress_gz.h
index 50b6e66..90073e5 100644
--- a/compress_gz.h
+++ b/compress_gz.h
@@ -60,7 +60,7 @@ private:
   };
   char peekbuf[512];
   size_t peeklen;
-  void construct (io_stream *, const char *);
+  void construct ();
   void check_header ();
   int get_byte ();
   unsigned long getLong ();
@@ -69,6 +69,7 @@ private:
   int do_flush (int);
   io_stream *original;
   bool owns_original;
+  const char *openmode;
   /* from zlib */
   z_stream stream;
   int z_err;                   /* error code for last stream operation */
diff --git a/compress_xz.cc b/compress_xz.cc
index a5167d6..bb64595 100644
--- a/compress_xz.cc
+++ b/compress_xz.cc
@@ -51,9 +51,6 @@ compress_xz::compress_xz (io_stream * parent)
   lasterr(0),
   compression_type (COMPRESSION_UNKNOWN)
 {
-  unsigned char * out_block = NULL;
-  unsigned char * in_block = NULL;
-
   /* read only */
   if (!parent || parent->error())
     {
@@ -62,6 +59,16 @@ compress_xz::compress_xz (io_stream * parent)
     }
   original = parent;
 
+  create ();
+  init_decoder ();
+}
+
+void
+compress_xz::create ()
+{
+  unsigned char * out_block = NULL;
+  unsigned char * in_block = NULL;
+
   state = (struct private_data *)calloc(sizeof(*state), 1);
   out_block = (unsigned char *)malloc(out_block_size);
   in_block = (unsigned char *)malloc(in_block_size);
@@ -79,12 +86,10 @@ compress_xz::compress_xz (io_stream * parent)
   state->out_block = out_block;
   state->in_block_size = in_block_size;
   state->in_block = in_block;
-  state->out_p = out_block;
+  state->out_p = state->out_block;
   state->stream.avail_in = 0;
   state->stream.next_out = state->out_block;
   state->stream.avail_out = state->out_block_size;
-
-  init_decoder ();
 }
 
 ssize_t
@@ -267,6 +272,17 @@ compress_xz::tell ()
 int
 compress_xz::seek (long where, io_stream_seek_t whence)
 {
+  if ((whence == IO_SEEK_SET) && (where == 0))
+    {
+      int result = original->seek(where, whence);
+      destroy ();
+      peeklen = 0;
+      lasterr = 0;
+      create ();
+      init_decoder ();
+      return result;
+    }
+
   throw new std::logic_error("compress_xz::seek is not implemented");
 }
 
@@ -334,14 +350,14 @@ compress_xz::destroy ()
 
       compression_type = COMPRESSION_UNKNOWN;
     }
-
-  if (original && owns_original)
-    delete original;
 }
 
 compress_xz::~compress_xz ()
 {
   destroy ();
+
+  if (original && owns_original)
+    delete original;
 }
 
 /* ===========================================================================
diff --git a/compress_xz.h b/compress_xz.h
index 24cbb09..31d499c 100644
--- a/compress_xz.h
+++ b/compress_xz.h
@@ -27,7 +27,7 @@ public:
   virtual ssize_t write (const void *buffer, size_t len); /* not implemented */
   virtual ssize_t peek (void *buffer, size_t len);
   virtual long tell (); /* not implemented */
-  virtual int seek (long where, io_stream_seek_t whence); /* not implemented */
+  virtual int seek (long where, io_stream_seek_t whence);
   virtual int error ();
   virtual const char *next_file_name () { return NULL; };
   virtual int set_mtime (time_t);
@@ -49,6 +49,7 @@ private:
   char peekbuf[512];
   size_t peeklen;
   int lasterr;
+  void create ();
   void destroy ();
 
   struct private_data {
diff --git a/compress_zstd.cc b/compress_zstd.cc
index 3588dbd..bb17785 100644
--- a/compress_zstd.cc
+++ b/compress_zstd.cc
@@ -35,7 +35,12 @@ compress_zstd::compress_zstd (io_stream * parent)
       return;
     }
   original = parent;
+  create();
+}
 
+void
+compress_zstd::create (void)
+{
   state = (struct private_data *)calloc(sizeof(*state), 1);
   if (state == NULL)
     {
@@ -179,6 +184,14 @@ compress_zstd::tell ()
 int
 compress_zstd::seek (long where, io_stream_seek_t whence)
 {
+  if ((whence == IO_SEEK_SET) && (where == 0))
+    {
+      int result = original->seek(where, whence);
+      destroy();
+      create();
+      return result;
+    }
+
   throw new std::logic_error("compress_zstd::seek is not implemented");
 }
 
@@ -240,14 +253,14 @@ compress_zstd::destroy ()
       free(state);
       state = NULL;
     }
-
-  if (original && owns_original)
-    delete original;
 }
 
 compress_zstd::~compress_zstd ()
 {
   destroy ();
+
+  if (original && owns_original)
+    delete original;
 }
 
 bool
diff --git a/compress_zstd.h b/compress_zstd.h
index be5712c..3303daa 100644
--- a/compress_zstd.h
+++ b/compress_zstd.h
@@ -25,7 +25,7 @@ public:
   virtual ssize_t write (const void *buffer, size_t len); /* not implemented */
   virtual ssize_t peek (void *buffer, size_t len);
   virtual long tell (); /* not implemented */
-  virtual int seek (long where, io_stream_seek_t whence); /* not implemented */
+  virtual int seek (long where, io_stream_seek_t whence);
   virtual int error ();
   virtual const char *next_file_name () { return NULL; };
   virtual int set_mtime (time_t);
@@ -42,6 +42,7 @@ private:
   io_stream *original;
   bool owns_original;
   int lasterr;
+  void create ();
   void destroy ();
 
   struct private_data {
-- 
2.32.0

Reply via email to