[PATCH setup 04/11] Add seek() method to archive and compress file classes

Jon Turney jon.turney@dronecode.org.uk
Tue Aug 10 17:02:21 GMT 2021


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



More information about the Cygwin-apps mailing list