OSDN Git Service

should include sys/types.h for mode_t
[lha/olha.git] / extract.c
index 9eada87..3096561 100644 (file)
--- a/extract.c
+++ b/extract.c
 #include <sys/types.h>
 #include "ar.h"
 
-void
-extract(struct lzh_istream *rp, int to_file, struct lzh_header *h)
+static void
+copy_stream_crc(FILE *arcfile, FILE *outfile,
+                unsigned long remainder, unsigned int *crc)
 {
-    int n;
-    char buf[MAXDICSIZ];
-    FILE *outfile = NULL;
-
-    if (to_file) {
-        if (memcmp(h->method, "-lhd-", sizeof(h->method)) == 0) {
-            /* directory */
-            if (mkdir(h->filename, 0777) == -1) {
-                if (errno != EEXIST)
-                    error("cannot make directory \"%s\"", opts.outdir);
-            }
-        }
-        else {
-            /* regular file */
-            if (file_exists(h->filename)) {
-                if (!opts.force_extract) {
-                    message("'%s' has been already exist. skip", h->filename);
-                    skip(rp->fp, h);
-                    return;
-                }
-            }
-            while ((outfile = fopen(h->filename, "wb")) == NULL) {
-                fprintf(stderr, "Can't open %s\nNew filename: ", h->filename);
-                if (get_line(h->filename, sizeof(h->filename)) == 0) {
-                    fprintf(stderr, "Not extracted\n");
-                    skip(rp->fp, h);
-                    return;
-                }
-                h->namelen = strlen(h->filename);
-            }
+    char buf[BUFSIZ];
+
+    while (remainder != 0) {
+        uint n = (uint)MIN(remainder, BUFSIZ);
+
+        /* no compress */
+        if (fread(buf, 1, n, arcfile) != n)
+            error("Can't read");
+        fwrite_crc(buf, n, outfile, crc);
+        if (outfile != stdout && opts.quiet < 1) {
+            putc('.', stdout);
         }
-        if (opts.quiet < 2)
-            printf("Extracting %s ", h->filename);
-    }
-    else {
-        outfile = stdout;
-        if (opts.quiet < 2)
-            printf("===== %s =====\n", h->filename);
+        remainder -= n;
     }
+}
+
+static void
+extract(struct lzh_istream *rp, FILE *outfile, struct lzh_header *h)
+{
+    unsigned int crc;
     crc = INIT_CRC;
-    opts.method = which_method(h->method);
-    if (opts.method == NULL) {
-        fprintf(stderr, "Unknown method: %.5s\n", h->method);
-        skip(rp->fp, h);
-    }
-    else {
-        crc = INIT_CRC;
-        if (opts.method->dicbit != 0)
-            decode_start(rp);
-        while (h->origsize != 0) {
-            n = (uint) ((h->origsize > MAXDICSIZ) ? MAXDICSIZ : h->origsize);
-            if (opts.method->dicbit != 0)
-                decode(rp, n, buf);
-            else if (fread(buf, 1, n, rp->fp) != n)
-                error("Can't read");
-            fwrite_crc(buf, n, outfile);
-            if (outfile != stdout && opts.quiet < 1) {
-                putc('.', stdout);
-            }
-            h->origsize -= n;
-        }
-    }
+
+    if (opts.method->dicbit != 0)
+        decode(rp, outfile, h->origsize, &crc);
+    else
+        copy_stream_crc(rp->fp, outfile, h->origsize, &crc);
 
     if ((crc ^ INIT_CRC) != h->file_crc)
         error("CRC error");
+}
 
-    if (to_file) {
-        fprintf(stdout, "\n");
-        if (outfile) {
-            struct utimbuf ut;
+void
+extract_to_file(struct lzh_istream *rp, struct lzh_header *h)
+{
+    FILE *outfile;
+    char filename[1024];
 
-            fclose(outfile);
+    if (opts.outdir)
+        makepath(filename, sizeof(filename),
+                 opts.outdir, h->filename, NULL);
+    else
+        string_copy(filename, h->filename, sizeof(filename));
 
-            ut.actime = ut.modtime = h->mtime;
-            utime(h->filename, &ut);
+    if (memcmp(h->method, "-lhd-", sizeof(h->method)) == 0) {
+        /* directory */
+        if (opts.quiet < 2)
+            printf("Extracting %s\n", filename);
+        return;
+    }
+
+    /* create regular file */
+    if (file_exists(filename)) {
+        if (!opts.force_extract) {
+            message("'%s' has been already exist. skip", filename);
+            skip(rp->fp, h);
+            return;
         }
     }
-    outfile = NULL;
+
+    if (mkdir_parent(filename) == -1) {
+        if (errno != EEXIST)
+            error("cannot make directory \"%s\"", opts.outdir);
+    }
+
+    outfile = fopen(filename, "wb");
+    if (outfile == NULL) {
+        fprintf(stderr, "Can't open %s (skip)\n", filename);
+
+        skip(rp->fp, h);
+        return;
+    }
+    if (opts.quiet < 2)
+        printf("Extracting %s ", filename);
+
+    extract(rp, outfile, h);
+    fclose(outfile);
+
+    /* adjust file information (timestamp etc) */
+    {
+        struct utimbuf ut;
+
+        ut.actime = ut.modtime = h->mtime;
+        utime(filename, &ut);
+    }
+
+    if (opts.quiet < 2)
+        fprintf(stdout, "\n");
+}
+
+void
+extract_to_stdout(struct lzh_istream *rp, struct lzh_header *h)
+{
+    if (memcmp(h->method, "-lhd-", sizeof(h->method)) == 0) {
+        return;
+    }
+
+    if (opts.quiet < 2)
+        printf("===== %s =====\n", h->filename);
+
+    /* extract */
+    extract(rp, stdout, h);
 }