Linux java jni调用C++封装动态库

news2024/11/19 19:25:32

        由于项目中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测试这样也完全可以。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1709990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

狂暴少帅短视频:成都科成博通文化传媒公司

狂暴少帅短视频&#xff1a;热血与激情的碰撞 在当下这个信息爆炸的时代&#xff0c;短视频以其独特的魅力迅速占领了人们的视线。而在众多短视频创作者中&#xff0c;一位名为“狂暴少帅”的创作者以其独特的风格和引人入胜的内容&#xff0c;赢得了广大网友的喜爱和追捧。今…

关于pdfbox读取pdf

最近&#xff0c;想着将pdf的文件进行读取其内容&#xff0c;发现了一个比较好用的依赖pdfbox。目前使用这个依赖&#xff0c;进行实现一个简单实例&#xff0c;如果之后需要使用到更深的了解&#xff0c;会进行更新。这里提醒一下&#xff1a;jdk8尽量采用pdfbox3.x版本。 对…

怎样查看JavaScript中没有输出结果的数组值?

在JavaScript中&#xff0c;可以方便地定义和使用数组&#xff0c;对于已经定义的数组&#xff0c;怎样查看其值呢&#xff1f; 看下面的示例&#xff0c;并运行它。 上面的示例中&#xff0c;标签不完整&#xff0c;请补充完整再试运行。你知道少了什么标签么&#xff1f; 注…

react ant 表格实现 拖拽排序和多选

项目背景 : react ant 要实现 : 有多选功能(实现批量删除 , 也可以全选) 可以拖拽(可以复制 , 方便顶部的搜索功能) 要实现效果如下 1 这是最初的拖拽功能实现 , 不能复制表格里的内容 , 不符合要求 2 更改了ROW的内容 , 实现了可以复制表格内容 代码 //控制是否可以选中表格…

拉普拉斯IPO:科技与产业深度融合,实现业务领域延展

我国拥有全球最具竞争优势的光伏产业链&#xff0c;基于降本增效的需求&#xff0c;光伏产业对于技术革新具有持续的需求。拉普拉斯新能源科技股份有限公司&#xff08;以下简称“拉普拉斯”&#xff09;凭借深厚的技术积累&#xff0c;以及对光伏产业深刻的理解&#xff0c;聚…

GitLab的安装及基础操作

1. 项目目标 &#xff08;1&#xff09;熟练使用rpm包安装gitlab &#xff08;2&#xff09;熟练配置gitlab &#xff08;3&#xff09;熟练创建gitlab群组、成员、项目 &#xff08;4&#xff09;熟练使用gitlab推送和拉取代码 2. 项目准备 2.1. 规划节点 主机名 主机I…

数据结构初阶 栈

一. 栈的基本介绍 1. 基本概念 栈是一种线性表 是一种特殊的数据结构 栈顶&#xff1a;进行数据插入和删除操作的一端 另一端叫做栈底 压栈&#xff1a;插入数据叫做压栈 压栈的数据在栈顶 出栈&#xff1a; 栈的删除操作叫做出栈 出栈操作也是在栈顶 栈遵循一个原则 叫做…

人脸检测--FaceNet(四)

FaceNet 是一个由 Google 研究团队开发的人脸识别系统&#xff0c;它基于深度学习技术&#xff0c;可以实现高精度的人脸识别、验证和聚类任务。FaceNet 通过学习直接从图像像素到人脸嵌入的映射&#xff0c;使得它在各种人脸识别任务中表现出色。下面是对 FaceNet 的详细介绍&…

python探索时钟模拟之旅:从设计到实现

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、设计时钟类 三、代码实现 四、扩展功能&#xff1a;指定步数后自动停止 五…

编程中的模块迷宫:区分与正确使用

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、模块混淆的陷阱 二、碳模块与探母模块的区别 三、如何正确使用模块 四、代码示例 五…

【Linux】数据链路层协议+ICMP协议+NAT技术

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;Linux 目录 &#x1f449;&#x1f3fb;数据链路层&#x1f449;&#x1f3fb;以太网以太网帧格式网卡Mac地址对比ip地址 &#x1f449;&#x1f3fb;MTUMTU…

9、C#【进阶】特性

特性 文章目录 1、特性概念2、自定义特性 Attribute3、特性的使用4、限制自定义特性的使用范围5、系统自带特性1、过时特性2、调用者信息特性3、条件编译特性4、外部dll包函数特性 1、特性概念 特性是一种允许我们向程序的程序集添加元数据的语言结构 它是用于保存程序机构信息…

5、xss-labs之level6

一、level6-----大小写绕过 1、测试分析 测试了之前用过的payload&#xff0c;发现都不行&#xff0c;并且level4使用的Java伪协议也不行&#xff0c;可以得出<>、script、onclick都被过滤 2、构造payload 因为href被过滤&#xff0c;可以试一下大写HREF 初试payload…

【debug】windows11安装WSL+Docker+本地部署cvcat

windows系统安装wsl虚拟机 首先观察是否已启用虚拟化&#xff1a; 在windows应用商店下载wsl 下载好后打开&#xff0c;创建用户名和密码&#xff0c;即可使用&#xff1a; 换源&#xff1a;ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirr…

双机多网口配置同网段地址,可以通过目的IP确定接收数据的网卡吗?

环境 两台机器两网卡同网段接入同一个二层交换机。 机器A ens38 00:0c:29:a4:8b:fb 10.0.0.11/24 ens39 00:0c:29:a4:8b:05 10.0.0.12/24 机器B ens38 00:0c:29:4f:a6:c4 10.0.0.21/24 ens39 00:0c:29:4f:a6:ce 10.0.0.22/24 初始ARP表 只有管理口接口的ARP表项&#xff0c…

【C++】list的使用方法和模拟实现

❤️欢迎来到我的博客❤️ 前言 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后…

Pytest用例自定义 - 重复、并行、串行

简介&#xff1a;面对快速迭代和持续交付的需求&#xff0c;提高测试效率变得至关重要。并行测试因其显著的时间节省优势而备受青睐。然而&#xff0c;并非所有测试都适合并行执行。在某些情况下&#xff0c;串行执行是必要的&#xff0c;以确保测试的正确性和稳定性。本文将探…

进程和用户管理

查看进程的命令 ps top pstree 发送信号命令 kill 使用是后加-l 用户管理命令 添加用户:sudo adduser 用户名 修改组:sudo usermod -G 用户名1 用户名2 修改家目录:sudo usermod -d /home/用户名 -m 用户名 删除用户名:sudo deluser --remove -home 用户名

newinit.sh挖矿攻击处理与规避方案

目录 攻击分析 恢复措施&#xff1a; 问题排查 攻击入口分析 预防 临时处理方案&#xff1a; 攻击分析 攻击者&#xff1a;职业黑客&#xff08;99%&#xff09; 攻击方式&#xff1a;挖矿病毒newinit.sh和蠕虫病毒pnscan 中毒现象: 服务器负载异常&#xff0c;具体表…

Celery教程

一、什么是Celery 1.1、celery是什么 Celery是一个简单、灵活且可靠的&#xff0c;处理大量消息的分布式系统&#xff0c;专注于实时处理的异步任务队列&#xff0c;同时也支持任务调度。 Celery的架构由三部分组成&#xff0c;消息中间件&#xff08;message broker&#x…