#include<jni.h>
#include<stdio.h>
#include<string.h>
//导入我们创建的头文件
#include "com_sheep_gamegroup_util_PngUtil.h"
//全局获取Context
jobject getGlobalContext(JNIEnv *env);
//根据Context获取对应安装的apk文件的md5值
char* getSignatureMd5(JNIEnv * env, jobject obj_package_manager, jobject obj_package_name);
//根据Context获取对应安装的apk文件的hashCode值
//jint getSignatureHashCode(JNIEnv* env, jobject obj_package_manager, jobject obj_package_name);
// 字节流转换为十六进制字符串
void ByteToHexStr(const unsigned char* source, char* dest, int sourceLen);
//调用android toast
void android_toast(JNIEnv *env, jobject context, jstring str);
//判断java String 与c String 是否相同
int j_str_cmp_c_str(JNIEnv *env, jstring jStr, char* cStr);
//合并字符串
jstring android_string_concat(JNIEnv *env, jstring jStr, char* cStr);
//合并字符串
jstring android_string_concat_string(JNIEnv *env, jstring jStr, jstring jStr2);
//根据Context获取PackageManager
jobject getPackageManager(JNIEnv * env, jobject context);
//根据Context获取对应的包名
jobject getPackageName(JNIEnv * env, jobject context);

/*
 * cd app\src\main
 * ndk-build
 * Class:     com_sheep_gamegroup_util_PngUtil
 * Method:    isKfzsSheepApp
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_sheep_gamegroup_util_PngUtil_isKfzsSheepApp
  (JNIEnv *env, jclass jclassp){
        jobject context = getGlobalContext(env);
        if(context == NULL){
            return (*env)->NewStringUTF(env, "error context is NULL");
        }
        jobject obj_package_manager = getPackageManager(env, context);
        jobject obj_package_name = getPackageName(env, context);
        char* md5 = getSignatureMd5(env, obj_package_manager, obj_package_name);
        //result已经释放
        if(strcmp(md5, "C69316882EADA62AE560C31076740400")  == 0){
            android_toast(env, context, (*env)->NewStringUTF(env, "恭喜，您使用的是正版小绵羊！"));
        } else {
            android_toast(env, context, (*env)->NewStringUTF(env, "注意，您使用的不是正版小绵羊！"));
            return (*env)->NewStringUTF(env, "error this is pirate app");
        }
        return NULL;
  }
/*
 * Class:     com_sheep_gamegroup_util_PngUtil
 * Method:    decodePng
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_sheep_gamegroup_util_PngUtil_decodePng
  (JNIEnv *env, jclass jclassp, jstring filePath, jstring gamePackageName, jstring comment){
        jobject context = getGlobalContext(env);
        if(context == NULL){
            return (*env)->NewStringUTF(env, "error context is NULL");
        }
        jobject obj_package_manager = getPackageManager(env, context);
        jobject obj_package_name = getPackageName(env, context);
        char* md5 = getSignatureMd5(env, obj_package_manager, obj_package_name);
        //result已经释放
        if(strcmp(md5, "C69316882EADA62AE560C31076740400")  == 0){
    //        android_toast(env, context, (*env)->NewStringUTF(env, "恭喜，您使用的是正版小绵羊！"));
        } else {
//            android_toast(env, context, (*env)->NewStringUTF(env, "注意，您使用的不是正版小绵羊！"));
            return (*env)->NewStringUTF(env, "error this is pirate app");
        }
        char* gameMd5 = getSignatureMd5(env, obj_package_manager, gamePackageName);

        //加密文本内容：包名;签名md5;试玩应用包名;试玩应用签名md5;任务id;图片总数;图片位置

        jstring result_a;
        jstring result_b;
        result_a = android_string_concat(env, obj_package_name, ";");
        (*env)->DeleteLocalRef(env, obj_package_name);
        result_b = android_string_concat(env, result_a, md5);
        (*env)->DeleteLocalRef(env, result_a);
        result_a = android_string_concat(env, result_b, ";");
        (*env)->DeleteLocalRef(env, result_b);
        result_b = android_string_concat_string(env, result_a, gamePackageName);
        (*env)->DeleteLocalRef(env, result_a);
        result_a = android_string_concat(env, result_b, ";");
        (*env)->DeleteLocalRef(env, result_b);
        result_b = android_string_concat(env, result_a, gameMd5);
        (*env)->DeleteLocalRef(env, result_a);
        result_a = android_string_concat(env, result_b, ";");
        (*env)->DeleteLocalRef(env, result_b);

        result_b = android_string_concat_string(env, result_a, comment);
        (*env)->DeleteLocalRef(env, result_a);
//        android_toast(env, context, result_b);

        //rsa公钥加密
        jclass kfzssafeClass = (*env)->FindClass(env, "go/kfzssafe/Kfzssafe");
        jmethodID publicEncryptMethodID = (*env)->GetStaticMethodID(env, kfzssafeClass,"publicEncrypt","(Ljava/lang/String;)Ljava/lang/String;");
        result_a = (*env)->CallStaticObjectMethod(env, kfzssafeClass, publicEncryptMethodID, result_b);
        (*env)->DeleteLocalRef(env, result_b);

//        JNIDecodePngUtil.addIEndData(file, result_a);

        jmethodID addIEndDataMethodID = (*env)->GetStaticMethodID(env, kfzssafeClass,"addIEndData2","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
        jstring result = (*env)->CallStaticObjectMethod(env, kfzssafeClass, addIEndDataMethodID, filePath, result_a);
        (*env)->DeleteLocalRef(env, result_a);



        free(md5);
        free(gameMd5);
        (*env)->DeleteLocalRef(env, gamePackageName);
        (*env)->DeleteLocalRef(env, obj_package_manager);
        (*env)->DeleteLocalRef(env, context);
        return result;
  }
//合并字符串
jstring android_string_concat(JNIEnv *env, jstring jStr, char* cStr){
    jclass String_clazz = (*env)->FindClass(env, "java/lang/String");
    jmethodID concat_methodID = (*env)->GetMethodID(env, String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    //需要在后面拼接的字符串...
    jstring strEnd = (*env)->NewStringUTF(env, cStr);
    jstring result = (*env)->CallObjectMethod(env, jStr, concat_methodID, strEnd);
    //释放内存
    (*env)->DeleteLocalRef(env, strEnd);
    return result;
}
//合并字符串
jstring android_string_concat_string(JNIEnv *env, jstring jStr, jstring jStr2){
    jclass String_clazz = (*env)->FindClass(env, "java/lang/String");
    jmethodID concat_methodID = (*env)->GetMethodID(env, String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring result = (*env)->CallObjectMethod(env, jStr, concat_methodID, jStr2);
    return result;
}
  //判断java String 与c String 是否相同
int j_str_cmp_c_str(JNIEnv *env, jstring jStr, char* cStr){
    const char *jStrToCStr = (*env)->GetStringUTFChars(env, jStr, 0);
    int result = strcmp(jStrToCStr, cStr);
    (*env)->ReleaseStringUTFChars(env, jStr, jStrToCStr);
    return result;
}
//调用android toast
void android_toast(JNIEnv *env, jobject context, jstring str){
    jclass tclss = (*env)->FindClass(env, "android/widget/Toast");
     jmethodID mid = (*env)->GetStaticMethodID(env, tclss,"makeText","(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;");
     jobject job = (*env)->CallStaticObjectMethod(env, tclss,mid,context,str);
     jmethodID showId = (*env)->GetMethodID(env, tclss,"show","()V");
     (*env)->CallVoidMethod(env, job,showId,context,str);
}
//获取Context
jobject getGlobalContext(JNIEnv *env)
{
    //获取Activity Thread的实例对象
    jclass activityThread = (*env)->FindClass(env, "android/app/ActivityThread");
    jmethodID currentActivityThread = (*env)->GetStaticMethodID(env, activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;");
    jobject at = (*env)->CallStaticObjectMethod(env, activityThread, currentActivityThread);
    //获取Application，也就是全局的Context
    jmethodID getApplication = (*env)->GetMethodID(env, activityThread, "getApplication", "()Landroid/app/Application;");
    jobject context = (*env)->CallObjectMethod(env, at, getApplication);
    return context;
}

// 字节流转换为十六进制字符串
//http://blog.csdn.net/pingd/article/details/41945417
void ByteToHexStr(const unsigned char* source, char* dest, int sourceLen)
{
    short i;
    unsigned char highByte, lowByte;

    for (i = 0; i < sourceLen; i++)
    {
        highByte = source[i] >> 4;
        lowByte = source[i] & 0x0f;

        highByte += 0x30;

        if (highByte > 0x39)
                dest[i * 2] = highByte + 0x07;
        else
                dest[i * 2] = highByte;

        lowByte += 0x30;
        if (lowByte > 0x39)
            dest[i * 2 + 1] = lowByte + 0x07;
        else
            dest[i * 2 + 1] = lowByte;
    }
    return;
}
//根据Context获取PackageManager
jobject getPackageManager(JNIEnv * env, jobject context) {
    jclass class_context = (*env)->GetObjectClass(env, context);
    jmethodID tem_method = (*env)->GetMethodID(env, class_context, "getPackageManager", "()Landroid/content/pm/PackageManager;");
    jobject obj_package_manager = (*env)->CallObjectMethod(env, context, tem_method);
    return obj_package_manager;
}
//根据Context获取对应的包名
jobject getPackageName(JNIEnv * env, jobject context) {
    jclass class_context = (*env)->GetObjectClass(env, context);
    // getPackageName
    jmethodID tem_method = (*env)->GetMethodID(env, class_context, "getPackageName", "()Ljava/lang/String;");
    jobject obj_package_name = (*env)->CallObjectMethod(env, context, tem_method);
    return obj_package_name;
}
//根据Context获取对应安装的apk文件的md5值
//TODO 这个方法中，获取PackageInfo可能会报错，直接挂掉，因为没有安装应用
char* getSignatureMd5(JNIEnv * env, jobject obj_package_manager, jobject obj_package_name) {
    jclass tem_class;
    jmethodID tem_method;
    // getPackageInfo
    tem_class = (*env)->GetObjectClass(env, obj_package_manager);
    tem_method = (*env)->GetMethodID(env, tem_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    jobject obj_package_info = (*env)->CallObjectMethod(env, obj_package_manager, tem_method, obj_package_name, 64);

    // Signature[] arrayOfSignature = localPackageInfo.signatures;
    // Signature localSignature = arrayOfSignature[0];
    tem_class = (*env)->GetObjectClass(env, obj_package_info);
    jfieldID fieldID_signatures = (*env)->GetFieldID(env, tem_class, "signatures", "[Landroid/content/pm/Signature;");
    jobjectArray signatures = (*env)->GetObjectField(env, obj_package_info, fieldID_signatures);
    jobject signature = (*env)->GetObjectArrayElement(env, signatures, 0);
    // localSignature.toByteArray()
    tem_class = (*env)->GetObjectClass(env, signature);
    tem_method = (*env)->GetMethodID(env, tem_class, "toByteArray", "()[B");
    jobject obj_sign_byte_array = (*env)->CallObjectMethod(env, signature, tem_method);// 这个就是拿到的签名byte数组

    //      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
    jclass class_MessageDigest = (*env)->FindClass(env, "java/security/MessageDigest");
    tem_method = (*env)->GetStaticMethodID(env, class_MessageDigest, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;");
    jobject obj_md5 = (*env)->CallStaticObjectMethod(env, class_MessageDigest, tem_method, (*env)->NewStringUTF(env, "md5"));
    //      localMessageDigest.update(localSignature.toByteArray());
    //tem_class = (*env)->GetObjectClass(env, obj_md5);
    tem_method = (*env)->GetMethodID(env, class_MessageDigest, "update", "([B)V");// 这个函数的返回值是void，写V
    (*env)->CallVoidMethod(env, obj_md5, tem_method, obj_sign_byte_array);
    // localMessageDigest.digest()
    tem_method = (*env)->GetMethodID(env, class_MessageDigest, "digest", "()[B");
    // 这个是md5以后的byte数组，现在只要将它转换成16进制字符串，就可以和之前的比较了
    jobject obj_array_sign = (*env)->CallObjectMethod(env, obj_md5, tem_method);// jni中有强转类型的概念吗
    //      // 这个就是签名的md5值
    //      String str2 = toHex(localMessageDigest.digest());

    // 尝试用c写一下：http://blog.csdn.net/pingd/article/details/41945417
    jsize int_array_length = (*env)->GetArrayLength(env, obj_array_sign);
    jbyte* byte_array_elements = (*env)->GetByteArrayElements(env, obj_array_sign, JNI_FALSE);
    char* char_result = (char*) malloc(int_array_length*2+1);// 开始没有+1，在有的情况下会越界产生问题，还是在后面补上\0比较好
    // 将byte数组转换成16进制字符串，发现这里不用强转，jbyte和unsigned char应该字节数是一样的
    ByteToHexStr(byte_array_elements, char_result, int_array_length);
    *(char_result+int_array_length*2) = '\0';// 在末尾补\0
    // release
    (*env)->ReleaseByteArrayElements(env, obj_array_sign, byte_array_elements, JNI_ABORT);
    return char_result;


    //java code=======================================================
    //      PackageInfo localPackageInfo = context.getPackageManager()
    //              .getPackageInfo(context.getPackageName(), 64);
    //      StringBuilder localStringBuilder = new StringBuilder();
    //      Signature[] arrayOfSignature = localPackageInfo.signatures;
    //      Signature localSignature = arrayOfSignature[0];
    //      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
    //      localMessageDigest.update(localSignature.toByteArray());
    //      // 这个就是签名的md5值
    //      String str2 = toHex(localMessageDigest.digest());
    //      localStringBuilder.append("Signature of ")
    //              .append(localPackageInfo.packageName).append('\n').append(str2);
    //      System.out.println(localStringBuilder.toString());
    //      TextView tv = (TextView) findViewById(R.id.tv);
    //      tv.setText(localStringBuilder.toString());


    //  private String toHex(byte[] paramArrayOfByte) {
    //      StringBuffer localStringBuffer = new StringBuffer();
    //      for (int i = 0; i < paramArrayOfByte.length; i++) {
    //          Object[] arrayOfObject = new Object[1];
    //          arrayOfObject[0] = Byte.valueOf(paramArrayOfByte[i]);
    //          localStringBuffer.append(String.format("%02x", arrayOfObject));
    //      }
    //      return localStringBuffer.toString();
    //  }
    //java code======================================================
}
/**
*校验APP包名和签名是否合法返回值为1表示合法
*/
// jint getSignatureHashCode(JNIEnv* env, jobject packageManager, jobject application_package){
//	// //获得PackageManager类
//	jclass packageManager_clazz=(*env)->GetObjectClass(env,packageManager);
//
//	//得到getPackageInfo方法的ID
//	jmethodID methodID_getPackageInfo=(*env)->GetMethodID(env,packageManager_clazz,"getPackageInfo",
//						"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
//
//	// //得到getPackageName方法的ID
//	jmethodID methodID_getPackageName = (*env)->GetMethodID(env,context_clazz,"getPackageName","()Ljava/lang/String;");
//
//
//	//获得PackageInfo
//	jobject packageInfo = (*env)->CallObjectMethod(env,packageManager,methodID_getPackageInfo,application_package,64);
//	jclass packageinfo_clazz = (*env)->GetObjectClass(env,packageInfo);
//
//	//获取签名
//	jfieldID fieldID_signatures = (*env)->GetFieldID(env,packageinfo_clazz,"signatures","[Landroid/content/pm/Signature;");
//	jobjectArray signature_arr = (jobjectArray)(*env)->GetObjectField(env,packageInfo,fieldID_signatures);
//
//	//Signature数组中取出第一个元素
//	jobject signature = (*env)->GetObjectArrayElement(env,signature_arr,0);
//
//	//读signature的hashcode
//	jclass signature_clazz = (*env)->GetObjectClass(env,signature);
//	jmethodID methodID_hashcode = (*env)->GetMethodID(env,signature_clazz,"hashCode","()I");
//	jint hashCode = (*env)->CallIntMethod(env,signature,methodID_hashcode);
//
//	return hashCode;
////	public class SignatureUtils {
////        public static int getSignatureHashCode(Context context){
////            Signature signature = getSignature(context);
////            int hashCode = signature.hashCode();
////            return hashCode;
////        }
////        public static Signature getSignature(Context argContext) {
////            Signature signature = null;
////            try {
////                String packageName = argContext.getPackageName();
////                PackageManager packageManager = argContext.getPackageManager();
////                PackageInfo packageInfo = packageManager.getPackageInfo(packageName,packageManager.GET_SIGNATURES);
////                Signature[] signatures = packageInfo.signatures;
////                signature = signatures[0];
////            } catch (PackageManager.NameNotFoundException e) {
////                e.printStackTrace();
////            }
////            return signature;
////        }
////    }
//
//}

