/*- * Copyright (c) 1999-2000 Robin Ericsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: crc-32.c,v 1.6 2000/03/25 10:36:06 lobbin Exp $ */ #include "config.h" #include #include #include #include #include #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include "gsfv.h" /* mudFTP, www.abandoned.org/drylock/ */ static void str_replace (char *buf, const char *s, const char *repl) { char out_buf[4608]; char *pc, *out; int len = strlen (s); gboolean found = FALSE; for ( pc = buf, out = out_buf; *pc && (out-out_buf) < (4608-len-4);) if ( !g_strncasecmp(pc, s, len)) { out += sprintf (out, repl); pc += len; found = TRUE; } else *out++ = *pc++; if ( found) { *out = '\0'; strcpy (buf, out_buf); } } void init_crc32 () { int i, j; unsigned long crc; for ( i = 0; i <= 255; i++ ) { crc = i; for ( j = 8; j > 0; j-- ) { if ( crc & 1 ) crc = (crc >> 1) ^ CRC32_POLYNOMIAL; else crc >>= 1; } CRC_Table[i] = crc; } } unsigned long generate_file_crc32 (FILE *fp, long size) { int count, i; unsigned long chunks, remainder; unsigned long crc; unsigned char buffer[16384]; gboolean update = FALSE; crc = 0xFFFFFFFFL; /* * reading single chars is _very_ bad for performance. Let's read * chunks of 16k at a time. For me, this gives about a six-fold * speedup over the old single-char freads. In any case, at this * point the whole thing clearly becomes IO-bound. */ chunks = ( size / 16384 ); remainder = ( size % 16384 ); for ( i = 0 ; i < chunks; i++ ) { count = 16384 * fread (buffer, 16384, 1, fp); gtk_progress_set_value (GTK_PROGRESS (progress_file), gtk_progress_get_value (GTK_PROGRESS (progress_file)) + 32); /* * 1 is totally synchronous. 2 or 3 is smooth, 25 slightly * choppy but bearable. Speed advantage of 25 over 1 is in the * OOM of several %. I'd rather have a speedy program than a * smooth scrolling progress bar, but a few percent shouldn't * matter much. A setting of 5 or so actually makes it less * choppy than 1, as unevenness in FS read performance is * smoothed out a little. So that seems to be a nice * compromise. */ if ( i % 5 == 0 ) while (gtk_events_pending()) gtk_main_iteration(); if (skip_file || aborted) return -1; crc = generate_buffer_crc32 (count, crc, buffer); } count = fread (buffer, 1, remainder, fp); gtk_progress_set_value (GTK_PROGRESS (progress_file), gtk_progress_get_value (GTK_PROGRESS (progress_file)) + 1); crc = generate_buffer_crc32 (count, crc, buffer); return (crc ^= 0xFFFFFFFFL); } unsigned long generate_buffer_crc32 (unsigned int count, unsigned long crc, void *buffer) { unsigned char *p; unsigned long temp1, temp2; p = (unsigned char *) buffer; while (count-- != 0) { temp1 = (crc >> 8) & 0x00FFFFFFL; temp2 = CRC_Table[((int) crc ^ *p++) & 0xff]; crc = temp1 ^ temp2; } return (crc); } /* parses a line, extracting fileaname and crc from that line this is used instead of a scanf because we cannot use spaces as a delimeter. So instead, go to the end of the line, then come back until the first space. which is the begining of the crc. Anything before that is part of the filename. replaces somthing like this: sscanf (line, "%s %s", filename, crc); */ void parse_line (const char *line,char *filename, char *crc) { gint i=0; gchar *line_ptr; line_ptr = g_malloc0(strlen(line) + 1); strcpy (line_ptr, line); for (i=0;line_ptr[i];i++); for (; line_ptr[i] != ' '; i--); strcpy (crc, line_ptr + i + 1 ); line_ptr [i] = '\0'; strcpy (filename, line_ptr ); g_free (line_ptr); } GList *parse_sfvfile (gchar *filename) { FILE *fp; FILE_DATA *fd = NULL; GList *files = NULL; gchar line[1024]; gboolean first = TRUE; if ( (fp = fopen (filename, "r")) == NULL) return NULL; while ( fgets (line, 1024, fp) != NULL) { gchar filename[1004]; gchar crc[20]; int i = 0; int length; size_t delim; if ( line[0] == ';' || !isalnum (line[0])) continue; /* sscanf (line, "%s %s", filename, crc); */ /* extract filename and crc from the line */ parse_line(line,filename,crc); /* what are these for, anyway? */ str_replace (filename, "\n", ""); str_replace (filename, "\r", ""); str_replace (crc, "\n", ""); str_replace (crc, "\r", ""); //g_message("Filename: %s", filename ); //g_message("CRC: %s", crc ); if (first) { register gchar *s; s = crc; while (*s) { /* make sure that the crc is composed of just 0-F (hex) */ if (!isxdigit((int) *s)) return NULL; s++; } first = FALSE; } fd = (FILE_DATA *) g_malloc0 ( sizeof (FILE_DATA) ); fd->filename = g_strdup (filename); fd->crc = g_strdup (crc); fd->exists = TRUE; fd->selected = TRUE; if ( files == NULL ) files = g_list_alloc (); files = g_list_append (files, fd); } return files; } void write_sfvfile (GList *files) { FILE *fp; GList *tmp; char date[100]; char timer[100]; struct tm *time; struct timeval tv; gettimeofday(&tv,NULL); time = localtime((time_t *) &tv.tv_sec); strftime ((char *) &date, 100, "%Y-%m-%d",time); strftime ((char *) &timer, 100, "%H:%M.%S", time); if ( (fp = fopen (gtk_entry_get_text (GTK_ENTRY (entry2)), "w")) == NULL) { popup_window ((void*)strerror(errno)); return; } fprintf (fp, "; Generated by GSFV v"VERSION" on %s at %s\n", date, timer); fprintf (fp, "; See http://www.localhost.nu/apps/gsfv/ for more info\n;\n"); if (add_comment) { FILE *fp2; gchar line[1024]; fp2 = fopen (gtk_entry_get_text (GTK_ENTRY (entry_commentfile)), "r"); if (fp2) { while ( fgets (line, 1024, fp2) != NULL) { fprintf (fp, "; %s", line); } fclose (fp2); } } if (add_fileinfos) for (tmp = files; tmp != NULL; tmp = tmp->next) { if (tmp->data != NULL) { struct tm *time; FILE_DATA *fd; fd = (FILE_DATA *) tmp->data; if (fd && fd->selected) { time = localtime (&fd->ctime); fprintf (fp,"; %12u %s%d:%s%d.%s%d %d-%s%d-%s%d %s\n", (int) fd->filesize, time->tm_hour < 10 ? "0" : "", time->tm_hour, time->tm_min < 10 ? "0" : "", time->tm_min, time->tm_sec < 10 ? "0" : "", time->tm_sec, time->tm_year + 1900, time->tm_mon < 10 ? "0" : "", time->tm_mon + 1, time->tm_mday < 10 ? "0" : "", time->tm_mday, fd->filename); } } } fprintf (fp, ";\n"); for (tmp = files; tmp != NULL; tmp = tmp->next) { if (tmp->data != NULL) { FILE_DATA *fd; fd = (FILE_DATA *) tmp->data; if (fd && fd->selected) { fprintf (fp, "%s %s\n", fd->filename, fd->crc); } } } fclose (fp); }