由于项目中java需要调用第三方提供的C++动态库;由于第三方动态库传入的参数较多,还伴随着指针传入操作,导致java调用极为不便!因此催生出对于第三方的C++动态库进行二次封装。java调用只需按结构传入一个结构化的string即可。话不多说开干!
第三方库
第三方C++的头文件HD10_safe.h如下:
#ifndef _HD10_safe_H_
#define _HD10_safe_H_
#ifdef _cplusplus
extern "C" {
#endif
typedef enum VKeyGenResultEx
{
KGRE_OK ,
KGRE_NOT_OK
}KeyGenResult;
typedef enum ECUS
{
BCM=1, DCM, IC_6000, GW, VWM, LDWS, DMS, VCU, RCU, ACC,
RWCD, PSU, BBM, AC_6000, TPMS, VMS, PEPS, IMMO, EMS, ESCL,
MMI, BMS, FC, EC, ECM, CPD_3000, AFS, TCO, TCU, DCU,
ECAS, ABS, EBS, EPB, AEBS, EVM, TCU_SH, ADAS, BS_LKA, CIM,
RIM, FIM, MCU, CABS, DSW, VCU_x5_M3S, SWG, CCU, WP_ECU, CMS_ECU,
EHBS, ACR, TBOX_5G, CSC, HCU, LKA, ADCU, CPD_6000, IC_3000, AC_3000,
LE_IC, LE_AC, LE_BCM, LE_GW, LE_VCU, LE_TPMS, LE_DCM, VDCU, PDU, DCDC, DCAC, DSSAD
}ECUs;
typedef unsigned char uint8;
typedef unsigned short uint16;
// Function
//
KeyGenResult HD10GenerateKeyEx(uint8* iSeedArray, /* Array for the seed [in] */
uint8 iSeedArraySize, /* Length of the array for the seed [in] */
const uint8 iSecurityLevel, /* Security level [in] */
uint8 * iKeyArray, /* Array for the key [in, out] */
uint8 * iKeySize, /* Length of the key [out] */
ECUs e /* enum ECUS elements */
);
#ifdef _cplusplus
}
#endif
#endif // _HD10_safe_H_
第三方动态库 libTXJsafe.so 如下:
C++调用
写一个C++ demo 调用动态库 test.cpp 代码如下:
#include <stdio.h>
#include "HD10_safe.h"
int main()
{
uint8 arr[2] = {0x12, 0x34};
uint8 seed[2] = {0x00, 0x00};
uint8 seedLen = 0;
int ret = HD10GenerateKeyEx(arr, 2, 7, seed, &seedLen, TCU);
printf("ret : %d, seedLen:%d \n", ret, seedLen);
for(int i = 0; i < seedLen; i++)
{
printf("seed[%d] : 0x%02x ;", i, seed[i]);
}
printf("\n");
return 0;
}
运行结果如下:
jni二次封装动态库
通过jni二次封装动态库 mysafelib.cpp 代码如下:
#include <iostream>
#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "HD10_safe.h"
// iString 输入参数格式:level(1byte) + ECUS(1byte) + SeedSize(1byte) + SeedValue(nbyte)
// rString 返回参数格式:keysize(1byte) + keyValue(nbyte)
extern "C" {
JNIEXPORT jstring JNICALL Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jstring iString);
}
// 十六进制字符串转字十六进制 "12" --> 0x12
int Str2Hex(char *p_hexstr, int iHexLen, char *pdststr);
// 十六进制数值转十六进制字符串 0x12 --> "12"
int Hex2Str(const char *p_strstr, int iStrLen, char *pdststr);
JNIEXPORT jstring JNICALL Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jstring iString)
{
char myRString[66] = {0};
char iHexStrOrg[64] = {0};
char iHexStr[32] = {0};
const char *iStrData = env->GetStringUTFChars(iString, 0);
memcpy(iHexStrOrg, iStrData, strlen(iStrData) > 64 ? 64 : strlen(iStrData));
env->ReleaseStringUTFChars(iString, iStrData);
int iHexStrLen = Str2Hex(iHexStrOrg, strlen(iHexStrOrg), iHexStr);
// std::cout << "strlen(iHexStrOrg) : " << strlen(iHexStrOrg) << std::endl;
if(iHexStrLen < 4) return env->NewStringUTF(myRString);
// std::cout << "iHexStrLen : " << iHexStrLen << std::endl;
uint8 seed[32] = {0};
uint8 key[33] = {0};
uint8 keyLen = 0;
uint8 u8Level = *(uint8 *)iHexStr;
uint8 u8ECU = *(uint8 *)(iHexStr + 1);
uint8 u8SeedSize = *(uint8 *)(iHexStr + 2);
// printf("u8SeedSize : %d \n", u8SeedSize);
if(u8SeedSize > 32) return env->NewStringUTF(myRString);
memcpy(seed, iHexStr + 3, u8SeedSize);
KeyGenResult ret = (KeyGenResult)HD10GenerateKeyEx(seed, u8SeedSize, u8Level, key + 1, &keyLen, (ECUs)u8ECU);
if(ret != KGRE_OK || keyLen > 32) return env->NewStringUTF(myRString);
// printf("ret : %d, keyLen:%d \n", (int)ret, keyLen);
// for(int i = 1; i <= keyLen; i++) printf("key[%d] : %02x; ", i, key[i]);
key[0] = keyLen * 2;
Hex2Str((const char*)key, keyLen + 1, myRString);
jstring rString = env->NewStringUTF(myRString);
printf("\n---------------successful-----------------\n");
return rString;
}
// 十六进制字符串转字十六进制 "12" --> 0x12
int Str2Hex(char *p_hexstr, int iHexLen, char *pdststr)
{
int iret = 0;
while(p_hexstr != NULL && pdststr != NULL && iHexLen > 1)
{
char cTemp = '0';
// printf("1:%c, 2:%c\n", p_hexstr[0], p_hexstr[1]);
// 小写统一转大写
if(p_hexstr[0] >= '0' && p_hexstr[0] <= '9')
{
cTemp = p_hexstr[0] - '0';
}
else if(p_hexstr[0] >= 'A' && p_hexstr[0] <= 'F')
{
cTemp = p_hexstr[0] - 'A' + 10;
}
else if(p_hexstr[0] >= 'a' && p_hexstr[0] <= 'f')
{
cTemp = p_hexstr[0] - 'a' + 10;
}
else
{
printf("the hex str is error!\n");
break;
}
*pdststr = cTemp * 16;
if(p_hexstr[1] >= '0' && p_hexstr[1] <= '9')
{
cTemp = p_hexstr[1] - '0';
}
else if(p_hexstr[1] >= 'A' && p_hexstr[1] <= 'F')
{
cTemp = p_hexstr[1] - 'A' + 10;
}
else if(p_hexstr[1] >= 'a' && p_hexstr[1] <= 'f')
{
cTemp = p_hexstr[1] - 'a' + 10;
}
else
{
printf("the hex str is error!\n");
break;
}
*pdststr += cTemp;
// printf("---iHexLen:%d, pdststr:%c\n", iHexLen, *pdststr);
iHexLen -= 2;
p_hexstr += 2;
pdststr++;
iret++;
}
// printf("iret : %d\n", iret);
return iret;
}
// 十六进制数值转十六进制字符串 0x12 --> "12"
int Hex2Str(const char *p_strstr, int iStrLen, char *pdststr)
{
int index_str = 0, index_hex = 0;
const char cHex[] = "0123456789ABCDEF";
while(index_str < iStrLen && p_strstr != NULL && pdststr != NULL)
{
pdststr[index_hex++] = cHex[((uint8)p_strstr[index_str])/16];
pdststr[index_hex++] = cHex[((uint8)p_strstr[index_str++])%16];
}
return index_hex;
}
编译生成对应二次封装的动态库如下:
java调用二次封装动态库
java调用二次封装库的demo文件如下:
package com.example;
public class MyClass {
static {
System.load("/home/lijd/testlib3/sodir/libmysafe.so"); // 加载C++动态库
}
private native String nativeMethod(String str); // 声明本地方法
public static void main(String[] args) {
byte[] seedValue = new byte[]{0x12, 0x34};
int seedSize = 2;//字节长度
int level = 7;
int ECUS = 29;
StringBuffer param = new StringBuffer();
param.append(byteToString(intToByte1(level)));
param.append(byteToString(intToByte1(ECUS)));
param.append(byteToString(intToByte1(seedSize)));
param.append(byteToString(seedValue));
String result = new MyClass().nativeMethod(param.toString()); // 调用本地方法
System.out.println("---MyClass---" + result.length() + " : " + result);
}
/**
* @title byteToString
* @description 将字节数组转为字符串
* @param buff
* 字节数据
* @return String 装换后的字符串数据
*/
public static final String byteToString(byte[] buff) {
StringBuilder sb = new StringBuilder();
if (null != buff && buff.length > 0) {
for (byte b : buff) {
short t = b;
if (t < 0)
t += 256;
short h = (short) (t / 16);
short l = (short) (t % 16);
switch (h) {
case 10:
sb.append("A");
break;
case 11:
sb.append("B");
break;
case 12:
sb.append("C");
break;
case 13:
sb.append("D");
break;
case 14:
sb.append("E");
break;
case 15:
sb.append("F");
break;
default:
sb.append(h);
break;
}
switch (l) {
case 10:
sb.append("A");
break;
case 11:
sb.append("B");
break;
case 12:
sb.append("C");
break;
case 13:
sb.append("D");
break;
case 14:
sb.append("E");
break;
case 15:
sb.append("F");
break;
default:
sb.append(l);
break;
}
}
}
return sb.toString();
}
public static byte[] intToByte1(int value) {
byte[] b = new byte[1];
for (int i = 0; i < 1; ++i) {
int offset = (b.length - 1 - i) * 8;
b[i] = (byte) (value >>> offset & 255);
}
return b;
}
}
执行javac 编译源文件生产class文件如下:
运行java的class文件如下:
至此,一切搞定!通过windows测试这样也完全可以。