Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Write a program that calculates the CRC-16 value for a given file and which can

ID: 3858979 • Letter: W

Question

Write a program that calculates the CRC-16 value for a given file and which can also verify the correctness of a given file that already has a CRC-16 value appended to it, as more fully described below.

Use the CRC polynomial: x15+x13+ x6+x4+x1+1.

Program operation:

The program must compile from the command line.

The program executable file name must be “crcheck”.

The program must run from the command line and take two (2) command line parameters.

The first command line parameter will be a flag value that identifies the mode of operation: “c” for calculating a CRC value, or “v” for verifying a CRC value. Only these two values are allowed. Any other values should produce a simple error message and a graceful exit from the program.

The second command line parameter will be the name of the file to be examined. The file should be a text file that is in the same folder as the program executable. If the file is not found, the program should issue a simple error message and exit gracefully.

The program should direct all output to the command window (terminal) screen. The details of what to output are described below.

The program MUST run on Eustis. Please make sure to test your program on Eustis before submitting the assignment.

What to submit:

Submit a single source code file written in C, C++, or Java. No other languages are permitted.

The source code file must be a .c, .cpp, or .java file.

Put all classes, functions, and methods in the one file.

If programming in Java, do not place the source in your own package so our test scripts can run without changes.

If you are coding in C or C++, you must use only the standard libraries, such as stdio.h, math.h, and Standard Template Library.

If using Java, your source file must be named crcheck.java.

You must also submit a README file, which must be a text file, and which contains:

The compilation command for your program

The run command for your program

Your statement that the program is entirely your own work and that you have neither developed your code together with any another person, nor copied program code from any other person, nor permitted your code to be copied or otherwise used by any other person, nor have you copied, modified, or otherwise used program code that you have found in any external source, including but not limited to, online sources.

Input file format:

Valid input files will be ASCII files that contain printable data. There will be no pad or fill characters in a raw input file.

If an input file contains any invalid data (other than an end-of-file marker), then the program should issue an appropriate brief error message and terminate gracefully.

The raw input file will consist of ASCII data of varying length up to 512 bytes, with the last 8 bytes reserved for the checksum. (Note: The CRC or checksum will be a 16 bit integer, or 4 hexadecimal digits, which will fill the last 4 bytes/characters, the leading 4 characters should be zeroes.)

In the event the input file is not 504 characters (512 – 8) the deficiency should be padded with the “.” character – as shown in the examples below. Note that the “.” character will affect the generated CRC.

Output format:

Output the ASCII file that is read, 64 characters to a line. Alphabetic characters in this output must be represented as it was read from the input file, regardless of case.

Next, you will show the result of each 64 characters line’s cumulative XOR operation involved in the CRC calculation or verification. For example:

abcdefghijklmnopqrstuvwxyz12345-ABCDEFGHIJKLMNOPQRSTUVWXYZ12345a - 0000206c

Note that the input is shown in black and the line’s CRC is shown in red. (There is no need to use color in the output for the assignment.)

At the end, when calculating CRC, you must show the CRC result in hexadecimal. Please note that in the event the input file is less than 512 characters, you must pad the remainder of the output file with blank spaces reserving the last 8 characters for the ASCII representation of the CRC, with leading zeroes as needed to obtain a 16-bit value for the CRC-15 code.

On the other hand, if verifying CRC, you must output (a) the accumulated CRC value in hexadecimal at the end of each 64 character output of the input file including pad spaces and the stated hexadecimal CRC (Note that the CRC even though it is hexadecimal data it will be printed in ASCII.); (b) the CRC (hexadecimal) calculated by the program; and (c) a message whether the CRC check passed or failed.

Specific Functions inside code:

You must implement the following functions/methods:

A function/method to read the data in the input file into an array.

An XOR function/method that takes as input two 32 bit unsigned binary integers and returns the XOR result. (Java does not support 16 bit unsigned integers unless using Java 8, hence the 32 bit unsigned integer appropriately used, provides adequate bit space for the CRC calculations.)

A function/method for CRC calculation

A function/method for CRC verification

Grading Rubric

The total possible score for this program is 100 points. The following point values will be deducted for the reasons stated:

[ -100 points ] Your program does not successfully compile on Eustis from the command line with one of these commands:

               C program:        prompt>             gcc –lm –o crcheck [your_file_name].c

               C++ program:   prompt>             g++ -lm –o crcheck [your_file_name].cpp

               Java program:   prompt>             javac crcheck.java

               Note: If you are submitting a Java program, the class file must be named “crcheck.java” and the class name must be “crcheck” (all lower case).

Explanation / Answer

#iinclude <string.h>

#include <sys/types.h>
#include <sys/stat.h>


unsigned long CRCTable[ 256 ];

/*
* To build this program under UNIX, define UNIX either on the command
* line or by editing this file. To define it on the command line, the
* program should be built like this:
*
* cc -o crcman -DUNIX crcman.c
*
* The code in this program assumes that the UNIX compiler is of the
* K&R variety, and does away with real function prototyping.
*/

#ifdef UNIX

#include <varargs.h>
#ifdef M_XENIX
#include <sys/ndir.h>
#else
#include <sys/dirent.h>
#endif /* M_XENIX */

#define SEPARATOR "/"
#define FILENAME_SIZE 81

void FatalError();
unsigned long CalculateFileCRC();
void ProcessAllFiles();
void BuildCRCFile();
void CheckFiles();
unsigned long CalculateBufferCRC();
void BuildCRCTable();

#else /* not UNIX, must be MSDOS */
/*
* Most MS-DOS compilers have converged on the same names for the
* structures and functions used when searching directories.
* Unfortunately, Borland C implementations still use a variant,
* which requires a few macro definitions to work around. The
* functions work in an identical manner, so the actual
* implementation of the code is straightforward. The addition of
* the MSDOS definition helps convince the Zortech compiler to use
* the same structure and function names as everyone else.
*
*/

#define MSDOS 1
#include <stdarg.h>
#include <dos.h>

#define SEPARATOR "\"
#define FILENAME_SIZE FILENAME_MAX

#ifdef __TURBOC__

#include <dir.h>
#define FILE_INFO struct ffblk
#define FIND_FIRST( n, i ) findfirst( ( n ), ( i ), FA_DIREC )
#define FIND_NEXT( info ) findnext( ( info ) )
#define FILE_NAME( info ) ( ( info ).ff_name )

#else

#define FILE_INFO struct find_t
#define FIND_FIRST( n, i ) _dos_findfirst( (n), _A_SUBDIR, (i) )
#define FIND_NEXT( info ) _dos_findnext( ( info ) )
#define FILE_NAME( info ) ( ( info ).name )

#endif

void FatalError( char *fmt, ... );
unsigned long CalculateFileCRC( FILE *file );
void ProcessAllFiles( char *path, FILE *crc_file );
void BuildCRCFile( char *input_dir_name, char *crc_file_name );
void CheckFiles( char *crc_file_name );
unsigned long CalculateBufferCRC( unsigned int count, unsigned long crc,
void *buffer );
void BuildCRCTable( void );

#endif /* UNIX */

/*
* The main program is fairly simple. It checks for valid occurences
* of the two different types of command lines, and executes them if
* found. Otherwise, it prints out a simple usage statement and exits.
*/

int main( argc, argv )
int argc;
char *argv[];
{
setbuf( stdout, NULL );
BuildCRCTable();
if ( argc == 2 )
CheckFiles( argv[ 1 ] );
else if ( argc == 4 && strcmp( argv[ 1 ], "-b" ) == 0 )
BuildCRCFile( argv[ 2 ], argv[ 3 ] );
else {
printf("Usage: CRCMAN [-c|v input_dir] crc-file ");
printf(" ");
printf("Using the -c option checks all files under the input_dir ");
printf("and appends their data to the crc-file. Otherwise, the ");
printf("program checks the CRC data of all of the files in the ");
printf("crc-file and prints the results ");
return( 1 );
}
return( 0 );
}

#define CRC32_POLYNOMIAL 0xEDB88320L

void BuildCRCTable()
{
int i;
int 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;
}
CRCTable[ i ] = crc;
}
}

void CheckFiles( crc_file_name )

char *crc_file_name;
{
FILE *crc_file;
FILE *test_file;
unsigned long log_crc;
unsigned long crc;
char log_name[ FILENAME_SIZE ];
int result;

crc_file = fopen( crc_file_name,
"r" );
if ( crc_file == NULL )
FatalError( "Couldn't open the log file: %s ", crc_file_name );
for ( ; ; ) {
result = fscanf( crc_file, "%lx %s", &log_crc, log_name );
if ( result <2 )
break;
test_file = fopen( log_name,
"rb" );
if ( test_file != NULL ) {
printf( "Checking %s ", log_name );
crc = CalculateFileCRC( test_file );
fclose( test_file );
if ( crc != log_crc )
printf( "Error: Expected %08lx, got %08lx ",
log_name, log_crc, crc );
else
printf( "OK " );
} else
printf( "Could not open file %s ", log_name );
}
}

void BuildCRCFile( input_dir_name, crc_file_name )

char *input_dir_name;
char *crc_file_name;
{
char path[ FILENAME_SIZE ];
FILE *crc_file;

strcpy( path, input_dir_name );
if ( path[ strlen( path ) - 1 ] == SEPARATOR[ 0 ] )
path[ strlen( path ) - 1 ] = '';
crc_file = fopen( crc_file_name,
"w" );
if ( crc_file == NULL )
FatalError( "Can't open crc log file: %s ", crc_file_name );
ProcessAllFiles( path, crc_file );
}

/*
* This routine is responsible for actually performing the
* calculation of the 32 bit CRC for the entire file. We
* precondition the CRC value with all 1's, then invert every bit
* after the entire file has been done. This gives us a CRC value
* that corresponds with the values calculated by PKZIP and ARJ.
* The actual calculation consists of reading in blocks from the
* file, then updating the CRC with the value for that block. The
* CRC work is done by another the CalculateBufferCRC routine.
*/

unsigned long CalculateFileCRC( file )
FILE *file;
{
unsigned long crc;
int count;
unsigned char buffer[ 512 ];
int i;

crc = 0xFFFFFFFFL;
i = 0;
for ( ; ; ) {
count = fread( buffer, 1, 512, file );
if ( ( i++ % 32 ) == 0 )
putc( '.', stdout );
if ( count == 0 )
break;
crc = CalculateBufferCRC( count, crc, buffer );
}
putc( ' ', stdout );
return( crc ^= 0xFFFFFFFFL );
}

/* This routine sits in a loop for each directory, opening each file
* and processing it. Before a file is opened, a check is made to
* see if the file is actually a directory. If it turns out that
* the file is a directory, a new path name is constructed, and this
* routine calls itself recursively so that all the files in the
* subdirectory are also processed.
*/

void ProcessAllFiles( path, crc_file )
char *path;
FILE *crc_file;
{
#ifdef UNIX
DIR *dirp;
#ifdef M_XENIX
struct direct *entry;
#else
struct dirent *entry;
#endif /* M_XENIX */
#define NAME entry->d_name
#else
FILE_INFO fileinfo;
int done;
#define NAME FILE_NAME( fileinfo )
#endif
char fullname[ FILENAME_SIZE ];
struct stat buf;
unsigned long crc;
FILE *file;

printf( "Searching %s ", path );
strcat( path, SEPARATOR );
#ifdef UNIX
dirp = opendir( path );
if ( dirp == NULL )
FatalError( "Error opening directory %s ", path );
entry = readdir( dirp );
while ( entry != 0 ) {
#else
strcpy( fullname, path );
strcat( fullname, "*.*" );
done = FIND_FIRST( fullname, &fileinfo );
while ( done == 0 ) {
#endif
strcpy( fullname, path );
if ( strcmp( NAME, "." ) && strcmp( NAME, ".." ) ) {
strcat( fullname, NAME );
if ( stat( fullname, &buf ) == -1 )
FatalError("Error reading stat from file %s! ", fullname);
if ( buf.st_mode & S_IFDIR )
ProcessAllFiles( fullname, crc_file );
else {
file = fopen( fullname,
"rb" );
if ( file != NULL ) {
printf( "Scanning %s ", fullname );
crc = CalculateFileCRC( file );
putc( ' ', stdout );
fprintf( crc_file, "%08lx %s ", crc, fullname );
fclose( file );
} else
printf( "Could not open %s! ", fullname );
}
}
#ifdef UNIX
entry = readdir( dirp );
#else
done = FIND_NEXT( &fileinfo );
#endif
}
}

unsigned long CalculateBufferCRC( count, crc, buffer )

unsigned int count;
unsigned long crc;
void *buffer;
{
unsigned char *p;
unsigned long temp1;
unsigned long temp2;

p = (unsigned char*) buffer;
while ( count-- != 0 ) {
temp1 = ( crc>> 8 ) & 0x00FFFFFFL;
temp2 = CRCTable[ ( (int) crc ^ *p++ ) & 0xff ];
crc = temp1 ^ temp2;
}
return( crc );
}

#ifdef UNIX

void FatalError( va_alist )
va_dcl
{
char *fmt;
va_list argptr;

va_start( argptr );
fmt = va_arg( argptr, char * );

#else

void FatalError( char *fmt, ... )
{
va_list argptr;
va_start( argptr, fmt );

#endif

printf( "Fatal error: " );
vprintf( fmt, argptr );
va_end( argptr );
exit( -1 );
}

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote