Logo Search packages:      
Sourcecode: yencode version File versions

file.c

/**************************************************************************************************
      $Header: /pub/cvsroot/yencode/src/file.c,v 1.24 2002/03/15 14:48:52 bboy Exp $

      Copyright (C) 2002  Don Moore <bboy@bboy.net>

      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at Your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "y.h"

extern char       *opt_output_dir;
extern int        opt_keep_paths;                                             /* Strip paths from filenames? */

/* Static list of extensions for yencfile_cmp().  Must be seeded. */
static char **sort_first = (char **)NULL;
static int  num_sort_first = 0;


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Comparison function for sorting files.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
ydecfile_cmp(const void *p1, const void *p2)
{
      const YDECFILE *y1 = *(YDECFILE * const *)p1;
      const YDECFILE *y2 = *(YDECFILE * const *)p2;
      register int cmp;

      if ((cmp = strcmp(y1->header->name, y2->header->name)))
            return (cmp);
      if (y1->header && y1->header->part && y2->header && y2->header->part)
            return (*y1->header->part - *y2->header->part);
      else
            return (cmp);
}
/*--- ydecfile_cmp() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Allocate the YHEADER structure.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static YHEADER *
yheader_create(void)
{
      YHEADER *new = (YHEADER *)xmalloc(sizeof(YHEADER));
      memset(new, 0, sizeof(YHEADER));
      return (new);
}
/*--- yheader_create() --------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Allocate the YPART structure.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static YPART *
ypart_create(void)
{
      YPART *new = (YPART *)xmalloc(sizeof(YPART));
      memset(new, 0, sizeof(YPART));
      return (new);
}
/*--- ypart_create() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Allocate the YFOOTER structure.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static YFOOTER *
yfooter_create(void)
{
      YFOOTER *new = (YFOOTER *)xmalloc(sizeof(YFOOTER));
      memset(new, 0, sizeof(YFOOTER));
      return (new);
}
/*--- yfooter_create() --------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YDECFILE_ADD_YHEADER
      Creates the YHEADER data (if necessary) and parses the input line to fill the header.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
ydecfile_add_yheader(YDECFILE *y, char *line, unsigned long lineno, int strict)
{
      char  *cp;

      if (y->header)
      {
            Notice("%s:%lu: %s", y->input_filename, lineno, _("duplicate `=ybegin' line ignored"));
            return;
      }
      y->header = yheader_create();

      if ((cp = strstr(line, " part=")))
      {
            y->header->part = (int *)xmalloc(sizeof(int));
            *y->header->part = (int)strtoul(cp+6, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " total=")))
      {
            y->header->total = (int *)xmalloc(sizeof(int));
            *y->header->total = (int)strtoul(cp+7, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " line=")))
      {
            y->header->line = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->header->line = (unsigned long)strtoul(cp+6, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " size=")))
      {
            y->header->size = (size_t *)xmalloc(sizeof(size_t));
            *y->header->size = (size_t)strtoul(cp+6, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " name=")))
      {
            char namebuf[PATH_MAX], *end;

            strncpy(namebuf, cp+6, sizeof(namebuf)-1);
            strtrim(namebuf);

            /* v3 says we should handle filenames in quotation marks */
            end = namebuf + strlen(namebuf) - 1;
            if ((*namebuf == '"' && *end == '"') || (*namebuf == '\'' && *end == '\''))
            {
                  *end = '\0';
                  y->header->name = xstrdup(strtrim(namebuf+1));
            }
            else
                  y->header->name = xstrdup(namebuf);
      }

      /* As of v2, decoders should be able to understand if the "begin" or "end"
            occur in the =ybegin line */
      if ((cp = strstr(line, " begin=")))
      {
            if (strict)
                  Info("%s:%lu: %s", y->input_filename, lineno, _("begin offset wrongly specified in the `=ybegin' header"));
            y->header->begin = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->header->begin = (unsigned long)strtoul(cp+7, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " end=")))
      {
            if (strict)
                  Info("%s:%lu: %s", y->input_filename, lineno, _("end offset wrongly specified in the `=ybegin' header"));
            y->header->end = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->header->end = (unsigned long)strtoul(cp+5, (char **)NULL, 10);
      }
      
      if (!y->header->name)
      {
            free(y->header);
            y->header = NULL;
            return;
      }
}
/*--- ydecfile_add_yheader() --------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YDECFILE_ADD_YPART
      Creates the YPART data (if necessary) and parses the input line to fill the part information.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
ydecfile_add_ypart(YDECFILE *y, char *line, unsigned long lineno, int strict)
{
      char *cp;

      if (y->part)
      {
            Notice("%s:%lu: %s", y->input_filename, lineno, _("duplicate `=ypart' line ignored"));
            return;
      }
      y->part = ypart_create();

      if ((cp = strstr(line, " begin=")))
      {
            y->part->begin = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->part->begin = (unsigned long)strtoul(cp+7, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " end=")))
      {
            y->part->end = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->part->end = (unsigned long)strtoul(cp+5, (char **)NULL, 10);
      }
}
/*--- ydecfile_add_ypart() ----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YDECFILE_ADD_YFOOTER
      Creates the YFOOTER data (if necessary) and parses the input line to fill the footer info.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
ydecfile_add_yfooter(YDECFILE *y, char *line, unsigned long lineno, int strict)
{
      char *cp;

      if (y->footer)
      {
            Notice("%s:%lu: %s", y->input_filename, lineno, _("duplicate `=yend' line ignored"));
            return;
      }
      y->footer = yfooter_create();

      if ((cp = strstr(line, " size=")))
      {
            y->footer->size = (size_t *)xmalloc(sizeof(size_t));
            *y->footer->size = (size_t)strtoul(cp+6, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " part=")))
      {
            y->footer->part = (int *)xmalloc(sizeof(int));
            *y->footer->part = (int)strtoul(cp+6, (char **)NULL, 10);
      }
      if ((cp = strstr(line, " crc32=")))
      {
            y->footer->crc32 = (crc32_t *)xmalloc(sizeof(crc32_t));
            *y->footer->crc32 = (crc32_t)strtoul(cp+7, (char **)NULL, 16);
      }
      if ((cp = strstr(line, " pcrc32=")))
      {
            y->footer->pcrc32 = (crc32_t *)xmalloc(sizeof(crc32_t));
            *y->footer->pcrc32 = (crc32_t)strtoul(cp+8, (char **)NULL, 16);
      }
}
/*--- ydecfile_add_yfooter() --------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YDECFILE_READ_KEYWORDS
      Loads the ybegin and ypart information from the specified YDECFILE and returns.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static void
ydecfile_read_keywords(YDECFILE *y, int strict)
{
      FILE                    *fp;
      unsigned char     buf[BUFSIZ];
      register int      got_begin = 0;
      register unsigned long  lineno = 0;

      if (!(fp = fopen(y->input_filename, "rb")))
            ErrERR("%s", y->input_filename);

      /* Find markers, calculating data length and CRC along the way */
      while (fgets(buf, sizeof(buf), fp))
      {
            lineno++;

            if (!YKEYWORD(buf))
                  continue;

            if (YKEYWORD_BEGIN(buf))
            {
                  ydecfile_add_yheader(y, buf, lineno, strict);
                  y->data_start = ftell(fp);
                  y->line_offset = lineno;
                  got_begin = 1;
            }
            else if (YKEYWORD_PART(buf))
            {
                  ydecfile_add_ypart(y, buf, lineno, strict);
                  y->data_start = ftell(fp);
                  y->line_offset = lineno;
            }
            else if (YKEYWORD_END(buf))
            {
                  ydecfile_add_yfooter(y, buf, lineno, strict);
                  fclose(fp);
                  return;
            }
            else
            {
                  /* In my test file, there was binary garbage "=y" after a newline, so don't warn.. it
                        could output garbage and trash the terminal */
#ifdef notdef
                  unsigned char *c;

                  /* Try to isolate just the unknown keyword */
                  for (c = buf; *c; c++)
                        if (isspace(*c) || iscntrl(*c))
                              *c = '\0';

                  Info("%s:%lu: `%s': %s", y->input_filename, lineno, buf, _("unknown keyword ignored"));
#endif
            }
      }
      fclose(fp);
}
/*--- ydecfile_read_keywords() ------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YDECFILE_VERIFY_KEYWORD_DATA
      Verifies the markers in the specified YDECFILE.  Returns a pointer to the YDECFILE or NULL if an
      error occurred (and processing should not be done on this file).
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static YDECFILE *
ydecfile_verify_keyword_data(YDECFILE *y, int strict)
{
      /*
      **  First, fix any data suspected of being broken but that we can extrapolate from elsewhere
      */
      /* The file is not valid if no header or footer were found */
      if (!y->header || !y->footer)
            return (NULL);

      /* Copy part begin/end data from header if it was specified there (erroneously) */
      if (y->header->begin && (!y->part || !y->part->begin))
      {
            if (!y->part)
                  y->part = ypart_create();
            y->part->begin = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->part->begin = *y->header->begin;
      }
      if (y->header->end && (!y->part || !y->part->end))
      {
            if (!y->part)
                  y->part = ypart_create();
            y->part->end = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->part->end = *y->header->end;
      }

      /* If no `end' was specified in =ypart, set it based on the size in the footer */
      if (y->part && !y->part->end && y->footer->size)
      {
            y->part->end = (unsigned long *)xmalloc(sizeof(unsigned long));
            *y->part->end = *y->part->begin + *y->footer->size - 1;
      }


      /*
      **  Warn and/or die if vital data is missing
      */
      if (!y->header->line)
      {
            Notice("%s: %s (%s)", y->input_filename, _("line length not specified"), _("file will not be processed"));
            return (NULL);
      }
      if (!y->header->name)
      {
            Notice("%s: %s (%s)", y->input_filename, _("output filename not specified"), _("file will not be processed"));
            return (NULL);
      }
      if (!y->header->size)
      {
            Notice("%s: %s (%s)", y->input_filename, _("file size not specified"), _("file will not be processed"));
            return (NULL);
      }

      return (y);
}
/*--- ydecfile_verify_keyword_data() ------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Adds the specified file to the list pointed to by ylist_head.  Errors are fatal.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
YDECFILE *
ydecfile_create(const char *filename, int strict)
{
      YDECFILE *y;                                                                              // The new file
      struct stat st;                                                                     // File stat info

      if (!filename)
            return (NULL);
      if (stat(filename, &st))                                                      // Treat file as invalid
      {
            WarnERR("%s", filename);
            return (NULL);
      }
      if (!S_ISREG(st.st_mode))
            return (NULL);

      /* Allocate structure and set default values */
      y = (YDECFILE *)xmalloc(sizeof(YDECFILE));
      memset(y, 0, sizeof(YDECFILE));
      y->input_filename = xstrdup(filename);
      y->input_st = (struct stat *)xmalloc(sizeof(struct stat));
      memcpy(y->input_st, &st, sizeof(struct stat));

      ydecfile_read_keywords(y, strict);

      return (ydecfile_verify_keyword_data(y, strict));
}
/*--- ydecfile_create() -------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Allocate the YENCPART structure.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
YENCPART *
yencpart_create(void)
{
      YENCPART *new = (YENCPART *)xmalloc(sizeof(YENCPART));
      memset(new, 0, sizeof(YENCPART));
      return (new);
}
/*--- yencpart_create() -------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YENCFILE_SEED_SORT_FIRST_EXTENSIONS
      Seeds the list of extensions which should be sorted first by yencfile_cmp().
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
yencfile_seed_sort_first_extensions(const char *seedstr)
{
      char  *ss, *c;

      ss = (seedstr) ? xstrdup(seedstr) : xstrdup(DEFAULT_SORT_FIRST_EXTENSIONS);

      while ((c = strsep(&ss, ",")))
      {
            strtrim(c);
            if (c[0] == '.')
                  c++;
            sort_first = (char **)xrealloc(sort_first, (num_sort_first + 1) * sizeof(char *));
            sort_first[num_sort_first++] = c;
      }
}
/*--- yencfile_seed_sort_first_extensions() -----------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YENCFILE_CMP
   Comparison function for sorting files.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
yencfile_cmp(const void *p1, const void *p2)
{
      const YENCFILE *y1 = *(YENCFILE * const *)p1;
      const YENCFILE *y2 = *(YENCFILE * const *)p2;

      /* See if each file has an extension that should be sorted first */
      if (num_sort_first)
      {
            char  *y1ext, *y2ext;
            int   y1first, y2first;
            register int ct;

            y1ext = strrchr(y1->input_filename, '.');
            y2ext = strrchr(y2->input_filename, '.');
            for (ct = y1first = y2first = 0; ct < num_sort_first; ct++)
            {
                  if (y1ext && !strcasecmp(y1ext+1, sort_first[ct]))
                        y1first = ct+1;
                  if (y2ext && !strcasecmp(y2ext+1, sort_first[ct]))
                        y2first = ct+1;
            }
            if (y1first && !y2first)
                  return (-1);
            if (y2first && !y1first)
                  return (1);
            if (y1first && y2first)
                  return (y1first - y2first);
      }
      return (strcmp(y1->input_filename, y2->input_filename));
}
/*--- yencfile_cmp() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      YENCFILE_CREATE
      Adds a file to the input file list.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
YENCFILE *
yencfile_create(const char *input_filename, const char *output_dir,
                               ysupportfile_t special_file_type, size_t multipart_size)
{
      YENCFILE    *y;
      struct stat st;
      char *c, base_name[PATH_MAX], prefix[PATH_MAX];

      y = (YENCFILE *)xmalloc(sizeof(YENCFILE));
      memset(y, 0, sizeof(YENCFILE));

      y->input_filename = xstrdup(input_filename);
      y->file_type = special_file_type;

      if (YSUPPORT_IS_SPECIAL(y->file_type))
            return (y);

   /* Check file, get filesize, create filename prefix */
      if (stat(y->input_filename, &st))
            ErrERR("%s", y->input_filename);
      if (!S_ISREG(st.st_mode))
      {
            Debug("%s: %s", y->input_filename, _("not a regular file (skipped)"));
            free(y);
            return (NULL);
      }
      y->filesize = st.st_size;

      /* Generate output prefix */
      if ((c = strrchr(y->input_filename, '/')))                  /* Copy basename of input file into `name' */
            strncpy(base_name, c+1, sizeof(base_name)-1);
      else
            strncpy(base_name, y->input_filename, sizeof(base_name)-1);
      if (output_dir)                                /* Generate prefix for output files */
            snprintf(prefix, sizeof(prefix), "%s/%s", output_dir, base_name);
      else
            strncpy(prefix, base_name, sizeof(prefix)-1);   
      y->output_prefix = xstrdup(prefix);

      /* Determine total number of parts if multipart */
      if (multipart_size && (y->filesize > multipart_size))
      {
            y->totalparts = y->filesize / multipart_size;
            if (y->filesize % multipart_size)
                  y->totalparts++;
      }
      else
            y->totalparts = 1;

      return (y);
}
/*--- yencfile_create() -------------------------------------------------------------------------*/

/* vi:set ts=3: */

Generated by  Doxygen 1.6.0   Back to index