-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updated sdat2img.py to latest source available (created by xpirt)
- Loading branch information
Showing
1 changed file
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
#==================================================== | ||
# FILE: sdat2img.py | ||
# AUTHORS: xpirt - luxi78 - howellzhu | ||
# DATE: 2017-01-04 2:01:45 CEST | ||
#==================================================== | ||
|
||
import sys, os, errno | ||
|
||
__version__ = '1.0' | ||
|
||
if sys.hexversion < 0x02070000: | ||
print >> sys.stderr, "Python 2.7 or newer is required." | ||
try: | ||
input = raw_input | ||
except NameError: pass | ||
input('Press ENTER to exit...') | ||
sys.exit(1) | ||
else: | ||
print('sdat2img binary - version: %s\n' % __version__) | ||
|
||
try: | ||
TRANSFER_LIST_FILE = str(sys.argv[1]) | ||
NEW_DATA_FILE = str(sys.argv[2]) | ||
except IndexError: | ||
print('\nUsage: sdat2img.py <transfer_list> <system_new_file> [system_img]\n') | ||
print(' <transfer_list>: transfer list file') | ||
print(' <system_new_file>: system new dat file') | ||
print(' [system_img]: output system image\n\n') | ||
print('Visit xda thread for more information.\n') | ||
try: | ||
input = raw_input | ||
except NameError: pass | ||
input('Press ENTER to exit...') | ||
sys.exit() | ||
|
||
try: | ||
OUTPUT_IMAGE_FILE = str(sys.argv[3]) | ||
except IndexError: | ||
OUTPUT_IMAGE_FILE = 'system.img' | ||
|
||
BLOCK_SIZE = 4096 | ||
|
||
def rangeset(src): | ||
src_set = src.split(',') | ||
num_set = [int(item) for item in src_set] | ||
if len(num_set) != num_set[0]+1: | ||
print('Error on parsing following data to rangeset:\n%s' % src) | ||
sys.exit(1) | ||
|
||
return tuple ([ (num_set[i], num_set[i+1]) for i in range(1, len(num_set), 2) ]) | ||
|
||
def parse_transfer_list_file(path): | ||
trans_list = open(TRANSFER_LIST_FILE, 'r') | ||
|
||
# First line in transfer list is the version number | ||
version = int(trans_list.readline()) | ||
|
||
# Second line in transfer list is the total number of blocks we expect to write | ||
new_blocks = int(trans_list.readline()) | ||
|
||
if version >= 2: | ||
# Third line is how many stash entries are needed simultaneously | ||
trans_list.readline() | ||
# Fourth line is the maximum number of blocks that will be stashed simultaneously | ||
trans_list.readline() | ||
|
||
# Subsequent lines are all individual transfer commands | ||
commands = [] | ||
for line in trans_list: | ||
line = line.split(' ') | ||
cmd = line[0] | ||
if cmd in ['erase', 'new', 'zero']: | ||
commands.append([cmd, rangeset(line[1])]) | ||
else: | ||
# Skip lines starting with numbers, they are not commands anyway | ||
if not cmd[0].isdigit(): | ||
print('Command "%s" is not valid.' % cmd) | ||
trans_list.close() | ||
sys.exit(1) | ||
|
||
trans_list.close() | ||
return version, new_blocks, commands | ||
|
||
def main(argv): | ||
version, new_blocks, commands = parse_transfer_list_file(TRANSFER_LIST_FILE) | ||
|
||
if version == 1: | ||
print('Android Lollipop 5.0 detected!\n') | ||
elif version == 2: | ||
print('Android Lollipop 5.1 detected!\n') | ||
elif version == 3: | ||
print('Android Marshmallow 6.x detected!\n') | ||
elif version == 4: | ||
print('Android Nougat 7.x / Oreo 8.x detected!\n') | ||
else: | ||
print('Unknown Android version!\n') | ||
|
||
# Don't clobber existing files to avoid accidental data loss | ||
try: | ||
output_img = open(OUTPUT_IMAGE_FILE, 'wb') | ||
except IOError as e: | ||
if e.errno == errno.EEXIST: | ||
print('Error: the output file "{}" already exists'.format(e.filename)) | ||
print('Remove it, rename it, or choose a different file name.') | ||
sys.exit(e.errno) | ||
else: | ||
raise | ||
|
||
new_data_file = open(NEW_DATA_FILE, 'rb') | ||
all_block_sets = [i for command in commands for i in command[1]] | ||
max_file_size = max(pair[1] for pair in all_block_sets)*BLOCK_SIZE | ||
|
||
for command in commands: | ||
if command[0] == 'new': | ||
for block in command[1]: | ||
begin = block[0] | ||
end = block[1] | ||
block_count = end - begin | ||
print('Copying {} blocks into position {}...'.format(block_count, begin)) | ||
|
||
# Position output file | ||
output_img.seek(begin*BLOCK_SIZE) | ||
|
||
# Copy one block at a time | ||
while(block_count > 0): | ||
output_img.write(new_data_file.read(BLOCK_SIZE)) | ||
block_count -= 1 | ||
else: | ||
print('Skipping command %s...' % command[0]) | ||
|
||
# Make file larger if necessary | ||
if(output_img.tell() < max_file_size): | ||
output_img.truncate(max_file_size) | ||
|
||
output_img.close() | ||
new_data_file.close() | ||
print('Done! Output image: %s' % os.path.realpath(output_img.name)) | ||
|
||
if __name__ == '__main__': | ||
main(sys.argv) |