/*----------------------------------------------------------------------*/
/*              LHarc Extract Command                                   */
/*                                                                      */
/*              Copyright(C) MCMLXXXIX  Yooichi.Tagawa                  */
/*                                                                      */
/*  V0.00  Original                             1988.05.23  Y.Tagawa    */
/*----------------------------------------------------------------------*/

#include "lharc.h"

extern int decode_lzhuf(), decode_larc(), decode_lh5();
extern int decode_stored_crc (), decode_stored_nocrc ();
extern int NotInterruptedCall;
extern int ForceReturn;
extern char *WildLZH;
extern char *LZHFileName;

static boolean
make_parent_path (name)
     char *name;
{
  char path[FILENAME_LENGTH];
  struct stat stbuf;
  register char *p;

  /* make parent directory name into PATH for recursive call */
  strcpy (path, name);
  for (p = path + strlen (path); p > path; p --)
    if (p[-1] == '/')
      {
        *--p = '\0';
        break;
      }

  if (p == path)
    {
      message ("Why?", "ROOT");
      return FALSE;             /* no more parent. */
    }

  if (stat (path, &stbuf) >= 0)
    {
      return TRUE;
    }
  errno = 0;

  if (mkdir (path) == 0)  /* try */
    return TRUE;                /* successful done. */
  errno = 0;

  if (!make_parent_path (path))
    return FALSE;

  if (mkdir (path) != 0)   /* try again */
    {
      message ("Cannot make directory", path);
      return FALSE;
    }

  return TRUE;
}

static int (*analyze_method (hdr))()
     LzHeader *hdr;
{
  int (*decode_proc)();

  if (bcmp (hdr->method, LZHUFF5_METHOD, METHOD_TYPE_STRAGE) == 0)
    decode_proc = decode_lh5;
  else if (bcmp (hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE) == 0)
    decode_proc = decode_lzhuf;
  else if ((bcmp (hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE) == 0) ||
           (bcmp (hdr->method, LARC4_METHOD, METHOD_TYPE_STRAGE) == 0))
    decode_proc = (hdr->has_crc) ? decode_stored_crc : decode_stored_nocrc;
  else if (bcmp (hdr->method, LARC5_METHOD, METHOD_TYPE_STRAGE) == 0)
    decode_proc = decode_larc;
  else
    decode_proc = (int (*)())0;
  return decode_proc;
}

void
extract_one (afp, hdr)
     FILE *afp;                 /* archive file */
     LzHeader *hdr;
{
  static char *name;
  static int crc;
  static int (*decode_proc)();         /* (ifp,original_size,name) */

  if( NotInterruptedCall ) {
     name = hdr->name;
     if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) {
        decode_proc = analyze_method (hdr);
        if (!decode_proc) {
           error ("Sorry, cannot extract this method, skipped.", name);
           return;
        }
        writting_filename = name;
        LZHFileName = name;
        errno = 0;
        if( !newwildcmp( WildLZH, name ) ) return;
        crc = (*decode_proc) (afp, hdr->original_size, name);
        if( ForceReturn ) return;
        errno = 0;
        if (hdr->has_crc && crc != hdr->crc) error ("CRC error", name);
     }
     else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY) {
        /* NAME has trailing SLASH '/', (^_^) */
        if (!make_parent_path (name)) return;
     }
     else { error ("Unknown information", name); }
  }
  else {
     crc = (*decode_proc) (afp, hdr->original_size, name);
     if( ForceReturn ) return;
     errno = 0;
     if (hdr->has_crc && crc != hdr->crc) error ("CRC error", name);
  }
}
