Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Redump/XGD ISOs and ISOs with empty directories #47

Merged
merged 2 commits into from
Jun 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 57 additions & 28 deletions extract-xiso.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,8 +441,9 @@
#endif


#define GLOBAL_LSEEK_OFFSET 0xFD90000ul
#define XGD3_LSEEK_OFFSET 0x2080000ul
#define GLOBAL_LSEEK_OFFSET 0x0FD90000ul
#define XGD3_LSEEK_OFFSET 0x02080000ul
#define XGD1_LSEEK_OFFSET 0x18300000ul

#define n_sectors( size ) ( ( size ) / XISO_SECTOR_SIZE + ( ( size ) % XISO_SECTOR_SIZE ? 1 : 0 ) )

Expand Down Expand Up @@ -882,18 +883,24 @@ int verify_xiso( int in_xiso, int32_t *out_root_dir_sector, int32_t *out_root_di
if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err();
if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) )
{
if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + GLOBAL_LSEEK_OFFSET, SEEK_SET ) == -1 ) seek_err();
if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err();
if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) {

if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + XGD3_LSEEK_OFFSET, SEEK_SET ) == -1 ) seek_err();
if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err();
if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) ) misc_err( "%s does not appear to be a valid xbox iso image\n", in_iso_name, 0, 0 )
else s_xbox_disc_lseek = XGD3_LSEEK_OFFSET;
}
else s_xbox_disc_lseek = GLOBAL_LSEEK_OFFSET;
}
else s_xbox_disc_lseek = 0;
if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + GLOBAL_LSEEK_OFFSET, SEEK_SET ) == -1 ) seek_err();
if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err();
if ( ! err && memcmp( buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH ) )
{
if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + XGD3_LSEEK_OFFSET, SEEK_SET ) == -1 ) seek_err();
if ( ! err && read( in_xiso, buffer, XISO_HEADER_DATA_LENGTH ) != XISO_HEADER_DATA_LENGTH ) read_err();
if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH))
{
if (lseek(in_xiso, (xoff_t)XISO_HEADER_OFFSET + XGD1_LSEEK_OFFSET, SEEK_SET) == -1) seek_err();
if (!err && read(in_xiso, buffer, XISO_HEADER_DATA_LENGTH) != XISO_HEADER_DATA_LENGTH) read_err();
if (!err && memcmp(buffer, XISO_HEADER_DATA, XISO_HEADER_DATA_LENGTH)) misc_err("%s does not appear to be a valid xbox iso image\n", in_iso_name, 0, 0)
else s_xbox_disc_lseek = XGD1_LSEEK_OFFSET;
}
else s_xbox_disc_lseek = XGD3_LSEEK_OFFSET;
}
else s_xbox_disc_lseek = GLOBAL_LSEEK_OFFSET;
}
else s_xbox_disc_lseek = 0;

// read root directory information
if ( ! err && read( in_xiso, out_root_dir_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) read_err();
Expand Down Expand Up @@ -1022,7 +1029,7 @@ int create_xiso( char *in_root_directory, char *in_output_directory, dir_node_av
}
if ( ! err ) {
if ( in_root ) {
if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + XISO_HEADER_DATA_LENGTH + XISO_SECTOR_OFFSET_SIZE + XISO_DIRTABLE_SIZE, SEEK_SET ) == -1 ) seek_err();
if ( lseek( in_xiso, (xoff_t) XISO_HEADER_OFFSET + XISO_HEADER_DATA_LENGTH + XISO_SECTOR_OFFSET_SIZE + XISO_DIRTABLE_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err();
if ( ! err && read( in_xiso, buf, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) read_err();
if ( ! err && write( xiso, buf, XISO_FILETIME_SIZE ) != XISO_FILETIME_SIZE ) write_err();

Expand Down Expand Up @@ -1197,9 +1204,16 @@ int traverse_xiso( int in_xiso, dir_node *in_dir_node, xoff_t in_dir_start, char

if ( ! err ) {
if ( tmp == XISO_PAD_SHORT ) {
if ( l_offset == 0 ) { // Directory is empty
if (in_mode == k_generate_avl) {
avl_insert(in_root, EMPTY_SUBDIRECTORY);
}
goto end_traverse;
}

l_offset = l_offset * XISO_DWORD_SIZE + ( XISO_SECTOR_SIZE - ( l_offset * XISO_DWORD_SIZE ) % XISO_SECTOR_SIZE );
err = lseek( in_xiso, in_dir_start + (xoff_t) l_offset, SEEK_SET ) == -1 ? 1 : 0;

if ( ! err ) goto read_entry; // me and my silly comments
} else {
l_offset = tmp;
Expand Down Expand Up @@ -1246,7 +1260,7 @@ int traverse_xiso( int in_xiso, dir_node *in_dir_node, xoff_t in_dir_start, char

avl->file_size = dir->file_size;
avl->old_start_sector = dir->start_sector;

if ( avl_insert( in_root, avl ) == k_avl_error ) misc_err( "this iso appears to be corrupt\n", 0, 0, 0 );
}
}
Expand Down Expand Up @@ -1291,7 +1305,10 @@ int traverse_xiso( int in_xiso, dir_node *in_dir_node, xoff_t in_dir_start, char
if ( ( err = mkdir( dir->filename, 0755 ) ) ) mkdir_err( dir->filename );
if ( ! err && dir->start_sector && ( err = chdir( dir->filename ) ) ) chdir_err( dir->filename );
}
if ( ! err && in_mode != k_list && in_mode != k_generate_avl ) exiso_log( "creating %s (0 bytes) [OK]\n", path );
if( ! err && in_mode != k_generate_avl ) {
exiso_log("%s%s%s%s (0 bytes)%s", in_mode == k_extract ? "creating " : "", in_path, dir->filename, PATH_CHAR_STR, in_mode == k_extract ? " [OK]" : ""); flush();
exiso_log("\n");
}
}
}

Expand Down Expand Up @@ -1344,6 +1361,8 @@ int traverse_xiso( int in_xiso, dir_node *in_dir_node, xoff_t in_dir_start, char
}
}

end_traverse:

if ( dir->filename ) free( dir->filename );

if ( ( dir = dir->parent ) ) goto left_processed;
Expand Down Expand Up @@ -1717,6 +1736,10 @@ int write_tree( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep
}

if ( context.path ) free( context.path );
} else {
memset(sector, XISO_PAD_BYTE, XISO_SECTOR_SIZE);
if ((pos = lseek(in_context->xiso, in_avl->start_sector * XISO_SECTOR_SIZE, SEEK_SET)) == -1) seek_err();
if (!err && write(in_context->xiso, sector, XISO_SECTOR_SIZE) != XISO_SECTOR_SIZE) write_err();
}
}
}
Expand All @@ -1738,7 +1761,7 @@ int write_file( dir_node_avl *in_avl, write_tree_context *in_context, int in_dep
if ( in_context->from == -1 ) {
if ( ( fd = open( in_avl->filename, READFLAGS, 0 ) ) == -1 ) open_err( in_avl->filename );
} else {
if ( lseek( fd = in_context->from, (xoff_t) in_avl->old_start_sector * XISO_SECTOR_SIZE, SEEK_SET ) == -1 ) seek_err();
if ( lseek( fd = in_context->from, (xoff_t) in_avl->old_start_sector * XISO_SECTOR_SIZE + s_xbox_disc_lseek, SEEK_SET ) == -1 ) seek_err();
}
}

Expand Down Expand Up @@ -1799,6 +1822,7 @@ int write_directory( dir_node_avl *in_avl, int in_xiso, int in_depth ) {
xoff_t pos;
int err = 0, pad;
unsigned short l_offset, r_offset;
unsigned long file_size = in_avl->file_size + (in_avl->subdirectory ? (XISO_SECTOR_SIZE - (in_avl->file_size % XISO_SECTOR_SIZE)) % XISO_SECTOR_SIZE : 0);
char length = (char) strlen( in_avl->filename ), attributes = in_avl->subdirectory ? XISO_ATTRIBUTE_DIR : XISO_ATTRIBUTE_ARC, sector[ XISO_SECTOR_SIZE ];

little32( in_avl->file_size );
Expand All @@ -1817,7 +1841,7 @@ int write_directory( dir_node_avl *in_avl, int in_xiso, int in_depth ) {
if ( ! err && write( in_xiso, &l_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err();
if ( ! err && write( in_xiso, &r_offset, XISO_TABLE_OFFSET_SIZE ) != XISO_TABLE_OFFSET_SIZE ) write_err();
if ( ! err && write( in_xiso, &in_avl->start_sector, XISO_SECTOR_OFFSET_SIZE ) != XISO_SECTOR_OFFSET_SIZE ) write_err();
if ( ! err && write( in_xiso, &in_avl->file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) write_err();
if ( ! err && write( in_xiso, &file_size, XISO_FILESIZE_SIZE ) != XISO_FILESIZE_SIZE ) write_err();
if ( ! err && write( in_xiso, &attributes, XISO_ATTRIBUTES_SIZE ) != XISO_ATTRIBUTES_SIZE ) write_err();
if ( ! err && write( in_xiso, &length, XISO_FILENAME_LENGTH_SIZE ) != XISO_FILENAME_LENGTH_SIZE ) write_err();
if ( ! err && write( in_xiso, in_avl->filename, length ) != length ) write_err();
Expand All @@ -1833,7 +1857,10 @@ int calculate_directory_offsets( dir_node_avl *in_avl, unsigned long *io_current
wdsafp_context context;

if ( in_avl->subdirectory ) {
if ( in_avl->subdirectory == EMPTY_SUBDIRECTORY ) in_avl->start_sector = 0;
if (in_avl->subdirectory == EMPTY_SUBDIRECTORY) {
in_avl->start_sector = *io_current_sector;
*io_current_sector += 1;
}
else {
context.current_sector = io_current_sector;
context.dir_start = (xoff_t) ( in_avl->start_sector = *io_current_sector ) * XISO_SECTOR_SIZE;
Expand Down Expand Up @@ -1862,10 +1889,8 @@ int write_dir_start_and_file_positions( dir_node_avl *in_avl, wdsafp_context *io


int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int in_depth ) {
if ( in_avl->subdirectory ) {
if ( in_avl->subdirectory != EMPTY_SUBDIRECTORY ) {
avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 );
}
if ( in_avl->subdirectory && in_avl->subdirectory != EMPTY_SUBDIRECTORY ) {
avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) calculate_total_files_and_bytes, nil, k_prefix, 0 );
} else {
++s_total_files;
s_total_bytes += in_avl->file_size;
Expand All @@ -1876,9 +1901,13 @@ int calculate_total_files_and_bytes( dir_node_avl *in_avl, void *in_context, int


int calculate_directory_requirements( dir_node_avl *in_avl, void *in_context, int in_depth ) {
if ( in_avl->subdirectory && in_avl->subdirectory != EMPTY_SUBDIRECTORY ) {
avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) calculate_directory_size, &in_avl->file_size, k_prefix, 0 );
avl_traverse_depth_first( in_avl->subdirectory, (traversal_callback) calculate_directory_requirements, in_context, k_prefix, 0 );
if ( in_avl->subdirectory ) {
if (in_avl->subdirectory != EMPTY_SUBDIRECTORY) {
avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_directory_size, &in_avl->file_size, k_prefix, 0);
avl_traverse_depth_first(in_avl->subdirectory, (traversal_callback)calculate_directory_requirements, in_context, k_prefix, 0);
} else {
in_avl->file_size = XISO_SECTOR_SIZE;
}
}

return 0;
Expand Down