/**************************************************************************************************
$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: */
syntax highlighted by Code2HTML, v. 0.9.1