Skip to content
Open
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
71 changes: 40 additions & 31 deletions Class Decompile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import re
import gc
import os

import concurrent.futures

IGNORED_CLASS_PREFIXES = [
'AFNetwork', 'AFHTTP', 'AFURL', 'AFSecurity',
Expand Down Expand Up @@ -44,8 +44,8 @@ def get_file_header(class_name):
// %s.m
//
// Generated by Class Decompile.
// Repository is https://github.com/poboke/Class-Decompile
// Copyright © 2016 www.poboke.com. All rights reserved.
// Repository is https://github.com/erduoniba/Class-Decompile
// Copyright © 2024 www.poboke.com. All rights reserved.
//

@implementation %s
Expand All @@ -58,6 +58,13 @@ def get_file_footer():
@end
'''

def write_to_file(file_path, codes):
with open(file_path, 'w', encoding='utf-8') as file:
file.write(codes)

del codes
gc.collect()


#pragma mark - Decompile

Expand Down Expand Up @@ -102,35 +109,37 @@ def start_decompile(input_class_name=None):
classes.setdefault(class_name, []).append(procedure)
total_count += 1

print 'total count :', total_count
print('total count :', total_count)

current_count = 0
for class_name in classes:
print '\n***** %s *****'%(class_name)
codes = get_file_header(class_name)
procedures = classes[class_name]
for procedure in procedures:
current_count += 1
percent = (float(current_count) / total_count) * 100
print '%05.2f%% | %s'%(percent, procedure.label_name)
pseudo_code = procedure.decompile()
if not pseudo_code:
continue
match = re.match(r'.+return\s.+;', pseudo_code, re.DOTALL)
method_type = 'id' if match else 'void'
method_name = procedure.method_name%method_type
codes += '%s\n{\n%s}\n\n'%(method_name, pseudo_code)
codes += get_file_footer()

file_path = get_file_path(class_name)
with open(file_path, 'w') as file:
file.write(codes)

del codes
gc.collect()
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = []
for class_name in classes:
print('\n***** %s *****'%(class_name))
codes = get_file_header(class_name)
procedures = classes[class_name]
for procedure in procedures:
current_count += 1
percent = (float(current_count) / total_count) * 100
print('%05.2f%% | %s'%(percent, procedure.label_name))
pseudo_code = procedure.decompile()
if not pseudo_code:
continue
match = re.match(r'.+return\s.+;', pseudo_code, re.DOTALL)
method_type = 'id' if match else 'void'
method_name = procedure.method_name%method_type
codes += '%s\n{\n%s}\n\n'%(method_name, pseudo_code)
codes += get_file_footer()

file_path = get_file_path(class_name)
future = executor.submit(write_to_file, file_path, codes)
futures.append(future)

for future in concurrent.futures.as_completed(futures):
future.result()

os.system('open "%s"'%(path))
print 'Done!'
print('Done!')


document = Document.getCurrentDocument()
Expand All @@ -152,11 +161,11 @@ def start_decompile(input_class_name=None):
message = 'Please input the class name:'
input_class_name = document.ask(message)
if input_class_name is None:
print 'Cancel decompile!'
print('Cancel decompile!')
elif input_class_name == '':
print 'Class name can not be empty!'
print('Class name can not be empty!')
else:
start_decompile(input_class_name)
elif button_index == 2:
print 'Cancel decompile!'
print('Cancel decompile!')