mirror of
https://github.com/claunia/edccchk.git
synced 2025-12-16 11:14:45 +00:00
659 lines
23 KiB
C
659 lines
23 KiB
C
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
#define TITLE "edccchk - CD image EDC/ECC Checker"
|
|
#define COPYR "Copyright (C) 2013 Natalia Portillo"
|
|
//
|
|
// 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "banner.h"
|
|
#include "common.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sector types
|
|
//
|
|
// Mode 1
|
|
// -----------------------------------------------------
|
|
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
// 0000h 00 FF FF FF FF FF FF FF FF FF FF 00 [-ADDR-] 01
|
|
// 0010h [---DATA...
|
|
// ...
|
|
// 0800h ...DATA---]
|
|
// 0810h [---EDC---] 00 00 00 00 00 00 00 00 [---ECC...
|
|
// ...
|
|
// 0920h ...ECC---]
|
|
// -----------------------------------------------------
|
|
//
|
|
// Mode 2 (XA), form 1
|
|
// -----------------------------------------------------
|
|
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
// 0000h 00 FF FF FF FF FF FF FF FF FF FF 00 [-ADDR-] 02
|
|
// 0010h [--FLAGS--] [--FLAGS--] [---DATA...
|
|
// ...
|
|
// 0810h ...DATA---] [---EDC---] [---ECC...
|
|
// ...
|
|
// 0920h ...ECC---]
|
|
// -----------------------------------------------------
|
|
//
|
|
// Mode 2 (XA), form 2
|
|
// -----------------------------------------------------
|
|
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
// 0000h 00 FF FF FF FF FF FF FF FF FF FF 00 [-ADDR-] 02
|
|
// 0010h [--FLAGS--] [--FLAGS--] [---DATA...
|
|
// ...
|
|
// 0920h ...DATA---] [---EDC---]
|
|
// -----------------------------------------------------
|
|
//
|
|
// ADDR: Sector address, encoded as minutes:seconds:frames in BCD
|
|
// FLAGS: Used in Mode 2 (XA) sectors describing the type of sector; repeated
|
|
// twice for redundancy
|
|
// DATA: Area of the sector which contains the actual data itself
|
|
// EDC: Error Detection Code
|
|
// ECC: Error Correction Code
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef DEBUG
|
|
#define DPRINTF(fmt, ...) \
|
|
do \
|
|
{ \
|
|
printf("edccchk-debug: " fmt, ##__VA_ARGS__); \
|
|
} while(0)
|
|
#else
|
|
#define DPRINTF(fmt, ...) \
|
|
do \
|
|
{ \
|
|
} while(0)
|
|
#endif
|
|
|
|
static uint32_t get32lsb(const uint8_t *src)
|
|
{
|
|
return (((uint32_t)(src[0])) << 0) | (((uint32_t)(src[1])) << 8) | (((uint32_t)(src[2])) << 16) |
|
|
(((uint32_t)(src[3])) << 24);
|
|
}
|
|
|
|
static uint32_t nondatasectors;
|
|
static uint32_t mode0sectors;
|
|
static uint32_t mode0errors;
|
|
static uint32_t mode1sectors;
|
|
static uint32_t mode1errors;
|
|
static uint32_t mode2f1sectors;
|
|
static uint32_t mode2f1errors;
|
|
static uint32_t mode2f1warnings;
|
|
static uint32_t mode2f2sectors;
|
|
static uint32_t mode2f2errors;
|
|
static uint32_t mode2f2warnings;
|
|
static uint32_t totalsectors;
|
|
static uint32_t totalerrors;
|
|
static uint32_t totalwarnings;
|
|
static uint32_t filledsectors;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LUTs used for computing ECC/EDC
|
|
//
|
|
static uint8_t ecc_f_lut[256];
|
|
static uint8_t ecc_b_lut[256];
|
|
static uint32_t edc_lut[256];
|
|
|
|
static void eccedc_init(void)
|
|
{
|
|
DPRINTF("Entering eccedc_init().\n");
|
|
size_t i;
|
|
for(i = 0; i < 256; i++)
|
|
{
|
|
uint32_t edc = i;
|
|
size_t j = (i << 1) ^ (i & 0x80 ? 0x11D : 0);
|
|
ecc_f_lut[i] = j;
|
|
ecc_b_lut[i ^ j] = i;
|
|
for(j = 0; j < 8; j++) { edc = (edc >> 1) ^ (edc & 1 ? 0xD8018001 : 0); }
|
|
edc_lut[i] = edc;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Compute EDC for a block
|
|
//
|
|
static uint32_t edc_compute(uint32_t edc, const uint8_t *src, size_t size)
|
|
{
|
|
DPRINTF("Entering edc_compute(%d, *%d, %d).\n");
|
|
for(; size; size--) { edc = (edc >> 8) ^ edc_lut[(edc ^ (*src++)) & 0xFF]; }
|
|
return edc;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Check ECC block (either P or Q)
|
|
// Returns true if the ECC data is an exact match
|
|
//
|
|
static int8_t ecc_checkpq(const uint8_t *address,
|
|
const uint8_t *data,
|
|
size_t major_count,
|
|
size_t minor_count,
|
|
size_t major_mult,
|
|
size_t minor_inc,
|
|
const uint8_t *ecc)
|
|
{
|
|
DPRINTF("Entering ecc_checkpq(*%d, *%d, %d, %d, %d, %d, *%d).\n");
|
|
size_t size = major_count * minor_count;
|
|
size_t major;
|
|
for(major = 0; major < major_count; major++)
|
|
{
|
|
size_t index = (major >> 1) * major_mult + (major & 1);
|
|
uint8_t ecc_a = 0;
|
|
uint8_t ecc_b = 0;
|
|
size_t minor;
|
|
for(minor = 0; minor < minor_count; minor++)
|
|
{
|
|
uint8_t temp;
|
|
if(index < 4) { temp = address[index]; }
|
|
else
|
|
{
|
|
temp = data[index - 4];
|
|
}
|
|
index += minor_inc;
|
|
if(index >= size) { index -= size; }
|
|
ecc_a ^= temp;
|
|
ecc_b ^= temp;
|
|
ecc_a = ecc_f_lut[ecc_a];
|
|
}
|
|
ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
|
|
|
|
if(ecc[major] != (ecc_a) || ecc[major + major_count] != (ecc_a ^ ecc_b)) { return 0; }
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// Check ECC P and Q codes for a sector
|
|
// Returns true if the ECC data is an exact match
|
|
//
|
|
static int8_t ecc_checksector(const uint8_t *address, const uint8_t *data, const uint8_t *ecc)
|
|
{
|
|
DPRINTF("Entering ecc_checksector(*%d, *%d, *%d).\n");
|
|
return ecc_checkpq(address, data, 86, 24, 2, 86, ecc) && // P
|
|
ecc_checkpq(address, data, 52, 43, 86, 88, ecc + 0xAC); // Q
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static const uint8_t zeroaddress[4] = {0, 0, 0, 0};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static off_t mycounter_analyze = (off_t)-1;
|
|
static off_t mycounter_encode = (off_t)-1;
|
|
static off_t mycounter_decode = (off_t)-1;
|
|
static off_t mycounter_total = 0;
|
|
|
|
static void resetcounter(off_t total)
|
|
{
|
|
mycounter_analyze = (off_t)-1;
|
|
mycounter_encode = (off_t)-1;
|
|
mycounter_decode = (off_t)-1;
|
|
mycounter_total = total;
|
|
}
|
|
|
|
static void encode_progress(void)
|
|
{
|
|
off_t a = (mycounter_analyze + 64) / 128;
|
|
off_t t = (mycounter_total + 64) / 128;
|
|
if(!t) { t = 1; }
|
|
fprintf(stderr, "Analyze(%02u%%)\r", (unsigned)((((off_t)100) * a) / t));
|
|
}
|
|
|
|
static void setcounter_analyze(off_t n)
|
|
{
|
|
int8_t p = ((n >> 20) != (mycounter_analyze >> 20));
|
|
mycounter_analyze = n;
|
|
if(p) { encode_progress(); }
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Returns nonzero on error
|
|
//
|
|
static int8_t ecmify(const char *infilename)
|
|
{
|
|
DPRINTF("Entering ecmify(\"%s\").\n", infilename);
|
|
int8_t returncode = 0;
|
|
int8_t filled = 0;
|
|
|
|
FILE *in = NULL;
|
|
|
|
uint8_t *queue = NULL;
|
|
size_t queue_start_ofs = 0;
|
|
size_t queue_bytes_available = 0;
|
|
|
|
uint32_t input_edc = 0;
|
|
|
|
off_t input_file_length;
|
|
off_t input_bytes_checked = 0;
|
|
off_t input_bytes_queued = 0;
|
|
|
|
size_t queue_size = ((size_t)(-1)) - 4095;
|
|
if((unsigned long)queue_size > 0x40000lu) { queue_size = (size_t)0x40000lu; }
|
|
|
|
//
|
|
// Allocate space for queue
|
|
//
|
|
DPRINTF("ecmify(): Allocation memory for queue.\n");
|
|
queue = malloc(queue_size);
|
|
if(!queue)
|
|
{
|
|
printf("Out of memory\n");
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// Open both files
|
|
//
|
|
DPRINTF("ecmify(): Opening file \"%s\".\n", infilename);
|
|
in = fopen(infilename, "rb");
|
|
if(!in) { goto error_in; }
|
|
|
|
printf("Checking %s...\n", infilename);
|
|
|
|
//
|
|
// Get the length of the input file
|
|
//
|
|
DPRINTF("ecmify(): Seeking to end of file.\n");
|
|
if(fseeko(in, 0, SEEK_END) != 0) { goto error_in; }
|
|
input_file_length = ftello(in);
|
|
DPRINTF("ecmify(): Got file length %d.\n", input_file_length);
|
|
if(input_file_length < 0) { goto error_in; }
|
|
|
|
resetcounter(input_file_length);
|
|
|
|
nondatasectors = 0;
|
|
mode0sectors = 0;
|
|
mode0errors = 0;
|
|
mode1sectors = 0;
|
|
mode1errors = 0;
|
|
mode2f1sectors = 0;
|
|
mode2f1errors = 0;
|
|
mode2f1warnings = 0;
|
|
mode2f2sectors = 0;
|
|
mode2f2errors = 0;
|
|
mode2f2warnings = 0;
|
|
totalsectors = 0;
|
|
totalerrors = 0;
|
|
filledsectors = 0;
|
|
|
|
DPRINTF("ecmify(): Entering main loop.\n");
|
|
for(;;)
|
|
{
|
|
//
|
|
// Refill queue if necessary
|
|
//
|
|
if((queue_bytes_available < 2352) &&
|
|
(((off_t)queue_bytes_available) < (input_file_length - input_bytes_queued)))
|
|
{
|
|
DPRINTF("ecmify(): Refilling queue.\n");
|
|
//
|
|
// We need to read more data
|
|
//
|
|
off_t willread = input_file_length - input_bytes_queued;
|
|
off_t maxread = queue_size - queue_bytes_available;
|
|
if(willread > maxread)
|
|
{
|
|
DPRINTF("Will read maximum.\n");
|
|
willread = maxread;
|
|
}
|
|
|
|
if(queue_start_ofs > 0)
|
|
{
|
|
memmove(queue, queue + queue_start_ofs, queue_bytes_available);
|
|
queue_start_ofs = 0;
|
|
}
|
|
if(willread)
|
|
{
|
|
setcounter_analyze(input_bytes_queued);
|
|
|
|
if(fseeko(in, input_bytes_queued, SEEK_SET) != 0) { goto error_in; }
|
|
if(fread(queue + queue_bytes_available, 1, willread, in) != (size_t)willread) { goto error_in; }
|
|
|
|
input_edc = edc_compute(input_edc, queue + queue_bytes_available, willread);
|
|
|
|
input_bytes_queued += willread;
|
|
queue_bytes_available += willread;
|
|
}
|
|
}
|
|
|
|
if(queue_bytes_available == 0)
|
|
{
|
|
DPRINTF("ecmify(): No data left in queue.\n");
|
|
//
|
|
// No data left to read -> quit
|
|
//
|
|
break;
|
|
}
|
|
|
|
uint8_t *sector = queue + queue_start_ofs;
|
|
|
|
// Data sector
|
|
if(sector[0x000] == 0x00 && // sync (12 bytes)
|
|
sector[0x001] == 0xFF && sector[0x002] == 0xFF && sector[0x003] == 0xFF && sector[0x004] == 0xFF &&
|
|
sector[0x005] == 0xFF && sector[0x006] == 0xFF && sector[0x007] == 0xFF && sector[0x008] == 0xFF &&
|
|
sector[0x009] == 0xFF && sector[0x00A] == 0xFF && sector[0x00B] == 0x00)
|
|
{
|
|
DPRINTF("ecmify(): Data sector, address %02X:%02X:%02X.\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
// Just for debug
|
|
// fprintf(stderr, "Address: %02X:%02X:%02X\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
if(sector[0x00F] == 0x00) // mode (1 byte)
|
|
{
|
|
DPRINTF("ecmify(): Mode 0 sector at address %02X:%02X:%02X.\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
mode0sectors++;
|
|
for(int i = 0x010; i < 0x930; i++)
|
|
{
|
|
if(sector[i] != 0x00)
|
|
{
|
|
mode0errors++;
|
|
totalerrors++;
|
|
fprintf(stderr,
|
|
"Mode 0 sector with error at address: %02X:%02X:%02X\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(sector[0x00F] == 0x01) // mode (1 byte)
|
|
{
|
|
DPRINTF("ecmify(): Mode 1 sector at address %02X:%02X:%02X.\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
mode1sectors++;
|
|
if(!ecc_checksector(sector + 0xC, sector + 0x10, sector + 0x81C) ||
|
|
edc_compute(0, sector, 0x810) != get32lsb(sector + 0x810) ||
|
|
sector[0x814] != 0x00 || // reserved (8 bytes)
|
|
sector[0x815] != 0x00 || sector[0x816] != 0x00 || sector[0x817] != 0x00 || sector[0x818] != 0x00 ||
|
|
sector[0x819] != 0x00 || sector[0x81A] != 0x00 || sector[0x81B] != 0x00)
|
|
{
|
|
mode1errors++;
|
|
totalerrors++;
|
|
fprintf(stderr,
|
|
"Mode 1 sector with error at address: %02X:%02X:%02X\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
if(edc_compute(0, sector, 0x810) != get32lsb(sector + 0x810))
|
|
fprintf(stderr, "%02X:%02X:%02X: Failed EDC\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
if(!ecc_checkpq(sector + 0xC, sector + 0x10, 86, 24, 2, 86, sector + 0x81C))
|
|
fprintf(stderr, "%02X:%02X:%02X: Failed ECC P\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
if(!ecc_checkpq(sector + 0xC, sector + 0x10, 52, 43, 86, 88, sector + 0x81C + 0xAC))
|
|
fprintf(stderr, "%02X:%02X:%02X: Failed ECC Q\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
}
|
|
|
|
filled = 1;
|
|
for(int i = 0x010; i < 0x810; i++)
|
|
{
|
|
if(sector[i] != 0x55)
|
|
{
|
|
filled = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(filled)
|
|
{
|
|
filledsectors++;
|
|
fprintf(stderr,
|
|
"Mode 1 sector at address: %02X:%02X:%02X is filled with 55h\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
}
|
|
}
|
|
else if(sector[0x00F] == 0x02) // mode (1 byte)
|
|
{
|
|
DPRINTF("ecmify(): Mode 2 sector at address %02X:%02X:%02X.\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
uint8_t *m2sec = sector + 0x10;
|
|
|
|
if((sector[0x012] & 0x20) == 0x20) // mode 2 form 2
|
|
{
|
|
mode2f2sectors++;
|
|
if(edc_compute(0, m2sec, 0x91C) != get32lsb(m2sec + 0x91C) && get32lsb(m2sec + 0x91C) != 0)
|
|
{
|
|
fprintf(stderr,
|
|
"Mode 2 form 2 sector with error at address: %02X:%02X:%02X\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
if(edc_compute(0, m2sec, 0x91C) != get32lsb(m2sec + 0x91C))
|
|
fprintf(
|
|
stderr, "%02X:%02X:%02X: Failed EDC\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
mode2f2errors++;
|
|
totalerrors++;
|
|
}
|
|
if(sector[0x010] != sector[0x014] || sector[0x011] != sector[0x015] ||
|
|
sector[0x012] != sector[0x016] || sector[0x013] != sector[0x017])
|
|
{
|
|
mode2f2warnings++;
|
|
totalwarnings++;
|
|
fprintf(stderr,
|
|
"Subheader copies differ in mode 2 form 2 sector at address: %02X:%02X:%02X\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
}
|
|
|
|
filled = 1;
|
|
for(int i = 0x018; i < 0x91C; i++)
|
|
{
|
|
if(sector[i] != 0x55)
|
|
{
|
|
filled = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(filled)
|
|
{
|
|
filledsectors++;
|
|
fprintf(stderr,
|
|
"Mode 2 form 2 sector at address: %02X:%02X:%02X is filled with 55h\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mode2f1sectors++;
|
|
if(!ecc_checksector(zeroaddress, m2sec, m2sec + 0x80C) ||
|
|
edc_compute(0, m2sec, 0x808) != get32lsb(m2sec + 0x808))
|
|
{
|
|
fprintf(stderr,
|
|
"Mode 2 form 1 sector with error at address: %02X:%02X:%02X\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
if(edc_compute(0, m2sec, 0x808) != get32lsb(m2sec + 0x808))
|
|
fprintf(
|
|
stderr, "%02X:%02X:%02X: Failed EDC\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
if(!ecc_checkpq(zeroaddress, m2sec, 86, 24, 2, 86, m2sec + 0x80C))
|
|
fprintf(
|
|
stderr, "%02X:%02X:%02X: Failed ECC P\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
if(!ecc_checkpq(zeroaddress, m2sec, 52, 43, 86, 88, m2sec + 0x80C))
|
|
fprintf(
|
|
stderr, "%02X:%02X:%02X: Failed ECC Q\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
|
mode2f1errors++;
|
|
totalerrors++;
|
|
}
|
|
if(sector[0x010] != sector[0x014] || sector[0x011] != sector[0x015] ||
|
|
sector[0x012] != sector[0x016] || sector[0x013] != sector[0x017])
|
|
{
|
|
mode2f1warnings++;
|
|
totalwarnings++;
|
|
fprintf(stderr,
|
|
"Subheader copies differ in mode 2 form 1 sector at address: %02X:%02X:%02X\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
}
|
|
|
|
filled = 1;
|
|
for(int i = 0x018; i < 0x818; i++)
|
|
{
|
|
if(sector[i] != 0x55)
|
|
{
|
|
filled = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(filled)
|
|
{
|
|
filledsectors++;
|
|
fprintf(stderr,
|
|
"Mode 2 form 1 sector at address: %02X:%02X:%02X is filled with 55h\n",
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
}
|
|
}
|
|
}
|
|
else // Unknown sector mode!!!
|
|
{
|
|
DPRINTF("ecmify(): Unknown data sector with mode %d at address %02X:%02X:%02X.\n",
|
|
sector[0x00F],
|
|
sector[0x00C],
|
|
sector[0x00D],
|
|
sector[0x00E]);
|
|
nondatasectors++;
|
|
}
|
|
}
|
|
else // Non data sector
|
|
{
|
|
DPRINTF("ecmify(): Non-data sector.\n");
|
|
nondatasectors++;
|
|
}
|
|
|
|
//
|
|
// Advance to the next sector
|
|
//
|
|
totalsectors++;
|
|
input_bytes_checked += 2352;
|
|
queue_start_ofs += 2352;
|
|
queue_bytes_available -= 2352;
|
|
|
|
DPRINTF("ecmify.totalsectors = %d\n", totalsectors);
|
|
DPRINTF("ecmify.input_bytes_checked = %d\n", input_bytes_checked);
|
|
DPRINTF("ecmify.queue_start_ofs = %d\n", queue_start_ofs);
|
|
DPRINTF("ecmify.queue_bytes_available = %d\n", queue_bytes_available);
|
|
}
|
|
|
|
//
|
|
// Show report
|
|
//
|
|
printf("Non-data sectors........ %d\n", nondatasectors);
|
|
printf("Mode 0 sectors.......... %d\n", mode0sectors);
|
|
printf("\twith errors..... %d\n", mode0errors);
|
|
printf("Mode 1 sectors.......... %d\n", mode1sectors);
|
|
printf("\twith errors..... %d\n", mode1errors);
|
|
printf("Mode 2 form 1 sectors... %d\n", mode2f1sectors);
|
|
printf("\twith errors..... %d\n", mode2f1errors);
|
|
printf("\twith warnings... %d\n", mode2f1warnings);
|
|
printf("Mode 2 form 2 sectors... %d\n", mode2f2sectors);
|
|
printf("\twith errors..... %d\n", mode2f2errors);
|
|
printf("\twith warnings... %d\n", mode2f2warnings);
|
|
printf("Filled sectors.......... %d\n", filledsectors);
|
|
printf("Total sectors........... %d\n", totalsectors);
|
|
printf("Total errors............ %d\n", totalerrors);
|
|
printf("Total warnings.......... %d\n", totalwarnings);
|
|
printf("Total errors+warnings... %d\n", totalerrors + totalwarnings);
|
|
//
|
|
// Success
|
|
//
|
|
printf("Done\n");
|
|
returncode = 0;
|
|
goto done;
|
|
|
|
error_in:
|
|
printfileerror(in, infilename);
|
|
goto error;
|
|
|
|
error:
|
|
returncode = 1;
|
|
goto done;
|
|
|
|
done:
|
|
if(queue != NULL) { free(queue); }
|
|
if(in != NULL) { fclose(in); }
|
|
|
|
return returncode;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
DPRINTF("Entering main().\n");
|
|
int returncode = 0;
|
|
char *infilename = NULL;
|
|
|
|
DPRINTF("Normalizing argv[0].\n");
|
|
normalize_argv0(argv[0]);
|
|
|
|
DPRINTF("Showing banner.\n");
|
|
banner();
|
|
|
|
//
|
|
// Check command line
|
|
//
|
|
switch(argc)
|
|
{
|
|
case 2:
|
|
infilename = argv[1];
|
|
//
|
|
// Initialize the ECC/EDC tables
|
|
//
|
|
eccedc_init();
|
|
if(ecmify(infilename)) { goto error; }
|
|
break;
|
|
default: goto usage;
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
returncode = 0;
|
|
goto done;
|
|
|
|
usage:
|
|
printf("Usage:\n"
|
|
"\n"
|
|
" edccchk cdimagefile\n");
|
|
|
|
error:
|
|
returncode = 1;
|
|
goto done;
|
|
|
|
done:
|
|
return returncode;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|