// extract_file [c]
static bool extract_file(Unshield* unshield, const char* prefix, int index)
{
  bool success;
  char dirname[256];
  char filename[256];
  char* p;
  int directory = unshield_file_directory(unshield, index);
  long int path_max;
  char* real_output_directory;
  char* real_filename;

  #ifdef PATH_MAX
    path_max = PATH_MAX;
  #else
    path_max = pathconf(path, _PC_PATH_MAX);
    if (path_max <= 0)
      path_max = 4096;
  #endif

  real_output_directory = malloc(path_max);
  real_filename = malloc(path_max);
  if (real_output_directory == NULL || real_filename == NULL)
  {
    fprintf(stderr,"Unable to allocate memory.");
    success=false;
    goto exit;
  }

  strcpy(dirname, output_directory);
  strcat(dirname, "/");

  if (prefix && prefix[0])
  {
    strcat(dirname, prefix);
    strcat(dirname, "/");
  }

  if (!junk_paths && directory >= 0)
  {
    const char* tmp = unshield_directory_name(unshield, directory);
    if (tmp && tmp[0])
    {
      strcat(dirname, tmp);
      strcat(dirname, "/");
    }
  }

  for (p = dirname + strlen(output_directory); *p != '\0'; p++)
  {
    switch (*p)
    {
      case '\\':
        *p = '/';
        break;

      case ' ':
      case '<':
      case '>':
      case '[':
      case ']':
        *p = '_';
        break;

      default:
        if (!raw_filename)
        {  
          if (!isprint(*p))
            *p = '_';
          else if (make_lowercase)
            *p = tolower(*p);
        }
        break;;
    }
  }

#ifdef HAVE_ICONV
  if (!convert_encoding(dirname, sizeof(dirname)))
  {
    success = false;
    goto exit;
  }
#endif


#if 0
  if (dirname[strlen(dirname)-1] != '/')
    strcat(dirname, "/");
#endif

  make_sure_directory_exists(dirname);

  snprintf(filename, sizeof(filename), "%s%s", 
      dirname, unshield_file_name(unshield, index));

  for (p = filename + strlen(dirname); *p != '\0'; p++)
  {
    if (!raw_filename)
    {
      if (!isprint(*p))
        *p = '_';
      else if (make_lowercase)
        *p = tolower(*p);
    }
  }

#ifdef HAVE_ICONV
  if (!convert_encoding(filename + strlen(dirname),
      sizeof(filename) - strlen(dirname)))
  {
    success = false;
    goto exit;
  }
#endif

  /* use GNU extension to return non-existing files to real_output_directory */
  realpath(output_directory, real_output_directory);
  realpath(filename, real_filename);
  if (real_filename == NULL || strncmp(real_filename,
                                       real_output_directory,
                                       strlen(real_output_directory)) != 0)
  {
    fprintf(stderr, "\n\nExtraction failed.\n");
    fprintf(stderr, "Possible directory traversal attack for: %s\n", filename);
    fprintf(stderr, "To be placed at: %s\n\n", real_filename);
    exit_status = 1;
    success = false;
    free(real_filename);
    free(real_output_directory);
    return success;
  }

  printf("  extracting: %s\n", filename);
  switch (format)
  {
    case FORMAT_NEW:
      success = unshield_file_save(unshield, index, filename);
      break;
    case FORMAT_OLD:
      success = unshield_file_save_old(unshield, index, filename);
      break;
    case FORMAT_RAW:
      success = unshield_file_save_raw(unshield, index, filename);
      break;
  }

exit:
  if (!success)
  {
    fprintf(stderr, "Failed to extract file '%s'.%s\n", 
        unshield_file_name(unshield, index),
        (log_level < 3) ? "Run unshield again with -D 3 for more information." : "");
    unlink(filename);
    exit_status = 1;
  }
  free(real_filename);
  free(real_output_directory);
  return success;
}