mirror of
https://github.com/claunia/edccchk.git
synced 2025-12-16 19:24:51 +00:00
Commit to git.\n\rAdded makefiles.
This commit is contained in:
21
Makefile
Normal file
21
Makefile
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
OBJS = edccchk.o
|
||||||
|
CC = gcc
|
||||||
|
DEBUG = -g
|
||||||
|
CFLAGS = -Wall -O0 -W -D_FILE_OFFSET_BITS=64 -std=c99 -c $(DEBUG)
|
||||||
|
LFLAGS = -Wall $(DEBUG)
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
edccchk : $(OBJS)
|
||||||
|
$(CC) $(LFLAGS) $(LIBS) $(OBJS) -o edccchk
|
||||||
|
|
||||||
|
edccchk.o : edccchk.c common.h banner.h version.h
|
||||||
|
$(CC) $(CFLAGS) edccchk.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
\rm *.o edccchk
|
||||||
|
|
||||||
|
tar:
|
||||||
|
tar Jcfv edccchk-src.txz banner.h common.h edccchk.c LICENSE Makefile README.md version.h
|
||||||
|
|
||||||
|
bindist : edccchk
|
||||||
|
tar Jcvf edccchk-bin.txz edccchk LICENSE README.md
|
||||||
21
Makefile.mingw32
Normal file
21
Makefile.mingw32
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
OBJS = edccchk.o
|
||||||
|
CC = i686-pc-mingw32-gcc
|
||||||
|
DEBUG = -g
|
||||||
|
CFLAGS = -Wall -O0 -W -D_FILE_OFFSET_BITS=64 -std=c99 -static -c $(DEBUG)
|
||||||
|
LFLAGS = -Wall $(DEBUG)
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
edccchk : $(OBJS)
|
||||||
|
$(CC) $(LFLAGS) $(LIBS) $(OBJS) -o edccchk.exe
|
||||||
|
|
||||||
|
edccchk.o : edccchk.c common.h banner.h version.h
|
||||||
|
$(CC) $(CFLAGS) edccchk.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
\rm *.o edccchk.exe
|
||||||
|
|
||||||
|
tar:
|
||||||
|
zip -9 edccchk-src.zip banner.h common.h edccchk.c LICENSE Makefile README.md version.h
|
||||||
|
|
||||||
|
bindist : edccchk
|
||||||
|
zip -9 edccchk-bin-win32.zip edccchk.exe LICENSE README.md
|
||||||
21
Makefile.mingw64
Normal file
21
Makefile.mingw64
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
OBJS = edccchk.o
|
||||||
|
CC = x86_64-pc-mingw64-gcc
|
||||||
|
DEBUG = -g
|
||||||
|
CFLAGS = -Wall -O0 -W -D_FILE_OFFSET_BITS=64 -std=c99 -static -c $(DEBUG)
|
||||||
|
LFLAGS = -Wall $(DEBUG)
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
edccchk : $(OBJS)
|
||||||
|
$(CC) $(LFLAGS) $(LIBS) $(OBJS) -o edccchk.exe
|
||||||
|
|
||||||
|
edccchk.o : edccchk.c common.h banner.h version.h
|
||||||
|
$(CC) $(CFLAGS) edccchk.c
|
||||||
|
|
||||||
|
clean:
|
||||||
|
\rm *.o edccchk.exe
|
||||||
|
|
||||||
|
tar:
|
||||||
|
zip -9 edccchk-src.zip banner.h common.h edccchk.c LICENSE Makefile README.md version.h
|
||||||
|
|
||||||
|
bindist : edccchk
|
||||||
|
zip -9 edccchk-bin-win64.zip edccchk.exe LICENSE README.md
|
||||||
41
README.md
41
README.md
@@ -1,4 +1,41 @@
|
|||||||
edccchk
|
edccchk v1.0
|
||||||
=======
|
============
|
||||||
|
|
||||||
EDC/ECC checker for RAW (2352 bytes/sector) CD images
|
EDC/ECC checker for RAW (2352 bytes/sector) CD images
|
||||||
|
|
||||||
|
Copyright © 2013 Natalia Portillo <claunia@claunia.com>
|
||||||
|
Based on ECM v1.03 Copyright © 2002-2011 Neill Corlett
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
edccchk <cdimage>
|
||||||
|
|
||||||
|
<cdimage> RAW 2352 bytes/sector image of a CD.
|
||||||
|
|
||||||
|
Features
|
||||||
|
========
|
||||||
|
|
||||||
|
Checks EDC and ECC fields consistency of CD sectors.
|
||||||
|
Supports Mode 0, Mode 1 and Mode 2 data sectors, ignores Audio sectors.
|
||||||
|
Shows failing sectors as MSF.
|
||||||
|
|
||||||
|
Known bugs
|
||||||
|
==========
|
||||||
|
|
||||||
|
Mode 2 form-less sectors all appear as errors. Mode 2 form 1 and form 2 sectors are processed correctly.
|
||||||
|
|
||||||
|
Changelog
|
||||||
|
=========
|
||||||
|
|
||||||
|
2013/12/08 v1.00 Converted ECM code to only check sectors.
|
||||||
|
Added support for mode 0 sectors.
|
||||||
|
|
||||||
|
To-Do
|
||||||
|
=====
|
||||||
|
|
||||||
|
* Support Mode 2 form-less sectors
|
||||||
|
* Support RAW+SUB images (2448 bytes/sector)
|
||||||
|
* Check Q-subchannel CRCs
|
||||||
|
* Check CD+G CRCs
|
||||||
|
* Check consistency of P and Q subchannels with sector headers
|
||||||
|
|||||||
71
banner.h
Normal file
71
banner.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void banner_ok(void) {
|
||||||
|
printf(TITLE "\n"
|
||||||
|
#include "version.h"
|
||||||
|
" (%d-bit "
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
"Windows, Cygwin"
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
"Windows, MinGW"
|
||||||
|
#elif defined(_WIN32) && defined(_MSC_VER) && (defined(__alpha) || defined(__ALPHA) || defined(__Alpha_AXP))
|
||||||
|
"Windows, Digital AXP C"
|
||||||
|
#elif defined(_WIN32) && defined(_MSC_VER) && defined(_M_ALPHA)
|
||||||
|
"Windows, Microsoft C, Alpha"
|
||||||
|
#elif defined(_WIN32) && defined(_MSC_VER) && defined(_M_MRX000)
|
||||||
|
"Windows, Microsoft C, MIPS"
|
||||||
|
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
"Windows, Microsoft C"
|
||||||
|
#elif defined(__WIN32__) || defined(_WIN32)
|
||||||
|
"Windows"
|
||||||
|
#elif defined(__DJGPP__)
|
||||||
|
"DOS, DJGPP"
|
||||||
|
#elif defined(__MSDOS__) && defined(__TURBOC__)
|
||||||
|
"DOS, Turbo C"
|
||||||
|
#elif defined(_DOS) && defined(__WATCOMC__)
|
||||||
|
"DOS, Watcom"
|
||||||
|
#elif defined(__MSDOS__) || defined(MSDOS) || defined(_DOS)
|
||||||
|
"DOS"
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
"Mac OS"
|
||||||
|
#elif defined(__linux) || defined(__linux__) || defined(__gnu_linux__) || defined(linux)
|
||||||
|
"Linux"
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
"OpenBSD"
|
||||||
|
#elif defined(BSD)
|
||||||
|
"BSD"
|
||||||
|
#elif defined(human68k) || defined(HUMAN68K) || defined(__human68k) || defined(__HUMAN68K) || defined(__human68k__) || defined(__HUMAN68K__)
|
||||||
|
"Human68k"
|
||||||
|
#elif defined(__unix__) || defined(__unix) || defined(unix)
|
||||||
|
"unknown Unix"
|
||||||
|
#else
|
||||||
|
"unknown platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"%s)\n"
|
||||||
|
" " COPYR "\n"
|
||||||
|
" http://www.claunia.com/\n"
|
||||||
|
" based on ecm v1.03\n"
|
||||||
|
" Copyright (C) 2002-2011 Neill Corlett"
|
||||||
|
"\n",
|
||||||
|
(int)(sizeof(size_t) * 8),
|
||||||
|
(sizeof(off_t) > 4 && sizeof(off_t) > sizeof(size_t)) ? ", large file support" : ""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void banner_error(void) {
|
||||||
|
printf("Configuration error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void banner(void) {
|
||||||
|
((sizeof(off_t) >= sizeof(size_t)) ? banner_ok : banner_error)();
|
||||||
|
//
|
||||||
|
// If we've displayed the banner, we'll also want to warn that this is a
|
||||||
|
// command-line app when we exit
|
||||||
|
//
|
||||||
|
atexit(commandlinewarning);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
641
common.h
Normal file
641
common.h
Normal file
@@ -0,0 +1,641 @@
|
|||||||
|
#ifndef __CMDPACK_COMMON_H__
|
||||||
|
#define __CMDPACK_COMMON_H__
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Common headers for Command-Line Pack programs
|
||||||
|
//
|
||||||
|
// 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/>.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Disable fopen() warnings on VC++. It means well...
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
// Try to enable 64-bit file offsets on platforms where it's optional
|
||||||
|
#define _LARGEFILE64_SOURCE 1
|
||||||
|
#define __USE_FILE_OFFSET64 1
|
||||||
|
#define __USE_LARGEFILE64 1
|
||||||
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
|
||||||
|
// Try to enable long filename support on Watcom
|
||||||
|
#define __WATCOM_LFN__ 1
|
||||||
|
|
||||||
|
// Convince MinGW that we want to glob arguments
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
int _dowildcard = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
// MSC toolchains use sys/utime.h; everything else uses utime.h
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <sys/utime.h>
|
||||||
|
#else
|
||||||
|
#include <utime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Try to bring in unistd.h if possible
|
||||||
|
#if !defined(__TURBOC__) && !defined(_MSC_VER)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bring in direct.h if we need to; sometimes mkdir/rmdir is defined here
|
||||||
|
#if defined(__WATCOMC__) || defined(_MSC_VER)
|
||||||
|
#include <direct.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Fill in S_ISDIR
|
||||||
|
#if !defined(_POSIX_VERSION) && !defined(S_ISDIR)
|
||||||
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__TURBOC__) || defined(__WATCOMC__) || defined(__MINGW32__) || defined(_MSC_VER)
|
||||||
|
//
|
||||||
|
// Already have a single-argument mkdir()
|
||||||
|
//
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
// Provide a single-argument mkdir()
|
||||||
|
//
|
||||||
|
#define mkdir(a) mkdir(a, S_IRWXU | S_IRWXG | S_IRWXO)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Enforce large memory model for 16-bit DOS targets
|
||||||
|
//
|
||||||
|
#if defined(__MSDOS__) || defined(MSDOS)
|
||||||
|
#if defined(__TURBOC__) || defined(__WATCOMC__)
|
||||||
|
#if !defined(__LARGE__)
|
||||||
|
#error This is not the memory model we should be using!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Try to figure out integer types
|
||||||
|
//
|
||||||
|
#if defined(_STDINT_H) || defined(_EXACT_WIDTH_INTS)
|
||||||
|
|
||||||
|
// _STDINT_H_ - presume stdint.h has already been included
|
||||||
|
// _EXACT_WIDTH_INTS - OpenWatcom already provides int*_t in sys/types.h
|
||||||
|
|
||||||
|
#elif defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L
|
||||||
|
|
||||||
|
// Assume C99 compliance when the compiler specifically tells us it is
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
|
// On Visual Studio, use its integral types
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Guess integer sizes from limits.h
|
||||||
|
|
||||||
|
//
|
||||||
|
// int8_t
|
||||||
|
//
|
||||||
|
#ifndef __int8_t_defined
|
||||||
|
#if SCHAR_MIN == -128 && SCHAR_MAX == 127 && UCHAR_MAX == 255
|
||||||
|
typedef signed char int8_t;
|
||||||
|
#else
|
||||||
|
#error Unknown how to define int8_t!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// uint8_t
|
||||||
|
//
|
||||||
|
#ifndef __uint8_t_defined
|
||||||
|
#if SCHAR_MIN == -128 && SCHAR_MAX == 127 && UCHAR_MAX == 255
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
#else
|
||||||
|
#error Unknown how to define uint8_t!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// int16_t
|
||||||
|
//
|
||||||
|
#ifndef __int16_t_defined
|
||||||
|
#if SHRT_MIN == -32768 && SHRT_MAX == 32767 && USHRT_MAX == 65535
|
||||||
|
typedef signed short int16_t;
|
||||||
|
#else
|
||||||
|
#error Unknown how to define int16_t!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// uint16_t
|
||||||
|
//
|
||||||
|
#ifndef __uint16_t_defined
|
||||||
|
#if SHRT_MIN == -32768 && SHRT_MAX == 32767 && USHRT_MAX == 65535
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
#else
|
||||||
|
#error Unknown how to define uint16_t!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// int32_t
|
||||||
|
//
|
||||||
|
#ifndef __int32_t_defined
|
||||||
|
#if INT_MIN == -2147483648 && INT_MAX == 2147483647 && UINT_MAX == 4294967295
|
||||||
|
typedef signed int int32_t;
|
||||||
|
#elif LONG_MIN == -2147483648 && LONG_MAX == 2147483647 && ULONG_MAX == 4294967295
|
||||||
|
typedef signed long int32_t;
|
||||||
|
#else
|
||||||
|
#error Unknown how to define int32_t!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// uint32_t
|
||||||
|
//
|
||||||
|
#ifndef __uint32_t_defined
|
||||||
|
#if INT_MIN == -2147483648 && INT_MAX == 2147483647 && UINT_MAX == 4294967295
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
#elif LONG_MIN == -2147483648 && LONG_MAX == 2147483647 && ULONG_MAX == 4294967295
|
||||||
|
typedef unsigned long uint32_t;
|
||||||
|
#else
|
||||||
|
#error Unknown how to define uint32_t!
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// There are some places in the code where it's assumed 'long' can hold at least
|
||||||
|
// 32 bits. Verify that here:
|
||||||
|
//
|
||||||
|
#if LONG_MAX < 2147483647 || ULONG_MAX < 4294967295
|
||||||
|
#error long type must be at least 32 bits!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Figure out how big file offsets should be
|
||||||
|
//
|
||||||
|
#if defined(_OFF64_T_) || defined(_OFF64_T_DEFINED) || defined(__off64_t_defined)
|
||||||
|
//
|
||||||
|
// We have off64_t
|
||||||
|
// Regular off_t may be smaller, so check this first
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef off_t
|
||||||
|
#undef off_t
|
||||||
|
#endif
|
||||||
|
#ifdef fseeko
|
||||||
|
#undef fseeko
|
||||||
|
#endif
|
||||||
|
#ifdef ftello
|
||||||
|
#undef ftello
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define off_t off64_t
|
||||||
|
#define fseeko fseeko64
|
||||||
|
#define ftello ftello64
|
||||||
|
|
||||||
|
#elif defined(_OFF_T) || defined(__OFF_T_TYPE) || defined(__off_t_defined) || defined(_OFF_T_DEFINED_)
|
||||||
|
//
|
||||||
|
// We have off_t
|
||||||
|
//
|
||||||
|
|
||||||
|
#else
|
||||||
|
//
|
||||||
|
// Assume offsets are just 'long'
|
||||||
|
//
|
||||||
|
#ifdef off_t
|
||||||
|
#undef off_t
|
||||||
|
#endif
|
||||||
|
#ifdef fseeko
|
||||||
|
#undef fseeko
|
||||||
|
#endif
|
||||||
|
#ifdef ftello
|
||||||
|
#undef ftello
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define off_t long
|
||||||
|
#define fseeko fseek
|
||||||
|
#define ftello ftell
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add the ability to read off_t
|
||||||
|
// (assumes off_t is a signed type)
|
||||||
|
//
|
||||||
|
off_t strtoofft(const char* s_start, char** endptr, int base) {
|
||||||
|
off_t max =
|
||||||
|
((((off_t)1) << ((sizeof(off_t)*8)-2)) - 1) +
|
||||||
|
((((off_t)1) << ((sizeof(off_t)*8)-2)) );
|
||||||
|
off_t min = ((-1) - max);
|
||||||
|
const char* s = s_start;
|
||||||
|
off_t accumulator;
|
||||||
|
off_t limit_tens;
|
||||||
|
off_t limit_ones;
|
||||||
|
int c;
|
||||||
|
int negative = 0;
|
||||||
|
int anyinput;
|
||||||
|
do {
|
||||||
|
c = *s++;
|
||||||
|
} while(isspace(c));
|
||||||
|
if(c == '-') {
|
||||||
|
negative = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else if (c == '+') {
|
||||||
|
c = *s++;
|
||||||
|
}
|
||||||
|
if(
|
||||||
|
(base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X')
|
||||||
|
) {
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
if(!base) {
|
||||||
|
base = (c == '0') ? 8 : 10;
|
||||||
|
}
|
||||||
|
limit_ones = max % ((off_t)base);
|
||||||
|
limit_tens = max / ((off_t)base);
|
||||||
|
if(negative) {
|
||||||
|
limit_ones++;
|
||||||
|
if(limit_ones >= base) { limit_ones = 0; limit_tens++; }
|
||||||
|
}
|
||||||
|
for(accumulator = 0, anyinput = 0;; c = *s++) {
|
||||||
|
if(isdigit(c)) {
|
||||||
|
c -= '0';
|
||||||
|
} else if(isalpha(c)) {
|
||||||
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(c >= base) { break; }
|
||||||
|
if(
|
||||||
|
(anyinput < 0) ||
|
||||||
|
(accumulator < 0) ||
|
||||||
|
(accumulator > limit_tens) ||
|
||||||
|
(accumulator == limit_tens && c > limit_ones)
|
||||||
|
) {
|
||||||
|
anyinput = -1;
|
||||||
|
} else {
|
||||||
|
anyinput = 1;
|
||||||
|
accumulator *= base;
|
||||||
|
accumulator += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(anyinput < 0) {
|
||||||
|
accumulator = negative ? min : max;
|
||||||
|
errno = ERANGE;
|
||||||
|
} else if(negative) {
|
||||||
|
accumulator = -accumulator;
|
||||||
|
}
|
||||||
|
if(endptr) {
|
||||||
|
*endptr = (char*)(anyinput ? (char*)s - 1 : s_start);
|
||||||
|
}
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add the ability to print off_t
|
||||||
|
//
|
||||||
|
void fprinthex(FILE* f, off_t off, int min_digits) {
|
||||||
|
unsigned anydigit = 0;
|
||||||
|
int place;
|
||||||
|
for(place = 2 * sizeof(off_t) - 1; place >= 0; place--) {
|
||||||
|
if(sizeof(off_t) > (((size_t)(place)) / 2)) {
|
||||||
|
unsigned digit = (off >> (4 * place)) & 0xF;
|
||||||
|
anydigit |= digit;
|
||||||
|
if(anydigit || place < min_digits) {
|
||||||
|
fputc("0123456789ABCDEF"[digit], f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprintdec_digit(FILE* f, off_t off) {
|
||||||
|
if(off == 0) { return; }
|
||||||
|
if(off >= 10) {
|
||||||
|
fprintdec_digit(f, off / ((off_t)10));
|
||||||
|
off %= ((off_t)10);
|
||||||
|
}
|
||||||
|
fputc('0' + off, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fprintdec(FILE* f, off_t off) {
|
||||||
|
if(off == 0) {
|
||||||
|
fputc('0', f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(off < 0) {
|
||||||
|
fputc('-', f);
|
||||||
|
off = -off;
|
||||||
|
if(off < 0) {
|
||||||
|
off_t ones = off % ((off_t)10);
|
||||||
|
off /= ((off_t)10);
|
||||||
|
off = -off;
|
||||||
|
fprintdec_digit(f, off);
|
||||||
|
fputc('0' - ones, f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintdec_digit(f, off);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Define truncate() for systems that don't have it
|
||||||
|
//
|
||||||
|
#if !defined(_POSIX_VERSION)
|
||||||
|
|
||||||
|
#if (defined(__MSDOS__) || defined(MSDOS)) && (defined(__TURBOC__) || defined(__WATCOMC__))
|
||||||
|
|
||||||
|
#include <dos.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
int truncate(const char *filename, off_t size) {
|
||||||
|
if(size < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Extend (or do nothing) if necessary
|
||||||
|
//
|
||||||
|
{ off_t end;
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
if(!f) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(fseeko(f, 0, SEEK_END) != 0) {
|
||||||
|
fclose(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
end = ftello(f);
|
||||||
|
if(end <= size) {
|
||||||
|
for(; end < size; end++) {
|
||||||
|
if(fputc(0, f) == EOF) {
|
||||||
|
fclose(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Shrink if necessary (DOS-specific call)
|
||||||
|
//
|
||||||
|
{ int doshandle = 0;
|
||||||
|
unsigned nwritten = 0;
|
||||||
|
if(_dos_open(filename, O_WRONLY, &doshandle)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(lseek(doshandle, size, SEEK_SET) == -1L) {
|
||||||
|
_dos_close(doshandle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(_dos_write(doshandle, &doshandle, 0, &nwritten)) {
|
||||||
|
_dos_close(doshandle);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
_dos_close(doshandle);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Success
|
||||||
|
//
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (defined(_WIN32) && defined(_MSC_VER))
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// Disable extension warnings for <windows.h> and friends
|
||||||
|
#pragma warning (disable: 4226)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#ifndef INVALID_SET_FILE_POINTER
|
||||||
|
#define INVALID_SET_FILE_POINTER ((DWORD)(-1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int truncate(const char *filename, off_t size) {
|
||||||
|
if(size < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Extend (or do nothing) if necessary
|
||||||
|
//
|
||||||
|
{ off_t end;
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
if(!f) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(fseeko(f, 0, SEEK_END) != 0) {
|
||||||
|
fclose(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
end = ftello(f);
|
||||||
|
if(end <= size) {
|
||||||
|
for(; end < size; end++) {
|
||||||
|
if(fputc(0, f) == EOF) {
|
||||||
|
fclose(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Shrink if necessary (Windows-specific call)
|
||||||
|
//
|
||||||
|
{ HANDLE f = CreateFile(
|
||||||
|
filename,
|
||||||
|
GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if(f == INVALID_HANDLE_VALUE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(size > ((off_t)0x7FFFFFFFL)) {
|
||||||
|
// use fancy 64-bit SetFilePointer
|
||||||
|
LONG lo = size;
|
||||||
|
LONG hi = size >> 32;
|
||||||
|
if(SetFilePointer(f, lo, &hi, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
||||||
|
CloseHandle(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use plain 32-bit SetFilePointer
|
||||||
|
if(SetFilePointer(f, size, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
|
||||||
|
CloseHandle(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!SetEndOfFile(f)) {
|
||||||
|
CloseHandle(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Success
|
||||||
|
//
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !defined(_POSIX_VERSION)
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Normalize argv[0]
|
||||||
|
//
|
||||||
|
void normalize_argv0(char* argv0) {
|
||||||
|
size_t i;
|
||||||
|
size_t start = 0;
|
||||||
|
int c;
|
||||||
|
for(i = 0; argv0[i]; i++) {
|
||||||
|
if(argv0[i] == '/' || argv0[i] == '\\') {
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
c = ((unsigned char)(argv0[start + i]));
|
||||||
|
if(c == '.') { c = 0; }
|
||||||
|
if(c != 0) { c = tolower(c); }
|
||||||
|
argv0[i++] = c;
|
||||||
|
} while(c != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void printfileerror(FILE* f, const char* name) {
|
||||||
|
int e = errno;
|
||||||
|
printf("Error: ");
|
||||||
|
if(name) { printf("%s: ", name); }
|
||||||
|
printf("%s\n", f && feof(f) ? "Unexpected end-of-file" : strerror(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Detect if the user double-clicked on the .exe rather than executing this from
|
||||||
|
// the command line, and if so, display a warning and wait for input before
|
||||||
|
// exiting
|
||||||
|
//
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
static HWND getconsolewindow(void) {
|
||||||
|
HWND hConsoleWindow = NULL;
|
||||||
|
HANDLE k32;
|
||||||
|
//
|
||||||
|
// See if GetConsoleWindow is available (Windows 2000 or later)
|
||||||
|
//
|
||||||
|
k32 = GetModuleHandle(TEXT("kernel32.dll"));
|
||||||
|
if(k32) {
|
||||||
|
typedef HWND (* WINAPI gcw_t)(void);
|
||||||
|
gcw_t gcw = (gcw_t)GetProcAddress(k32, TEXT("GetConsoleWindow"));
|
||||||
|
if(gcw) {
|
||||||
|
hConsoleWindow = gcw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// There is an alternative method that involves FindWindow, but it's too
|
||||||
|
// cumbersome for just printing a warning.
|
||||||
|
//
|
||||||
|
return hConsoleWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void commandlinewarning(void) {
|
||||||
|
HWND hConsoleWindow;
|
||||||
|
DWORD processId = 0;
|
||||||
|
//
|
||||||
|
// This trick doesn't work in Win9x
|
||||||
|
//
|
||||||
|
if(GetVersion() >= ((DWORD)0x80000000LU)) { return; }
|
||||||
|
//
|
||||||
|
// See if the console window belongs to my own process
|
||||||
|
//
|
||||||
|
hConsoleWindow = getconsolewindow();
|
||||||
|
if(!hConsoleWindow) { return; }
|
||||||
|
GetWindowThreadProcessId(hConsoleWindow, &processId);
|
||||||
|
if(GetCurrentProcessId() == processId) {
|
||||||
|
printf(
|
||||||
|
"\n"
|
||||||
|
"Note: This is a command-line application.\n"
|
||||||
|
"It was meant to run from a Windows command prompt.\n\n"
|
||||||
|
"Press ENTER to close this window..."
|
||||||
|
);
|
||||||
|
fflush(stdout);
|
||||||
|
fgetc(stdin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void commandlinewarning(void) {}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Work around some problems with the Mariko CC toolchain
|
||||||
|
//
|
||||||
|
#ifdef MARIKO_CC
|
||||||
|
|
||||||
|
// 32-bit signed and unsigned mod seem buggy; this solves it
|
||||||
|
unsigned long __umodsi3(unsigned long a, unsigned long b) { return a - (a / b) * b; }
|
||||||
|
signed long __modsi3(signed long a, signed long b) { return a - (a / b) * b; }
|
||||||
|
|
||||||
|
// Some kind of soft float linkage issue?
|
||||||
|
void __cmpdf2(void) {}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#endif
|
||||||
636
edccchk.c
Normal file
636
edccchk.c
Normal file
@@ -0,0 +1,636 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
#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 "common.h"
|
||||||
|
#include "banner.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
|
||||||
|
//
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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 mode2f2sectors;
|
||||||
|
static uint32_t mode2f2errors;
|
||||||
|
static uint32_t totalsectors;
|
||||||
|
static uint32_t totalerrors;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
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};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Check if this is a sector we can compress
|
||||||
|
//
|
||||||
|
// Sector types:
|
||||||
|
// 0: Literal bytes (not a sector)
|
||||||
|
// 1: 2352 mode 1 predict sync, mode, reserved, edc, ecc
|
||||||
|
// 2: 2336 mode 2 form 1 predict redundant flags, edc, ecc
|
||||||
|
// 3: 2336 mode 2 form 2 predict redundant flags, edc
|
||||||
|
//
|
||||||
|
static int8_t detect_sector(const uint8_t* sector, size_t size_available) {
|
||||||
|
if(
|
||||||
|
size_available >= 2352 &&
|
||||||
|
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 &&
|
||||||
|
sector[0x00F] == 0x01 && // mode (1 byte)
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
// Might be Mode 1
|
||||||
|
//
|
||||||
|
if(
|
||||||
|
ecc_checksector(
|
||||||
|
sector + 0xC,
|
||||||
|
sector + 0x10,
|
||||||
|
sector + 0x81C
|
||||||
|
) &&
|
||||||
|
edc_compute(0, sector, 0x810) == get32lsb(sector + 0x810)
|
||||||
|
) {
|
||||||
|
return 1; // Mode 1
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(
|
||||||
|
size_available >= 2336 &&
|
||||||
|
sector[0] == sector[4] && // flags (4 bytes)
|
||||||
|
sector[1] == sector[5] && // versus redundant copy
|
||||||
|
sector[2] == sector[6] &&
|
||||||
|
sector[3] == sector[7]
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
// Might be Mode 2, Form 1 or 2
|
||||||
|
//
|
||||||
|
if(
|
||||||
|
ecc_checksector(
|
||||||
|
zeroaddress,
|
||||||
|
sector,
|
||||||
|
sector + 0x80C
|
||||||
|
) &&
|
||||||
|
edc_compute(0, sector, 0x808) == get32lsb(sector + 0x808)
|
||||||
|
) {
|
||||||
|
return 2; // Mode 2, Form 1
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Might be Mode 2, Form 2
|
||||||
|
//
|
||||||
|
if(
|
||||||
|
edc_compute(0, sector, 0x91C) == get32lsb(sector + 0x91C)
|
||||||
|
) {
|
||||||
|
return 3; // Mode 2, Form 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Nothing
|
||||||
|
//
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static uint8_t sector_buffer[2352];
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setcounter_encode(off_t n) {
|
||||||
|
int8_t p = ((n >> 20) != (mycounter_encode >> 20));
|
||||||
|
mycounter_encode = n;
|
||||||
|
if(p) { encode_progress(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Returns nonzero on error
|
||||||
|
//
|
||||||
|
static int8_t ecmify(
|
||||||
|
const char* infilename
|
||||||
|
) {
|
||||||
|
int8_t returncode = 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;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Current sector type (run)
|
||||||
|
//
|
||||||
|
int8_t curtype = -1; // not a valid type
|
||||||
|
uint32_t curtype_count = 0;
|
||||||
|
off_t curtype_in_start = 0;
|
||||||
|
|
||||||
|
uint32_t literal_skip = 0;
|
||||||
|
|
||||||
|
off_t input_file_length;
|
||||||
|
off_t input_bytes_checked = 0;
|
||||||
|
off_t input_bytes_queued = 0;
|
||||||
|
|
||||||
|
off_t typetally[4] = {0,0,0,0};
|
||||||
|
|
||||||
|
size_t queue_size = ((size_t)(-1)) - 4095;
|
||||||
|
if((unsigned long)queue_size > 0x40000lu) {
|
||||||
|
queue_size = (size_t)0x40000lu;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocate space for queue
|
||||||
|
//
|
||||||
|
queue = malloc(queue_size);
|
||||||
|
if(!queue) {
|
||||||
|
printf("Out of memory\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Open both files
|
||||||
|
//
|
||||||
|
in = fopen(infilename, "rb");
|
||||||
|
if(!in) { goto error_in; }
|
||||||
|
|
||||||
|
printf("Checking %s...\n", infilename);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get the length of the input file
|
||||||
|
//
|
||||||
|
if(fseeko(in, 0, SEEK_END) != 0) { goto error_in; }
|
||||||
|
input_file_length = ftello(in);
|
||||||
|
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;
|
||||||
|
mode2f2sectors= 0;
|
||||||
|
mode2f2errors= 0;
|
||||||
|
totalsectors= 0;
|
||||||
|
totalerrors= 0;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
int8_t detecttype;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Refill queue if necessary
|
||||||
|
//
|
||||||
|
if(
|
||||||
|
(queue_bytes_available < 2352) &&
|
||||||
|
(((off_t)queue_bytes_available) < (input_file_length - input_bytes_queued))
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
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) {
|
||||||
|
//
|
||||||
|
// No data left to read -> quit
|
||||||
|
//
|
||||||
|
detecttype = -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Just for debug
|
||||||
|
// fprintf(stderr, "Address: %02X:%02X:%02X\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
||||||
|
if(sector[0x00F] == 0x00) // mode (1 byte)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(sector[0x00F] == 0x02) // mode (1 byte)
|
||||||
|
{
|
||||||
|
uint8_t* m2sec = sector + 0x10;
|
||||||
|
|
||||||
|
if((sector[0x012] & 0x20) == 0x20) // mode 2 form 2
|
||||||
|
{
|
||||||
|
mode2f2sectors++;
|
||||||
|
if(edc_compute(0, m2sec, 0x91C) != get32lsb(m2sec + 0x91C))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Mode 2 form 2 sector with error at address: %02X:%02X:%02X\n", sector[0x00C], sector[0x00D], sector[0x00E]);
|
||||||
|
mode2f2errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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]);
|
||||||
|
mode2f1errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Unknown sector mode!!!
|
||||||
|
{
|
||||||
|
nondatasectors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Non data sector
|
||||||
|
{
|
||||||
|
nondatasectors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Current type is negative ==> quit
|
||||||
|
//
|
||||||
|
if(detecttype < 0) { break; }
|
||||||
|
|
||||||
|
//
|
||||||
|
// Advance to the next sector
|
||||||
|
//
|
||||||
|
totalsectors++;
|
||||||
|
input_bytes_checked += 2352;
|
||||||
|
queue_start_ofs += 2352;
|
||||||
|
queue_bytes_available -= 2352;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Show report
|
||||||
|
//
|
||||||
|
totalsectors++;
|
||||||
|
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("Mode 2 form 2 sectors... %d\n", mode2f2sectors);
|
||||||
|
printf("\twith errors..... %d\n", mode2f2errors);
|
||||||
|
printf("Total sectors........... %d\n", totalsectors);
|
||||||
|
printf("Total errors............ %d\n", totalerrors);
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
int returncode = 0;
|
||||||
|
char* infilename = NULL;
|
||||||
|
|
||||||
|
normalize_argv0(argv[0]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Reference in New Issue
Block a user