# -*- coding: UTF-8 -*-
import os,sys
import random
import string
import re
import time
import json
import shutil
import hashlib
import time
import argparse

import sys


script_path = os.path.split(os.path.realpath(sys.argv[0]))[0]

swiftFunPattern = "func.*?\\{"

#目前oc只向对象实例方法注入垃圾代码
ocFunPattern = "-.*?\\{"

#需要忽略的文件,写入这里后,这些文件将不会被添加垃圾代码
ignore_files = ["ZHAuthorSetVC.m", "DownloadManager.swift"]

#用于匹配 // 注释 的文本信息,在插入函数垃圾代码前,需要清除掉注释,避免在被注释的函数中添加垃圾代码而导致编译不过
explanatoryPattern = "(^//.*)"

#判断是否应该被忽略插入垃圾代码
def isNeedIgnore(fileName):
    global ignore_files
    for file in ignore_files:
        if fileName.find(file) != -1:
            return True
    return False
    
#单词列表，用以随机名称
with open(os.path.join(script_path, "./word_list.json"), "r") as fileObj:
    word_name_list = json.load(fileObj)

# 随机获取一个字符
def get_random_char():
    # 可以根据需要更改字符的范围
    ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
    digits = '0123456789'
    # 这里可以选择不同的字符集合进行随机选择
    char_sets = [ascii_uppercase, ascii_lowercase, digits]
    char_set = random.choice(char_sets)
    return random.choice(char_set)
    
#获取一个随机变量名称
def getVeriableName():
    global word_name_list
    return random.choice(word_name_list) + "_" + get_random_char()
    
    
#向OC文件的既有函数添加垃圾代码
def addClashCode2OC(filePath):
    global ocFunPattern
    print("\n开始向:\n%s\n添加垃圾代码\n" %filePath)
    with open(filePath,"r",errors="ignore") as fileObj:
        fileContent_text = fileObj.read()
        fileObj.close()
    matches = re.finditer(ocFunPattern,fileContent_text)
    #倒序遍历匹配的结果
    for match in reversed(list(matches)):
        firstPart_text = fileContent_text[:match.end()]
        firstPart_text = firstPart_text +"\n" + "        " + getOCFakeCode() + "\n"
        fileContent_text = firstPart_text + fileContent_text[match.end():]
        #print("match position:",match.end())
    with open(filePath,"w",errors="ignore") as fileObj:
        fileObj.write(fileContent_text)



#获取OC垃圾伪装代码
def getOCFakeCode():
    random_number = random.randint(1, 2)
    if random_number == 1:
        return getOCFakeCode_1()
    else:
        return getOCFakeCode_2()
        
#oc代码格式1
def getOCFakeCode_1():
    vn1 = getVeriableName()
    vn2 = getVeriableName()
    vn_key = getVeriableName()
    resultText = "\nNSDateFormatter *%s = [NSDateFormatter new];\n[%s setDateFormat:@\"yyyy-MM-dd HH:mm\"];\nNSString *%s = [%s stringFromDate:[NSDate date]];\n[[NSUserDefaults standardUserDefaults] setObject:%s forKey:@\"%s\"];\n" %(vn1,vn1,vn2,vn1,vn2,vn_key)
    return resultText
    
#oc代码格式2
def getOCFakeCode_2():
    digits = '0123456789'
    value1 = random.choice(digits)
    
    vn1 = getVeriableName()
    vn2 = getVeriableName()
    vn_key = getVeriableName()
    resultText = "\nNSInteger %s = %s;\nNSInteger %s = [[NSUserDefaults standardUserDefaults] integerForKey:@\"%s\"];\n%s *= %s;\n[[NSUserDefaults standardUserDefaults] setInteger:%s forKey:@\"%s\"];\n" %(vn1,value1,vn2,vn_key,vn2,vn1,vn2,vn_key)
    return resultText
    

    
#向Swift文件的既有函数添加垃圾代码
def addClashCode2Swift(filePath):
    global swiftFunPattern
    print("\n开始向:\n%s\n添加垃圾代码\n" %filePath)
    with open(filePath,"r",errors="ignore") as fileObj:
        fileContent_text = fileObj.read()
        fileObj.close()
    matches = re.finditer(swiftFunPattern,fileContent_text)
    #倒序遍历匹配的结果
    for match in reversed(list(matches)):
        firstPart_text = fileContent_text[:match.end()]
        firstPart_text = firstPart_text +"\n" + "        " + getSwiftFakeCode() + "\n"
        fileContent_text = firstPart_text + fileContent_text[match.end():]
        #print("match position:",match.end())
    with open(filePath,"w",errors="ignore") as fileObj:
        fileObj.write(fileContent_text)
        
#获取swift垃圾伪装代码
def getSwiftFakeCode():
    random_number = random.randint(1, 2)
    if random_number == 1:
        return getSwiftFakeCode_1()
    else:
        return getSwiftFakeCode_2()
    
#swift代码格式1
def getSwiftFakeCode_1():
    vn1 = getVeriableName()
    digits = '0123456789'
    value1 = random.choice(digits)
    
    vn2 = getVeriableName()
    vn2_key = getVeriableName()
    
    vn3 = getVeriableName()
    
    resultText = "\nlet %s:Int = %s\nlet %s:Int = UserDefaults.standard.integer(forKey: \"%s\")\nvar %s = %s * %s\nUserDefaults.standard .setValue(%s, forKey: \"%s\")\n" %(vn1,value1,vn2,vn2_key,vn3,vn1,vn2,vn3,vn2_key)
    return resultText

#swift代码格式2
def getSwiftFakeCode_2():
    vn1 = getVeriableName()
    vn2 = getVeriableName()
    vn_key = getVeriableName()
    resultText = "\nlet %s = DateFormatter() \n%s.dateStyle = .full\nlet %s = %s.string(from: NSDate.now)\nUserDefaults.standard .setValue(%s, forKey: \"%s\")\n" %(vn1,vn1,vn2,vn1,vn2,vn_key)
    return resultText

        
#解析初始化参数
def parase_args():
    global script_path
    parseParam = argparse.ArgumentParser(description='添加垃圾代码.\n')
    #存放代码的根路径,即需要 函数 被添加垃圾代码 的根路径,该程序将遍历这个目录下的所有文件(即包含子目录的子文件 执行垃圾代码添加)
    parseParam.add_argument('--code_dir', dest='code_dir', type=str, required=False, default=script_path, help='需要添加垃圾函数代码的根目录')
    print("paraseParam:",parseParam)
    return parseParam.parse_args()
    
#进行循环处理目录中的文件
def cycleDealDir(need_dealDir):
    print("开始循环这个目录:",need_dealDir)
    if not os.path.exists(need_dealDir):
        print("当前目录不存在:",need_dealDir)
    #以walk的方式,本身就会遍历完毕当前目录下的所有文件
    for parent,folders,files in os.walk(need_dealDir):
        #print("遍历子文件...")
        for file in files:
            filePath = os.path.join(parent, file)
            file_extension = file.split(".")[-1]
            if file_extension == "swift" and not isNeedIgnore(file):
                addClashCode2Swift(filePath)
            elif file_extension == "m" and not isNeedIgnore(file):
                addClashCode2OC(filePath)
            else:
                print("其他类型的文件暂不处理:",file)
    
            
def main():
    #解析参数
    parseParam = parase_args()
    
    #获取只要添加垃圾代码的目标 文件夹
    cycleDealDir(parseParam.code_dir)
    
#遍历获取目标文件夹中的目标文件
#过滤 需要忽略的目标文件

 

if __name__ == "__main__":
    main()


