From d9461a9401d64bc1c8ffb53f108bc1771736f8cd Mon Sep 17 00:00:00 2001 From: Braden McDaniel Date: Fri, 1 Nov 2013 16:06:06 -0400 Subject: [PATCH] Normalize line endings --- AUTHORS | 82 +- docs/NEWS | 106 +- docs/options | 128 +- libfriidump/CMakeLists.txt | 210 +-- libfriidump/disc.c | 3348 +++++++++++++++++------------------ libfriidump/ecma-267.c | 218 +-- libfriidump/ecma-267.h | 94 +- libfriidump/rs.c | 632 +++---- libfriidump/rs.h | 20 +- libfriidump/unscrambler.c | 740 ++++---- libmultihash/CMakeLists.txt | 154 +- libmultihash/crc32.c | 240 +-- libmultihash/crc32.h | 106 +- libmultihash/md5.c | 954 +++++----- libmultihash/multihash.h | 254 +-- 15 files changed, 3643 insertions(+), 3643 deletions(-) diff --git a/AUTHORS b/AUTHORS index d57416c..8ce9c63 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,41 +1,41 @@ -FriiDump came to existance thanks to the work by a lot of people, most of which -are probably not aware of this fact ;). So here is proper credit: - -The DVD seed bruteforcing algorithm and code were taken from unscrambler 0.4 -by Victor Muņoz (xt5@ingenieria-inversa.cl, -http://www.ingenieria-inversa.cl/?lp_lang_pref=en). - -The theoritical basis of the dumping methods were suggested in several comments -to Victor's post. The most important comments came from Victor himself (xt5), -FuzzyLogic and svpe. - -The code to actually perform the dumping was derived from the work of Kevin -East, AKA SeventhSon (kev@kev.nu, http://www.kev.nu/360/), which, in turn, -derives from work by a lot of other people. See his page for full details. - -Many hints were taken from RawDump, whose author is unknown. - -A program that helped me a lot to understand the drive cache behaviour is -PLScsi by Pat LaVarre (http://members.aol.com/plscsi/). - -Nintendo disc structure information was taken from: -- http://www.gc-linux.org/docs/yagcd.html -- http://www.wiili.org/index.php/GameCube_Optical_Disc - -Code to tell whether a Wii disc contains an update or was inspired by a program -by wiidevel@stacktic.org. Sorry but I cannot find the URL anymore :(. - -Other minor pieces of code were taken from tcpdump (www.tcpdump.org), Python -(www.python.org) and the glibc printf manpage. - -GDR8163B and Windows testing was performed by tasso85. - -Thanks also go out to the ConsoleTribe staff for giving me the possibility to -use their forum for the program support. - -Glue, endless hours spent understanding drive cache behaviour and rest of the -code are by me, Arep . - -Finally, obvious thanks go out to Nintendo for making all of their great -consoles, who constantly help me to waste the rest of my spare time I do not -spend coding ;). +FriiDump came to existance thanks to the work by a lot of people, most of which +are probably not aware of this fact ;). So here is proper credit: + +The DVD seed bruteforcing algorithm and code were taken from unscrambler 0.4 +by Victor Muņoz (xt5@ingenieria-inversa.cl, +http://www.ingenieria-inversa.cl/?lp_lang_pref=en). + +The theoritical basis of the dumping methods were suggested in several comments +to Victor's post. The most important comments came from Victor himself (xt5), +FuzzyLogic and svpe. + +The code to actually perform the dumping was derived from the work of Kevin +East, AKA SeventhSon (kev@kev.nu, http://www.kev.nu/360/), which, in turn, +derives from work by a lot of other people. See his page for full details. + +Many hints were taken from RawDump, whose author is unknown. + +A program that helped me a lot to understand the drive cache behaviour is +PLScsi by Pat LaVarre (http://members.aol.com/plscsi/). + +Nintendo disc structure information was taken from: +- http://www.gc-linux.org/docs/yagcd.html +- http://www.wiili.org/index.php/GameCube_Optical_Disc + +Code to tell whether a Wii disc contains an update or was inspired by a program +by wiidevel@stacktic.org. Sorry but I cannot find the URL anymore :(. + +Other minor pieces of code were taken from tcpdump (www.tcpdump.org), Python +(www.python.org) and the glibc printf manpage. + +GDR8163B and Windows testing was performed by tasso85. + +Thanks also go out to the ConsoleTribe staff for giving me the possibility to +use their forum for the program support. + +Glue, endless hours spent understanding drive cache behaviour and rest of the +code are by me, Arep . + +Finally, obvious thanks go out to Nintendo for making all of their great +consoles, who constantly help me to waste the rest of my spare time I do not +spend coding ;). diff --git a/docs/NEWS b/docs/NEWS index c5c3208..57c27ec 100644 --- a/docs/NEWS +++ b/docs/NEWS @@ -1,53 +1,53 @@ -Since last official version original method 1 have been renamed to method 0 -and it undergone certain changes. Methods 2, 3, 4 have been renamed to 7, 8 -and 9 respectively. Method 0 should work with all drives as long as they -are supported by one of memory dump commands, so if drive is unrecognized it -is preferable to keep method at 0, and try all commands. If one of such -combinations turns out to work, you can proceed then testing other methods -with this commad. In case none of commands work, you could try to determine -drive's Read Buffer command's parameters with supplied 'BruteForce3C.exe'. - -Generally program's overall bahaviour regarding commandline haven't changed -and you should be able to use same options as with official versions, though -in case you were using unrecognized drive, which would nevertheless work with -Hitachi command, you'll need to set command to 2 now (e.g. --command 2) and -method to 7, 8 or 9. - -Performance have increased since official release and should be now about the -same as with 'RawDump'. - -Regarding supported drives: - -1. Hitachi-LG GDR8161B, GDR8162B, GDR8163B, GDR8164B, GDR8082N -Those drives can read GC/Wii media without swapping. Expected performance is -1600..1900 MB/h for *4B, *3B and 2100..2600 MB/h for *2B, *1B. Custom memory -dump command is used, which returns 2064 bytes of data. It was reproted that -they can not read other (e.g. PC) discs this way though, this needs -confirmation. - -2. Lite-On LH-18A1H, DVDRW LH-18A1P, DVDRW LH-20A1H, DVDRW LH-20A1P -Reading performance for PC DVDs can go up to 5000 MB/h, which means program's -core as well as new methods are capable to output data at least at this rate. -Reading performance for GC was about 1600..1700 MB/h so likely this slowdown is -caused by drive logic itself. Though I only had one GC game to test with, so -possibly better results can be achieved depending on media. Best results were -obtained, when using method 5 with parameter 16,27 (--method5=16,27). This -combination isn't set as default because it can cause noticable delays -depending on medium quality and to make methods more general for use with other -devices. Lite-On won't read GC/Wii DVDs at all without swapping. Lite-On -returns 2384 bytes of data (2064 + ECC) by means of vendor specific READ BUFFER -command. Tested with models LH-18A1H, LH-18A1P and LH-20A1H. - -3. Plextor -Plextor would return 2064 bytes of already unscrambled data with READ BUFFER -command. It works good with ordinary DVDs but due the lack of streamed reading -support is practically useless for GC/Wii dumping because of very low -performance. Works nevertheless and could be used for some experiments and -testing. Results from PX-760A. - -4. Toshiba Samsung SH-D162A, SH-D162B, SH-D162C, SH-D162D -Returns 2384 data bytes per sector like Lite-On does. Appears to support -streamed reading but performance with tested model (SH-D162D) was somewhat low -and unstable even with ordinary DVDs. Looks promising, if only good-working -method could be determined. Latest drives added, definitely need more testing -at this point. +Since last official version original method 1 have been renamed to method 0 +and it undergone certain changes. Methods 2, 3, 4 have been renamed to 7, 8 +and 9 respectively. Method 0 should work with all drives as long as they +are supported by one of memory dump commands, so if drive is unrecognized it +is preferable to keep method at 0, and try all commands. If one of such +combinations turns out to work, you can proceed then testing other methods +with this commad. In case none of commands work, you could try to determine +drive's Read Buffer command's parameters with supplied 'BruteForce3C.exe'. + +Generally program's overall bahaviour regarding commandline haven't changed +and you should be able to use same options as with official versions, though +in case you were using unrecognized drive, which would nevertheless work with +Hitachi command, you'll need to set command to 2 now (e.g. --command 2) and +method to 7, 8 or 9. + +Performance have increased since official release and should be now about the +same as with 'RawDump'. + +Regarding supported drives: + +1. Hitachi-LG GDR8161B, GDR8162B, GDR8163B, GDR8164B, GDR8082N +Those drives can read GC/Wii media without swapping. Expected performance is +1600..1900 MB/h for *4B, *3B and 2100..2600 MB/h for *2B, *1B. Custom memory +dump command is used, which returns 2064 bytes of data. It was reproted that +they can not read other (e.g. PC) discs this way though, this needs +confirmation. + +2. Lite-On LH-18A1H, DVDRW LH-18A1P, DVDRW LH-20A1H, DVDRW LH-20A1P +Reading performance for PC DVDs can go up to 5000 MB/h, which means program's +core as well as new methods are capable to output data at least at this rate. +Reading performance for GC was about 1600..1700 MB/h so likely this slowdown is +caused by drive logic itself. Though I only had one GC game to test with, so +possibly better results can be achieved depending on media. Best results were +obtained, when using method 5 with parameter 16,27 (--method5=16,27). This +combination isn't set as default because it can cause noticable delays +depending on medium quality and to make methods more general for use with other +devices. Lite-On won't read GC/Wii DVDs at all without swapping. Lite-On +returns 2384 bytes of data (2064 + ECC) by means of vendor specific READ BUFFER +command. Tested with models LH-18A1H, LH-18A1P and LH-20A1H. + +3. Plextor +Plextor would return 2064 bytes of already unscrambled data with READ BUFFER +command. It works good with ordinary DVDs but due the lack of streamed reading +support is practically useless for GC/Wii dumping because of very low +performance. Works nevertheless and could be used for some experiments and +testing. Results from PX-760A. + +4. Toshiba Samsung SH-D162A, SH-D162B, SH-D162C, SH-D162D +Returns 2384 data bytes per sector like Lite-On does. Appears to support +streamed reading but performance with tested model (SH-D162D) was somewhat low +and unstable even with ordinary DVDs. Looks promising, if only good-working +method could be determined. Latest drives added, definitely need more testing +at this point. diff --git a/docs/options b/docs/options index 4055e6d..feea5bb 100644 --- a/docs/options +++ b/docs/options @@ -1,64 +1,64 @@ -FriiDump 0.5.3 - Copyright (C) 2007 Arep -This software comes with ABSOLUTELY NO WARRANTY. -This is free software, and you are welcome to redistribute it -under certain conditions; see COPYING for details. - -Official support forum: http://wii.console-tribe.com - -Forum for this UNOFFICIAL VERSION: http://forum.redump.org - - -Available command line options: - - -h, --help Show this help - -a, --autodump Dump the disc to an ISO file with an - automatically-generated name, resuming the dump - if possible - -g, --gui Use more verbose output that can be easily - parsed by a GUI frontend - -d, --device Dump disc from device - -p, --stop Instruct device to stop disc rotation - -c, --command Force memory dump command: - 0 - vanilla 2064 - 1 - vanilla 2384 - 2 - Hitachi - 3 - Lite-On - 4 - Renesas - -x, --speed Set streaming speed (1, 24, 32, 64, etc., - where 1 = 150 KiB/s and so on) - -T, --type Force disc type: - 0 - GameCube - 1 - Wii - 2 - Wii_DL - 3 - DVD - -S, --size Force disc size - -r, --raw Output to file in raw format (2064-byte - sectors) - -i, --iso Output to file in ISO format (2048-byte - sectors) - -u, --unscramble Convert (unscramble) raw image contained in - to ISO format - -H, --nohash Do not compute CRC32/MD5/SHA-1 hashes - for generated files - -s, --resume Resume partial dump - - General ----------------------------------- - -0, --method0[=,] Use dumping method 0 (Optional argument - specifies how many sectors to request from disc - and read from cache at a time. Values should be - separated with a comma. Default 16,16) - - Non-Streaming ----------------------------- - -1, --method1[=,] Use dumping method 1 (Default 16,16) - -2, --method2[=,] Use dumping method 2 (Default 16,16) - -3, --method3[=,] Use dumping method 3 (Default 16,16) - - Streaming --------------------------------- - -4, --method4[=,] Use dumping method 4 (Default 27,27) - -5, --method5[=,] Use dumping method 5 (Default 27,27) - -6, --method6[=,] Use dumping method 6 (Default 27,27) - - Hitachi ----------------------------------- - -7, --method7 Use dumping method 7 (Read and dump 5 blocks - at a time, using streaming read) - -8, --method8 Use dumping method 8 (Read and dump 5 blocks - at a time, using streaming read, using DMA) - -9, --method9 Use dumping method 9 (Read and dump 5 blocks - at a time, using streaming read, using DMA and - some speed tricks) +FriiDump 0.5.3 - Copyright (C) 2007 Arep +This software comes with ABSOLUTELY NO WARRANTY. +This is free software, and you are welcome to redistribute it +under certain conditions; see COPYING for details. + +Official support forum: http://wii.console-tribe.com + +Forum for this UNOFFICIAL VERSION: http://forum.redump.org + + +Available command line options: + + -h, --help Show this help + -a, --autodump Dump the disc to an ISO file with an + automatically-generated name, resuming the dump + if possible + -g, --gui Use more verbose output that can be easily + parsed by a GUI frontend + -d, --device Dump disc from device + -p, --stop Instruct device to stop disc rotation + -c, --command Force memory dump command: + 0 - vanilla 2064 + 1 - vanilla 2384 + 2 - Hitachi + 3 - Lite-On + 4 - Renesas + -x, --speed Set streaming speed (1, 24, 32, 64, etc., + where 1 = 150 KiB/s and so on) + -T, --type Force disc type: + 0 - GameCube + 1 - Wii + 2 - Wii_DL + 3 - DVD + -S, --size Force disc size + -r, --raw Output to file in raw format (2064-byte + sectors) + -i, --iso Output to file in ISO format (2048-byte + sectors) + -u, --unscramble Convert (unscramble) raw image contained in + to ISO format + -H, --nohash Do not compute CRC32/MD5/SHA-1 hashes + for generated files + -s, --resume Resume partial dump + - General ----------------------------------- + -0, --method0[=,] Use dumping method 0 (Optional argument + specifies how many sectors to request from disc + and read from cache at a time. Values should be + separated with a comma. Default 16,16) + - Non-Streaming ----------------------------- + -1, --method1[=,] Use dumping method 1 (Default 16,16) + -2, --method2[=,] Use dumping method 2 (Default 16,16) + -3, --method3[=,] Use dumping method 3 (Default 16,16) + - Streaming --------------------------------- + -4, --method4[=,] Use dumping method 4 (Default 27,27) + -5, --method5[=,] Use dumping method 5 (Default 27,27) + -6, --method6[=,] Use dumping method 6 (Default 27,27) + - Hitachi ----------------------------------- + -7, --method7 Use dumping method 7 (Read and dump 5 blocks + at a time, using streaming read) + -8, --method8 Use dumping method 8 (Read and dump 5 blocks + at a time, using streaming read, using DMA) + -9, --method9 Use dumping method 9 (Read and dump 5 blocks + at a time, using streaming read, using DMA and + some speed tricks) diff --git a/libfriidump/CMakeLists.txt b/libfriidump/CMakeLists.txt index 759995f..51af292 100644 --- a/libfriidump/CMakeLists.txt +++ b/libfriidump/CMakeLists.txt @@ -1,105 +1,105 @@ -# Create a library called "Hello" which includes the source file "hello.cxx". -# The extension is already found. Any number of sources could be listed here. -add_library ( - friidumplib - ${libfriidump_type} - #SHARED - #STATIC - - brickblocker.h - brickblocker.c - byteorder.h - constants.h - disc.h - disc.c - dumper.h - dumper.c - dvd_drive.h - dvd_drive.c - hitachi.c - ecma-267.h - ecma-267.c - lite-on.c - misc.h - misc.c - renesas.c - rs.h - rs.c - unscrambler.h - unscrambler.c - vanilla_2064.c - vanilla_2384.c - win32compat.h - win32compat.c -) - -set_target_properties (friidumplib PROPERTIES OUTPUT_NAME "friidump") - -include_directories ( - ${FriiDump_SOURCE_DIR}/libmultihash -) - -# Make sure the linker can find the Hello library once it is built. -link_directories ( - ${FriiDump_BINARY_DIR}/libmultihash -) - -# Link the executable to the Hello library. -target_link_libraries ( - friidumplib - - multihashlib -) - -# Before making a release, the LTVERSION string should be modified. -# The string is of the form CURRENT:REVISION:AGE. -# -# CURRENT (C) -# The most recent interface number that this library implements. -# -# REVISION (R) -# The implementation number that this library implements. -# -# AGE (A) -# The difference between the newest and oldest interfaces that this -# library implements. In other works, the library implements all the -# interface numbers in the range from number 'CURRENT - AGE' to -# 'CURRENT'. -# -# This means that: -# -# - If interfaces have been changed or added, but binary compatibility has -# been preserved, change to C+1:0:A+1 -# -# - If binary compatibility has been broken (eg removed or changed -# interfaces) change to C+1:0:0 -# -# - If the interface is the same as the previous version, change to C:R+1:A -# -#set_target_properties (friidumplib PROPERTIES SOVERSION 1.0.0) - - -# Windows stuff to correctly build DLL or static library -#get_target_property (libfriidump_type friidumplib TYPE) -if (WIN32) - if (libfriidump_type STREQUAL "SHARED") -# MESSAGE ("Building libfriidump DLL") - ADD_DEFINITIONS (-DFRIIDUMPLIB_BUILD_DLL) - set_target_properties (friidumplib PROPERTIES DEFINE_SYMBOL FRIIDUMPLIB_EXPORTS) - - install ( - TARGETS friidumplib - RUNTIME DESTINATION / - #ARCHIVE DESTINATION lib - ) - endif (libfriidump_type STREQUAL "SHARED") -else (WIN32) - # Install stuff, only if a shared library is being built - if (libfriidump_type STREQUAL "SHARED") - install ( - TARGETS friidumplib - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib/static - ) - endif (libfriidump_type STREQUAL "SHARED") -endif (WIN32) +# Create a library called "Hello" which includes the source file "hello.cxx". +# The extension is already found. Any number of sources could be listed here. +add_library ( + friidumplib + ${libfriidump_type} + #SHARED + #STATIC + + brickblocker.h + brickblocker.c + byteorder.h + constants.h + disc.h + disc.c + dumper.h + dumper.c + dvd_drive.h + dvd_drive.c + hitachi.c + ecma-267.h + ecma-267.c + lite-on.c + misc.h + misc.c + renesas.c + rs.h + rs.c + unscrambler.h + unscrambler.c + vanilla_2064.c + vanilla_2384.c + win32compat.h + win32compat.c +) + +set_target_properties (friidumplib PROPERTIES OUTPUT_NAME "friidump") + +include_directories ( + ${FriiDump_SOURCE_DIR}/libmultihash +) + +# Make sure the linker can find the Hello library once it is built. +link_directories ( + ${FriiDump_BINARY_DIR}/libmultihash +) + +# Link the executable to the Hello library. +target_link_libraries ( + friidumplib + + multihashlib +) + +# Before making a release, the LTVERSION string should be modified. +# The string is of the form CURRENT:REVISION:AGE. +# +# CURRENT (C) +# The most recent interface number that this library implements. +# +# REVISION (R) +# The implementation number that this library implements. +# +# AGE (A) +# The difference between the newest and oldest interfaces that this +# library implements. In other works, the library implements all the +# interface numbers in the range from number 'CURRENT - AGE' to +# 'CURRENT'. +# +# This means that: +# +# - If interfaces have been changed or added, but binary compatibility has +# been preserved, change to C+1:0:A+1 +# +# - If binary compatibility has been broken (eg removed or changed +# interfaces) change to C+1:0:0 +# +# - If the interface is the same as the previous version, change to C:R+1:A +# +#set_target_properties (friidumplib PROPERTIES SOVERSION 1.0.0) + + +# Windows stuff to correctly build DLL or static library +#get_target_property (libfriidump_type friidumplib TYPE) +if (WIN32) + if (libfriidump_type STREQUAL "SHARED") +# MESSAGE ("Building libfriidump DLL") + ADD_DEFINITIONS (-DFRIIDUMPLIB_BUILD_DLL) + set_target_properties (friidumplib PROPERTIES DEFINE_SYMBOL FRIIDUMPLIB_EXPORTS) + + install ( + TARGETS friidumplib + RUNTIME DESTINATION / + #ARCHIVE DESTINATION lib + ) + endif (libfriidump_type STREQUAL "SHARED") +else (WIN32) + # Install stuff, only if a shared library is being built + if (libfriidump_type STREQUAL "SHARED") + install ( + TARGETS friidumplib + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static + ) + endif (libfriidump_type STREQUAL "SHARED") +endif (WIN32) diff --git a/libfriidump/disc.c b/libfriidump/disc.c index 6d76c2c..3333564 100644 --- a/libfriidump/disc.c +++ b/libfriidump/disc.c @@ -1,1675 +1,1675 @@ -/*************************************************************************** - * Copyright (C) 2007 by Arep * - * Support is provided through the forums at * - * http://wii.console-tribe.com * - * * - * 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. * - ***************************************************************************/ - -/*! \file - * \brief Analyser and dumper for Nintendo GameCube/Wii discs. - * - * The functions in this file can be used to retrieve information about a Nintendo GameCube/Wii optical disc. Information is both structural (i.e.: Number of - * sectors, partitions, etc) and game-related (i.e.: Game Title, version, etc). This is the main object that should be used by applications. - * - * Most of the disc structure information used in this file comes from http://www.gc-linux.org/docs/yagcd.html and - * http://www.wiili.org/index.php/GameCube_Optical_Disc . - */ - -#include "misc.h" -#include -#include -#include -//#include -#include "constants.h" -#include "byteorder.h" -#include "disc.h" -#include "dvd_drive.h" -#include "unscrambler.h" - -// #define cachedebug(...) debug (__VA_ARGS__); -#define cachedebug(...) - - -/* Cache always deals with 16-sector blocks. All numbers refer to the 16-sector blocks */ -#define DISC_MINIMUM_CACHE_SIZE 5 -#define DISC_DEFAULT_CACHE_SIZE 40 -#define CACHE_ENTRY_INVALID ((u_int32_t) -1) - - -#define DISC_GAMECUBE_SECTORS_NO 0x0AE0B0 /* 712880 */ -#define DISC_WII_SECTORS_NO_SL 0x230480 /* 2294912 */ -#define DISC_WII_SECTORS_NO_DL 0x3F69C0 /* 4155840 */ - - -#define MAX_READ_RETRIES 5 - -#define DEFAULT_READ_METHOD 0 -#define DEFAULT_READ_SECTOR disc_read_sector_0 - - -typedef int (*disc_read_sector_func) (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata); - -u_int8_t buf[1024*1024*4]; -u_int8_t buf_unscrambled[1024*1024*4]; - -//struct timeval tim; -//double t1, t2; - -/*! \brief A structure that represents a Nintendo GameCube/Wii optical disc. - */ -struct disc_s { - dvd_drive *dvd; //!< The structure for the DVD-drive the disc is inserted in. - disc_type type; //!< The disc type. - char system_id; //!< A letter identifying the target system. - char game_id[2 + 1]; //!< Two letters identifying the game. - disc_region region; //!< The disc region. - char maker[3]; //!< Two letters identifying the maker of the game. - u_int8_t version; //!< A number identifying the game version. - char *version_string; //!< The same as version, in a more human-understandable format. - char *title; //!< The game title. - bool has_update; //!< True if the game contains a system update (Only possible for Wii discs). - u_int32_t sectors_no; //!< The number of sectors of the disc. - u_int32_t layerbreak; //!< For dual-layer DVDs. - - u_int32_t sec_disc; - u_int32_t sec_mem; - u_int32_t max_cnt; - u_int32_t max_blk; - - /* Read function & stuff */ - int command; //!< Buffer access command ID. - int read_method; //!< The read method ID. -// int def_read_method; //!< Default read method ID. - disc_read_sector_func read_sector; //!< The actual function that will be used to perform read operations, corresponding to read_method. - bool unscrambling; //!< If true, raw data read from the disc will be unscrambled to assure it is error-free. Disabling this is only useful for raw performance tests. - unscrambler *u; //!< The unscrambler structure that will be used to perform the unscrambling. - - /* Read cache */ - u_int32_t cache_size; //!< The number of blocks that will be cached when read. - u_int8_t **raw_cache; //!< Memory area for raw sectors cache. - u_int8_t **cache; //!< Memory area for unscrambled sectors cache. - u_int32_t *cache_map; //!< Data structure used by the caching system to know which blocks are in memory. -}; - - -static void disc_cache_init (disc *d, u_int32_t size) { - u_int32_t i; - - if (size < DISC_MINIMUM_CACHE_SIZE) { - error ("Invalid cache size %u (must be >= %u)", size, DISC_MINIMUM_CACHE_SIZE); - exit (3); - } else { - d -> cache_size = size; - d -> cache = (u_int8_t **) malloc (sizeof (u_int8_t *) * size); - d -> raw_cache = (u_int8_t **) malloc (sizeof (u_int8_t *) * size); - for (i = 0; i < size; i++) { - d -> cache[i] = (u_int8_t *) malloc (sizeof (u_int8_t) * BLOCK_SIZE); - d -> raw_cache[i] = (u_int8_t *) malloc (sizeof (u_int8_t) * RAW_BLOCK_SIZE); - } - - d -> cache_map = (u_int32_t *) malloc (sizeof (u_int32_t) * size); - for (i = 0; i < size; i++) - d -> cache_map[i] = CACHE_ENTRY_INVALID; - } - - return; -} - - -static void disc_cache_destroy (disc *d) { - u_int32_t i; - - my_free (d -> cache_map); - - for (i = 0; i < d -> cache_size; i++) { - my_free (d -> cache[i]); - my_free (d -> raw_cache[i]); - } - my_free (d -> cache); - my_free (d -> raw_cache); - d -> cache_size = 0; - - return; -} - - -void disc_cache_add_block (disc *d, u_int32_t block, u_int8_t *data, u_int8_t *rawdata) { - u_int32_t pos; - u_int32_t cnt; - - pos = block % d -> cache_size; - //uniform unscrambled output - memcpy (d -> cache[pos], data, BLOCK_SIZE); - if (d -> type == DISC_TYPE_DVD) { - for (cnt = 0; cnt < SECTORS_PER_BLOCK; cnt++) { - memcpy (rawdata+(cnt*RAW_SECTOR_SIZE)+12, data+(cnt*SECTOR_SIZE), SECTOR_SIZE); - } - } else { - for (cnt = 0; cnt < SECTORS_PER_BLOCK; cnt++) { - memcpy (rawdata+(cnt*RAW_SECTOR_SIZE)+6, data+(cnt*SECTOR_SIZE), SECTOR_SIZE); - } - } - memcpy (d -> raw_cache[pos], rawdata, RAW_BLOCK_SIZE); - d -> cache_map[pos] = block; - - cachedebug ("Cached block %u (sectors %u-%u) at position %u", block, block * SECTORS_PER_BLOCK, (block + 1) * SECTORS_PER_BLOCK - 1, pos); - - return; -} - - -static bool disc_cache_lookup_block (disc *d, u_int32_t block, u_int8_t **data, u_int8_t **rawdata) { - u_int32_t pos; - bool out; - - pos = block % d -> cache_size; - - if (d -> cache_map[pos] == block) { - cachedebug ("Cache HIT for block %u", block); - if (data) - *data = d -> cache[pos]; - if (rawdata) - *rawdata = d -> raw_cache[pos]; - out = true; - } else { - cachedebug ("Cache MISS for block %u", block); - if (data) - *data = NULL; - if (rawdata) - *rawdata = NULL; - out = false; - } - - return (out); -} - - -static int disc_read_sector_generic (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata, u_int32_t method) { - bool out; - u_int32_t start_block; - int ret, retry; - u_int32_t step, cnt, max_cnt, max_blk; - u_int32_t block_len, block_size, _block_size, last_block_size, block_cnt; -//fprintf (stdout,"disc_read_sector_%d", method); - start_block = sector_no / SECTORS_PER_BLOCK; - - out = false; - step = d->sec_mem; - max_cnt = d->max_cnt; - max_blk = d->max_blk; - - block_size = step*2064; - last_block_size = block_size; - block_len = 1; - if (block_size > 27 * 2064) { - block_len = block_size / (27*2064); - if (block_size % (27*2064) != 0) block_len += 1; - block_size = 27*2064; - last_block_size = (step*2064) - (27*2064*(block_len-1)); - } - _block_size=block_size; - - for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { - /* Assume everything will turn out well */ - out = true; - - //Streaming read - if (retry < 3) { - cnt=0; - while (cnt <= max_cnt){ - - _block_size=block_size; - if (method == 0 || method == 1 || method == 4) { - if (sector_no+(cnt*step) +992 +16 <= d -> sectors_no) //smaller than last sector - dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step) +992, 16, NULL, NULL, 0); - else if (sector_no+(cnt*step) -992 >= 0) //larger than first sector - dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step) -992, 16, NULL, NULL, 0); - else dvd_flush_cache_READ12 (d -> dvd, sector_no+(cnt*step), NULL); - } - - if (method == 0 || method == 2 || method == 5) dvd_flush_cache_READ12 (d -> dvd, sector_no+(cnt*step), NULL); - if (method == 0 || method == 1 || method == 2 || method == 3) ret = dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step), d->sec_disc, NULL, &buf_unscrambled[0], 2064*step); - if (method == 4 || method == 5 || method == 6) ret = dvd_read_streaming (d -> dvd, sector_no+(cnt*step), d->sec_disc, NULL, &buf_unscrambled[0], 2064*step); - if (ret >= 0) { - for (block_cnt=0; block_cnt dvd, block_cnt*27*2064, 1, _block_size, &buf[(cnt*(2064 * step))+(block_cnt*27*2064)]) < 0) { - error ("Memdump failed"); - //retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ //no it's not! - out = false; - break; - } - if (block_cnt==block_len-1) _block_size = last_block_size; - } - if (!out) break; - //do this check only on 1st layer - else if (((buf[cnt*(2064*step)] & 1) == 0) && ((buf[cnt*(2064*step)+1]<<16)+(buf[cnt*(2064*step)+2]<<8)+(buf[cnt*(2064*step)+3]) != 0x30000 + sector_no+(cnt*step))) { - out = false; - break; - } - else cnt += 1; - } else { - error ("dvd_read_streaming() failed with %d", ret); - out = false; - break; - } - - } - - if (cnt < max_cnt) out = false; - else { -#ifdef DEBUG - if (d -> unscrambling) { -#endif - /* Try to unscramble all data to see if EDC fails */ - //for(cnt=0; cnt <= 4; cnt++) { - for(cnt=max_blk; cnt--;) { - if (!unscrambler_unscramble_16sectors (d -> u, sector_no+(cnt*16), &buf[cnt*(2064*16)], &buf_unscrambled[cnt*(2048*16)])) - out = false; - } -#ifdef DEBUG - } -#endif - } - if (out) { - /* If data were unscrambled correctly, add them to the cache */ - //for(cnt = 0; cnt <= 4; cnt++) { - for(cnt=max_blk; cnt--;) { - disc_cache_add_block (d, start_block+cnt, &buf_unscrambled[cnt*(2048*16)], &buf[cnt*(2064*16)]); - } - } - } //if (retry < 3) - - //Simple read on 4rth try - else { - if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector - dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); - else if (sector_no -992 >= 0) //larger than first sector - dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); - else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); - - dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); - ret = dvd_read_sector_dummy (d -> dvd, sector_no, SECTORS_PER_BLOCK, NULL, NULL, 0); - if (ret >= 0) { - if (dvd_memdump (d -> dvd, 0, 1, RAW_BLOCK_SIZE, buf) < 0) { - error ("Memdump failed"); - //retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ - out = false; - } - else if ( ((*(buf) & 1) == 0) && ((*(buf+1)<<16)+(*(buf+2)<<8)+(*(buf+3)) != 0x30000+sector_no) ) out = false; - else { -#ifdef DEBUG - if (d -> unscrambling) { -#endif - /* Try to unscramble all data to see if EDC fails */ - if (!unscrambler_unscramble_16sectors (d -> u, sector_no, buf, buf_unscrambled)) - out = false; -#ifdef DEBUG - } -#endif - } - if (out) { - /* If data were unscrambled correctly, add them to the cache */ - disc_cache_add_block (d, start_block, buf_unscrambled, buf); - } - } else { - error ("dvd_read_sector_dummy() failed with %d", ret); - out = false; - } - } //else - } //for - - if (!out) - error ("Too many retries, giving up"); - - return (out); -} - - -///////////////////////////// General ///////////////////////////// -static int disc_read_sector_0 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 0); -} - - - -////////////////////////// Non-Streaming ////////////////////////// -static int disc_read_sector_1 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 1); - -} - -static int disc_read_sector_2 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 2); - -} - - -static int disc_read_sector_3 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 3); - -} - - - -//////////////////////////// Streaming //////////////////////////// -static int disc_read_sector_4 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 4); -} - - -static int disc_read_sector_5 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 5); -} - - -static int disc_read_sector_6 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - return disc_read_sector_generic (d, sector_no, data, rawdata, 6); -} - - - -///////////////////////////// Hitachi ///////////////////////////// -static int disc_read_sector_7 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - bool out; - u_int32_t start_block; - int j, ret, retry; - u_int8_t buf[5][16 * 2064]; - u_int8_t buf_unscrambled[5][16 * 2048]; -//fprintf (stdout,"disc_read_sector_7"); - start_block = sector_no / SECTORS_PER_BLOCK; - - out = false; - for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { - /* Assume everything will turn out well */ - out = true; - - if (retry > 0) { - warning ("Read retry %d for sector %u", retry, sector_no); - - /* Try to reset in-memory data by seeking to a distant sector */ -// if (sector_no > 1000) -// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0); -// else -// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0); - if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector - dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); - else if (sector_no -992 >= 0) //larger than first sector - dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); - else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); - } - - if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, NULL, 0)) >= 0) { - for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { - if (dvd_memdump (d -> dvd, 0 + (j * 16 * 2064), 1, 16 * 2064, buf[j]) < 0) { /* Dumping in a single block is faster */ - error ("Memdump failed"); - out = false; - retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ - } else { -#ifdef DEBUG - if (d -> unscrambling) { -#endif - /* Try to unscramble all data to see if EDC fails */ - if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j])) - out = false; -#ifdef DEBUG - } -#endif - } - } - - if (out) { - /* It seems all data was unscrambled correctly, so cache them out */ - for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no; j++) - disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]); - - } - } else { - error ("dvd_read_sector_streaming() failed with %d", ret); - out = false; - } - } - - if (!out) - error ("Too many retries, giving up"); - - return (out); -} - - -static int disc_read_sector_8 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - bool out; - u_int32_t ram_offset; - int j, k, ret, retry; - u_int8_t *sect, buf[5][RAW_BLOCK_SIZE]; - u_int8_t readbuf[BLOCK_SIZE]; - u_int8_t buf_unscrambled[5][BLOCK_SIZE]; - u_int32_t start_block; -//fprintf (stdout,"disc_read_sector_8"); - start_block = sector_no / SECTORS_PER_BLOCK; - - out = false; - for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { - /* Assume everything will turn out well */ - out = true; - - if (retry > 0) { - warning ("Read retry %d for sector %u", retry, sector_no); - - /* Try to reset in-memory data by seeking to a distant sector */ -// if (sector_no > 1000) -// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0); -// else -// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0); - if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector - dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); - else if (sector_no -992 >= 0) //larger than first sector - dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); - else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); - } - - /* First READ command, this will cache 5 16-sector blocks. Immediately dump relevant data */ - if (sector_no > d -> sectors_no - 1000) - dvd_read_sector_streaming (d -> dvd, sector_no - 16 * 5 * 2, NULL, NULL, 0); - else - dvd_read_sector_streaming (d -> dvd, sector_no + 16 * 5, NULL, NULL, 0); - if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, readbuf, sizeof (readbuf))) >= 0) { - for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { - /* Reconstruct raw sectors */ - for (k = 0; k < 16; k++) { - sect = &buf[j][k * RAW_SECTOR_SIZE]; - ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE; - /* Get first 12 bytes (ID. IED and CPR_MAI fields) and last 4 bytes (EDC field) with memdump */ - if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) { - error ("Memdump (1) failed"); - out = false; - retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ - } else if (dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060) < 0) { /* Dumping in a single block is faster */ - error ("Memdump (2) failed"); - out = false; - } - } - } - - /* Now the same for remaining 4 16-sector blocks */ - for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { - if (j == 0 || (ret = dvd_read_sector_streaming (d -> dvd, sector_no + j * 16, NULL, readbuf, sizeof (readbuf))) >= 0) { - /* Copy "user data" field which has been incorrectly unscrambled by the DVD drive firmware */ - for (k = 0; k < 16; k++) { - sect = &buf[j][k * RAW_SECTOR_SIZE]; - memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE); - } -#ifdef DEBUG - if (d -> unscrambling) { -#endif - /* Try to unscramble all data to see if EDC fails */ - if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j])) - out = false; -#ifdef DEBUG - } -#endif - } else { - error ("dvd_read_sector_streaming() failed with %d", ret); - out = false; - } - } - - if (out) { - /* It seems all data were unscrambled correctly, so cache them out */ - for (j = 0; j < 5 && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++) - disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]); - } - } else { - error ("dvd_read_sector_streaming() failed with %d", ret); - out = false; - } - } - - if (!out) - error ("Too many retries, giving up"); - - return (out); -} - - -static int disc_read_sector_9 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - bool out; - u_int32_t ram_offset; - int j, k, ret, retry; - u_int8_t *sect, buf[5][RAW_BLOCK_SIZE]; - u_int8_t readbuf[BLOCK_SIZE], tmp[16]; - u_int8_t buf_unscrambled[5][BLOCK_SIZE]; - u_int32_t start_block; -//fprintf (stdout,"disc_read_sector_9"); - start_block = sector_no / SECTORS_PER_BLOCK; - - out = false; - for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { - /* Assume everything will turn out well */ - out = true; - - if (retry > 0) { - warning ("Read retry %d for sector %u", retry, sector_no); - - /* Try to reset in-memory data by seeking to a distant sector */ -// if (sector_no > 1000) -// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0); -// else -// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0); - if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector - dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); - else if (sector_no -992 >= 0) //larger than first sector - dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); - else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); - } - - /* First READ command, this will cache 5 16-sector blocks. Immediately dump relevant data */ - if (sector_no > d -> sectors_no - 1000) - dvd_read_sector_streaming (d -> dvd, sector_no - 16 * 5 * 2, NULL, NULL, 0); - else - dvd_read_sector_streaming (d -> dvd, sector_no + 16 * 5, NULL, NULL, 0); - if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, readbuf, BLOCK_SIZE)) >= 0) { - for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { - /* Reconstruct raw sectors */ - for (k = 0; k < 16; k++) { - sect = &buf[j][k * RAW_SECTOR_SIZE]; - ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE; - /* Get first 12 bytes (ID. IED and CPR_MAI fields) and last 4 bytes (EDC field) with memdump */ - if (j == 0 && k == 0) { - if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) { - error ("Memdump (1) failed"); - out = false; - retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ - } - } else { - memcpy (sect, tmp + 4, 12); - } - - if (out && dvd_memdump (d -> dvd, ram_offset + 2060, 1, 16, tmp) < 0) { /* Dumping in a single block is faster */ - error ("Memdump (2) failed"); - out = false; - } else { - memcpy (sect + 2060, tmp, 4); - } - } - } - - /* Now the same for remaining 4 16-sector blocks */ - for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { - if (j == 0 || (ret = dvd_read_sector_streaming (d -> dvd, sector_no + j * 16, NULL, readbuf, BLOCK_SIZE)) >= 0) { - /* Copy "user data" field which has been incorrectly unscrambled by the DVD drive firmware */ - for (k = 0; k < 16; k++) { - sect = &buf[j][k * RAW_SECTOR_SIZE]; - memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE); - } -#ifdef DEBUG - if (d -> unscrambling) { -#endif - /* Try to unscramble all data to see if EDC fails */ - if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j])) - out = false; -#ifdef DEBUG - } -#endif - } else { - error ("dvd_read_sector_streaming() failed with %d", ret); - out = false; - } - } - - if (out) { - /* It seems all data were unscrambled correctly, so cache them out */ - for (j = 0; j < 5 && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++) - disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]); - } - } else { - error ("dvd_read_sector_streaming() failed with %d", ret); - out = false; - } - } - - if (!out) - error ("Too many retries, giving up"); - - return (out); -} - - -/* We could also use the 'System ID' (first byte of the image) to tell the discs apart */ -static disc_type disc_detect_type (disc *d, u_int32_t forced_type, u_int32_t sectors_no) { - req_sense sense; - - if (forced_type==0) { - d -> type = DISC_TYPE_GAMECUBE; - d -> sectors_no = DISC_GAMECUBE_SECTORS_NO; - } else if (forced_type==1) { - d -> type = DISC_TYPE_WII; - d -> sectors_no = DISC_WII_SECTORS_NO_SL; - } else if (forced_type==2) { - d -> type = DISC_TYPE_WII_DL; - d -> sectors_no = DISC_WII_SECTORS_NO_DL; - //dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL); - } else if (forced_type==3) { - d -> type = DISC_TYPE_DVD; - if (sectors_no == -1) dvd_get_size(d->dvd, &(d -> sectors_no), NULL); - dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL); - } else { - - /* Try to read a sector beyond the end of GameCube discs */ - if (!dvd_read_sector_dummy (d -> dvd, DISC_GAMECUBE_SECTORS_NO + 100, SECTORS_PER_BLOCK, &sense, NULL, 0) && sense.sense_key == 0x05 && sense.asc == 0x21) { - d -> type = DISC_TYPE_GAMECUBE; - d -> sectors_no = DISC_GAMECUBE_SECTORS_NO; - } else { - if (!dvd_read_sector_dummy (d -> dvd, DISC_WII_SECTORS_NO_SL + 100, SECTORS_PER_BLOCK, &sense, NULL, 0) && sense.sense_key == 0x05 && sense.asc == 0x21) { - d -> type = DISC_TYPE_WII; - d -> sectors_no = DISC_WII_SECTORS_NO_SL; - } else { - d -> type = DISC_TYPE_WII_DL; - d -> sectors_no = DISC_WII_SECTORS_NO_DL; - //dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL); - } - } - - } - if (sectors_no != -1) d -> sectors_no = sectors_no; - - return (d -> type); -} - - -/** - * Reads a sector from the disc (or from the cache), using the preset read method. - * @param d The disc structure. - * @param sector_no The requested sector number. - * @param data A buffer to hold the unscrambled sector data (or NULL). - * @param rawdata A buffer to hold the raw sector data (or NULL). - * @return - */ -int disc_read_sector (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { - u_int32_t block; - u_int8_t *cdata, *crawdata; - int out; - - /* Unscrambled data cannot be requested if unscrambling was disabled */ - MY_ASSERT (!(data && !d -> unscrambling)); - - block = sector_no / SECTORS_PER_BLOCK; - - /* See if sector is in cache */ - if (!(out = disc_cache_lookup_block (d, block, &cdata, &crawdata))) { - /* Requested block is not in cache, try to read it from media */ - out = d -> read_sector (d, sector_no, data, rawdata); - - /* Now requested sector is in cache, for sure ;) */ - if (out) - MY_ASSERT (disc_cache_lookup_block (d, block, &cdata, &crawdata)); - } - - if (out) { - if (data) - *data = cdata + (sector_no % SECTORS_PER_BLOCK) * SECTOR_SIZE; - if (rawdata) - *rawdata = crawdata + (sector_no % SECTORS_PER_BLOCK) * RAW_SECTOR_SIZE; - } else { - if (data) - *data = NULL; - if (rawdata) - *rawdata = NULL; - } - - return (out); -} - - -static bool disc_analyze (disc *d) { - u_int8_t *buf; - char tmp[0x03E0 + 1]; - bool unscramble_old, out; - - /* Force unscrambling for this read */ - unscramble_old = d -> unscrambling; - disc_set_unscrambling (d, true); - - if (disc_read_sector (d, 0, &buf, NULL)) { - /* System ID */ - d -> system_id = buf[0]; -// if (d -> system_id == 'G') { -// d -> type = DISC_TYPE_GAMECUBE; -// d -> sectors_no = DISC_GAMECUBE_SECTORS_NO; -// } else if (d -> system_id == 'R') { -// d -> type = DISC_TYPE_WII; -// d -> sectors_no = DISC_WII_SECTORS_NO; -// } else { -// error ("Unknown system ID: '%c'", d -> system_id); -// MY_ASSERT (false); -// } - - /* Game ID */ - strncpy (d -> game_id, (char *) buf + 1, 2); - d -> game_id[2] = '\0'; - - /* Region */ - switch (buf[3]) { - case 'P': - d -> region = DISC_REGION_PAL; - break; - case 'E': - d -> region = DISC_REGION_NTSC; - break; - case 'J': - d -> region = DISC_REGION_JAPAN; - break; - case 'U': - d -> region = DISC_REGION_AUSTRALIA; - break; - case 'F': - d -> region = DISC_REGION_FRANCE; - break; - case 'D': - d -> region = DISC_REGION_GERMANY; - break; - case 'I': - d -> region = DISC_REGION_ITALY; - break; - case 'S': - d -> region = DISC_REGION_SPAIN; - break; - case 'X': - d -> region = DISC_REGION_PAL_X; - break; - case 'Y': - d -> region = DISC_REGION_PAL_Y; - break; - default: - d -> region = DISC_REGION_UNKNOWN; - break; - } - - /* Maker code */ - strncpy (d -> maker, (char *) buf + 4, 2); - d -> maker[2] = '\0'; - - /* Version */ - d -> version = buf[7]; - snprintf (tmp, sizeof (tmp), "1.%02u", d -> version); - my_strdup (d -> version_string, tmp); - - /* Game title */ - memcpy (tmp, buf + 0x0020, sizeof (tmp) - 1); - tmp[sizeof (tmp) - 1] = '\0'; - strtrimr (tmp); - my_strdup (d -> title, tmp); - - out = true; - } else { - error ("Cannot analyze disc"); - out = false; - } - - disc_set_unscrambling (d, unscramble_old); - - return (out); -} - - -static char disc_type_strings[4][15] = { - "GameCube", - "Wii", - "Wii_DL", - "DVD" -}; - -/** - * Retrieves the disc type. - * @param d The disc structure. - * @param dt This will be set to the disc type. - * @param dt_s This will point to a string describing the disc type. - * @return A string describing the disc type. - */ -char *disc_get_type (disc *d, disc_type *dt, char **dt_s) { - if (dt) - *dt = d -> type; - - if (dt_s) { - if (d -> type < DISC_TYPE_DVD) - *dt_s = disc_type_strings[d -> type]; - else - *dt_s = disc_type_strings[DISC_TYPE_DVD]; - } - - return (*dt_s); -} - - -/** - * Retrieves the disc game ID. - * @param d The disc structure. - * @param gid_s This will point to a string containing the game ID. - * @return A string containing the game ID. - */ -char *disc_get_gameid (disc *d, char **gid_s) { - if (gid_s) - *gid_s = d -> game_id; - - return (*gid_s); -} - - -static char disc_region_strings[11][15] = { - "Europe/PAL", - "USA/NTSC", - "Japan/NTSC", - "Australia/PAL", - "France/PAL", - "Germany/PAL", - "Italy/PAL", - "Spain/PAL", - "Europe(X)/PAL", - "Europe(Y)/PAL", - "Unknown" -}; - -/** - * Retrieves the disc region. - * @param d The disc structure. - * @param dr This will be set to the disc region. - * @param dr_s This will point to a string describing the disc region. - * @return A string describing the disc region. - */ -char *disc_get_region (disc *d, disc_region *dr, char **dr_s) { - if (dr) - *dr = d -> region; - - if (dr_s) { - if (d -> region < DISC_REGION_UNKNOWN) - *dr_s = disc_region_strings[d -> region]; - else - *dr_s = disc_region_strings[DISC_REGION_UNKNOWN]; - } - - return (*dr_s); -} - - -/* The following list has been derived from http://wiitdb.com/Company/HomePage */ -static struct { - char *code; - char *name; -} makers[] = { - {"0A", "Jaleco"}, - {"0B", "Coconuts Japan"}, - {"0C", "Coconuts Japan / G.X.Media"}, - {"0D", "Micronet"}, - {"0E", "Technos"}, - {"0F", "Mebio Software"}, - {"0G", "Shouei System"}, - {"0H", "Starfish"}, - {"0J", "Mitsui Fudosan / Dentsu"}, - {"0L", "Warashi Inc."}, - {"0N", "Nowpro"}, - {"0P", "Game Village"}, - {"0Q", "IE Institute"}, - {"01", "Nintendo"}, - {"02", "Rocket Games / Ajinomoto"}, - {"03", "Imagineer-Zoom"}, - {"04", "Gray Matter"}, - {"05", "Zamuse"}, - {"06", "Falcom"}, - {"07", "Enix"}, - {"08", "Capcom"}, - {"09", "Hot B Co."}, - {"1A", "Yanoman"}, - {"1C", "Tecmo Products"}, - {"1D", "Japan Glary Business"}, - {"1E", "Forum / OpenSystem"}, - {"1F", "Virgin Games (Japan)"}, - {"1G", "SMDE"}, - {"1J", "Daikokudenki"}, - {"1P", "Creatures Inc."}, - {"1Q", "TDK Deep Impresion"}, - {"2A", "Culture Brain"}, - {"2C", "Palsoft"}, - {"2D", "Visit Co.,Ltd."}, - {"2E", "Intec"}, - {"2F", "System Sacom"}, - {"2G", "Poppo"}, - {"2H", "Ubisoft Japan"}, - {"2J", "Media Works"}, - {"2K", "NEC InterChannel"}, - {"2L", "Tam"}, - {"2M", "Jordan"}, - {"2N", "Smilesoft / Rocket"}, - {"2Q", "Mediakite"}, - {"3B", "Arcade Zone Ltd"}, - {"3C", "Entertainment International / Empire Software"}, - {"3D", "Loriciel"}, - {"3E", "Gremlin Graphics"}, - {"3F", "K.Amusement Leasing Co."}, - {"4B", "Raya Systems"}, - {"4C", "Renovation Products"}, - {"4D", "Malibu Games"}, - {"4F", "Eidos"}, - {"4G", "Playmates Interactive"}, - {"4J", "Fox Interactive"}, - {"4K", "Time Warner Interactive"}, - {"4Q", "Disney Interactive"}, - {"4S", "Black Pearl"}, - {"4U", "Advanced Productions"}, - {"4X", "GT Interactive"}, - {"4Y", "RARE"}, - {"4Z", "Crave Entertainment"}, - {"5A", "Mindscape / Red Orb Entertainment"}, - {"5B", "Romstar"}, - {"5C", "Taxan"}, - {"5D", "Midway / Tradewest"}, - {"5F", "American Softworks"}, - {"5G", "Majesco Sales Inc"}, - {"5H", "3DO"}, - {"5K", "Hasbro"}, - {"5L", "NewKidCo"}, - {"5M", "Telegames"}, - {"5N", "Metro3D"}, - {"5P", "Vatical Entertainment"}, - {"5Q", "LEGO Media"}, - {"5S", "Xicat Interactive"}, - {"5T", "Cryo Interactive"}, - {"5W", "Red Storm Entertainment"}, - {"5X", "Microids"}, - {"5Z", "Data Design / Conspiracy / Swing"}, - {"6B", "Laser Beam"}, - {"6E", "Elite Systems"}, - {"6F", "Electro Brain"}, - {"6G", "The Learning Company"}, - {"6H", "BBC"}, - {"6J", "Software 2000"}, - {"6K", "UFO Interactive Games"}, - {"6L", "BAM! Entertainment"}, - {"6M", "Studio 3"}, - {"6Q", "Classified Games"}, - {"6S", "TDK Mediactive"}, - {"6U", "DreamCatcher"}, - {"6V", "JoWood Produtions"}, - {"6W", "Sega"}, - {"6X", "Wannado Edition"}, - {"6Y", "LSP (Light & Shadow Prod.)"}, - {"6Z", "ITE Media"}, - {"7A", "Triffix Entertainment"}, - {"7C", "Microprose Software"}, - {"7D", "Sierra / Universal Interactive"}, - {"7F", "Kemco"}, - {"7G", "Rage Software"}, - {"7H", "Encore"}, - {"7J", "Zoo"}, - {"7K", "Kiddinx"}, - {"7L", "Simon & Schuster Interactive"}, - {"7M", "Asmik Ace Entertainment Inc."}, - {"7N", "Empire Interactive"}, - {"7Q", "Jester Interactive"}, - {"7S", "Rockstar Games"}, - {"7T", "Scholastic"}, - {"7U", "Ignition Entertainment"}, - {"7V", "Summitsoft"}, - {"7W", "Stadlbauer"}, - {"8B", "BulletProof Software (BPS)"}, - {"8C", "Vic Tokai Inc."}, - {"8E", "Character Soft"}, - {"8F", "I'Max"}, - {"8G", "Saurus"}, - {"8J", "General Entertainment"}, - {"8N", "Success"}, - {"8P", "Sega Japan"}, - {"9A", "Nichibutsu / Nihon Bussan"}, - {"9B", "Tecmo"}, - {"9C", "Imagineer"}, - {"9F", "Nova"}, - {"9G", "Take2 / Den'Z / Global Star"}, - {"9H", "Bottom Up"}, - {"9J", "TGL (Technical Group Laboratory)"}, - {"9L", "Hasbro Japan"}, - {"9N", "Marvelous Entertainment"}, - {"9P", "Keynet Inc."}, - {"9Q", "Hands-On Entertainment"}, - {"12", "Infocom"}, - {"13", "Electronic Arts Japan"}, - {"15", "Cobra Team"}, - {"16", "Human / Field"}, - {"17", "KOEI"}, - {"18", "Hudson Soft"}, - {"19", "S.C.P."}, - {"20", "Destination Software / Zoo Games / KSS"}, - {"21", "Sunsoft / Tokai Engineering"}, - {"22", "POW (Planning Office Wada) / VR1 Japan"}, - {"23", "Micro World"}, - {"25", "San-X"}, - {"26", "Enix"}, - {"27", "Loriciel / Electro Brain"}, - {"28", "Kemco Japan"}, - {"29", "Seta"}, - {"30", "Viacom"}, - {"31", "Carrozzeria"}, - {"32", "Dynamic"}, - {"34", "Magifact"}, - {"35", "Hect"}, - {"36", "Codemasters"}, - {"37", "Taito / GAGA Communications"}, - {"38", "Laguna"}, - {"39", "Telstar / Event / Taito"}, - {"40", "Seika Corp."}, - {"41", "Ubi Soft Entertainment"}, - {"42", "Sunsoft US"}, - {"44", "Life Fitness"}, - {"46", "System 3"}, - {"47", "Spectrum Holobyte"}, - {"49", "IREM"}, - {"50", "Absolute Entertainment"}, - {"51", "Acclaim"}, - {"52", "Activision"}, - {"53", "American Sammy"}, - {"54", "Take 2 Interactive / GameTek"}, - {"55", "Hi Tech"}, - {"56", "LJN LTD."}, - {"58", "Mattel"}, - {"60", "Titus"}, - {"61", "Virgin Interactive"}, - {"62", "Maxis"}, - {"64", "LucasArts Entertainment"}, - {"67", "Ocean"}, - {"68", "Bethesda Softworks"}, - {"69", "Electronic Arts"}, - {"70", "Atari (Infogrames)"}, - {"71", "Interplay"}, - {"72", "JVC (US)"}, - {"73", "Parker Brothers"}, - {"75", "Sales Curve (Storm / SCI)"}, - {"78", "THQ"}, - {"79", "Accolade"}, - {"80", "Misawa"}, - {"81", "Teichiku"}, - {"82", "Namco Ltd."}, - {"83", "LOZC"}, - {"84", "KOEI"}, - {"86", "Tokuma Shoten Intermedia"}, - {"87", "Tsukuda Original"}, - {"88", "DATAM-Polystar"}, - {"90", "Takara Amusement"}, - {"91", "Chun Soft"}, - {"92", "Video System / Mc O' River"}, - {"93", "BEC"}, - {"95", "Varie"}, - {"96", "Yonezawa / S'pal"}, - {"97", "Kaneko"}, - {"99", "Marvelous Entertainment"}, - {"A0", "Telenet"}, - {"A1", "Hori"}, - {"A4", "Konami"}, - {"A5", "K.Amusement Leasing Co."}, - {"A6", "Kawada"}, - {"A7", "Takara"}, - {"A9", "Technos Japan Corp."}, - {"AA", "JVC / Victor"}, - {"AC", "Toei Animation"}, - {"AD", "Toho"}, - {"AF", "Namco"}, - {"AG", "Media Rings Corporation"}, - {"AH", "J-Wing"}, - {"AJ", "Pioneer LDC"}, - {"AK", "KID"}, - {"AL", "Mediafactory"}, - {"AP", "Infogrames / Hudson"}, - {"AQ", "Kiratto. Ludic Inc"}, - {"B0", "Acclaim Japan"}, - {"B1", "ASCII"}, - {"B2", "Bandai"}, - {"B4", "Enix"}, - {"B6", "HAL Laboratory"}, - {"B7", "SNK"}, - {"B9", "Pony Canyon"}, - {"BA", "Culture Brain"}, - {"BB", "Sunsoft"}, - {"BC", "Toshiba EMI"}, - {"BD", "Sony Imagesoft"}, - {"BF", "Sammy"}, - {"BG", "Magical"}, - {"BH", "Visco"}, - {"BJ", "Compile"}, - {"BL", "MTO Inc."}, - {"BN", "Sunrise Interactive"}, - {"BP", "Global A Entertainment"}, - {"BQ", "Fuuki"}, - {"C0", "Taito"}, - {"C2", "Kemco"}, - {"C3", "Square"}, - {"C4", "Tokuma Shoten"}, - {"C5", "Data East"}, - {"C6", "Tonkin House / Tokyo Shoseki"}, - {"C8", "Koei"}, - {"CA", "Konami / Ultra / Palcom"}, - {"CB", "NTVIC / VAP"}, - {"CC", "Use Co.,Ltd."}, - {"CD", "Meldac"}, - {"CE", "Pony Canyon / FCI"}, - {"CF", "Angel / Sotsu Agency / Sunrise"}, - {"CG", "Yumedia / Aroma Co., Ltd"}, - {"CJ", "Boss"}, - {"CK", "Axela / Crea-Tech"}, - {"CL", "Sekaibunka-Sha / Sumire Kobo / Marigul Management Inc."}, - {"CM", "Konami Computer Entertainment Osaka"}, - {"CN", "NEC Interchannel"}, - {"CP", "Enterbrain"}, - {"CQ", "From Software"}, - {"D0", "Taito / Disco"}, - {"D1", "Sofel"}, - {"D2", "Quest / Bothtec"}, - {"D3", "Sigma"}, - {"D4", "Ask Kodansha"}, - {"D6", "Naxat"}, - {"D7", "Copya System"}, - {"D8", "Capcom Co., Ltd."}, - {"D9", "Banpresto"}, - {"DA", "Tomy"}, - {"DB", "LJN Japan"}, - {"DD", "NCS"}, - {"DE", "Human Entertainment"}, - {"DF", "Altron"}, - {"DG", "Jaleco"}, - {"DH", "Gaps Inc."}, - {"DN", "Elf"}, - {"DQ", "Compile Heart"}, - {"E0", "Jaleco"}, - {"E2", "Yutaka"}, - {"E3", "Varie"}, - {"E4", "T&ESoft"}, - {"E5", "Epoch"}, - {"E7", "Athena"}, - {"E8", "Asmik"}, - {"E9", "Natsume"}, - {"EA", "King Records"}, - {"EB", "Atlus"}, - {"EC", "Epic / Sony Records"}, - {"EE", "IGS (Information Global Service)"}, - {"EG", "Chatnoir"}, - {"EH", "Right Stuff"}, - {"EL", "Spike"}, - {"EM", "Konami Computer Entertainment Tokyo"}, - {"EN", "Alphadream Corporation"}, - {"EP", "Sting"}, - {"ES", "Star-Fish"}, - {"F0", "A Wave"}, - {"F1", "Motown Software"}, - {"F2", "Left Field Entertainment"}, - {"F3", "Extreme Ent. Grp."}, - {"F4", "TecMagik"}, - {"F9", "Cybersoft"}, - {"FB", "Psygnosis"}, - {"FE", "Davidson / Western Tech."}, - {"FK", "The Game Factory"}, - {"FL", "Hip Games"}, - {"FM", "Aspyr"}, - {"FP", "Mastiff"}, - {"FQ", "iQue"}, - {"FR", "Digital Tainment Pool"}, - {"FS", "XS Games / Jack Of All Games"}, - {"FT", "Daiwon"}, - {"G0", "Alpha Unit"}, - {"G1", "PCCW Japan"}, - {"G2", "Yuke's Media Creations"}, - {"G4", "KiKi Co Ltd"}, - {"G5", "Open Sesame Inc"}, - {"G6", "Sims"}, - {"G7", "Broccoli"}, - {"G8", "Avex"}, - {"G9", "D3 Publisher"}, - {"GB", "Konami Computer Entertainment Japan"}, - {"GD", "Square-Enix"}, - {"GE", "KSG"}, - {"GF", "Micott & Basara Inc."}, - {"GH", "Orbital Media"}, - {"GJ", "Detn8 Games"}, - {"GL", "Gameloft / Ubi Soft"}, - {"GM", "Gamecock Media Group"}, - {"GN", "Oxygen Games"}, - {"GT", "505 Games"}, - {"GY", "The Game Factory"}, - {"H1", "Treasure"}, - {"H2", "Aruze"}, - {"H3", "Ertain"}, - {"H4", "SNK Playmore"}, - {"HJ", "Genius Products"}, - {"HY", "Reef Entertainment"}, - {"HZ", "Nordcurrent"}, - {"IH", "Yojigen"}, - {"J9", "AQ Interactive"}, - {"JF", "Arc System Works"}, - {"JW", "Atari"}, - {"K6", "Nihon System"}, - {"KB", "NIS America"}, - {"KM", "Deep Silver"}, - {"LH", "Trend Verlag / East Entertainment"}, - {"LT", "Legacy Interactive"}, - {"MJ", "Mumbo Jumbo"}, - {"MR", "Mindscape"}, - {"MS", "Milestone / UFO Interactive"}, - {"MT", "Blast !"}, - {"N9", "Terabox"}, - {"NK", "Neko Entertainment / Diffusion / Naps team"}, - {"NP", "Nobilis"}, - {"NR", "Data Design / Destineer Studios"}, - {"PL", "Playlogic"}, - {"RM", "Rondomedia"}, - {"RS", "Warner Bros. Interactive Entertainment Inc."}, - {"RT", "RTL Games"}, - {"RW", "RealNetworks"}, - {"S5", "Southpeak Interactive"}, - {"SP", "Blade Interactive Studios"}, - {"SV", "SevenGames"}, - {"TK", "Tasuke / Works"}, - {"UG", "Metro 3D / Data Design"}, - {"VN", "Valcon Games"}, - {"VP", "Virgin Play"}, - {"WR", "Warner Bros. Interactive Entertainment Inc."}, - {"XJ", "Xseed Games"}, - {"XS", "Aksys Games"}, - {NULL, NULL} -}; - -/** - * Retrieves the disk maker. - * @param d The disc structure. - * @param m This will point to a string containing the disc maker ID. - * @param m_s This will point to a string describing the disc maker. - * @return A string describing the disc maker. - */ -char *disc_get_maker (disc *d, char **m, char **m_s) { - u_int32_t i; - - if (m) - *m = d -> maker; - - if (m_s) { - for (i = 0; makers[i].code; i++) { - if (strcasecmp (d -> maker, makers[i].code) == 0) { - *m_s = makers[i].name; - break; - } - } - if (!makers[i].code) { - *m_s = "Unknown"; - } - } - - return (*m_s); -} - - -/** - * Retrieves the disc version. - * @param d The disc structure. - * @param v This will contain the version ID. - * @param v_s This will point to a string describing the disc version. - * @return A string describing the disc version. - */ -char *disc_get_version (disc *d, u_int8_t *v, char **v_s) { - if (v) - *v = d -> version; - - if (v_s) - *v_s = d -> version_string; - - return (*v_s); -} - - -/** - * Retrieves the disc game title. - * @param d The disc structure. - * @param t_s This will point to a string describing the disc title. - * @return A string describing the disc title. - */ -char *disc_get_title (disc *d, char **t_s) { - if (t_s) - *t_s = d -> title; - - return (*t_s); -} - - -/** - * Retrieves if the disc has an update. - * @param d The disc structure. - * @return True if the disc contains an update, false otherwise. - */ -bool disc_get_update (disc *d) { - return (d -> has_update); -} - - -/** - * Retrieves the number of sectors of the disc. - * @param d The disc structure. - * @return The number of sectors. - */ -u_int32_t disc_get_sectors_no (disc *d) { - return (d -> sectors_no); -} - -u_int32_t disc_get_layerbreak (disc *d) { - return (d -> layerbreak); -} - -u_int32_t disc_get_command (disc *d) { - return (d -> command); -} - -u_int32_t disc_get_method (disc *d) { - return (d -> read_method); -} - -u_int32_t disc_get_def_method (disc *d) { - return dvd_get_def_method(d -> dvd);//(d -> def_read_method); -} - -u_int32_t disc_get_sec_disc (disc *d) { - return (d -> sec_disc); -} - -u_int32_t disc_get_sec_mem (disc *d) { - return (d -> sec_mem); -} - -/* wiidevel@stacktic.org */ -static bool disc_check_update (disc *d) { - u_int8_t *buf; - u_int32_t x; - bool unscramble_old; - - if (d -> type == DISC_TYPE_WII || d -> type == DISC_TYPE_WII_DL) { - /* Force unscrambling for this read */ - unscramble_old = d -> unscrambling; - disc_set_unscrambling (d, true); - - /* We need to read offset 0x50004 of the disc. Sector 160 has offset 0x50000 */ - if (disc_read_sector (d, 160, &buf, NULL)) { - x = my_ntohl (*(u_int32_t *) (buf + 4)); - if (x == 0xA5BED6AE) - d -> has_update = false; - else - d -> has_update = true; - } else { - error ("disc_check_update() failed"); - } - - disc_set_unscrambling (d, unscramble_old); - } else { - /* GameCube discs never have an update, as actually the GC firmware cannot be upgrade */ - d -> has_update = false; - } - - return (d -> has_update); -} - - -/** - * Sets the disc read method. - * @param d The disc structure. - * @param method The requested method. - * @return True if the method was set correctly, false otherwise (i. e.: method too small/big). - */ -bool disc_set_read_method (disc *d, int method) { - bool out; - u_int32_t deviation; - u_int32_t counter; - u_int32_t cnt1; - - d -> command = dvd_get_command(d -> dvd); -// d -> def_read_method = dvd_get_def_method(d -> dvd); - d -> read_method = method; - - out = true; - switch (method) { - case 0: - d -> read_sector = disc_read_sector_0; - break; - case 1: - d -> read_sector = disc_read_sector_1; - break; - case 2: - d -> read_sector = disc_read_sector_2; - break; - case 3: - d -> read_sector = disc_read_sector_3; - break; - case 4: - d -> read_sector = disc_read_sector_4; - break; - case 5: - d -> read_sector = disc_read_sector_5; - break; - case 6: - d -> read_sector = disc_read_sector_6; - break; - case 7: - d -> read_sector = disc_read_sector_7; - break; - case 8: - d -> read_sector = disc_read_sector_8; - break; - case 9: - d -> read_sector = disc_read_sector_9; - break; - default: - switch (dvd_get_def_method(d -> dvd)) { - case 0: - d -> read_method = 0; - d -> read_sector = disc_read_sector_0; - break; - case 1: - d -> read_method = 1; - d -> read_sector = disc_read_sector_1; - break; - case 2: - d -> read_method = 2; - d -> read_sector = disc_read_sector_2; - break; - case 3: - d -> read_method = 3; - d -> read_sector = disc_read_sector_3; - break; - case 4: - d -> read_method = 4; - d -> read_sector = disc_read_sector_4; - break; - case 5: - d -> read_method = 5; - d -> read_sector = disc_read_sector_5; - break; - case 6: - d -> read_method = 6; - d -> read_sector = disc_read_sector_6; - break; - case 7: - d -> read_method = 7; - d -> read_sector = disc_read_sector_7; - break; - case 8: - d -> read_method = 8; - d -> read_sector = disc_read_sector_8; - break; - case 9: - d -> read_method = 9; - d -> read_sector = disc_read_sector_9; - break; - default: - d -> read_method = DEFAULT_READ_METHOD; - d -> read_sector = DEFAULT_READ_SECTOR; - break; - } - } - - if (d->sec_disc==-1) { - if ((d->read_method == 4) || (d->read_method == 5) || (d->read_method == 6)) - d->sec_disc=27; - else - d->sec_disc=16; - } - if (d->sec_mem==-1) { - if ((d->read_method == 4) || (d->read_method == 5) || (d->read_method == 6)) - d->sec_mem=27; - else - d->sec_mem=16; - } - - deviation = d->sec_mem % SECTORS_PER_BLOCK; - counter=0; - - if (deviation>3) { - cnt1=deviation; - while (1==1) { - cnt1+=deviation; - counter++; - if (cnt1%SECTORS_PER_BLOCK<=1) break; - } - } - d -> max_cnt = counter; - d -> max_blk = ((d->sec_mem*(d->max_cnt+1))-((d->sec_mem*(d->max_cnt+1)) % SECTORS_PER_BLOCK)) / 16; - - if (out) { - debug ("Read method set to %d", d -> read_method); - } else { - error ("Cannot set read method\n"); - } - - return (out); -} - - -/** - * Controls the unscrambling process. - * @param d The disc structure. - * @param unscramble If true, every raw sectors read will be unscrambled to check if they are error-free, otherwise read data will be returned as-is. - */ -void disc_set_unscrambling (disc *d, bool unscramble) { - d -> unscrambling = unscramble; - debug ("Sectors unscrambling %s", unscramble ? "enabled" : "disabled"); - - return; -} - - -static void disc_crack_seeds (disc *d) { - int i; - - /* As a Nintendo GameCube/Wii disc should not have too many keys, 20 should be enough */ - debug ("Retrieving all DVD seeds"); - for (i = 0; i < 20 * 16; i += 16) - disc_read_sector (d, i, NULL, NULL); - - return; -} - - -/** - * Creates a new structure representing a Nintendo GameCube/Wii optical disc. - * @param dvd_device The CD/DVD-ROM device, in OS-dependent format (i.e.: /dev/something on Unix, x: on Windows). - * @return The newly-created structure, to be used with the other commands. - */ -disc *disc_new (char *dvd_device, u_int32_t command) { - dvd_drive *dvd; - disc *d; - - if ((dvd = dvd_drive_new (dvd_device, command))) { - d = (disc *) malloc (sizeof (disc)); - memset (d, 0, sizeof (disc)); - d -> dvd = dvd; - d -> u = unscrambler_new (); - disc_set_unscrambling (d, true); // Unscramble by default - disc_set_read_method (d, DEFAULT_READ_METHOD); - disc_cache_init (d, DISC_DEFAULT_CACHE_SIZE); - } else { - d = NULL; - } - - return (d); -} - - -bool disc_init (disc *d, u_int32_t disctype, u_int32_t sectors_no) { - bool out; - - d -> sectors_no = 1000; // TODO - disc_detect_type (d, disctype, sectors_no); - disc_crack_seeds (d); -// unscrambler_set_bruteforce (d -> u, false); // Disabling bruteforcing will allow us to detect errors more quickly - unscrambler_set_bruteforce (d -> u, true); - if (d -> type==DISC_TYPE_DVD) { - my_strdup (d -> title, "DVD"+'\0'); - out = true; - } - else if (disc_analyze (d)) { - disc_check_update (d); - out = true; - } else { - out = false; - } - - return (out); -} - - -/** - * Frees resources used by a disc structure and destroys it. - * @param d The disc structure. - * @return NULL. - */ -void *disc_destroy (disc *d) { - disc_cache_destroy (d); - unscrambler_destroy (d -> u); - my_free (d -> version_string); - my_free (d -> title); - dvd_drive_destroy (d -> dvd); - my_free (d); - - return (NULL); -} - - -char *disc_get_drive_model_string (disc *d) { - return (dvd_get_model_string (d -> dvd)); -} - - -bool disc_get_drive_support_status (disc *d) { - return (dvd_get_support_status (d -> dvd)); -} - -void disc_set_speed (disc *d, u_int32_t speed) { - if (speed != -1) dvd_set_speed (d -> dvd, speed, NULL); -} - -void disc_set_streaming_speed (disc *d, u_int32_t speed) { - if (speed != -1) dvd_set_streaming (d -> dvd, speed, NULL); -} - -bool disc_stop_unit (disc *d, bool start) { - if (dvd_stop_unit (d -> dvd, start, NULL) == 0) return true; - else return false; -} - -void init_range (disc *d, u_int32_t sec_disc, u_int32_t sec_mem) { - if ((sec_disc>=1)&&(sec_disc<=100)) d->sec_disc = sec_disc; - else d->sec_disc = -1; - if ((sec_mem>=16)&&(sec_mem<=100)) d->sec_mem = sec_mem; - else d->sec_mem = -1; +/*************************************************************************** + * Copyright (C) 2007 by Arep * + * Support is provided through the forums at * + * http://wii.console-tribe.com * + * * + * 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. * + ***************************************************************************/ + +/*! \file + * \brief Analyser and dumper for Nintendo GameCube/Wii discs. + * + * The functions in this file can be used to retrieve information about a Nintendo GameCube/Wii optical disc. Information is both structural (i.e.: Number of + * sectors, partitions, etc) and game-related (i.e.: Game Title, version, etc). This is the main object that should be used by applications. + * + * Most of the disc structure information used in this file comes from http://www.gc-linux.org/docs/yagcd.html and + * http://www.wiili.org/index.php/GameCube_Optical_Disc . + */ + +#include "misc.h" +#include +#include +#include +//#include +#include "constants.h" +#include "byteorder.h" +#include "disc.h" +#include "dvd_drive.h" +#include "unscrambler.h" + +// #define cachedebug(...) debug (__VA_ARGS__); +#define cachedebug(...) + + +/* Cache always deals with 16-sector blocks. All numbers refer to the 16-sector blocks */ +#define DISC_MINIMUM_CACHE_SIZE 5 +#define DISC_DEFAULT_CACHE_SIZE 40 +#define CACHE_ENTRY_INVALID ((u_int32_t) -1) + + +#define DISC_GAMECUBE_SECTORS_NO 0x0AE0B0 /* 712880 */ +#define DISC_WII_SECTORS_NO_SL 0x230480 /* 2294912 */ +#define DISC_WII_SECTORS_NO_DL 0x3F69C0 /* 4155840 */ + + +#define MAX_READ_RETRIES 5 + +#define DEFAULT_READ_METHOD 0 +#define DEFAULT_READ_SECTOR disc_read_sector_0 + + +typedef int (*disc_read_sector_func) (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata); + +u_int8_t buf[1024*1024*4]; +u_int8_t buf_unscrambled[1024*1024*4]; + +//struct timeval tim; +//double t1, t2; + +/*! \brief A structure that represents a Nintendo GameCube/Wii optical disc. + */ +struct disc_s { + dvd_drive *dvd; //!< The structure for the DVD-drive the disc is inserted in. + disc_type type; //!< The disc type. + char system_id; //!< A letter identifying the target system. + char game_id[2 + 1]; //!< Two letters identifying the game. + disc_region region; //!< The disc region. + char maker[3]; //!< Two letters identifying the maker of the game. + u_int8_t version; //!< A number identifying the game version. + char *version_string; //!< The same as version, in a more human-understandable format. + char *title; //!< The game title. + bool has_update; //!< True if the game contains a system update (Only possible for Wii discs). + u_int32_t sectors_no; //!< The number of sectors of the disc. + u_int32_t layerbreak; //!< For dual-layer DVDs. + + u_int32_t sec_disc; + u_int32_t sec_mem; + u_int32_t max_cnt; + u_int32_t max_blk; + + /* Read function & stuff */ + int command; //!< Buffer access command ID. + int read_method; //!< The read method ID. +// int def_read_method; //!< Default read method ID. + disc_read_sector_func read_sector; //!< The actual function that will be used to perform read operations, corresponding to read_method. + bool unscrambling; //!< If true, raw data read from the disc will be unscrambled to assure it is error-free. Disabling this is only useful for raw performance tests. + unscrambler *u; //!< The unscrambler structure that will be used to perform the unscrambling. + + /* Read cache */ + u_int32_t cache_size; //!< The number of blocks that will be cached when read. + u_int8_t **raw_cache; //!< Memory area for raw sectors cache. + u_int8_t **cache; //!< Memory area for unscrambled sectors cache. + u_int32_t *cache_map; //!< Data structure used by the caching system to know which blocks are in memory. +}; + + +static void disc_cache_init (disc *d, u_int32_t size) { + u_int32_t i; + + if (size < DISC_MINIMUM_CACHE_SIZE) { + error ("Invalid cache size %u (must be >= %u)", size, DISC_MINIMUM_CACHE_SIZE); + exit (3); + } else { + d -> cache_size = size; + d -> cache = (u_int8_t **) malloc (sizeof (u_int8_t *) * size); + d -> raw_cache = (u_int8_t **) malloc (sizeof (u_int8_t *) * size); + for (i = 0; i < size; i++) { + d -> cache[i] = (u_int8_t *) malloc (sizeof (u_int8_t) * BLOCK_SIZE); + d -> raw_cache[i] = (u_int8_t *) malloc (sizeof (u_int8_t) * RAW_BLOCK_SIZE); + } + + d -> cache_map = (u_int32_t *) malloc (sizeof (u_int32_t) * size); + for (i = 0; i < size; i++) + d -> cache_map[i] = CACHE_ENTRY_INVALID; + } + + return; +} + + +static void disc_cache_destroy (disc *d) { + u_int32_t i; + + my_free (d -> cache_map); + + for (i = 0; i < d -> cache_size; i++) { + my_free (d -> cache[i]); + my_free (d -> raw_cache[i]); + } + my_free (d -> cache); + my_free (d -> raw_cache); + d -> cache_size = 0; + + return; +} + + +void disc_cache_add_block (disc *d, u_int32_t block, u_int8_t *data, u_int8_t *rawdata) { + u_int32_t pos; + u_int32_t cnt; + + pos = block % d -> cache_size; + //uniform unscrambled output + memcpy (d -> cache[pos], data, BLOCK_SIZE); + if (d -> type == DISC_TYPE_DVD) { + for (cnt = 0; cnt < SECTORS_PER_BLOCK; cnt++) { + memcpy (rawdata+(cnt*RAW_SECTOR_SIZE)+12, data+(cnt*SECTOR_SIZE), SECTOR_SIZE); + } + } else { + for (cnt = 0; cnt < SECTORS_PER_BLOCK; cnt++) { + memcpy (rawdata+(cnt*RAW_SECTOR_SIZE)+6, data+(cnt*SECTOR_SIZE), SECTOR_SIZE); + } + } + memcpy (d -> raw_cache[pos], rawdata, RAW_BLOCK_SIZE); + d -> cache_map[pos] = block; + + cachedebug ("Cached block %u (sectors %u-%u) at position %u", block, block * SECTORS_PER_BLOCK, (block + 1) * SECTORS_PER_BLOCK - 1, pos); + + return; +} + + +static bool disc_cache_lookup_block (disc *d, u_int32_t block, u_int8_t **data, u_int8_t **rawdata) { + u_int32_t pos; + bool out; + + pos = block % d -> cache_size; + + if (d -> cache_map[pos] == block) { + cachedebug ("Cache HIT for block %u", block); + if (data) + *data = d -> cache[pos]; + if (rawdata) + *rawdata = d -> raw_cache[pos]; + out = true; + } else { + cachedebug ("Cache MISS for block %u", block); + if (data) + *data = NULL; + if (rawdata) + *rawdata = NULL; + out = false; + } + + return (out); +} + + +static int disc_read_sector_generic (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata, u_int32_t method) { + bool out; + u_int32_t start_block; + int ret, retry; + u_int32_t step, cnt, max_cnt, max_blk; + u_int32_t block_len, block_size, _block_size, last_block_size, block_cnt; +//fprintf (stdout,"disc_read_sector_%d", method); + start_block = sector_no / SECTORS_PER_BLOCK; + + out = false; + step = d->sec_mem; + max_cnt = d->max_cnt; + max_blk = d->max_blk; + + block_size = step*2064; + last_block_size = block_size; + block_len = 1; + if (block_size > 27 * 2064) { + block_len = block_size / (27*2064); + if (block_size % (27*2064) != 0) block_len += 1; + block_size = 27*2064; + last_block_size = (step*2064) - (27*2064*(block_len-1)); + } + _block_size=block_size; + + for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { + /* Assume everything will turn out well */ + out = true; + + //Streaming read + if (retry < 3) { + cnt=0; + while (cnt <= max_cnt){ + + _block_size=block_size; + if (method == 0 || method == 1 || method == 4) { + if (sector_no+(cnt*step) +992 +16 <= d -> sectors_no) //smaller than last sector + dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step) +992, 16, NULL, NULL, 0); + else if (sector_no+(cnt*step) -992 >= 0) //larger than first sector + dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step) -992, 16, NULL, NULL, 0); + else dvd_flush_cache_READ12 (d -> dvd, sector_no+(cnt*step), NULL); + } + + if (method == 0 || method == 2 || method == 5) dvd_flush_cache_READ12 (d -> dvd, sector_no+(cnt*step), NULL); + if (method == 0 || method == 1 || method == 2 || method == 3) ret = dvd_read_sector_dummy (d -> dvd, sector_no+(cnt*step), d->sec_disc, NULL, &buf_unscrambled[0], 2064*step); + if (method == 4 || method == 5 || method == 6) ret = dvd_read_streaming (d -> dvd, sector_no+(cnt*step), d->sec_disc, NULL, &buf_unscrambled[0], 2064*step); + if (ret >= 0) { + for (block_cnt=0; block_cnt dvd, block_cnt*27*2064, 1, _block_size, &buf[(cnt*(2064 * step))+(block_cnt*27*2064)]) < 0) { + error ("Memdump failed"); + //retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ //no it's not! + out = false; + break; + } + if (block_cnt==block_len-1) _block_size = last_block_size; + } + if (!out) break; + //do this check only on 1st layer + else if (((buf[cnt*(2064*step)] & 1) == 0) && ((buf[cnt*(2064*step)+1]<<16)+(buf[cnt*(2064*step)+2]<<8)+(buf[cnt*(2064*step)+3]) != 0x30000 + sector_no+(cnt*step))) { + out = false; + break; + } + else cnt += 1; + } else { + error ("dvd_read_streaming() failed with %d", ret); + out = false; + break; + } + + } + + if (cnt < max_cnt) out = false; + else { +#ifdef DEBUG + if (d -> unscrambling) { +#endif + /* Try to unscramble all data to see if EDC fails */ + //for(cnt=0; cnt <= 4; cnt++) { + for(cnt=max_blk; cnt--;) { + if (!unscrambler_unscramble_16sectors (d -> u, sector_no+(cnt*16), &buf[cnt*(2064*16)], &buf_unscrambled[cnt*(2048*16)])) + out = false; + } +#ifdef DEBUG + } +#endif + } + if (out) { + /* If data were unscrambled correctly, add them to the cache */ + //for(cnt = 0; cnt <= 4; cnt++) { + for(cnt=max_blk; cnt--;) { + disc_cache_add_block (d, start_block+cnt, &buf_unscrambled[cnt*(2048*16)], &buf[cnt*(2064*16)]); + } + } + } //if (retry < 3) + + //Simple read on 4rth try + else { + if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector + dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); + else if (sector_no -992 >= 0) //larger than first sector + dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); + else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); + + dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); + ret = dvd_read_sector_dummy (d -> dvd, sector_no, SECTORS_PER_BLOCK, NULL, NULL, 0); + if (ret >= 0) { + if (dvd_memdump (d -> dvd, 0, 1, RAW_BLOCK_SIZE, buf) < 0) { + error ("Memdump failed"); + //retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ + out = false; + } + else if ( ((*(buf) & 1) == 0) && ((*(buf+1)<<16)+(*(buf+2)<<8)+(*(buf+3)) != 0x30000+sector_no) ) out = false; + else { +#ifdef DEBUG + if (d -> unscrambling) { +#endif + /* Try to unscramble all data to see if EDC fails */ + if (!unscrambler_unscramble_16sectors (d -> u, sector_no, buf, buf_unscrambled)) + out = false; +#ifdef DEBUG + } +#endif + } + if (out) { + /* If data were unscrambled correctly, add them to the cache */ + disc_cache_add_block (d, start_block, buf_unscrambled, buf); + } + } else { + error ("dvd_read_sector_dummy() failed with %d", ret); + out = false; + } + } //else + } //for + + if (!out) + error ("Too many retries, giving up"); + + return (out); +} + + +///////////////////////////// General ///////////////////////////// +static int disc_read_sector_0 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 0); +} + + + +////////////////////////// Non-Streaming ////////////////////////// +static int disc_read_sector_1 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 1); + +} + +static int disc_read_sector_2 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 2); + +} + + +static int disc_read_sector_3 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 3); + +} + + + +//////////////////////////// Streaming //////////////////////////// +static int disc_read_sector_4 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 4); +} + + +static int disc_read_sector_5 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 5); +} + + +static int disc_read_sector_6 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + return disc_read_sector_generic (d, sector_no, data, rawdata, 6); +} + + + +///////////////////////////// Hitachi ///////////////////////////// +static int disc_read_sector_7 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + bool out; + u_int32_t start_block; + int j, ret, retry; + u_int8_t buf[5][16 * 2064]; + u_int8_t buf_unscrambled[5][16 * 2048]; +//fprintf (stdout,"disc_read_sector_7"); + start_block = sector_no / SECTORS_PER_BLOCK; + + out = false; + for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { + /* Assume everything will turn out well */ + out = true; + + if (retry > 0) { + warning ("Read retry %d for sector %u", retry, sector_no); + + /* Try to reset in-memory data by seeking to a distant sector */ +// if (sector_no > 1000) +// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0); +// else +// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0); + if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector + dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); + else if (sector_no -992 >= 0) //larger than first sector + dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); + else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); + } + + if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, NULL, 0)) >= 0) { + for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { + if (dvd_memdump (d -> dvd, 0 + (j * 16 * 2064), 1, 16 * 2064, buf[j]) < 0) { /* Dumping in a single block is faster */ + error ("Memdump failed"); + out = false; + retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ + } else { +#ifdef DEBUG + if (d -> unscrambling) { +#endif + /* Try to unscramble all data to see if EDC fails */ + if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j])) + out = false; +#ifdef DEBUG + } +#endif + } + } + + if (out) { + /* It seems all data was unscrambled correctly, so cache them out */ + for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no; j++) + disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]); + + } + } else { + error ("dvd_read_sector_streaming() failed with %d", ret); + out = false; + } + } + + if (!out) + error ("Too many retries, giving up"); + + return (out); +} + + +static int disc_read_sector_8 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + bool out; + u_int32_t ram_offset; + int j, k, ret, retry; + u_int8_t *sect, buf[5][RAW_BLOCK_SIZE]; + u_int8_t readbuf[BLOCK_SIZE]; + u_int8_t buf_unscrambled[5][BLOCK_SIZE]; + u_int32_t start_block; +//fprintf (stdout,"disc_read_sector_8"); + start_block = sector_no / SECTORS_PER_BLOCK; + + out = false; + for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { + /* Assume everything will turn out well */ + out = true; + + if (retry > 0) { + warning ("Read retry %d for sector %u", retry, sector_no); + + /* Try to reset in-memory data by seeking to a distant sector */ +// if (sector_no > 1000) +// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0); +// else +// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0); + if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector + dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); + else if (sector_no -992 >= 0) //larger than first sector + dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); + else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); + } + + /* First READ command, this will cache 5 16-sector blocks. Immediately dump relevant data */ + if (sector_no > d -> sectors_no - 1000) + dvd_read_sector_streaming (d -> dvd, sector_no - 16 * 5 * 2, NULL, NULL, 0); + else + dvd_read_sector_streaming (d -> dvd, sector_no + 16 * 5, NULL, NULL, 0); + if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, readbuf, sizeof (readbuf))) >= 0) { + for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { + /* Reconstruct raw sectors */ + for (k = 0; k < 16; k++) { + sect = &buf[j][k * RAW_SECTOR_SIZE]; + ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE; + /* Get first 12 bytes (ID. IED and CPR_MAI fields) and last 4 bytes (EDC field) with memdump */ + if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) { + error ("Memdump (1) failed"); + out = false; + retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ + } else if (dvd_memdump (d -> dvd, ram_offset + 2060, 1, 4, sect + 2060) < 0) { /* Dumping in a single block is faster */ + error ("Memdump (2) failed"); + out = false; + } + } + } + + /* Now the same for remaining 4 16-sector blocks */ + for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { + if (j == 0 || (ret = dvd_read_sector_streaming (d -> dvd, sector_no + j * 16, NULL, readbuf, sizeof (readbuf))) >= 0) { + /* Copy "user data" field which has been incorrectly unscrambled by the DVD drive firmware */ + for (k = 0; k < 16; k++) { + sect = &buf[j][k * RAW_SECTOR_SIZE]; + memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE); + } +#ifdef DEBUG + if (d -> unscrambling) { +#endif + /* Try to unscramble all data to see if EDC fails */ + if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j])) + out = false; +#ifdef DEBUG + } +#endif + } else { + error ("dvd_read_sector_streaming() failed with %d", ret); + out = false; + } + } + + if (out) { + /* It seems all data were unscrambled correctly, so cache them out */ + for (j = 0; j < 5 && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++) + disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]); + } + } else { + error ("dvd_read_sector_streaming() failed with %d", ret); + out = false; + } + } + + if (!out) + error ("Too many retries, giving up"); + + return (out); +} + + +static int disc_read_sector_9 (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + bool out; + u_int32_t ram_offset; + int j, k, ret, retry; + u_int8_t *sect, buf[5][RAW_BLOCK_SIZE]; + u_int8_t readbuf[BLOCK_SIZE], tmp[16]; + u_int8_t buf_unscrambled[5][BLOCK_SIZE]; + u_int32_t start_block; +//fprintf (stdout,"disc_read_sector_9"); + start_block = sector_no / SECTORS_PER_BLOCK; + + out = false; + for (retry = 0; !out && retry < MAX_READ_RETRIES; retry++) { + /* Assume everything will turn out well */ + out = true; + + if (retry > 0) { + warning ("Read retry %d for sector %u", retry, sector_no); + + /* Try to reset in-memory data by seeking to a distant sector */ +// if (sector_no > 1000) +// dvd_read_sector_streaming (d -> dvd, 0, NULL, NULL, 0); +// else +// dvd_read_sector_streaming (d -> dvd, 1500, NULL, NULL, 0); + if (sector_no +992 +16 <= d -> sectors_no) //smaller than last sector + dvd_read_sector_dummy (d -> dvd, sector_no +992, 16, NULL, NULL, 0); + else if (sector_no -992 >= 0) //larger than first sector + dvd_read_sector_dummy (d -> dvd, sector_no -992, 16, NULL, NULL, 0); + else dvd_flush_cache_READ12 (d -> dvd, sector_no, NULL); + } + + /* First READ command, this will cache 5 16-sector blocks. Immediately dump relevant data */ + if (sector_no > d -> sectors_no - 1000) + dvd_read_sector_streaming (d -> dvd, sector_no - 16 * 5 * 2, NULL, NULL, 0); + else + dvd_read_sector_streaming (d -> dvd, sector_no + 16 * 5, NULL, NULL, 0); + if ((ret = dvd_read_sector_streaming (d -> dvd, sector_no, NULL, readbuf, BLOCK_SIZE)) >= 0) { + for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { + /* Reconstruct raw sectors */ + for (k = 0; k < 16; k++) { + sect = &buf[j][k * RAW_SECTOR_SIZE]; + ram_offset = (j * RAW_BLOCK_SIZE) + k * RAW_SECTOR_SIZE; + /* Get first 12 bytes (ID. IED and CPR_MAI fields) and last 4 bytes (EDC field) with memdump */ + if (j == 0 && k == 0) { + if (dvd_memdump (d -> dvd, ram_offset, 1, 12, sect) < 0) { + error ("Memdump (1) failed"); + out = false; + retry = MAX_READ_RETRIES; /* Well, if this fails going on is useless */ + } + } else { + memcpy (sect, tmp + 4, 12); + } + + if (out && dvd_memdump (d -> dvd, ram_offset + 2060, 1, 16, tmp) < 0) { /* Dumping in a single block is faster */ + error ("Memdump (2) failed"); + out = false; + } else { + memcpy (sect + 2060, tmp, 4); + } + } + } + + /* Now the same for remaining 4 16-sector blocks */ + for (j = 0; j < 5 && sector_no + j * 16 < d -> sectors_no && out; j++) { + if (j == 0 || (ret = dvd_read_sector_streaming (d -> dvd, sector_no + j * 16, NULL, readbuf, BLOCK_SIZE)) >= 0) { + /* Copy "user data" field which has been incorrectly unscrambled by the DVD drive firmware */ + for (k = 0; k < 16; k++) { + sect = &buf[j][k * RAW_SECTOR_SIZE]; + memcpy (sect + 12, readbuf + k * SECTOR_SIZE, SECTOR_SIZE); + } +#ifdef DEBUG + if (d -> unscrambling) { +#endif + /* Try to unscramble all data to see if EDC fails */ + if (!unscrambler_unscramble_16sectors (d -> u, sector_no + (j * 16), buf[j], buf_unscrambled[j])) + out = false; +#ifdef DEBUG + } +#endif + } else { + error ("dvd_read_sector_streaming() failed with %d", ret); + out = false; + } + } + + if (out) { + /* It seems all data were unscrambled correctly, so cache them out */ + for (j = 0; j < 5 && sector_no + j * SECTORS_PER_BLOCK < d -> sectors_no; j++) + disc_cache_add_block (d, start_block + j, buf_unscrambled[j], buf[j]); + } + } else { + error ("dvd_read_sector_streaming() failed with %d", ret); + out = false; + } + } + + if (!out) + error ("Too many retries, giving up"); + + return (out); +} + + +/* We could also use the 'System ID' (first byte of the image) to tell the discs apart */ +static disc_type disc_detect_type (disc *d, u_int32_t forced_type, u_int32_t sectors_no) { + req_sense sense; + + if (forced_type==0) { + d -> type = DISC_TYPE_GAMECUBE; + d -> sectors_no = DISC_GAMECUBE_SECTORS_NO; + } else if (forced_type==1) { + d -> type = DISC_TYPE_WII; + d -> sectors_no = DISC_WII_SECTORS_NO_SL; + } else if (forced_type==2) { + d -> type = DISC_TYPE_WII_DL; + d -> sectors_no = DISC_WII_SECTORS_NO_DL; + //dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL); + } else if (forced_type==3) { + d -> type = DISC_TYPE_DVD; + if (sectors_no == -1) dvd_get_size(d->dvd, &(d -> sectors_no), NULL); + dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL); + } else { + + /* Try to read a sector beyond the end of GameCube discs */ + if (!dvd_read_sector_dummy (d -> dvd, DISC_GAMECUBE_SECTORS_NO + 100, SECTORS_PER_BLOCK, &sense, NULL, 0) && sense.sense_key == 0x05 && sense.asc == 0x21) { + d -> type = DISC_TYPE_GAMECUBE; + d -> sectors_no = DISC_GAMECUBE_SECTORS_NO; + } else { + if (!dvd_read_sector_dummy (d -> dvd, DISC_WII_SECTORS_NO_SL + 100, SECTORS_PER_BLOCK, &sense, NULL, 0) && sense.sense_key == 0x05 && sense.asc == 0x21) { + d -> type = DISC_TYPE_WII; + d -> sectors_no = DISC_WII_SECTORS_NO_SL; + } else { + d -> type = DISC_TYPE_WII_DL; + d -> sectors_no = DISC_WII_SECTORS_NO_DL; + //dvd_get_layerbreak(d->dvd, &(d -> layerbreak), NULL); + } + } + + } + if (sectors_no != -1) d -> sectors_no = sectors_no; + + return (d -> type); +} + + +/** + * Reads a sector from the disc (or from the cache), using the preset read method. + * @param d The disc structure. + * @param sector_no The requested sector number. + * @param data A buffer to hold the unscrambled sector data (or NULL). + * @param rawdata A buffer to hold the raw sector data (or NULL). + * @return + */ +int disc_read_sector (disc *d, u_int32_t sector_no, u_int8_t **data, u_int8_t **rawdata) { + u_int32_t block; + u_int8_t *cdata, *crawdata; + int out; + + /* Unscrambled data cannot be requested if unscrambling was disabled */ + MY_ASSERT (!(data && !d -> unscrambling)); + + block = sector_no / SECTORS_PER_BLOCK; + + /* See if sector is in cache */ + if (!(out = disc_cache_lookup_block (d, block, &cdata, &crawdata))) { + /* Requested block is not in cache, try to read it from media */ + out = d -> read_sector (d, sector_no, data, rawdata); + + /* Now requested sector is in cache, for sure ;) */ + if (out) + MY_ASSERT (disc_cache_lookup_block (d, block, &cdata, &crawdata)); + } + + if (out) { + if (data) + *data = cdata + (sector_no % SECTORS_PER_BLOCK) * SECTOR_SIZE; + if (rawdata) + *rawdata = crawdata + (sector_no % SECTORS_PER_BLOCK) * RAW_SECTOR_SIZE; + } else { + if (data) + *data = NULL; + if (rawdata) + *rawdata = NULL; + } + + return (out); +} + + +static bool disc_analyze (disc *d) { + u_int8_t *buf; + char tmp[0x03E0 + 1]; + bool unscramble_old, out; + + /* Force unscrambling for this read */ + unscramble_old = d -> unscrambling; + disc_set_unscrambling (d, true); + + if (disc_read_sector (d, 0, &buf, NULL)) { + /* System ID */ + d -> system_id = buf[0]; +// if (d -> system_id == 'G') { +// d -> type = DISC_TYPE_GAMECUBE; +// d -> sectors_no = DISC_GAMECUBE_SECTORS_NO; +// } else if (d -> system_id == 'R') { +// d -> type = DISC_TYPE_WII; +// d -> sectors_no = DISC_WII_SECTORS_NO; +// } else { +// error ("Unknown system ID: '%c'", d -> system_id); +// MY_ASSERT (false); +// } + + /* Game ID */ + strncpy (d -> game_id, (char *) buf + 1, 2); + d -> game_id[2] = '\0'; + + /* Region */ + switch (buf[3]) { + case 'P': + d -> region = DISC_REGION_PAL; + break; + case 'E': + d -> region = DISC_REGION_NTSC; + break; + case 'J': + d -> region = DISC_REGION_JAPAN; + break; + case 'U': + d -> region = DISC_REGION_AUSTRALIA; + break; + case 'F': + d -> region = DISC_REGION_FRANCE; + break; + case 'D': + d -> region = DISC_REGION_GERMANY; + break; + case 'I': + d -> region = DISC_REGION_ITALY; + break; + case 'S': + d -> region = DISC_REGION_SPAIN; + break; + case 'X': + d -> region = DISC_REGION_PAL_X; + break; + case 'Y': + d -> region = DISC_REGION_PAL_Y; + break; + default: + d -> region = DISC_REGION_UNKNOWN; + break; + } + + /* Maker code */ + strncpy (d -> maker, (char *) buf + 4, 2); + d -> maker[2] = '\0'; + + /* Version */ + d -> version = buf[7]; + snprintf (tmp, sizeof (tmp), "1.%02u", d -> version); + my_strdup (d -> version_string, tmp); + + /* Game title */ + memcpy (tmp, buf + 0x0020, sizeof (tmp) - 1); + tmp[sizeof (tmp) - 1] = '\0'; + strtrimr (tmp); + my_strdup (d -> title, tmp); + + out = true; + } else { + error ("Cannot analyze disc"); + out = false; + } + + disc_set_unscrambling (d, unscramble_old); + + return (out); +} + + +static char disc_type_strings[4][15] = { + "GameCube", + "Wii", + "Wii_DL", + "DVD" +}; + +/** + * Retrieves the disc type. + * @param d The disc structure. + * @param dt This will be set to the disc type. + * @param dt_s This will point to a string describing the disc type. + * @return A string describing the disc type. + */ +char *disc_get_type (disc *d, disc_type *dt, char **dt_s) { + if (dt) + *dt = d -> type; + + if (dt_s) { + if (d -> type < DISC_TYPE_DVD) + *dt_s = disc_type_strings[d -> type]; + else + *dt_s = disc_type_strings[DISC_TYPE_DVD]; + } + + return (*dt_s); +} + + +/** + * Retrieves the disc game ID. + * @param d The disc structure. + * @param gid_s This will point to a string containing the game ID. + * @return A string containing the game ID. + */ +char *disc_get_gameid (disc *d, char **gid_s) { + if (gid_s) + *gid_s = d -> game_id; + + return (*gid_s); +} + + +static char disc_region_strings[11][15] = { + "Europe/PAL", + "USA/NTSC", + "Japan/NTSC", + "Australia/PAL", + "France/PAL", + "Germany/PAL", + "Italy/PAL", + "Spain/PAL", + "Europe(X)/PAL", + "Europe(Y)/PAL", + "Unknown" +}; + +/** + * Retrieves the disc region. + * @param d The disc structure. + * @param dr This will be set to the disc region. + * @param dr_s This will point to a string describing the disc region. + * @return A string describing the disc region. + */ +char *disc_get_region (disc *d, disc_region *dr, char **dr_s) { + if (dr) + *dr = d -> region; + + if (dr_s) { + if (d -> region < DISC_REGION_UNKNOWN) + *dr_s = disc_region_strings[d -> region]; + else + *dr_s = disc_region_strings[DISC_REGION_UNKNOWN]; + } + + return (*dr_s); +} + + +/* The following list has been derived from http://wiitdb.com/Company/HomePage */ +static struct { + char *code; + char *name; +} makers[] = { + {"0A", "Jaleco"}, + {"0B", "Coconuts Japan"}, + {"0C", "Coconuts Japan / G.X.Media"}, + {"0D", "Micronet"}, + {"0E", "Technos"}, + {"0F", "Mebio Software"}, + {"0G", "Shouei System"}, + {"0H", "Starfish"}, + {"0J", "Mitsui Fudosan / Dentsu"}, + {"0L", "Warashi Inc."}, + {"0N", "Nowpro"}, + {"0P", "Game Village"}, + {"0Q", "IE Institute"}, + {"01", "Nintendo"}, + {"02", "Rocket Games / Ajinomoto"}, + {"03", "Imagineer-Zoom"}, + {"04", "Gray Matter"}, + {"05", "Zamuse"}, + {"06", "Falcom"}, + {"07", "Enix"}, + {"08", "Capcom"}, + {"09", "Hot B Co."}, + {"1A", "Yanoman"}, + {"1C", "Tecmo Products"}, + {"1D", "Japan Glary Business"}, + {"1E", "Forum / OpenSystem"}, + {"1F", "Virgin Games (Japan)"}, + {"1G", "SMDE"}, + {"1J", "Daikokudenki"}, + {"1P", "Creatures Inc."}, + {"1Q", "TDK Deep Impresion"}, + {"2A", "Culture Brain"}, + {"2C", "Palsoft"}, + {"2D", "Visit Co.,Ltd."}, + {"2E", "Intec"}, + {"2F", "System Sacom"}, + {"2G", "Poppo"}, + {"2H", "Ubisoft Japan"}, + {"2J", "Media Works"}, + {"2K", "NEC InterChannel"}, + {"2L", "Tam"}, + {"2M", "Jordan"}, + {"2N", "Smilesoft / Rocket"}, + {"2Q", "Mediakite"}, + {"3B", "Arcade Zone Ltd"}, + {"3C", "Entertainment International / Empire Software"}, + {"3D", "Loriciel"}, + {"3E", "Gremlin Graphics"}, + {"3F", "K.Amusement Leasing Co."}, + {"4B", "Raya Systems"}, + {"4C", "Renovation Products"}, + {"4D", "Malibu Games"}, + {"4F", "Eidos"}, + {"4G", "Playmates Interactive"}, + {"4J", "Fox Interactive"}, + {"4K", "Time Warner Interactive"}, + {"4Q", "Disney Interactive"}, + {"4S", "Black Pearl"}, + {"4U", "Advanced Productions"}, + {"4X", "GT Interactive"}, + {"4Y", "RARE"}, + {"4Z", "Crave Entertainment"}, + {"5A", "Mindscape / Red Orb Entertainment"}, + {"5B", "Romstar"}, + {"5C", "Taxan"}, + {"5D", "Midway / Tradewest"}, + {"5F", "American Softworks"}, + {"5G", "Majesco Sales Inc"}, + {"5H", "3DO"}, + {"5K", "Hasbro"}, + {"5L", "NewKidCo"}, + {"5M", "Telegames"}, + {"5N", "Metro3D"}, + {"5P", "Vatical Entertainment"}, + {"5Q", "LEGO Media"}, + {"5S", "Xicat Interactive"}, + {"5T", "Cryo Interactive"}, + {"5W", "Red Storm Entertainment"}, + {"5X", "Microids"}, + {"5Z", "Data Design / Conspiracy / Swing"}, + {"6B", "Laser Beam"}, + {"6E", "Elite Systems"}, + {"6F", "Electro Brain"}, + {"6G", "The Learning Company"}, + {"6H", "BBC"}, + {"6J", "Software 2000"}, + {"6K", "UFO Interactive Games"}, + {"6L", "BAM! Entertainment"}, + {"6M", "Studio 3"}, + {"6Q", "Classified Games"}, + {"6S", "TDK Mediactive"}, + {"6U", "DreamCatcher"}, + {"6V", "JoWood Produtions"}, + {"6W", "Sega"}, + {"6X", "Wannado Edition"}, + {"6Y", "LSP (Light & Shadow Prod.)"}, + {"6Z", "ITE Media"}, + {"7A", "Triffix Entertainment"}, + {"7C", "Microprose Software"}, + {"7D", "Sierra / Universal Interactive"}, + {"7F", "Kemco"}, + {"7G", "Rage Software"}, + {"7H", "Encore"}, + {"7J", "Zoo"}, + {"7K", "Kiddinx"}, + {"7L", "Simon & Schuster Interactive"}, + {"7M", "Asmik Ace Entertainment Inc."}, + {"7N", "Empire Interactive"}, + {"7Q", "Jester Interactive"}, + {"7S", "Rockstar Games"}, + {"7T", "Scholastic"}, + {"7U", "Ignition Entertainment"}, + {"7V", "Summitsoft"}, + {"7W", "Stadlbauer"}, + {"8B", "BulletProof Software (BPS)"}, + {"8C", "Vic Tokai Inc."}, + {"8E", "Character Soft"}, + {"8F", "I'Max"}, + {"8G", "Saurus"}, + {"8J", "General Entertainment"}, + {"8N", "Success"}, + {"8P", "Sega Japan"}, + {"9A", "Nichibutsu / Nihon Bussan"}, + {"9B", "Tecmo"}, + {"9C", "Imagineer"}, + {"9F", "Nova"}, + {"9G", "Take2 / Den'Z / Global Star"}, + {"9H", "Bottom Up"}, + {"9J", "TGL (Technical Group Laboratory)"}, + {"9L", "Hasbro Japan"}, + {"9N", "Marvelous Entertainment"}, + {"9P", "Keynet Inc."}, + {"9Q", "Hands-On Entertainment"}, + {"12", "Infocom"}, + {"13", "Electronic Arts Japan"}, + {"15", "Cobra Team"}, + {"16", "Human / Field"}, + {"17", "KOEI"}, + {"18", "Hudson Soft"}, + {"19", "S.C.P."}, + {"20", "Destination Software / Zoo Games / KSS"}, + {"21", "Sunsoft / Tokai Engineering"}, + {"22", "POW (Planning Office Wada) / VR1 Japan"}, + {"23", "Micro World"}, + {"25", "San-X"}, + {"26", "Enix"}, + {"27", "Loriciel / Electro Brain"}, + {"28", "Kemco Japan"}, + {"29", "Seta"}, + {"30", "Viacom"}, + {"31", "Carrozzeria"}, + {"32", "Dynamic"}, + {"34", "Magifact"}, + {"35", "Hect"}, + {"36", "Codemasters"}, + {"37", "Taito / GAGA Communications"}, + {"38", "Laguna"}, + {"39", "Telstar / Event / Taito"}, + {"40", "Seika Corp."}, + {"41", "Ubi Soft Entertainment"}, + {"42", "Sunsoft US"}, + {"44", "Life Fitness"}, + {"46", "System 3"}, + {"47", "Spectrum Holobyte"}, + {"49", "IREM"}, + {"50", "Absolute Entertainment"}, + {"51", "Acclaim"}, + {"52", "Activision"}, + {"53", "American Sammy"}, + {"54", "Take 2 Interactive / GameTek"}, + {"55", "Hi Tech"}, + {"56", "LJN LTD."}, + {"58", "Mattel"}, + {"60", "Titus"}, + {"61", "Virgin Interactive"}, + {"62", "Maxis"}, + {"64", "LucasArts Entertainment"}, + {"67", "Ocean"}, + {"68", "Bethesda Softworks"}, + {"69", "Electronic Arts"}, + {"70", "Atari (Infogrames)"}, + {"71", "Interplay"}, + {"72", "JVC (US)"}, + {"73", "Parker Brothers"}, + {"75", "Sales Curve (Storm / SCI)"}, + {"78", "THQ"}, + {"79", "Accolade"}, + {"80", "Misawa"}, + {"81", "Teichiku"}, + {"82", "Namco Ltd."}, + {"83", "LOZC"}, + {"84", "KOEI"}, + {"86", "Tokuma Shoten Intermedia"}, + {"87", "Tsukuda Original"}, + {"88", "DATAM-Polystar"}, + {"90", "Takara Amusement"}, + {"91", "Chun Soft"}, + {"92", "Video System / Mc O' River"}, + {"93", "BEC"}, + {"95", "Varie"}, + {"96", "Yonezawa / S'pal"}, + {"97", "Kaneko"}, + {"99", "Marvelous Entertainment"}, + {"A0", "Telenet"}, + {"A1", "Hori"}, + {"A4", "Konami"}, + {"A5", "K.Amusement Leasing Co."}, + {"A6", "Kawada"}, + {"A7", "Takara"}, + {"A9", "Technos Japan Corp."}, + {"AA", "JVC / Victor"}, + {"AC", "Toei Animation"}, + {"AD", "Toho"}, + {"AF", "Namco"}, + {"AG", "Media Rings Corporation"}, + {"AH", "J-Wing"}, + {"AJ", "Pioneer LDC"}, + {"AK", "KID"}, + {"AL", "Mediafactory"}, + {"AP", "Infogrames / Hudson"}, + {"AQ", "Kiratto. Ludic Inc"}, + {"B0", "Acclaim Japan"}, + {"B1", "ASCII"}, + {"B2", "Bandai"}, + {"B4", "Enix"}, + {"B6", "HAL Laboratory"}, + {"B7", "SNK"}, + {"B9", "Pony Canyon"}, + {"BA", "Culture Brain"}, + {"BB", "Sunsoft"}, + {"BC", "Toshiba EMI"}, + {"BD", "Sony Imagesoft"}, + {"BF", "Sammy"}, + {"BG", "Magical"}, + {"BH", "Visco"}, + {"BJ", "Compile"}, + {"BL", "MTO Inc."}, + {"BN", "Sunrise Interactive"}, + {"BP", "Global A Entertainment"}, + {"BQ", "Fuuki"}, + {"C0", "Taito"}, + {"C2", "Kemco"}, + {"C3", "Square"}, + {"C4", "Tokuma Shoten"}, + {"C5", "Data East"}, + {"C6", "Tonkin House / Tokyo Shoseki"}, + {"C8", "Koei"}, + {"CA", "Konami / Ultra / Palcom"}, + {"CB", "NTVIC / VAP"}, + {"CC", "Use Co.,Ltd."}, + {"CD", "Meldac"}, + {"CE", "Pony Canyon / FCI"}, + {"CF", "Angel / Sotsu Agency / Sunrise"}, + {"CG", "Yumedia / Aroma Co., Ltd"}, + {"CJ", "Boss"}, + {"CK", "Axela / Crea-Tech"}, + {"CL", "Sekaibunka-Sha / Sumire Kobo / Marigul Management Inc."}, + {"CM", "Konami Computer Entertainment Osaka"}, + {"CN", "NEC Interchannel"}, + {"CP", "Enterbrain"}, + {"CQ", "From Software"}, + {"D0", "Taito / Disco"}, + {"D1", "Sofel"}, + {"D2", "Quest / Bothtec"}, + {"D3", "Sigma"}, + {"D4", "Ask Kodansha"}, + {"D6", "Naxat"}, + {"D7", "Copya System"}, + {"D8", "Capcom Co., Ltd."}, + {"D9", "Banpresto"}, + {"DA", "Tomy"}, + {"DB", "LJN Japan"}, + {"DD", "NCS"}, + {"DE", "Human Entertainment"}, + {"DF", "Altron"}, + {"DG", "Jaleco"}, + {"DH", "Gaps Inc."}, + {"DN", "Elf"}, + {"DQ", "Compile Heart"}, + {"E0", "Jaleco"}, + {"E2", "Yutaka"}, + {"E3", "Varie"}, + {"E4", "T&ESoft"}, + {"E5", "Epoch"}, + {"E7", "Athena"}, + {"E8", "Asmik"}, + {"E9", "Natsume"}, + {"EA", "King Records"}, + {"EB", "Atlus"}, + {"EC", "Epic / Sony Records"}, + {"EE", "IGS (Information Global Service)"}, + {"EG", "Chatnoir"}, + {"EH", "Right Stuff"}, + {"EL", "Spike"}, + {"EM", "Konami Computer Entertainment Tokyo"}, + {"EN", "Alphadream Corporation"}, + {"EP", "Sting"}, + {"ES", "Star-Fish"}, + {"F0", "A Wave"}, + {"F1", "Motown Software"}, + {"F2", "Left Field Entertainment"}, + {"F3", "Extreme Ent. Grp."}, + {"F4", "TecMagik"}, + {"F9", "Cybersoft"}, + {"FB", "Psygnosis"}, + {"FE", "Davidson / Western Tech."}, + {"FK", "The Game Factory"}, + {"FL", "Hip Games"}, + {"FM", "Aspyr"}, + {"FP", "Mastiff"}, + {"FQ", "iQue"}, + {"FR", "Digital Tainment Pool"}, + {"FS", "XS Games / Jack Of All Games"}, + {"FT", "Daiwon"}, + {"G0", "Alpha Unit"}, + {"G1", "PCCW Japan"}, + {"G2", "Yuke's Media Creations"}, + {"G4", "KiKi Co Ltd"}, + {"G5", "Open Sesame Inc"}, + {"G6", "Sims"}, + {"G7", "Broccoli"}, + {"G8", "Avex"}, + {"G9", "D3 Publisher"}, + {"GB", "Konami Computer Entertainment Japan"}, + {"GD", "Square-Enix"}, + {"GE", "KSG"}, + {"GF", "Micott & Basara Inc."}, + {"GH", "Orbital Media"}, + {"GJ", "Detn8 Games"}, + {"GL", "Gameloft / Ubi Soft"}, + {"GM", "Gamecock Media Group"}, + {"GN", "Oxygen Games"}, + {"GT", "505 Games"}, + {"GY", "The Game Factory"}, + {"H1", "Treasure"}, + {"H2", "Aruze"}, + {"H3", "Ertain"}, + {"H4", "SNK Playmore"}, + {"HJ", "Genius Products"}, + {"HY", "Reef Entertainment"}, + {"HZ", "Nordcurrent"}, + {"IH", "Yojigen"}, + {"J9", "AQ Interactive"}, + {"JF", "Arc System Works"}, + {"JW", "Atari"}, + {"K6", "Nihon System"}, + {"KB", "NIS America"}, + {"KM", "Deep Silver"}, + {"LH", "Trend Verlag / East Entertainment"}, + {"LT", "Legacy Interactive"}, + {"MJ", "Mumbo Jumbo"}, + {"MR", "Mindscape"}, + {"MS", "Milestone / UFO Interactive"}, + {"MT", "Blast !"}, + {"N9", "Terabox"}, + {"NK", "Neko Entertainment / Diffusion / Naps team"}, + {"NP", "Nobilis"}, + {"NR", "Data Design / Destineer Studios"}, + {"PL", "Playlogic"}, + {"RM", "Rondomedia"}, + {"RS", "Warner Bros. Interactive Entertainment Inc."}, + {"RT", "RTL Games"}, + {"RW", "RealNetworks"}, + {"S5", "Southpeak Interactive"}, + {"SP", "Blade Interactive Studios"}, + {"SV", "SevenGames"}, + {"TK", "Tasuke / Works"}, + {"UG", "Metro 3D / Data Design"}, + {"VN", "Valcon Games"}, + {"VP", "Virgin Play"}, + {"WR", "Warner Bros. Interactive Entertainment Inc."}, + {"XJ", "Xseed Games"}, + {"XS", "Aksys Games"}, + {NULL, NULL} +}; + +/** + * Retrieves the disk maker. + * @param d The disc structure. + * @param m This will point to a string containing the disc maker ID. + * @param m_s This will point to a string describing the disc maker. + * @return A string describing the disc maker. + */ +char *disc_get_maker (disc *d, char **m, char **m_s) { + u_int32_t i; + + if (m) + *m = d -> maker; + + if (m_s) { + for (i = 0; makers[i].code; i++) { + if (strcasecmp (d -> maker, makers[i].code) == 0) { + *m_s = makers[i].name; + break; + } + } + if (!makers[i].code) { + *m_s = "Unknown"; + } + } + + return (*m_s); +} + + +/** + * Retrieves the disc version. + * @param d The disc structure. + * @param v This will contain the version ID. + * @param v_s This will point to a string describing the disc version. + * @return A string describing the disc version. + */ +char *disc_get_version (disc *d, u_int8_t *v, char **v_s) { + if (v) + *v = d -> version; + + if (v_s) + *v_s = d -> version_string; + + return (*v_s); +} + + +/** + * Retrieves the disc game title. + * @param d The disc structure. + * @param t_s This will point to a string describing the disc title. + * @return A string describing the disc title. + */ +char *disc_get_title (disc *d, char **t_s) { + if (t_s) + *t_s = d -> title; + + return (*t_s); +} + + +/** + * Retrieves if the disc has an update. + * @param d The disc structure. + * @return True if the disc contains an update, false otherwise. + */ +bool disc_get_update (disc *d) { + return (d -> has_update); +} + + +/** + * Retrieves the number of sectors of the disc. + * @param d The disc structure. + * @return The number of sectors. + */ +u_int32_t disc_get_sectors_no (disc *d) { + return (d -> sectors_no); +} + +u_int32_t disc_get_layerbreak (disc *d) { + return (d -> layerbreak); +} + +u_int32_t disc_get_command (disc *d) { + return (d -> command); +} + +u_int32_t disc_get_method (disc *d) { + return (d -> read_method); +} + +u_int32_t disc_get_def_method (disc *d) { + return dvd_get_def_method(d -> dvd);//(d -> def_read_method); +} + +u_int32_t disc_get_sec_disc (disc *d) { + return (d -> sec_disc); +} + +u_int32_t disc_get_sec_mem (disc *d) { + return (d -> sec_mem); +} + +/* wiidevel@stacktic.org */ +static bool disc_check_update (disc *d) { + u_int8_t *buf; + u_int32_t x; + bool unscramble_old; + + if (d -> type == DISC_TYPE_WII || d -> type == DISC_TYPE_WII_DL) { + /* Force unscrambling for this read */ + unscramble_old = d -> unscrambling; + disc_set_unscrambling (d, true); + + /* We need to read offset 0x50004 of the disc. Sector 160 has offset 0x50000 */ + if (disc_read_sector (d, 160, &buf, NULL)) { + x = my_ntohl (*(u_int32_t *) (buf + 4)); + if (x == 0xA5BED6AE) + d -> has_update = false; + else + d -> has_update = true; + } else { + error ("disc_check_update() failed"); + } + + disc_set_unscrambling (d, unscramble_old); + } else { + /* GameCube discs never have an update, as actually the GC firmware cannot be upgrade */ + d -> has_update = false; + } + + return (d -> has_update); +} + + +/** + * Sets the disc read method. + * @param d The disc structure. + * @param method The requested method. + * @return True if the method was set correctly, false otherwise (i. e.: method too small/big). + */ +bool disc_set_read_method (disc *d, int method) { + bool out; + u_int32_t deviation; + u_int32_t counter; + u_int32_t cnt1; + + d -> command = dvd_get_command(d -> dvd); +// d -> def_read_method = dvd_get_def_method(d -> dvd); + d -> read_method = method; + + out = true; + switch (method) { + case 0: + d -> read_sector = disc_read_sector_0; + break; + case 1: + d -> read_sector = disc_read_sector_1; + break; + case 2: + d -> read_sector = disc_read_sector_2; + break; + case 3: + d -> read_sector = disc_read_sector_3; + break; + case 4: + d -> read_sector = disc_read_sector_4; + break; + case 5: + d -> read_sector = disc_read_sector_5; + break; + case 6: + d -> read_sector = disc_read_sector_6; + break; + case 7: + d -> read_sector = disc_read_sector_7; + break; + case 8: + d -> read_sector = disc_read_sector_8; + break; + case 9: + d -> read_sector = disc_read_sector_9; + break; + default: + switch (dvd_get_def_method(d -> dvd)) { + case 0: + d -> read_method = 0; + d -> read_sector = disc_read_sector_0; + break; + case 1: + d -> read_method = 1; + d -> read_sector = disc_read_sector_1; + break; + case 2: + d -> read_method = 2; + d -> read_sector = disc_read_sector_2; + break; + case 3: + d -> read_method = 3; + d -> read_sector = disc_read_sector_3; + break; + case 4: + d -> read_method = 4; + d -> read_sector = disc_read_sector_4; + break; + case 5: + d -> read_method = 5; + d -> read_sector = disc_read_sector_5; + break; + case 6: + d -> read_method = 6; + d -> read_sector = disc_read_sector_6; + break; + case 7: + d -> read_method = 7; + d -> read_sector = disc_read_sector_7; + break; + case 8: + d -> read_method = 8; + d -> read_sector = disc_read_sector_8; + break; + case 9: + d -> read_method = 9; + d -> read_sector = disc_read_sector_9; + break; + default: + d -> read_method = DEFAULT_READ_METHOD; + d -> read_sector = DEFAULT_READ_SECTOR; + break; + } + } + + if (d->sec_disc==-1) { + if ((d->read_method == 4) || (d->read_method == 5) || (d->read_method == 6)) + d->sec_disc=27; + else + d->sec_disc=16; + } + if (d->sec_mem==-1) { + if ((d->read_method == 4) || (d->read_method == 5) || (d->read_method == 6)) + d->sec_mem=27; + else + d->sec_mem=16; + } + + deviation = d->sec_mem % SECTORS_PER_BLOCK; + counter=0; + + if (deviation>3) { + cnt1=deviation; + while (1==1) { + cnt1+=deviation; + counter++; + if (cnt1%SECTORS_PER_BLOCK<=1) break; + } + } + d -> max_cnt = counter; + d -> max_blk = ((d->sec_mem*(d->max_cnt+1))-((d->sec_mem*(d->max_cnt+1)) % SECTORS_PER_BLOCK)) / 16; + + if (out) { + debug ("Read method set to %d", d -> read_method); + } else { + error ("Cannot set read method\n"); + } + + return (out); +} + + +/** + * Controls the unscrambling process. + * @param d The disc structure. + * @param unscramble If true, every raw sectors read will be unscrambled to check if they are error-free, otherwise read data will be returned as-is. + */ +void disc_set_unscrambling (disc *d, bool unscramble) { + d -> unscrambling = unscramble; + debug ("Sectors unscrambling %s", unscramble ? "enabled" : "disabled"); + + return; +} + + +static void disc_crack_seeds (disc *d) { + int i; + + /* As a Nintendo GameCube/Wii disc should not have too many keys, 20 should be enough */ + debug ("Retrieving all DVD seeds"); + for (i = 0; i < 20 * 16; i += 16) + disc_read_sector (d, i, NULL, NULL); + + return; +} + + +/** + * Creates a new structure representing a Nintendo GameCube/Wii optical disc. + * @param dvd_device The CD/DVD-ROM device, in OS-dependent format (i.e.: /dev/something on Unix, x: on Windows). + * @return The newly-created structure, to be used with the other commands. + */ +disc *disc_new (char *dvd_device, u_int32_t command) { + dvd_drive *dvd; + disc *d; + + if ((dvd = dvd_drive_new (dvd_device, command))) { + d = (disc *) malloc (sizeof (disc)); + memset (d, 0, sizeof (disc)); + d -> dvd = dvd; + d -> u = unscrambler_new (); + disc_set_unscrambling (d, true); // Unscramble by default + disc_set_read_method (d, DEFAULT_READ_METHOD); + disc_cache_init (d, DISC_DEFAULT_CACHE_SIZE); + } else { + d = NULL; + } + + return (d); +} + + +bool disc_init (disc *d, u_int32_t disctype, u_int32_t sectors_no) { + bool out; + + d -> sectors_no = 1000; // TODO + disc_detect_type (d, disctype, sectors_no); + disc_crack_seeds (d); +// unscrambler_set_bruteforce (d -> u, false); // Disabling bruteforcing will allow us to detect errors more quickly + unscrambler_set_bruteforce (d -> u, true); + if (d -> type==DISC_TYPE_DVD) { + my_strdup (d -> title, "DVD"+'\0'); + out = true; + } + else if (disc_analyze (d)) { + disc_check_update (d); + out = true; + } else { + out = false; + } + + return (out); +} + + +/** + * Frees resources used by a disc structure and destroys it. + * @param d The disc structure. + * @return NULL. + */ +void *disc_destroy (disc *d) { + disc_cache_destroy (d); + unscrambler_destroy (d -> u); + my_free (d -> version_string); + my_free (d -> title); + dvd_drive_destroy (d -> dvd); + my_free (d); + + return (NULL); +} + + +char *disc_get_drive_model_string (disc *d) { + return (dvd_get_model_string (d -> dvd)); +} + + +bool disc_get_drive_support_status (disc *d) { + return (dvd_get_support_status (d -> dvd)); +} + +void disc_set_speed (disc *d, u_int32_t speed) { + if (speed != -1) dvd_set_speed (d -> dvd, speed, NULL); +} + +void disc_set_streaming_speed (disc *d, u_int32_t speed) { + if (speed != -1) dvd_set_streaming (d -> dvd, speed, NULL); +} + +bool disc_stop_unit (disc *d, bool start) { + if (dvd_stop_unit (d -> dvd, start, NULL) == 0) return true; + else return false; +} + +void init_range (disc *d, u_int32_t sec_disc, u_int32_t sec_mem) { + if ((sec_disc>=1)&&(sec_disc<=100)) d->sec_disc = sec_disc; + else d->sec_disc = -1; + if ((sec_mem>=16)&&(sec_mem<=100)) d->sec_mem = sec_mem; + else d->sec_mem = -1; } \ No newline at end of file diff --git a/libfriidump/ecma-267.c b/libfriidump/ecma-267.c index 46c3d9a..48a23e2 100644 --- a/libfriidump/ecma-267.c +++ b/libfriidump/ecma-267.c @@ -1,109 +1,109 @@ -/* -unscrambler 0.4: unscramble not standard IVs scrambled DVDs thru -bruteforce, intended for Gamecube/WII Optical Disks. - -Copyright (C) 2006 Victor Muņoz (xt5@ingenieria-inversa.cl) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "ecma-267.h" - -/* EDC stuff */ -unsigned int edc_table[256] = { - 0x00000000, 0x80000011, 0x80000033, 0x00000022, 0x80000077, 0x00000066, 0x00000044, 0x80000055, - 0x800000FF, 0x000000EE, 0x000000CC, 0x800000DD, 0x00000088, 0x80000099, 0x800000BB, 0x000000AA, - 0x800001EF, 0x000001FE, 0x000001DC, 0x800001CD, 0x00000198, 0x80000189, 0x800001AB, 0x000001BA, - 0x00000110, 0x80000101, 0x80000123, 0x00000132, 0x80000167, 0x00000176, 0x00000154, 0x80000145, - 0x800003CF, 0x000003DE, 0x000003FC, 0x800003ED, 0x000003B8, 0x800003A9, 0x8000038B, 0x0000039A, - 0x00000330, 0x80000321, 0x80000303, 0x00000312, 0x80000347, 0x00000356, 0x00000374, 0x80000365, - 0x00000220, 0x80000231, 0x80000213, 0x00000202, 0x80000257, 0x00000246, 0x00000264, 0x80000275, - 0x800002DF, 0x000002CE, 0x000002EC, 0x800002FD, 0x000002A8, 0x800002B9, 0x8000029B, 0x0000028A, - 0x8000078F, 0x0000079E, 0x000007BC, 0x800007AD, 0x000007F8, 0x800007E9, 0x800007CB, 0x000007DA, - 0x00000770, 0x80000761, 0x80000743, 0x00000752, 0x80000707, 0x00000716, 0x00000734, 0x80000725, - 0x00000660, 0x80000671, 0x80000653, 0x00000642, 0x80000617, 0x00000606, 0x00000624, 0x80000635, - 0x8000069F, 0x0000068E, 0x000006AC, 0x800006BD, 0x000006E8, 0x800006F9, 0x800006DB, 0x000006CA, - 0x00000440, 0x80000451, 0x80000473, 0x00000462, 0x80000437, 0x00000426, 0x00000404, 0x80000415, - 0x800004BF, 0x000004AE, 0x0000048C, 0x8000049D, 0x000004C8, 0x800004D9, 0x800004FB, 0x000004EA, - 0x800005AF, 0x000005BE, 0x0000059C, 0x8000058D, 0x000005D8, 0x800005C9, 0x800005EB, 0x000005FA, - 0x00000550, 0x80000541, 0x80000563, 0x00000572, 0x80000527, 0x00000536, 0x00000514, 0x80000505, - 0x80000F0F, 0x00000F1E, 0x00000F3C, 0x80000F2D, 0x00000F78, 0x80000F69, 0x80000F4B, 0x00000F5A, - 0x00000FF0, 0x80000FE1, 0x80000FC3, 0x00000FD2, 0x80000F87, 0x00000F96, 0x00000FB4, 0x80000FA5, - 0x00000EE0, 0x80000EF1, 0x80000ED3, 0x00000EC2, 0x80000E97, 0x00000E86, 0x00000EA4, 0x80000EB5, - 0x80000E1F, 0x00000E0E, 0x00000E2C, 0x80000E3D, 0x00000E68, 0x80000E79, 0x80000E5B, 0x00000E4A, - 0x00000CC0, 0x80000CD1, 0x80000CF3, 0x00000CE2, 0x80000CB7, 0x00000CA6, 0x00000C84, 0x80000C95, - 0x80000C3F, 0x00000C2E, 0x00000C0C, 0x80000C1D, 0x00000C48, 0x80000C59, 0x80000C7B, 0x00000C6A, - 0x80000D2F, 0x00000D3E, 0x00000D1C, 0x80000D0D, 0x00000D58, 0x80000D49, 0x80000D6B, 0x00000D7A, - 0x00000DD0, 0x80000DC1, 0x80000DE3, 0x00000DF2, 0x80000DA7, 0x00000DB6, 0x00000D94, 0x80000D85, - 0x00000880, 0x80000891, 0x800008B3, 0x000008A2, 0x800008F7, 0x000008E6, 0x000008C4, 0x800008D5, - 0x8000087F, 0x0000086E, 0x0000084C, 0x8000085D, 0x00000808, 0x80000819, 0x8000083B, 0x0000082A, - 0x8000096F, 0x0000097E, 0x0000095C, 0x8000094D, 0x00000918, 0x80000909, 0x8000092B, 0x0000093A, - 0x00000990, 0x80000981, 0x800009A3, 0x000009B2, 0x800009E7, 0x000009F6, 0x000009D4, 0x800009C5, - 0x80000B4F, 0x00000B5E, 0x00000B7C, 0x80000B6D, 0x00000B38, 0x80000B29, 0x80000B0B, 0x00000B1A, - 0x00000BB0, 0x80000BA1, 0x80000B83, 0x00000B92, 0x80000BC7, 0x00000BD6, 0x00000BF4, 0x80000BE5, - 0x00000AA0, 0x80000AB1, 0x80000A93, 0x00000A82, 0x80000AD7, 0x00000AC6, 0x00000AE4, 0x80000AF5, - 0x80000A5F, 0x00000A4E, 0x00000A6C, 0x80000A7D, 0x00000A28, 0x80000A39, 0x80000A1B, 0x00000A0AL -}; - -u32 edc_calc(u32 edc, u8 *ptr, u32 len) { - while (len--) edc=edc_table[((edc>>24)^*ptr++)&0xFF]^(edc<<8); - return edc; -} - -/* end of EDC stuff */ - -/* LFSR stuff */ - -u16 ecma267_ivs[]= { - 0x0001, 0x5500, 0x0002, 0x2A00, - 0x0004, 0x5400, 0x0008, 0x2800, - 0x0010, 0x5000, 0x0020, 0x2001, - 0x0040, 0x4002, 0x0080, 0x0005 -}; - - -unsigned short LFSR; - -void LFSR_ecma_init(int iv) { - LFSR=ecma267_ivs[iv]; -} - -void LFSR_init(u16 seed) { - LFSR=seed; -} - -int LFSR_tick() { - int ret; - int n; - - ret=LFSR>>14; - - n=ret^((LFSR>>10)&1); - LFSR=((LFSR<<1)|n)&0x7FFF; - - return ret; -} - -unsigned char LFSR_byte() { - u8 ret; - int i; - - ret=0; - for(i=0; i<8; i++) ret=(ret<<1)|LFSR_tick(); - - return ret; -} - -/* end of LFSR stuff */ +/* +unscrambler 0.4: unscramble not standard IVs scrambled DVDs thru +bruteforce, intended for Gamecube/WII Optical Disks. + +Copyright (C) 2006 Victor Muņoz (xt5@ingenieria-inversa.cl) + +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "ecma-267.h" + +/* EDC stuff */ +unsigned int edc_table[256] = { + 0x00000000, 0x80000011, 0x80000033, 0x00000022, 0x80000077, 0x00000066, 0x00000044, 0x80000055, + 0x800000FF, 0x000000EE, 0x000000CC, 0x800000DD, 0x00000088, 0x80000099, 0x800000BB, 0x000000AA, + 0x800001EF, 0x000001FE, 0x000001DC, 0x800001CD, 0x00000198, 0x80000189, 0x800001AB, 0x000001BA, + 0x00000110, 0x80000101, 0x80000123, 0x00000132, 0x80000167, 0x00000176, 0x00000154, 0x80000145, + 0x800003CF, 0x000003DE, 0x000003FC, 0x800003ED, 0x000003B8, 0x800003A9, 0x8000038B, 0x0000039A, + 0x00000330, 0x80000321, 0x80000303, 0x00000312, 0x80000347, 0x00000356, 0x00000374, 0x80000365, + 0x00000220, 0x80000231, 0x80000213, 0x00000202, 0x80000257, 0x00000246, 0x00000264, 0x80000275, + 0x800002DF, 0x000002CE, 0x000002EC, 0x800002FD, 0x000002A8, 0x800002B9, 0x8000029B, 0x0000028A, + 0x8000078F, 0x0000079E, 0x000007BC, 0x800007AD, 0x000007F8, 0x800007E9, 0x800007CB, 0x000007DA, + 0x00000770, 0x80000761, 0x80000743, 0x00000752, 0x80000707, 0x00000716, 0x00000734, 0x80000725, + 0x00000660, 0x80000671, 0x80000653, 0x00000642, 0x80000617, 0x00000606, 0x00000624, 0x80000635, + 0x8000069F, 0x0000068E, 0x000006AC, 0x800006BD, 0x000006E8, 0x800006F9, 0x800006DB, 0x000006CA, + 0x00000440, 0x80000451, 0x80000473, 0x00000462, 0x80000437, 0x00000426, 0x00000404, 0x80000415, + 0x800004BF, 0x000004AE, 0x0000048C, 0x8000049D, 0x000004C8, 0x800004D9, 0x800004FB, 0x000004EA, + 0x800005AF, 0x000005BE, 0x0000059C, 0x8000058D, 0x000005D8, 0x800005C9, 0x800005EB, 0x000005FA, + 0x00000550, 0x80000541, 0x80000563, 0x00000572, 0x80000527, 0x00000536, 0x00000514, 0x80000505, + 0x80000F0F, 0x00000F1E, 0x00000F3C, 0x80000F2D, 0x00000F78, 0x80000F69, 0x80000F4B, 0x00000F5A, + 0x00000FF0, 0x80000FE1, 0x80000FC3, 0x00000FD2, 0x80000F87, 0x00000F96, 0x00000FB4, 0x80000FA5, + 0x00000EE0, 0x80000EF1, 0x80000ED3, 0x00000EC2, 0x80000E97, 0x00000E86, 0x00000EA4, 0x80000EB5, + 0x80000E1F, 0x00000E0E, 0x00000E2C, 0x80000E3D, 0x00000E68, 0x80000E79, 0x80000E5B, 0x00000E4A, + 0x00000CC0, 0x80000CD1, 0x80000CF3, 0x00000CE2, 0x80000CB7, 0x00000CA6, 0x00000C84, 0x80000C95, + 0x80000C3F, 0x00000C2E, 0x00000C0C, 0x80000C1D, 0x00000C48, 0x80000C59, 0x80000C7B, 0x00000C6A, + 0x80000D2F, 0x00000D3E, 0x00000D1C, 0x80000D0D, 0x00000D58, 0x80000D49, 0x80000D6B, 0x00000D7A, + 0x00000DD0, 0x80000DC1, 0x80000DE3, 0x00000DF2, 0x80000DA7, 0x00000DB6, 0x00000D94, 0x80000D85, + 0x00000880, 0x80000891, 0x800008B3, 0x000008A2, 0x800008F7, 0x000008E6, 0x000008C4, 0x800008D5, + 0x8000087F, 0x0000086E, 0x0000084C, 0x8000085D, 0x00000808, 0x80000819, 0x8000083B, 0x0000082A, + 0x8000096F, 0x0000097E, 0x0000095C, 0x8000094D, 0x00000918, 0x80000909, 0x8000092B, 0x0000093A, + 0x00000990, 0x80000981, 0x800009A3, 0x000009B2, 0x800009E7, 0x000009F6, 0x000009D4, 0x800009C5, + 0x80000B4F, 0x00000B5E, 0x00000B7C, 0x80000B6D, 0x00000B38, 0x80000B29, 0x80000B0B, 0x00000B1A, + 0x00000BB0, 0x80000BA1, 0x80000B83, 0x00000B92, 0x80000BC7, 0x00000BD6, 0x00000BF4, 0x80000BE5, + 0x00000AA0, 0x80000AB1, 0x80000A93, 0x00000A82, 0x80000AD7, 0x00000AC6, 0x00000AE4, 0x80000AF5, + 0x80000A5F, 0x00000A4E, 0x00000A6C, 0x80000A7D, 0x00000A28, 0x80000A39, 0x80000A1B, 0x00000A0AL +}; + +u32 edc_calc(u32 edc, u8 *ptr, u32 len) { + while (len--) edc=edc_table[((edc>>24)^*ptr++)&0xFF]^(edc<<8); + return edc; +} + +/* end of EDC stuff */ + +/* LFSR stuff */ + +u16 ecma267_ivs[]= { + 0x0001, 0x5500, 0x0002, 0x2A00, + 0x0004, 0x5400, 0x0008, 0x2800, + 0x0010, 0x5000, 0x0020, 0x2001, + 0x0040, 0x4002, 0x0080, 0x0005 +}; + + +unsigned short LFSR; + +void LFSR_ecma_init(int iv) { + LFSR=ecma267_ivs[iv]; +} + +void LFSR_init(u16 seed) { + LFSR=seed; +} + +int LFSR_tick() { + int ret; + int n; + + ret=LFSR>>14; + + n=ret^((LFSR>>10)&1); + LFSR=((LFSR<<1)|n)&0x7FFF; + + return ret; +} + +unsigned char LFSR_byte() { + u8 ret; + int i; + + ret=0; + for(i=0; i<8; i++) ret=(ret<<1)|LFSR_tick(); + + return ret; +} + +/* end of LFSR stuff */ diff --git a/libfriidump/ecma-267.h b/libfriidump/ecma-267.h index a3eefb1..e63c9c8 100644 --- a/libfriidump/ecma-267.h +++ b/libfriidump/ecma-267.h @@ -1,47 +1,47 @@ -/* -unscrambler 0.4: unscramble not standard IVs scrambled DVDs thru -bruteforce, intended for Gamecube/WII Optical Disks. - -Copyright (C) 2006 Victor Muņoz (xt5@ingenieria-inversa.cl) - -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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -typedef unsigned int u32; -typedef int s32; - -typedef unsigned short u16; -typedef short s16; - -typedef unsigned char u8; -typedef char s8; - -/* EDC stuff */ - -u32 edc_calc(u32 edc, u8 *ptr, u32 len); - -/* end of EDC stuff */ - -/* LFSR stuff */ - -void LFSR_ecma_init(int iv); - -void LFSR_init(u16 seed); - -int LFSR_tick(); - -u8 LFSR_byte(); - -/* end of LFSR stuff */ +/* +unscrambler 0.4: unscramble not standard IVs scrambled DVDs thru +bruteforce, intended for Gamecube/WII Optical Disks. + +Copyright (C) 2006 Victor Muņoz (xt5@ingenieria-inversa.cl) + +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +typedef unsigned int u32; +typedef int s32; + +typedef unsigned short u16; +typedef short s16; + +typedef unsigned char u8; +typedef char s8; + +/* EDC stuff */ + +u32 edc_calc(u32 edc, u8 *ptr, u32 len); + +/* end of EDC stuff */ + +/* LFSR stuff */ + +void LFSR_ecma_init(int iv); + +void LFSR_init(u16 seed); + +int LFSR_tick(); + +u8 LFSR_byte(); + +/* end of LFSR stuff */ diff --git a/libfriidump/rs.c b/libfriidump/rs.c index ba2c4dc..4534d5b 100644 --- a/libfriidump/rs.c +++ b/libfriidump/rs.c @@ -1,316 +1,316 @@ -#include -#include -#include -#include - -#define mm 8 /* RS code over GF(2**mm) - change to suit */ -#define n 256 /* n = size of the field */ -#define nn 182 /* nn=2**mm -1 length of codeword */ -#define kk 172 /* kk = nn-2*tt */ /* Degree of g(x) = 2*tt */ - -//#define NN n-1 -//#define FCR 0 -//#define PRIM 1 -#define _NROOTS nn-kk -//#define PAD NN-nn -//#define A0 NN -//#define IPRIM 1 - -const int NN = n-1; -const int FCR = 0; -const int PRIM = 1; -const int NROOTS = nn-kk; -const int PAD = (n-1)-nn; -const int A0 = n-1; -const int IPRIM = 1; - - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/**** Primitive polynomial ****/ -int pp [mm+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1}; /* 1+x^2+x^3+x^4+x^8 */ - -/* generator polynomial, tables for Galois field */ -int alpha_to[n], index_of[n], gg[nn-kk+1]; - -int b0 = 1; - -/* data[] is the info vector, bb[] is the parity vector, recd[] is the - noise corrupted received vector */ -int recd[nn], data[kk], bb[nn-kk]; - -int modnn(int x){ - while (x >= 0xff) { - x -= 0xff; - x = (x >> 0xff) + (x & 0xff); - } - return x; -} - - -void generate_gf() - { - register int i, mask ; - - mask = 1 ; - alpha_to[mm] = 0 ; - for (i=0; i>= 1 ; - for (i=mm+1; i<255; i++) - { if (alpha_to[i-1] >= mask) - alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i-1]^mask)<<1) ; - else alpha_to[i] = alpha_to[i-1]<<1 ; - index_of[alpha_to[i]] = i ; - } - index_of[0] = A0 ;//-1 - } - - -void gen_poly() -/* Obtain the generator polynomial of the tt-error correcting, length */ - { - register int i, j, root; - - gg[0] = 1; - - for (i = 0,root=0*1; i < nn-kk; i++,root += 1) { - gg[i+1] = 1; - - for (j = i; j > 0; j--){ - if (gg[j] != 0) - gg[j] = gg[j-1] ^ alpha_to[modnn(index_of[gg[j]] + root)]; - else - gg[j] = gg[j-1]; - } - - gg[0] = alpha_to[modnn(index_of[gg[0]] + root)]; - } - for (i=0; i <= nn-kk; i++) { - gg[i] = index_of[gg[i]]; - } - } - - -void rs_encode(unsigned char *data, unsigned char *bb) - { - register int i,j ; - int feedback; - - for (i=0; i 0) { - /* Init lambda to be the erasure locator polynomial */ - lambda[1] = alpha_to[modnn(PRIM*(NN-1-eras_pos[0]))]; - for (i = 1; i < no_eras; i++) { - u = modnn(PRIM*(NN-1-eras_pos[i])); - for (j = i+1; j > 0; j--) { - tmp = index_of[lambda[j - 1]]; - if(tmp != A0) - lambda[j] ^= alpha_to[modnn(u + tmp)]; - } - } - } - for(i=0;i 0; j--){ - if (reg[j] != A0) { - reg[j] = modnn(reg[j] + j); - q ^= alpha_to[reg[j]]; - } - } - if (q != 0) - continue; /* Not a root */ - /* store root (index-form) and error location number */ - root[count] = i; - loc[count] = k; - /* If we've already found max possible roots, - * abort the search to save time - */ - if(++count == deg_lambda) - break; - } - - if (deg_lambda != count) { - /* - * deg(lambda) unequal to number of roots => uncorrectable - * error detected - */ - count = -1; - goto finish; - } - /* - * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo - * x**NROOTS). in index form. Also find deg(omega). - */ - deg_omega = deg_lambda-1; - for (i = 0; i <= deg_omega;i++){ - tmp = 0; - for(j=i;j >= 0; j--){ - if ((s[i - j] != A0) && (lambda[j] != A0)) - tmp ^= alpha_to[modnn(s[i - j] + lambda[j])]; - } - omega[i] = index_of[tmp]; - } - - /* - * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = - * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form - */ - for (j = count-1; j >=0; j--) { - num1 = 0; - for (i = deg_omega; i >= 0; i--) { - if (omega[i] != A0) - num1 ^= alpha_to[modnn(omega[i] + i * root[j])]; - } - num2 = alpha_to[modnn(root[j] * (FCR - 1) + NN)]; - den = 0; - - /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ - for (i = min(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) { - if(lambda[i+1] != A0) - den ^= alpha_to[modnn(lambda[i+1] + i * root[j])]; - } - /* Apply error to data */ - if (num1 != 0 && loc[j] >= PAD) { - data[loc[j]-PAD] ^= alpha_to[modnn(index_of[num1] + index_of[num2] + NN - index_of[den])]; - } - } - - finish: - if(eras_pos != NULL){ - for(i=0;i +#include +#include +#include + +#define mm 8 /* RS code over GF(2**mm) - change to suit */ +#define n 256 /* n = size of the field */ +#define nn 182 /* nn=2**mm -1 length of codeword */ +#define kk 172 /* kk = nn-2*tt */ /* Degree of g(x) = 2*tt */ + +//#define NN n-1 +//#define FCR 0 +//#define PRIM 1 +#define _NROOTS nn-kk +//#define PAD NN-nn +//#define A0 NN +//#define IPRIM 1 + +const int NN = n-1; +const int FCR = 0; +const int PRIM = 1; +const int NROOTS = nn-kk; +const int PAD = (n-1)-nn; +const int A0 = n-1; +const int IPRIM = 1; + + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/**** Primitive polynomial ****/ +int pp [mm+1] = { 1, 0, 1, 1, 1, 0, 0, 0, 1}; /* 1+x^2+x^3+x^4+x^8 */ + +/* generator polynomial, tables for Galois field */ +int alpha_to[n], index_of[n], gg[nn-kk+1]; + +int b0 = 1; + +/* data[] is the info vector, bb[] is the parity vector, recd[] is the + noise corrupted received vector */ +int recd[nn], data[kk], bb[nn-kk]; + +int modnn(int x){ + while (x >= 0xff) { + x -= 0xff; + x = (x >> 0xff) + (x & 0xff); + } + return x; +} + + +void generate_gf() + { + register int i, mask ; + + mask = 1 ; + alpha_to[mm] = 0 ; + for (i=0; i>= 1 ; + for (i=mm+1; i<255; i++) + { if (alpha_to[i-1] >= mask) + alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i-1]^mask)<<1) ; + else alpha_to[i] = alpha_to[i-1]<<1 ; + index_of[alpha_to[i]] = i ; + } + index_of[0] = A0 ;//-1 + } + + +void gen_poly() +/* Obtain the generator polynomial of the tt-error correcting, length */ + { + register int i, j, root; + + gg[0] = 1; + + for (i = 0,root=0*1; i < nn-kk; i++,root += 1) { + gg[i+1] = 1; + + for (j = i; j > 0; j--){ + if (gg[j] != 0) + gg[j] = gg[j-1] ^ alpha_to[modnn(index_of[gg[j]] + root)]; + else + gg[j] = gg[j-1]; + } + + gg[0] = alpha_to[modnn(index_of[gg[0]] + root)]; + } + for (i=0; i <= nn-kk; i++) { + gg[i] = index_of[gg[i]]; + } + } + + +void rs_encode(unsigned char *data, unsigned char *bb) + { + register int i,j ; + int feedback; + + for (i=0; i 0) { + /* Init lambda to be the erasure locator polynomial */ + lambda[1] = alpha_to[modnn(PRIM*(NN-1-eras_pos[0]))]; + for (i = 1; i < no_eras; i++) { + u = modnn(PRIM*(NN-1-eras_pos[i])); + for (j = i+1; j > 0; j--) { + tmp = index_of[lambda[j - 1]]; + if(tmp != A0) + lambda[j] ^= alpha_to[modnn(u + tmp)]; + } + } + } + for(i=0;i 0; j--){ + if (reg[j] != A0) { + reg[j] = modnn(reg[j] + j); + q ^= alpha_to[reg[j]]; + } + } + if (q != 0) + continue; /* Not a root */ + /* store root (index-form) and error location number */ + root[count] = i; + loc[count] = k; + /* If we've already found max possible roots, + * abort the search to save time + */ + if(++count == deg_lambda) + break; + } + + if (deg_lambda != count) { + /* + * deg(lambda) unequal to number of roots => uncorrectable + * error detected + */ + count = -1; + goto finish; + } + /* + * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo + * x**NROOTS). in index form. Also find deg(omega). + */ + deg_omega = deg_lambda-1; + for (i = 0; i <= deg_omega;i++){ + tmp = 0; + for(j=i;j >= 0; j--){ + if ((s[i - j] != A0) && (lambda[j] != A0)) + tmp ^= alpha_to[modnn(s[i - j] + lambda[j])]; + } + omega[i] = index_of[tmp]; + } + + /* + * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = + * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form + */ + for (j = count-1; j >=0; j--) { + num1 = 0; + for (i = deg_omega; i >= 0; i--) { + if (omega[i] != A0) + num1 ^= alpha_to[modnn(omega[i] + i * root[j])]; + } + num2 = alpha_to[modnn(root[j] * (FCR - 1) + NN)]; + den = 0; + + /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ + for (i = min(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) { + if(lambda[i+1] != A0) + den ^= alpha_to[modnn(lambda[i+1] + i * root[j])]; + } + /* Apply error to data */ + if (num1 != 0 && loc[j] >= PAD) { + data[loc[j]-PAD] ^= alpha_to[modnn(index_of[num1] + index_of[num2] + NN - index_of[den])]; + } + } + + finish: + if(eras_pos != NULL){ + for(i=0;i -#include -#include -#include - -int modnn(int x); -void generate_gf(); -void gen_poly(); -void rs_encode(unsigned char *data, unsigned char *bb); -int rs_decode(unsigned char *data, int *eras_pos, int no_eras); +#include +#include +#include +#include + +int modnn(int x); +void generate_gf(); +void gen_poly(); +void rs_encode(unsigned char *data, unsigned char *bb); +int rs_decode(unsigned char *data, int *eras_pos, int no_eras); diff --git a/libfriidump/unscrambler.c b/libfriidump/unscrambler.c index 6bfa788..2198ee9 100644 --- a/libfriidump/unscrambler.c +++ b/libfriidump/unscrambler.c @@ -1,370 +1,370 @@ -/*************************************************************************** - * Copyright (C) 2007 by Arep * - * Support is provided through the forums at * - * http://wii.console-tribe.com * - * * - * 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. * - ***************************************************************************/ - -/*! \file - * \brief Unscrambler for Nintendo GameCube/Wii discs. - * - * As Nintendo GameCube/Wii discs use the standars DVD-ROM scrambling algorithm, but with different, unknown, seeds, the actual seeds have to be brute-forced. - * The functions in this file take care of the brute-forcing and of the actual unscrambling of the read sectors. - * - * The code in this file has been derived from unscrambler 0.4, Copyright (C) 2006 Victor Muņoz (xt5@ingenieria-inversa.cl), GPL v2+, - * http://www.ingenieria-inversa.cl/?lp_lang_pref=en . - */ - -#include "misc.h" -#include -#include -#include -#include -#include "constants.h" -#include "byteorder.h" -#include "ecma-267.h" -#include "unscrambler.h" - -// #define unscramblerdebug(...) debug (__VA_ARGS__); -#define unscramblerdebug(...) - -/*! \brief Size of the seeds cache (Do not touch) */ -#define MAX_SEEDS 4 - -/*! \brief Number of bytes of a sector on which the EDC is calculated */ -#define EDC_LENGTH (RAW_SECTOR_SIZE - 4) /* The EDC value is contained in the bottom 4 bytes of a frame */ - - -/*! \brief A structure that represents a seed - */ -typedef struct t_seed { - int seed; //!< The seed, in numeric format. - unsigned char streamcipher[SECTOR_SIZE]; //!< The stream cipher generated from the seed through the LFSR. -} t_seed; - - -/*! \brief A structure that represents an unscrambler - */ -struct unscrambler_s { - t_seed seeds[(MAX_SEEDS + 1) * 16]; //!< The seeds cache. - bool bruteforce_seeds; //!< If true, whenever a seed for a sector is not cached, it will be found via a bruteforce attack, otherwise an error will be returned. -}; - -void unscrambler_set_disctype (u_int8_t disc_type){ - disctype = disc_type; -// fprintf (stdout,"%d",disctype); -} - -/** - * Adds a seed to the cache, calculating its streamcipher. - * @param seeds The seed cache. - * @param seed The seed to add. - * @return A structure representing the added seed, or NULL if it could not be added. - */ -static t_seed *add_seed (t_seed *seeds, unsigned short seed) { - int i; - t_seed *out; - - unscramblerdebug ("Caching seed %04x\n", seed); - - if (seeds -> seed == -2) { - out = NULL; - } else { - seeds -> seed = seed; - - LFSR_init (seed); - for (i = 0; i < SECTOR_SIZE; i++) - seeds -> streamcipher[i] = LFSR_byte (); - - out = seeds; - } - - return (out); -} - - -/** - * Tests if the specified seed is the one used for the specified sector block: the check is done comparing the generated EDC with the one at the bottom of each - * sector. Sectors are processed in blocks, as the same seed is used for 16 consecutive sectors. - * @param buf The sector. - * @param j The seed. - * @return true if the seed is correct, false otherwise. - */ -static bool test_seed (u_int8_t *buf, int j) { - int i; - u_int8_t tmp[RAW_SECTOR_SIZE]; - u_int32_t edc_calculated, edc_correct; - bool out; - - memcpy (tmp, buf, RAW_SECTOR_SIZE); - - LFSR_init (j); - for (i = 12; i < EDC_LENGTH; i++) - tmp[i] ^= LFSR_byte (); - - edc_calculated = edc_calc (0x00000000, tmp, EDC_LENGTH); - edc_correct = my_ntohl (*((u_int32_t *) (&tmp[EDC_LENGTH]))); - if (edc_calculated == edc_correct) - out = true; - else - out = false; - - return (out); -} - - -/** - * Unscramble a complete block, using an already-cached seed. - * @param seed The seed to use for the unscrambling. - * @param _bin The 16-sector block to unscramble (RAW_BLOCK_SIZE). - * @param _bout The unscrambled 16-sector block (BLOCK_SIZE). - * @return True if the unscrambling was successful, false otherwise. - */ -static bool unscramble_frame (t_seed *seed, u_int8_t *_bin, u_int8_t *_bout) { - int i, j; - u_int8_t tmp[RAW_SECTOR_SIZE], *bin, *bout; - u_int32_t *_4bin, *_4cipher, edc_calculated, edc_correct; - bool out; - - out = true; - for(j = 0; j < 16; j++) { - bin = &_bin[RAW_SECTOR_SIZE * j]; - bout = &_bout[SECTOR_SIZE * j]; - - memcpy (tmp, bin, RAW_SECTOR_SIZE); - _4bin = (u_int32_t *) &tmp[12]; /* Scrambled data begin at byte 12 */ - _4cipher = (u_int32_t *) seed -> streamcipher; - for (i = 0; i < 512; i++) /* Well, the scrambling algorithm is just a bitwise XOR... */ - _4bin[i] ^= _4cipher[i]; - - //memcpy (bout, tmp + 6, SECTOR_SIZE); // copy CPR_MAI bytes - - if (disctype==3) { //Regular - memcpy (bout, tmp + 12, SECTOR_SIZE); // DVD: copy 2048 bytes (starting from CPR_MAI) - } - else { //Nintendo - memcpy (bout, tmp + 6, SECTOR_SIZE); // Nintendo: copy 2048 bytes (up to CPR_MAI) - memcpy (&_bin[(RAW_SECTOR_SIZE * j)+2054], &tmp[2054], 6); - } - - edc_calculated = edc_calc (0x00000000, tmp, EDC_LENGTH); - edc_correct = my_ntohl (*((u_int32_t *) (&tmp[EDC_LENGTH]))); - if (edc_calculated != edc_correct) { - debug ("Bad EDC (%08x), must be %08x (sector = %d)", edc_calculated, edc_correct, j); - out = false; - } - } - - return (out); -} - - -/** - * Initializes the seed cache. - * @param u The unscrambler structure. - */ -static void unscrambler_init_seeds (unscrambler *u) { - int i, j; - - for (i = 0; i < 16; i++) { - for (j = 0; j < MAX_SEEDS; j++) - u -> seeds[i * MAX_SEEDS + j].seed = -1; - - u -> seeds[i * MAX_SEEDS + j].seed = -2; // TODO Check what this does - } - - return; -} - - -/** - * Creates a new structure representing an unscrambler. - * @return The newly-created structure, to be used with the other commands. - */ -unscrambler *unscrambler_new (void) { - unscrambler *u; - - u = (unscrambler *) malloc (sizeof (unscrambler)); - unscrambler_init_seeds (u); - u -> bruteforce_seeds = true; - - return (u); -} - - -/** - * Frees resources used by an unscrambler structure and destroys it. - * @param u The unscrambler structure. - * @return NULL. - */ -void *unscrambler_destroy (unscrambler *u) { - my_free (u); - - return (NULL); -} - - -void unscrambler_set_bruteforce (unscrambler *u, bool b) { - u -> bruteforce_seeds = b; - debug ("Seed bruteforcing %s", b ? "enabled" : "disabled"); - - return; -} - - -/** - * Unscrambles a 16-sector block. - * @param u The unscrambler structure. - * @param sector_no The number of the first sector in the block. - * @param inbuf The 16-sector block to unscramble. Each block must be RAW_SECTOR_SIZE bytes long, so that the total size is RAW_BLOCK_SIZE. - * @param outbuf The unscrambled 16-sector block. Each block will be SECTOR_SIZE bytes long, so that the total size is BLOCK_SIZE. - * @return True if the unscrambling was successful, false otherwise. - */ -bool unscrambler_unscramble_16sectors (unscrambler *u, u_int32_t sector_no, u_int8_t *inbuf, u_int8_t *outbuf) { - t_seed *seeds; - t_seed *current_seed; - int j; - bool out; - - out = true; - - seeds = &(u -> seeds[((sector_no / 16) & 0x0F) * MAX_SEEDS]); - - /* Try to find the seed used for this sector */ - current_seed = NULL; - while (!current_seed && (seeds -> seed) >= 0) { - if (test_seed (inbuf, seeds -> seed)) - current_seed = seeds; - else - seeds++; - } - - if (!current_seed && u -> bruteforce_seeds) { - /* The seed is not cached, yet. Try to find it with brute force... */ - unscramblerdebug ("Brute-forcing seed for sector %d...", sector_no); - - for (j = 0; !current_seed && j < 0x7FFF; j++) { - if (test_seed (inbuf, j)) { - if (!(current_seed = add_seed (seeds, j))) { - error ("No enough cache space for caching seed"); - out = false; - } - } - } - - if (current_seed) - unscramblerdebug ("Seed found: %04x", --j); - } - - if (current_seed) { - /* OK, somehow seed was found: unscramble frame, write it and go on */ - if (!unscramble_frame (current_seed, inbuf, outbuf)) { - error ("Error unscrambling frame %u\n", sector_no); - out = false; - } else { - out = true; - } - } else { - /* Well, we only get here if there are read errors */ - error ("Cannot find seed for frame %u", sector_no); - out = false; - } - - return (out); -} - - -/** - * Unscrambles a complete file. - * @param u The unscrambler structure. - * @param infile The input file name. - * @param outfile The output file name. - * @param progress A function to be called repeatedly during the operation, useful to report progress data/statistics. - * @param progress_data Data to be passed as-is to the progress function. - * @return True if the unscrambling was successful, false otherwise. - */ -bool unscrambler_unscramble_file (unscrambler *u, char *infile, char *outfile, unscrambler_progress_func progress, void *progress_data, u_int32_t *current_sector) { - FILE *in, *outfp; - bool out; - u_int8_t b_in[RAW_BLOCK_SIZE], b_out[BLOCK_SIZE]; - size_t r; - my_off_t filesize; - int s; - u_int32_t total_sectors; - - out = false; - if(!(in = fopen (infile ? infile : "", "rb"))) { - error ("Cannot open input file \"%s\"", infile); - } else if (!(outfp = fopen (outfile ? outfile : "", "wb"))) { - error ("Cannot open output file \"%s\"", outfile); - fclose (in); - } else { - /* Find out how many sectors we need to process */ - my_fseek (in, 0, SEEK_END); - filesize = my_ftell (in); - total_sectors = (u_int32_t) (filesize / RAW_SECTOR_SIZE); - rewind (in); - - /* First call to progress function */ - if (progress) - progress (true, 0, total_sectors, progress_data); - - s = 0, out = true; - while ((r = fread (b_in, 1, RAW_BLOCK_SIZE, in)) > 0 && out) { - if (r < RAW_BLOCK_SIZE) { - warning ("Short block read (%u bytes), padding with zeroes!", r); - memset (b_in + r, 0, sizeof (b_in) - r); - } - - if (unscrambler_unscramble_16sectors (u, s, b_in, b_out)) { - clearerr (outfp); - - if (!b_out) { - error ("NULL buffer"); - out = false; - *(current_sector) = s; - } - else fwrite (b_out, SECTOR_SIZE, SECTORS_PER_BLOCK, outfp); - if (ferror (outfp)) { - error ("fwrite() to ISO output file failed"); - out = false; - *(current_sector) = s; - } - } else { - debug ("unscrambler_unscramble_16sectors() failed"); - out = false; - *(current_sector) = s; - } - - s += 16; - - if ((s % 320 == 0) || (s == total_sectors)) { //speedhack - if (progress) - progress (false, s, total_sectors, progress_data); - } - } - - if (out) { - debug ("Image successfully unscrambled"); - } - - fclose (in); - fclose (outfp); - } - - return (out); -} +/*************************************************************************** + * Copyright (C) 2007 by Arep * + * Support is provided through the forums at * + * http://wii.console-tribe.com * + * * + * 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. * + ***************************************************************************/ + +/*! \file + * \brief Unscrambler for Nintendo GameCube/Wii discs. + * + * As Nintendo GameCube/Wii discs use the standars DVD-ROM scrambling algorithm, but with different, unknown, seeds, the actual seeds have to be brute-forced. + * The functions in this file take care of the brute-forcing and of the actual unscrambling of the read sectors. + * + * The code in this file has been derived from unscrambler 0.4, Copyright (C) 2006 Victor Muņoz (xt5@ingenieria-inversa.cl), GPL v2+, + * http://www.ingenieria-inversa.cl/?lp_lang_pref=en . + */ + +#include "misc.h" +#include +#include +#include +#include +#include "constants.h" +#include "byteorder.h" +#include "ecma-267.h" +#include "unscrambler.h" + +// #define unscramblerdebug(...) debug (__VA_ARGS__); +#define unscramblerdebug(...) + +/*! \brief Size of the seeds cache (Do not touch) */ +#define MAX_SEEDS 4 + +/*! \brief Number of bytes of a sector on which the EDC is calculated */ +#define EDC_LENGTH (RAW_SECTOR_SIZE - 4) /* The EDC value is contained in the bottom 4 bytes of a frame */ + + +/*! \brief A structure that represents a seed + */ +typedef struct t_seed { + int seed; //!< The seed, in numeric format. + unsigned char streamcipher[SECTOR_SIZE]; //!< The stream cipher generated from the seed through the LFSR. +} t_seed; + + +/*! \brief A structure that represents an unscrambler + */ +struct unscrambler_s { + t_seed seeds[(MAX_SEEDS + 1) * 16]; //!< The seeds cache. + bool bruteforce_seeds; //!< If true, whenever a seed for a sector is not cached, it will be found via a bruteforce attack, otherwise an error will be returned. +}; + +void unscrambler_set_disctype (u_int8_t disc_type){ + disctype = disc_type; +// fprintf (stdout,"%d",disctype); +} + +/** + * Adds a seed to the cache, calculating its streamcipher. + * @param seeds The seed cache. + * @param seed The seed to add. + * @return A structure representing the added seed, or NULL if it could not be added. + */ +static t_seed *add_seed (t_seed *seeds, unsigned short seed) { + int i; + t_seed *out; + + unscramblerdebug ("Caching seed %04x\n", seed); + + if (seeds -> seed == -2) { + out = NULL; + } else { + seeds -> seed = seed; + + LFSR_init (seed); + for (i = 0; i < SECTOR_SIZE; i++) + seeds -> streamcipher[i] = LFSR_byte (); + + out = seeds; + } + + return (out); +} + + +/** + * Tests if the specified seed is the one used for the specified sector block: the check is done comparing the generated EDC with the one at the bottom of each + * sector. Sectors are processed in blocks, as the same seed is used for 16 consecutive sectors. + * @param buf The sector. + * @param j The seed. + * @return true if the seed is correct, false otherwise. + */ +static bool test_seed (u_int8_t *buf, int j) { + int i; + u_int8_t tmp[RAW_SECTOR_SIZE]; + u_int32_t edc_calculated, edc_correct; + bool out; + + memcpy (tmp, buf, RAW_SECTOR_SIZE); + + LFSR_init (j); + for (i = 12; i < EDC_LENGTH; i++) + tmp[i] ^= LFSR_byte (); + + edc_calculated = edc_calc (0x00000000, tmp, EDC_LENGTH); + edc_correct = my_ntohl (*((u_int32_t *) (&tmp[EDC_LENGTH]))); + if (edc_calculated == edc_correct) + out = true; + else + out = false; + + return (out); +} + + +/** + * Unscramble a complete block, using an already-cached seed. + * @param seed The seed to use for the unscrambling. + * @param _bin The 16-sector block to unscramble (RAW_BLOCK_SIZE). + * @param _bout The unscrambled 16-sector block (BLOCK_SIZE). + * @return True if the unscrambling was successful, false otherwise. + */ +static bool unscramble_frame (t_seed *seed, u_int8_t *_bin, u_int8_t *_bout) { + int i, j; + u_int8_t tmp[RAW_SECTOR_SIZE], *bin, *bout; + u_int32_t *_4bin, *_4cipher, edc_calculated, edc_correct; + bool out; + + out = true; + for(j = 0; j < 16; j++) { + bin = &_bin[RAW_SECTOR_SIZE * j]; + bout = &_bout[SECTOR_SIZE * j]; + + memcpy (tmp, bin, RAW_SECTOR_SIZE); + _4bin = (u_int32_t *) &tmp[12]; /* Scrambled data begin at byte 12 */ + _4cipher = (u_int32_t *) seed -> streamcipher; + for (i = 0; i < 512; i++) /* Well, the scrambling algorithm is just a bitwise XOR... */ + _4bin[i] ^= _4cipher[i]; + + //memcpy (bout, tmp + 6, SECTOR_SIZE); // copy CPR_MAI bytes + + if (disctype==3) { //Regular + memcpy (bout, tmp + 12, SECTOR_SIZE); // DVD: copy 2048 bytes (starting from CPR_MAI) + } + else { //Nintendo + memcpy (bout, tmp + 6, SECTOR_SIZE); // Nintendo: copy 2048 bytes (up to CPR_MAI) + memcpy (&_bin[(RAW_SECTOR_SIZE * j)+2054], &tmp[2054], 6); + } + + edc_calculated = edc_calc (0x00000000, tmp, EDC_LENGTH); + edc_correct = my_ntohl (*((u_int32_t *) (&tmp[EDC_LENGTH]))); + if (edc_calculated != edc_correct) { + debug ("Bad EDC (%08x), must be %08x (sector = %d)", edc_calculated, edc_correct, j); + out = false; + } + } + + return (out); +} + + +/** + * Initializes the seed cache. + * @param u The unscrambler structure. + */ +static void unscrambler_init_seeds (unscrambler *u) { + int i, j; + + for (i = 0; i < 16; i++) { + for (j = 0; j < MAX_SEEDS; j++) + u -> seeds[i * MAX_SEEDS + j].seed = -1; + + u -> seeds[i * MAX_SEEDS + j].seed = -2; // TODO Check what this does + } + + return; +} + + +/** + * Creates a new structure representing an unscrambler. + * @return The newly-created structure, to be used with the other commands. + */ +unscrambler *unscrambler_new (void) { + unscrambler *u; + + u = (unscrambler *) malloc (sizeof (unscrambler)); + unscrambler_init_seeds (u); + u -> bruteforce_seeds = true; + + return (u); +} + + +/** + * Frees resources used by an unscrambler structure and destroys it. + * @param u The unscrambler structure. + * @return NULL. + */ +void *unscrambler_destroy (unscrambler *u) { + my_free (u); + + return (NULL); +} + + +void unscrambler_set_bruteforce (unscrambler *u, bool b) { + u -> bruteforce_seeds = b; + debug ("Seed bruteforcing %s", b ? "enabled" : "disabled"); + + return; +} + + +/** + * Unscrambles a 16-sector block. + * @param u The unscrambler structure. + * @param sector_no The number of the first sector in the block. + * @param inbuf The 16-sector block to unscramble. Each block must be RAW_SECTOR_SIZE bytes long, so that the total size is RAW_BLOCK_SIZE. + * @param outbuf The unscrambled 16-sector block. Each block will be SECTOR_SIZE bytes long, so that the total size is BLOCK_SIZE. + * @return True if the unscrambling was successful, false otherwise. + */ +bool unscrambler_unscramble_16sectors (unscrambler *u, u_int32_t sector_no, u_int8_t *inbuf, u_int8_t *outbuf) { + t_seed *seeds; + t_seed *current_seed; + int j; + bool out; + + out = true; + + seeds = &(u -> seeds[((sector_no / 16) & 0x0F) * MAX_SEEDS]); + + /* Try to find the seed used for this sector */ + current_seed = NULL; + while (!current_seed && (seeds -> seed) >= 0) { + if (test_seed (inbuf, seeds -> seed)) + current_seed = seeds; + else + seeds++; + } + + if (!current_seed && u -> bruteforce_seeds) { + /* The seed is not cached, yet. Try to find it with brute force... */ + unscramblerdebug ("Brute-forcing seed for sector %d...", sector_no); + + for (j = 0; !current_seed && j < 0x7FFF; j++) { + if (test_seed (inbuf, j)) { + if (!(current_seed = add_seed (seeds, j))) { + error ("No enough cache space for caching seed"); + out = false; + } + } + } + + if (current_seed) + unscramblerdebug ("Seed found: %04x", --j); + } + + if (current_seed) { + /* OK, somehow seed was found: unscramble frame, write it and go on */ + if (!unscramble_frame (current_seed, inbuf, outbuf)) { + error ("Error unscrambling frame %u\n", sector_no); + out = false; + } else { + out = true; + } + } else { + /* Well, we only get here if there are read errors */ + error ("Cannot find seed for frame %u", sector_no); + out = false; + } + + return (out); +} + + +/** + * Unscrambles a complete file. + * @param u The unscrambler structure. + * @param infile The input file name. + * @param outfile The output file name. + * @param progress A function to be called repeatedly during the operation, useful to report progress data/statistics. + * @param progress_data Data to be passed as-is to the progress function. + * @return True if the unscrambling was successful, false otherwise. + */ +bool unscrambler_unscramble_file (unscrambler *u, char *infile, char *outfile, unscrambler_progress_func progress, void *progress_data, u_int32_t *current_sector) { + FILE *in, *outfp; + bool out; + u_int8_t b_in[RAW_BLOCK_SIZE], b_out[BLOCK_SIZE]; + size_t r; + my_off_t filesize; + int s; + u_int32_t total_sectors; + + out = false; + if(!(in = fopen (infile ? infile : "", "rb"))) { + error ("Cannot open input file \"%s\"", infile); + } else if (!(outfp = fopen (outfile ? outfile : "", "wb"))) { + error ("Cannot open output file \"%s\"", outfile); + fclose (in); + } else { + /* Find out how many sectors we need to process */ + my_fseek (in, 0, SEEK_END); + filesize = my_ftell (in); + total_sectors = (u_int32_t) (filesize / RAW_SECTOR_SIZE); + rewind (in); + + /* First call to progress function */ + if (progress) + progress (true, 0, total_sectors, progress_data); + + s = 0, out = true; + while ((r = fread (b_in, 1, RAW_BLOCK_SIZE, in)) > 0 && out) { + if (r < RAW_BLOCK_SIZE) { + warning ("Short block read (%u bytes), padding with zeroes!", r); + memset (b_in + r, 0, sizeof (b_in) - r); + } + + if (unscrambler_unscramble_16sectors (u, s, b_in, b_out)) { + clearerr (outfp); + + if (!b_out) { + error ("NULL buffer"); + out = false; + *(current_sector) = s; + } + else fwrite (b_out, SECTOR_SIZE, SECTORS_PER_BLOCK, outfp); + if (ferror (outfp)) { + error ("fwrite() to ISO output file failed"); + out = false; + *(current_sector) = s; + } + } else { + debug ("unscrambler_unscramble_16sectors() failed"); + out = false; + *(current_sector) = s; + } + + s += 16; + + if ((s % 320 == 0) || (s == total_sectors)) { //speedhack + if (progress) + progress (false, s, total_sectors, progress_data); + } + } + + if (out) { + debug ("Image successfully unscrambled"); + } + + fclose (in); + fclose (outfp); + } + + return (out); +} diff --git a/libmultihash/CMakeLists.txt b/libmultihash/CMakeLists.txt index 31fbd8a..27d8384 100644 --- a/libmultihash/CMakeLists.txt +++ b/libmultihash/CMakeLists.txt @@ -1,77 +1,77 @@ -# Create a library called "Hello" which includes the source file "hello.cxx". -# The extension is already found. Any number of sources could be listed here. -add_library ( - multihashlib - ${libmultihash_type} - #SHARED - #STATIC - - crc32.c - edonkey.c - md4.c - md5.c - multihash.c - sha1.c - crc32.h - edonkey.h - md4.h - md5.h - multihash.h - sha1.h -) - -set_target_properties (multihashlib PROPERTIES OUTPUT_NAME "multihash") - -# Before making a release, the LTVERSION string should be modified. -# The string is of the form CURRENT:REVISION:AGE. -# -# CURRENT (C) -# The most recent interface number that this library implements. -# -# REVISION (R) -# The implementation number that this library implements. -# -# AGE (A) -# The difference between the newest and oldest interfaces that this -# library implements. In other works, the library implements all the -# interface numbers in the range from number 'CURRENT - AGE' to -# 'CURRENT'. -# -# This means that: -# -# - If interfaces have been changed or added, but binary compatibility has -# been preserved, change to C+1:0:A+1 -# -# - If binary compatibility has been broken (eg removed or changed -# interfaces) change to C+1:0:0 -# -# - If the interface is the same as the previous version, change to C:R+1:A -# -set_target_properties (multihashlib PROPERTIES SOVERSION 1.0.0) - - -#get_target_property(libhash_type multihashlib TYPE) -if (WIN32) - if (libhash_type STREQUAL "SHARED") -# MESSAGE ("Building libmultihash DLL") - ADD_DEFINITIONS (-DMULTIHASH_BUILD_DLL) - - set_target_properties (multihashlib PROPERTIES DEFINE_SYMBOL MULTIHASH_EXPORTS) - - install ( - TARGETS multihashlib - RUNTIME DESTINATION / - #ARCHIVE DESTINATION lib - ) - endif (libhash_type STREQUAL "SHARED") -else (WIN32) - # Install stuff, only if a shared library is being built - if (libhash_type STREQUAL "SHARED") - install ( - TARGETS multihashlib - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib/static - ) - endif (libhash_type STREQUAL "SHARED") -endif (WIN32) - +# Create a library called "Hello" which includes the source file "hello.cxx". +# The extension is already found. Any number of sources could be listed here. +add_library ( + multihashlib + ${libmultihash_type} + #SHARED + #STATIC + + crc32.c + edonkey.c + md4.c + md5.c + multihash.c + sha1.c + crc32.h + edonkey.h + md4.h + md5.h + multihash.h + sha1.h +) + +set_target_properties (multihashlib PROPERTIES OUTPUT_NAME "multihash") + +# Before making a release, the LTVERSION string should be modified. +# The string is of the form CURRENT:REVISION:AGE. +# +# CURRENT (C) +# The most recent interface number that this library implements. +# +# REVISION (R) +# The implementation number that this library implements. +# +# AGE (A) +# The difference between the newest and oldest interfaces that this +# library implements. In other works, the library implements all the +# interface numbers in the range from number 'CURRENT - AGE' to +# 'CURRENT'. +# +# This means that: +# +# - If interfaces have been changed or added, but binary compatibility has +# been preserved, change to C+1:0:A+1 +# +# - If binary compatibility has been broken (eg removed or changed +# interfaces) change to C+1:0:0 +# +# - If the interface is the same as the previous version, change to C:R+1:A +# +set_target_properties (multihashlib PROPERTIES SOVERSION 1.0.0) + + +#get_target_property(libhash_type multihashlib TYPE) +if (WIN32) + if (libhash_type STREQUAL "SHARED") +# MESSAGE ("Building libmultihash DLL") + ADD_DEFINITIONS (-DMULTIHASH_BUILD_DLL) + + set_target_properties (multihashlib PROPERTIES DEFINE_SYMBOL MULTIHASH_EXPORTS) + + install ( + TARGETS multihashlib + RUNTIME DESTINATION / + #ARCHIVE DESTINATION lib + ) + endif (libhash_type STREQUAL "SHARED") +else (WIN32) + # Install stuff, only if a shared library is being built + if (libhash_type STREQUAL "SHARED") + install ( + TARGETS multihashlib + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static + ) + endif (libhash_type STREQUAL "SHARED") +endif (WIN32) + diff --git a/libmultihash/crc32.c b/libmultihash/crc32.c index 6f86b1f..7bf6894 100644 --- a/libmultihash/crc32.c +++ b/libmultihash/crc32.c @@ -1,120 +1,120 @@ -/* - * Copyright (c) 1995, Edward B. Hamrick - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that - * - * (i) the above copyright notice and the text in this "C" comment block - * appear in all copies of the software and related documentation, and - * - * (ii) any modifications to this source file must be sent, via e-mail - * to the copyright owner (currently hamrick@primenet.com) within - * 30 days of such modification. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL EDWARD B. HAMRICK BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "crc32.h" - -/* This is a pre-computed table to make crc computations efficient */ -static unsigned long crctable[] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, - 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, - 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, - 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, - 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, - 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, - 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, - 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, - 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, - 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, - 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, - 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, - 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, - 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, - 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, - 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, - 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, - 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, - 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, - 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, - 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, - 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, - 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, - 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, - 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, - 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, - 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, - 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, - 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, - 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, - 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, - 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, - 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, - 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, - 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, - 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, - 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, - 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, - 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, - 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, - 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, - 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, - 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, - 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, - 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, - 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, - 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, - 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, - 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, - 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, - 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, - 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL -}; - -/* - * This CRC algorithm is the same as that used in zip. Normally it - * should be initialized with 0xffffffff, and the final CRC stored - * should be crc ^ 0xffffffff. - * - * It implements the polynomial: - * - * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 - */ - -unsigned long CrcUpdate( /* returns updated crc */ - unsigned long crc, /* starting crc */ - unsigned char *buffer, /* buffer to use to update crc */ - long length /* length of buffer */ -) -{ - long i; - - for (i=0; i> 8); - } - - return crc; -} +/* + * Copyright (c) 1995, Edward B. Hamrick + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that + * + * (i) the above copyright notice and the text in this "C" comment block + * appear in all copies of the software and related documentation, and + * + * (ii) any modifications to this source file must be sent, via e-mail + * to the copyright owner (currently hamrick@primenet.com) within + * 30 days of such modification. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL EDWARD B. HAMRICK BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "crc32.h" + +/* This is a pre-computed table to make crc computations efficient */ +static unsigned long crctable[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, + 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, + 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, + 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, + 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, + 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, + 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, + 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, + 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, + 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, + 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, + 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, + 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, + 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, + 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, + 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, + 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, + 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, + 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, + 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, + 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, + 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, + 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, + 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, + 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, + 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, + 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +/* + * This CRC algorithm is the same as that used in zip. Normally it + * should be initialized with 0xffffffff, and the final CRC stored + * should be crc ^ 0xffffffff. + * + * It implements the polynomial: + * + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 + */ + +unsigned long CrcUpdate( /* returns updated crc */ + unsigned long crc, /* starting crc */ + unsigned char *buffer, /* buffer to use to update crc */ + long length /* length of buffer */ +) +{ + long i; + + for (i=0; i> 8); + } + + return crc; +} diff --git a/libmultihash/crc32.h b/libmultihash/crc32.h index 2a1acbe..d1cf7f1 100644 --- a/libmultihash/crc32.h +++ b/libmultihash/crc32.h @@ -1,53 +1,53 @@ -/* - * Copyright (c) 1995, Edward B. Hamrick - * - * Permission to use, copy, modify, distribute, and sell this software and - * its documentation for any purpose is hereby granted without fee, provided - * that - * - * (i) the above copyright notice and the text in this "C" comment block - * appear in all copies of the software and related documentation, and - * - * (ii) any modifications to this source file must be sent, via e-mail - * to the copyright owner (currently hamrick@primenet.com) within - * 30 days of such modification. - * - * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, - * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - * - * IN NO EVENT SHALL EDWARD B. HAMRICK BE LIABLE FOR ANY SPECIAL, INCIDENTAL, - * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER - * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF - * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * This CRC algorithm is the same as that used in zip. Normally it - * should be initialized with 0xffffffff, and the final CRC stored - * should be crc ^ 0xffffffff. - * - * It implements the polynomial: - * - * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 - */ - -#ifndef __CRC_H -#define __CRC_H - -#ifdef __cplusplus -extern "C" { -#endif - -unsigned long CrcUpdate( /* returns updated crc */ - unsigned long crc, /* starting crc */ - unsigned char *buffer, /* buffer to use to update crc */ - long length /* length of buffer */ -); - -#ifdef __cplusplus -} -#endif - -#endif +/* + * Copyright (c) 1995, Edward B. Hamrick + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that + * + * (i) the above copyright notice and the text in this "C" comment block + * appear in all copies of the software and related documentation, and + * + * (ii) any modifications to this source file must be sent, via e-mail + * to the copyright owner (currently hamrick@primenet.com) within + * 30 days of such modification. + * + * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL EDWARD B. HAMRICK BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF + * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This CRC algorithm is the same as that used in zip. Normally it + * should be initialized with 0xffffffff, and the final CRC stored + * should be crc ^ 0xffffffff. + * + * It implements the polynomial: + * + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 + */ + +#ifndef __CRC_H +#define __CRC_H + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned long CrcUpdate( /* returns updated crc */ + unsigned long crc, /* starting crc */ + unsigned char *buffer, /* buffer to use to update crc */ + long length /* length of buffer */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmultihash/md5.c b/libmultihash/md5.c index f90f4cb..a438f27 100644 --- a/libmultihash/md5.c +++ b/libmultihash/md5.c @@ -1,477 +1,477 @@ -/* - ********************************************************************** - ** md5.c ** - ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** - ** Created: 2/17/90 RLR ** - ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** - ********************************************************************** - */ - -/* - ********************************************************************** - ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** - ** ** - ** License to copy and use this software is granted provided that ** - ** it is identified as the "RSA Data Security, Inc. MD5 Message ** - ** Digest Algorithm" in all material mentioning or referencing this ** - ** software or this function. ** - ** ** - ** License is also granted to make and use derivative works ** - ** provided that such works are identified as "derived from the RSA ** - ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** - ** material mentioning or referencing the derived work. ** - ** ** - ** RSA Data Security, Inc. makes no representations concerning ** - ** either the merchantability of this software or the suitability ** - ** of this software for any particular purpose. It is provided "as ** - ** is" without express or implied warranty of any kind. ** - ** ** - ** These notices must be retained in any copies of any part of this ** - ** documentation and/or software. ** - ********************************************************************** - */ - -/* -- include the following line if the md5.h header file is separate -- */ -#include "md5.h" - -/* forward declaration */ -static void Transform (); - -static unsigned char PADDING[64] = { - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -/* F, G and H are basic MD5 functions: selection, majority, parity */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ -/* Rotation is separate from addition to prevent recomputation */ -#define FF(a, b, c, d, x, s, ac) \ - {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) \ - {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) \ - {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) \ - {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -void MD5Init (mdContext) -MD5_CTX *mdContext; -{ - mdContext->i[0] = mdContext->i[1] = (UINT4)0; - - /* Load magic initialization constants. - */ - mdContext->buf[0] = (UINT4)0x67452301; - mdContext->buf[1] = (UINT4)0xefcdab89; - mdContext->buf[2] = (UINT4)0x98badcfe; - mdContext->buf[3] = (UINT4)0x10325476; -} - -void MD5Update (mdContext, inBuf, inLen) -MD5_CTX *mdContext; -unsigned char *inBuf; -unsigned int inLen; -{ - UINT4 in[16]; - int mdi; - unsigned int i, ii; - - /* compute number of bytes mod 64 */ - mdi = (int)((mdContext->i[0] >> 3) & 0x3F); - - /* update number of bits */ - if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) - mdContext->i[1]++; - mdContext->i[0] += ((UINT4)inLen << 3); - mdContext->i[1] += ((UINT4)inLen >> 29); - - while (inLen--) { - /* add new character to buffer, increment mdi */ - mdContext->in[mdi++] = *inBuf++; - - /* transform if necessary */ - if (mdi == 0x40) { - for (i = 0, ii = 0; i < 16; i++, ii += 4) - in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | - (((UINT4)mdContext->in[ii+2]) << 16) | - (((UINT4)mdContext->in[ii+1]) << 8) | - ((UINT4)mdContext->in[ii]); - Transform (mdContext->buf, in); - mdi = 0; - } - } -} - -void MD5Final (mdContext) -MD5_CTX *mdContext; -{ - UINT4 in[16]; - int mdi; - unsigned int i, ii; - unsigned int padLen; - - /* save number of bits */ - in[14] = mdContext->i[0]; - in[15] = mdContext->i[1]; - - /* compute number of bytes mod 64 */ - mdi = (int)((mdContext->i[0] >> 3) & 0x3F); - - /* pad out to 56 mod 64 */ - padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); - MD5Update (mdContext, PADDING, padLen); - - /* append length in bits and transform */ - for (i = 0, ii = 0; i < 14; i++, ii += 4) - in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | - (((UINT4)mdContext->in[ii+2]) << 16) | - (((UINT4)mdContext->in[ii+1]) << 8) | - ((UINT4)mdContext->in[ii]); - Transform (mdContext->buf, in); - - /* store buffer in digest */ - for (i = 0, ii = 0; i < 4; i++, ii += 4) { - mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); - mdContext->digest[ii+1] = - (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); - mdContext->digest[ii+2] = - (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); - mdContext->digest[ii+3] = - (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); - } -} - -/* Basic MD5 step. Transform buf based on in. - */ -static void Transform (buf, in) -UINT4 *buf; -UINT4 *in; -{ - UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 - FF ( a, b, c, d, in[ 0], S11, 3614090360U); /* 1 */ - FF ( d, a, b, c, in[ 1], S12, 3905402710U); /* 2 */ - FF ( c, d, a, b, in[ 2], S13, 606105819U); /* 3 */ - FF ( b, c, d, a, in[ 3], S14, 3250441966U); /* 4 */ - FF ( a, b, c, d, in[ 4], S11, 4118548399U); /* 5 */ - FF ( d, a, b, c, in[ 5], S12, 1200080426U); /* 6 */ - FF ( c, d, a, b, in[ 6], S13, 2821735955U); /* 7 */ - FF ( b, c, d, a, in[ 7], S14, 4249261313U); /* 8 */ - FF ( a, b, c, d, in[ 8], S11, 1770035416U); /* 9 */ - FF ( d, a, b, c, in[ 9], S12, 2336552879U); /* 10 */ - FF ( c, d, a, b, in[10], S13, 4294925233U); /* 11 */ - FF ( b, c, d, a, in[11], S14, 2304563134U); /* 12 */ - FF ( a, b, c, d, in[12], S11, 1804603682U); /* 13 */ - FF ( d, a, b, c, in[13], S12, 4254626195U); /* 14 */ - FF ( c, d, a, b, in[14], S13, 2792965006U); /* 15 */ - FF ( b, c, d, a, in[15], S14, 1236535329U); /* 16 */ - - /* Round 2 */ -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 - GG ( a, b, c, d, in[ 1], S21, 4129170786U); /* 17 */ - GG ( d, a, b, c, in[ 6], S22, 3225465664U); /* 18 */ - GG ( c, d, a, b, in[11], S23, 643717713U); /* 19 */ - GG ( b, c, d, a, in[ 0], S24, 3921069994U); /* 20 */ - GG ( a, b, c, d, in[ 5], S21, 3593408605U); /* 21 */ - GG ( d, a, b, c, in[10], S22, 38016083U); /* 22 */ - GG ( c, d, a, b, in[15], S23, 3634488961U); /* 23 */ - GG ( b, c, d, a, in[ 4], S24, 3889429448U); /* 24 */ - GG ( a, b, c, d, in[ 9], S21, 568446438U); /* 25 */ - GG ( d, a, b, c, in[14], S22, 3275163606U); /* 26 */ - GG ( c, d, a, b, in[ 3], S23, 4107603335U); /* 27 */ - GG ( b, c, d, a, in[ 8], S24, 1163531501U); /* 28 */ - GG ( a, b, c, d, in[13], S21, 2850285829U); /* 29 */ - GG ( d, a, b, c, in[ 2], S22, 4243563512U); /* 30 */ - GG ( c, d, a, b, in[ 7], S23, 1735328473U); /* 31 */ - GG ( b, c, d, a, in[12], S24, 2368359562U); /* 32 */ - - /* Round 3 */ -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 - HH ( a, b, c, d, in[ 5], S31, 4294588738U); /* 33 */ - HH ( d, a, b, c, in[ 8], S32, 2272392833U); /* 34 */ - HH ( c, d, a, b, in[11], S33, 1839030562U); /* 35 */ - HH ( b, c, d, a, in[14], S34, 4259657740U); /* 36 */ - HH ( a, b, c, d, in[ 1], S31, 2763975236U); /* 37 */ - HH ( d, a, b, c, in[ 4], S32, 1272893353U); /* 38 */ - HH ( c, d, a, b, in[ 7], S33, 4139469664U); /* 39 */ - HH ( b, c, d, a, in[10], S34, 3200236656U); /* 40 */ - HH ( a, b, c, d, in[13], S31, 681279174U); /* 41 */ - HH ( d, a, b, c, in[ 0], S32, 3936430074U); /* 42 */ - HH ( c, d, a, b, in[ 3], S33, 3572445317U); /* 43 */ - HH ( b, c, d, a, in[ 6], S34, 76029189U); /* 44 */ - HH ( a, b, c, d, in[ 9], S31, 3654602809U); /* 45 */ - HH ( d, a, b, c, in[12], S32, 3873151461U); /* 46 */ - HH ( c, d, a, b, in[15], S33, 530742520U); /* 47 */ - HH ( b, c, d, a, in[ 2], S34, 3299628645U); /* 48 */ - - /* Round 4 */ -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - II ( a, b, c, d, in[ 0], S41, 4096336452U); /* 49 */ - II ( d, a, b, c, in[ 7], S42, 1126891415U); /* 50 */ - II ( c, d, a, b, in[14], S43, 2878612391U); /* 51 */ - II ( b, c, d, a, in[ 5], S44, 4237533241U); /* 52 */ - II ( a, b, c, d, in[12], S41, 1700485571U); /* 53 */ - II ( d, a, b, c, in[ 3], S42, 2399980690U); /* 54 */ - II ( c, d, a, b, in[10], S43, 4293915773U); /* 55 */ - II ( b, c, d, a, in[ 1], S44, 2240044497U); /* 56 */ - II ( a, b, c, d, in[ 8], S41, 1873313359U); /* 57 */ - II ( d, a, b, c, in[15], S42, 4264355552U); /* 58 */ - II ( c, d, a, b, in[ 6], S43, 2734768916U); /* 59 */ - II ( b, c, d, a, in[13], S44, 1309151649U); /* 60 */ - II ( a, b, c, d, in[ 4], S41, 4149444226U); /* 61 */ - II ( d, a, b, c, in[11], S42, 3174756917U); /* 62 */ - II ( c, d, a, b, in[ 2], S43, 718787259U); /* 63 */ - II ( b, c, d, a, in[ 9], S44, 3951481745U); /* 64 */ - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -/* - ********************************************************************** - ** End of md5.c ** - ******************************* (cut) ******************************** - */ - -#if 0 -/* - ********************************************************************** - ** md5driver.c -- sample routines to test ** - ** RSA Data Security, Inc. MD5 message digest algorithm. ** - ** Created: 2/16/90 RLR ** - ** Updated: 1/91 SRD ** - ********************************************************************** - */ - -/* - ********************************************************************** - ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** - ** ** - ** RSA Data Security, Inc. makes no representations concerning ** - ** either the merchantability of this software or the suitability ** - ** of this software for any particular purpose. It is provided "as ** - ** is" without express or implied warranty of any kind. ** - ** ** - ** These notices must be retained in any copies of any part of this ** - ** documentation and/or software. ** - ********************************************************************** - */ - -#include -#include -#include -#include -/* -- include the following file if the file md5.h is separate -- */ -/* #include "md5.h" */ - -/* Prints message digest buffer in mdContext as 32 hexadecimal digits. - Order is from low-order byte to high-order byte of digest. - Each byte is printed with high-order hexadecimal digit first. - */ -static void MDPrint (mdContext) -MD5_CTX *mdContext; -{ - int i; - - for (i = 0; i < 16; i++) - printf ("%02x", mdContext->digest[i]); -} - -/* size of test block */ -#define TEST_BLOCK_SIZE 1000 - -/* number of blocks to process */ -#define TEST_BLOCKS 10000 - -/* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */ -static long TEST_BYTES = (long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS; - -/* A time trial routine, to measure the speed of MD5. - Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE - characters. - */ -static void MDTimeTrial () -{ - MD5_CTX mdContext; - time_t endTime, startTime; - unsigned char data[TEST_BLOCK_SIZE]; - unsigned int i; - - /* initialize test data */ - for (i = 0; i < TEST_BLOCK_SIZE; i++) - data[i] = (unsigned char)(i & 0xFF); - - /* start timer */ - printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES); - time (&startTime); - - /* digest data in TEST_BLOCK_SIZE byte blocks */ - MD5Init (&mdContext); - for (i = TEST_BLOCKS; i > 0; i--) - MD5Update (&mdContext, data, TEST_BLOCK_SIZE); - MD5Final (&mdContext); - - /* stop timer, get time difference */ - time (&endTime); - MDPrint (&mdContext); - printf (" is digest of test input.\n"); - printf - ("Seconds to process test input: %ld\n", (long)(endTime-startTime)); - printf - ("Characters processed per second: %ld\n", - TEST_BYTES/(endTime-startTime)); -} - -/* Computes the message digest for string inString. - Prints out message digest, a space, the string (in quotes) and a - carriage return. - */ -static void MDString (inString) -char *inString; -{ - MD5_CTX mdContext; - unsigned int len = strlen (inString); - - MD5Init (&mdContext); - MD5Update (&mdContext, inString, len); - MD5Final (&mdContext); - MDPrint (&mdContext); - printf (" \"%s\"\n\n", inString); -} - -/* Computes the message digest for a specified file. - Prints out message digest, a space, the file name, and a carriage - return. - */ -static void MDFile (filename) -char *filename; -{ - FILE *inFile = fopen (filename, "rb"); - MD5_CTX mdContext; - int bytes; - unsigned char data[1024]; - - if (inFile == NULL) { - printf ("%s can't be opened.\n", filename); - return; - } - - MD5Init (&mdContext); - while ((bytes = fread (data, 1, 1024, inFile)) != 0) - MD5Update (&mdContext, data, bytes); - MD5Final (&mdContext); - MDPrint (&mdContext); - printf (" %s\n", filename); - fclose (inFile); -} - -/* Writes the message digest of the data from stdin onto stdout, - followed by a carriage return. - */ -static void MDFilter () -{ - MD5_CTX mdContext; - int bytes; - unsigned char data[16]; - - MD5Init (&mdContext); - while ((bytes = fread (data, 1, 16, stdin)) != 0) - MD5Update (&mdContext, data, bytes); - MD5Final (&mdContext); - MDPrint (&mdContext); - printf ("\n"); -} - -/* Runs a standard suite of test data. - */ -static void MDTestSuite () -{ - printf ("MD5 test suite results:\n\n"); - MDString (""); - MDString ("a"); - MDString ("abc"); - MDString ("message digest"); - MDString ("abcdefghijklmnopqrstuvwxyz"); - MDString - ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); - MDString - ("1234567890123456789012345678901234567890\ -1234567890123456789012345678901234567890"); - /* Contents of file foo are "abc" */ - MDFile ("foo"); -} - -void main (argc, argv) -int argc; -char *argv[]; -{ - int i; - - /* For each command line argument in turn: - ** filename -- prints message digest and name of file - ** -sstring -- prints message digest and contents of string - ** -t -- prints time trial statistics for 1M characters - ** -x -- execute a standard suite of test data - ** (no args) -- writes messages digest of stdin onto stdout - */ - if (argc == 1) - MDFilter (); - else - for (i = 1; i < argc; i++) - if (argv[i][0] == '-' && argv[i][1] == 's') - MDString (argv[i] + 2); - else if (strcmp (argv[i], "-t") == 0) - MDTimeTrial (); - else if (strcmp (argv[i], "-x") == 0) - MDTestSuite (); - else MDFile (argv[i]); -} - -/* - ********************************************************************** - ** End of md5driver.c ** - ******************************* (cut) ******************************** - */ -#endif +/* + ********************************************************************** + ** md5.c ** + ** RSA Data Security, Inc. MD5 Message Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version ** + ********************************************************************** + */ + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +/* -- include the following line if the md5.h header file is separate -- */ +#include "md5.h" + +/* forward declaration */ +static void Transform (); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G and H are basic MD5 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +void MD5Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +void MD5Final (mdContext) +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } +} + +/* Basic MD5 step. Transform buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, 3614090360U); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, 3905402710U); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, 606105819U); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, 3250441966U); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, 4118548399U); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, 1200080426U); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, 2821735955U); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, 4249261313U); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, 1770035416U); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, 2336552879U); /* 10 */ + FF ( c, d, a, b, in[10], S13, 4294925233U); /* 11 */ + FF ( b, c, d, a, in[11], S14, 2304563134U); /* 12 */ + FF ( a, b, c, d, in[12], S11, 1804603682U); /* 13 */ + FF ( d, a, b, c, in[13], S12, 4254626195U); /* 14 */ + FF ( c, d, a, b, in[14], S13, 2792965006U); /* 15 */ + FF ( b, c, d, a, in[15], S14, 1236535329U); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, 4129170786U); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, 3225465664U); /* 18 */ + GG ( c, d, a, b, in[11], S23, 643717713U); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, 3921069994U); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, 3593408605U); /* 21 */ + GG ( d, a, b, c, in[10], S22, 38016083U); /* 22 */ + GG ( c, d, a, b, in[15], S23, 3634488961U); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, 3889429448U); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, 568446438U); /* 25 */ + GG ( d, a, b, c, in[14], S22, 3275163606U); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, 4107603335U); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, 1163531501U); /* 28 */ + GG ( a, b, c, d, in[13], S21, 2850285829U); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, 4243563512U); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, 1735328473U); /* 31 */ + GG ( b, c, d, a, in[12], S24, 2368359562U); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, 4294588738U); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, 2272392833U); /* 34 */ + HH ( c, d, a, b, in[11], S33, 1839030562U); /* 35 */ + HH ( b, c, d, a, in[14], S34, 4259657740U); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, 2763975236U); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, 1272893353U); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, 4139469664U); /* 39 */ + HH ( b, c, d, a, in[10], S34, 3200236656U); /* 40 */ + HH ( a, b, c, d, in[13], S31, 681279174U); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, 3936430074U); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, 3572445317U); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, 76029189U); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, 3654602809U); /* 45 */ + HH ( d, a, b, c, in[12], S32, 3873151461U); /* 46 */ + HH ( c, d, a, b, in[15], S33, 530742520U); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, 3299628645U); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, 4096336452U); /* 49 */ + II ( d, a, b, c, in[ 7], S42, 1126891415U); /* 50 */ + II ( c, d, a, b, in[14], S43, 2878612391U); /* 51 */ + II ( b, c, d, a, in[ 5], S44, 4237533241U); /* 52 */ + II ( a, b, c, d, in[12], S41, 1700485571U); /* 53 */ + II ( d, a, b, c, in[ 3], S42, 2399980690U); /* 54 */ + II ( c, d, a, b, in[10], S43, 4293915773U); /* 55 */ + II ( b, c, d, a, in[ 1], S44, 2240044497U); /* 56 */ + II ( a, b, c, d, in[ 8], S41, 1873313359U); /* 57 */ + II ( d, a, b, c, in[15], S42, 4264355552U); /* 58 */ + II ( c, d, a, b, in[ 6], S43, 2734768916U); /* 59 */ + II ( b, c, d, a, in[13], S44, 1309151649U); /* 60 */ + II ( a, b, c, d, in[ 4], S41, 4149444226U); /* 61 */ + II ( d, a, b, c, in[11], S42, 3174756917U); /* 62 */ + II ( c, d, a, b, in[ 2], S43, 718787259U); /* 63 */ + II ( b, c, d, a, in[ 9], S44, 3951481745U); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + ********************************************************************** + ** End of md5.c ** + ******************************* (cut) ******************************** + */ + +#if 0 +/* + ********************************************************************** + ** md5driver.c -- sample routines to test ** + ** RSA Data Security, Inc. MD5 message digest algorithm. ** + ** Created: 2/16/90 RLR ** + ** Updated: 1/91 SRD ** + ********************************************************************** + */ + +/* + ********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + ********************************************************************** + */ + +#include +#include +#include +#include +/* -- include the following file if the file md5.h is separate -- */ +/* #include "md5.h" */ + +/* Prints message digest buffer in mdContext as 32 hexadecimal digits. + Order is from low-order byte to high-order byte of digest. + Each byte is printed with high-order hexadecimal digit first. + */ +static void MDPrint (mdContext) +MD5_CTX *mdContext; +{ + int i; + + for (i = 0; i < 16; i++) + printf ("%02x", mdContext->digest[i]); +} + +/* size of test block */ +#define TEST_BLOCK_SIZE 1000 + +/* number of blocks to process */ +#define TEST_BLOCKS 10000 + +/* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */ +static long TEST_BYTES = (long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS; + +/* A time trial routine, to measure the speed of MD5. + Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE + characters. + */ +static void MDTimeTrial () +{ + MD5_CTX mdContext; + time_t endTime, startTime; + unsigned char data[TEST_BLOCK_SIZE]; + unsigned int i; + + /* initialize test data */ + for (i = 0; i < TEST_BLOCK_SIZE; i++) + data[i] = (unsigned char)(i & 0xFF); + + /* start timer */ + printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES); + time (&startTime); + + /* digest data in TEST_BLOCK_SIZE byte blocks */ + MD5Init (&mdContext); + for (i = TEST_BLOCKS; i > 0; i--) + MD5Update (&mdContext, data, TEST_BLOCK_SIZE); + MD5Final (&mdContext); + + /* stop timer, get time difference */ + time (&endTime); + MDPrint (&mdContext); + printf (" is digest of test input.\n"); + printf + ("Seconds to process test input: %ld\n", (long)(endTime-startTime)); + printf + ("Characters processed per second: %ld\n", + TEST_BYTES/(endTime-startTime)); +} + +/* Computes the message digest for string inString. + Prints out message digest, a space, the string (in quotes) and a + carriage return. + */ +static void MDString (inString) +char *inString; +{ + MD5_CTX mdContext; + unsigned int len = strlen (inString); + + MD5Init (&mdContext); + MD5Update (&mdContext, inString, len); + MD5Final (&mdContext); + MDPrint (&mdContext); + printf (" \"%s\"\n\n", inString); +} + +/* Computes the message digest for a specified file. + Prints out message digest, a space, the file name, and a carriage + return. + */ +static void MDFile (filename) +char *filename; +{ + FILE *inFile = fopen (filename, "rb"); + MD5_CTX mdContext; + int bytes; + unsigned char data[1024]; + + if (inFile == NULL) { + printf ("%s can't be opened.\n", filename); + return; + } + + MD5Init (&mdContext); + while ((bytes = fread (data, 1, 1024, inFile)) != 0) + MD5Update (&mdContext, data, bytes); + MD5Final (&mdContext); + MDPrint (&mdContext); + printf (" %s\n", filename); + fclose (inFile); +} + +/* Writes the message digest of the data from stdin onto stdout, + followed by a carriage return. + */ +static void MDFilter () +{ + MD5_CTX mdContext; + int bytes; + unsigned char data[16]; + + MD5Init (&mdContext); + while ((bytes = fread (data, 1, 16, stdin)) != 0) + MD5Update (&mdContext, data, bytes); + MD5Final (&mdContext); + MDPrint (&mdContext); + printf ("\n"); +} + +/* Runs a standard suite of test data. + */ +static void MDTestSuite () +{ + printf ("MD5 test suite results:\n\n"); + MDString (""); + MDString ("a"); + MDString ("abc"); + MDString ("message digest"); + MDString ("abcdefghijklmnopqrstuvwxyz"); + MDString + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + MDString + ("1234567890123456789012345678901234567890\ +1234567890123456789012345678901234567890"); + /* Contents of file foo are "abc" */ + MDFile ("foo"); +} + +void main (argc, argv) +int argc; +char *argv[]; +{ + int i; + + /* For each command line argument in turn: + ** filename -- prints message digest and name of file + ** -sstring -- prints message digest and contents of string + ** -t -- prints time trial statistics for 1M characters + ** -x -- execute a standard suite of test data + ** (no args) -- writes messages digest of stdin onto stdout + */ + if (argc == 1) + MDFilter (); + else + for (i = 1; i < argc; i++) + if (argv[i][0] == '-' && argv[i][1] == 's') + MDString (argv[i] + 2); + else if (strcmp (argv[i], "-t") == 0) + MDTimeTrial (); + else if (strcmp (argv[i], "-x") == 0) + MDTestSuite (); + else MDFile (argv[i]); +} + +/* + ********************************************************************** + ** End of md5driver.c ** + ******************************* (cut) ******************************** + */ +#endif diff --git a/libmultihash/multihash.h b/libmultihash/multihash.h index 2fe6522..05c0785 100644 --- a/libmultihash/multihash.h +++ b/libmultihash/multihash.h @@ -1,127 +1,127 @@ -/*************************************************************************** - * Copyright (C) 2007 by SukkoPera * - * sukkopera@sukkology.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. * - ***************************************************************************/ - -#ifndef MULTIHASH_H_INCLUDED -#define MULTIHASH_H_INCLUDED - -#ifdef WIN32 -#include - -/* Definition of the types we use for Windows */ -#define u_int8_t BYTE -#define u_int16_t WORD -#define u_int32_t DWORD - -/* Some functions have different names */ -#define snprintf _snprintf - -/* Stuff to export library symbols */ -#ifdef MULTIHASH_BUILD_DLL -#ifdef MULTIHASH_EXPORTS -#define MULTIHASH_EXPORT __declspec(dllexport) /* Building the lib */ -#else -#define MULTIHASH_EXPORT __declspec(dllimport) /* Building user code */ -#endif -#else -#define MULTIHASH_EXPORT -#endif - -#else /* !WIN32 */ - -#define MULTIHASH_EXPORT - -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -#define USE_CRC32 -#define USE_MD4 -#define USE_MD5 -#define USE_ED2K -#define USE_SHA1 - -#ifdef USE_CRC32 -#include -#include "crc32.h" -#define LEN_CRC32 8 -#endif - -#ifdef USE_MD4 -#include "md4.h" -#define LEN_MD4 32 -#define MD4_DIGESTSIZE 16 -#endif - -#ifdef USE_MD5 -#include "md5.h" -#define LEN_MD5 32 -#endif - -#ifdef USE_ED2K -#include "edonkey.h" -#define LEN_ED2K 32 -#endif - -#ifdef USE_SHA1 -#include "sha1.h" -#define LEN_SHA1 40 -#endif - -/* This must be as long as the longest hash (in bytes) */ -#define MAX_DIGESTSIZE 20 - -typedef struct { -#ifdef USE_CRC32 - u_int32_t crc32; - char crc32_s[LEN_CRC32 + 1]; -#endif -#ifdef USE_MD4 - md4_context md4; - char md4_s[LEN_MD4 + 1]; -#endif -#ifdef USE_MD5 - MD5_CTX md5; - char md5_s[LEN_MD5 + 1]; -#endif -#ifdef USE_ED2K - ed2khash_context ed2k; - char ed2k_s[LEN_ED2K + 1]; -#endif -#ifdef USE_SHA1 - SHA1_CTX sha1; - char sha1_s[LEN_SHA1 + 1]; -#endif -} multihash; - - -/* Prototypes */ -MULTIHASH_EXPORT void multihash_init (multihash *mh); -MULTIHASH_EXPORT void multihash_update (multihash *mh, unsigned char *data, int bytes); -MULTIHASH_EXPORT void multihash_finish (multihash *mh); -MULTIHASH_EXPORT int multihash_file (multihash *mh, char *filename); - -#ifdef __cplusplus -} -#endif - -#endif +/*************************************************************************** + * Copyright (C) 2007 by SukkoPera * + * sukkopera@sukkology.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. * + ***************************************************************************/ + +#ifndef MULTIHASH_H_INCLUDED +#define MULTIHASH_H_INCLUDED + +#ifdef WIN32 +#include + +/* Definition of the types we use for Windows */ +#define u_int8_t BYTE +#define u_int16_t WORD +#define u_int32_t DWORD + +/* Some functions have different names */ +#define snprintf _snprintf + +/* Stuff to export library symbols */ +#ifdef MULTIHASH_BUILD_DLL +#ifdef MULTIHASH_EXPORTS +#define MULTIHASH_EXPORT __declspec(dllexport) /* Building the lib */ +#else +#define MULTIHASH_EXPORT __declspec(dllimport) /* Building user code */ +#endif +#else +#define MULTIHASH_EXPORT +#endif + +#else /* !WIN32 */ + +#define MULTIHASH_EXPORT + +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#define USE_CRC32 +#define USE_MD4 +#define USE_MD5 +#define USE_ED2K +#define USE_SHA1 + +#ifdef USE_CRC32 +#include +#include "crc32.h" +#define LEN_CRC32 8 +#endif + +#ifdef USE_MD4 +#include "md4.h" +#define LEN_MD4 32 +#define MD4_DIGESTSIZE 16 +#endif + +#ifdef USE_MD5 +#include "md5.h" +#define LEN_MD5 32 +#endif + +#ifdef USE_ED2K +#include "edonkey.h" +#define LEN_ED2K 32 +#endif + +#ifdef USE_SHA1 +#include "sha1.h" +#define LEN_SHA1 40 +#endif + +/* This must be as long as the longest hash (in bytes) */ +#define MAX_DIGESTSIZE 20 + +typedef struct { +#ifdef USE_CRC32 + u_int32_t crc32; + char crc32_s[LEN_CRC32 + 1]; +#endif +#ifdef USE_MD4 + md4_context md4; + char md4_s[LEN_MD4 + 1]; +#endif +#ifdef USE_MD5 + MD5_CTX md5; + char md5_s[LEN_MD5 + 1]; +#endif +#ifdef USE_ED2K + ed2khash_context ed2k; + char ed2k_s[LEN_ED2K + 1]; +#endif +#ifdef USE_SHA1 + SHA1_CTX sha1; + char sha1_s[LEN_SHA1 + 1]; +#endif +} multihash; + + +/* Prototypes */ +MULTIHASH_EXPORT void multihash_init (multihash *mh); +MULTIHASH_EXPORT void multihash_update (multihash *mh, unsigned char *data, int bytes); +MULTIHASH_EXPORT void multihash_finish (multihash *mh); +MULTIHASH_EXPORT int multihash_file (multihash *mh, char *filename); + +#ifdef __cplusplus +} +#endif + +#endif