V0.37.0.250711_alpha:新增一个数字签名项目

This commit is contained in:
jinchao 2025-07-11 14:21:06 +08:00
parent 729d4dcaa9
commit b1f1c4970f
23 changed files with 1406 additions and 146 deletions

View File

@ -1,141 +1,173 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/25.0.2 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="25.0.2">
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2">
<diagram name="第 1 页" id="n4mM9-rLUw7j7IC2DLn1">
<mxGraphModel dx="676" dy="395" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<mxGraphModel dx="1680" dy="991" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="DPG0hEwUPDznWshsaorW-109" value="" style="group" vertex="1" connectable="0" parent="1">
<mxGeometry x="40" y="240" width="460" height="650" as="geometry" />
<mxCell id="nnVTWkkhsZWMSzmyXnU6-1" value="" style="group" vertex="1" connectable="0" parent="1">
<mxGeometry x="40" y="40" width="340" height="140" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-42" value="&lt;font&gt;仿真调度引擎退出&lt;/font&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.terminator;whiteSpace=wrap;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="190" y="610" width="140" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-37" value="仿真调度引擎" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#FFFFCC;fontStyle=1;verticalAlign=top;" parent="nnVTWkkhsZWMSzmyXnU6-1" vertex="1">
<mxGeometry width="340" height="140" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-43" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;仿真调度引擎启动&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.start_1;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="180" width="160" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-36" value="仿真运行控制" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#FFFF99;" parent="nnVTWkkhsZWMSzmyXnU6-1" vertex="1">
<mxGeometry x="10" y="90" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;labelBackgroundColor=none;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-79" target="DPG0hEwUPDznWshsaorW-42">
<mxCell id="DPG0hEwUPDznWshsaorW-38" value="仿真运行状态发布" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#FFFF99;" parent="nnVTWkkhsZWMSzmyXnU6-1" vertex="1">
<mxGeometry x="180" y="90" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-107" value="构型验证" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#FFFF99;" parent="nnVTWkkhsZWMSzmyXnU6-1" vertex="1">
<mxGeometry x="180" y="40" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-108" value="命令参数解析" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#FFFF99;" parent="nnVTWkkhsZWMSzmyXnU6-1" vertex="1">
<mxGeometry x="10" y="40" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="nnVTWkkhsZWMSzmyXnU6-14" value="" style="group" vertex="1" connectable="0" parent="1">
<mxGeometry x="30" y="240" width="490" height="860" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-42" value="&lt;font&gt;结束&lt;/font&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.terminator;whiteSpace=wrap;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="280" y="820" width="140" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-43" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;开始&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.start_1;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="190" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-44" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;labelBackgroundColor=none;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-79" target="DPG0hEwUPDznWshsaorW-42" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="480" y="430" as="targetPoint" />
<mxPoint x="490" y="570" as="targetPoint" />
<Array as="points">
<mxPoint x="430" y="800" />
<mxPoint x="350" y="800" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-80" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-45" target="DPG0hEwUPDznWshsaorW-79">
<mxCell id="DPG0hEwUPDznWshsaorW-76" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;fontSize=14;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-48" target="DPG0hEwUPDznWshsaorW-63" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-45" value="预加载仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="340" y="210" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-76" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=14;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-48" target="DPG0hEwUPDznWshsaorW-51">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-77" value="&lt;font style=&quot;font-size: 14px;&quot;&gt;N&lt;/font&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="DPG0hEwUPDznWshsaorW-76">
<mxCell id="DPG0hEwUPDznWshsaorW-77" value="&lt;font style=&quot;font-size: 14px;&quot;&gt;N&lt;/font&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;" parent="DPG0hEwUPDznWshsaorW-76" vertex="1" connectable="0">
<mxGeometry x="0.2286" relative="1" as="geometry">
<mxPoint x="-10" y="-8" as="offset" />
<mxPoint x="-10" y="-1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-48" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;预加载模式?&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="190" y="120" width="140" height="60" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-48" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;测试模式?&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="200" y="380" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-81" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-51" target="DPG0hEwUPDznWshsaorW-59">
<mxCell id="DPG0hEwUPDznWshsaorW-81" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-51" target="DPG0hEwUPDznWshsaorW-59" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-51" value="加载仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="210" y="210" width="100" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-51" value="加载仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="210" y="120" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;labelBackgroundColor=none;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-59" target="DPG0hEwUPDznWshsaorW-63">
<mxCell id="DPG0hEwUPDznWshsaorW-58" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;labelBackgroundColor=none;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-59" target="nnVTWkkhsZWMSzmyXnU6-2" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="260" y="329.9999999999999" as="targetPoint" />
<mxPoint x="270" y="389.9999999999999" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-59" value="初始化仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="200" y="270" width="120" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-59" value="初始化仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="210" y="180" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-62" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;labelBackgroundColor=none;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-63" target="DPG0hEwUPDznWshsaorW-98">
<mxCell id="DPG0hEwUPDznWshsaorW-62" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;labelBackgroundColor=none;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-63" target="DPG0hEwUPDznWshsaorW-98" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="260" y="390" as="targetPoint" />
<mxPoint x="270" y="530" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-63" value="启动仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="200" y="330" width="120" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-63" value="启动仿真" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="210" y="470" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-65" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;labelBackgroundColor=none;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-82" target="DPG0hEwUPDznWshsaorW-42">
<mxCell id="DPG0hEwUPDznWshsaorW-65" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;labelBackgroundColor=none;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-82" target="DPG0hEwUPDznWshsaorW-42" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;labelBackgroundColor=none;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-43" target="DPG0hEwUPDznWshsaorW-74">
<mxCell id="DPG0hEwUPDznWshsaorW-67" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;labelBackgroundColor=none;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-43" target="DPG0hEwUPDznWshsaorW-74" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="316" y="60" as="targetPoint" />
<mxPoint x="326" y="60" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-70" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=14;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;labelBackgroundColor=none;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-48" target="DPG0hEwUPDznWshsaorW-45">
<mxCell id="DPG0hEwUPDznWshsaorW-70" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0;entryDx=0;entryDy=0;fontSize=14;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;labelBackgroundColor=none;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-48" target="DPG0hEwUPDznWshsaorW-79" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="398.5" y="90" as="sourcePoint" />
<mxPoint x="376" y="470" as="targetPoint" />
<mxPoint x="408.5" y="230" as="sourcePoint" />
<mxPoint x="410" y="350" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-71" value="Y" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;labelBackgroundColor=none;" vertex="1" connectable="0" parent="DPG0hEwUPDznWshsaorW-70">
<mxCell id="DPG0hEwUPDznWshsaorW-71" value="Y" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;labelBackgroundColor=none;" parent="DPG0hEwUPDznWshsaorW-70" vertex="1" connectable="0">
<mxGeometry x="0.0439" relative="1" as="geometry">
<mxPoint x="-69" y="-10" as="offset" />
<mxPoint x="-50" y="-10" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-74" value="命令参数解析" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="200" y="60" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-75" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-74" target="DPG0hEwUPDznWshsaorW-48">
<mxCell id="nnVTWkkhsZWMSzmyXnU6-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-74" target="DPG0hEwUPDznWshsaorW-51">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-79" value="输出校验信息" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="340" y="270" width="120" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-74" value="命令参数解析" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="210" y="60" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-82" value="卸载仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="200" y="550" width="120" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-75" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="nnVTWkkhsZWMSzmyXnU6-2" target="nnVTWkkhsZWMSzmyXnU6-9" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="280" y="160" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-87" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-86" target="DPG0hEwUPDznWshsaorW-82">
<mxCell id="DPG0hEwUPDznWshsaorW-79" value="输出验证结果" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="370" y="470" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-82" value="卸载仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="210" y="740" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-87" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-86" target="DPG0hEwUPDznWshsaorW-82" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-102" value="如果是终止指令" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="DPG0hEwUPDznWshsaorW-87">
<mxCell id="DPG0hEwUPDznWshsaorW-102" value="终止指令" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;" parent="DPG0hEwUPDznWshsaorW-87" vertex="1" connectable="0">
<mxGeometry x="-0.1111" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
<mxPoint x="31" y="-3" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-104" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-86" target="DPG0hEwUPDznWshsaorW-103">
<mxGeometry relative="1" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-104" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-86" target="DPG0hEwUPDznWshsaorW-103" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="120" y="680" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-106" value="暂停/继续指令" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="DPG0hEwUPDznWshsaorW-104">
<mxCell id="DPG0hEwUPDznWshsaorW-106" value="暂停/继续指令" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=none;" parent="DPG0hEwUPDznWshsaorW-104" vertex="1" connectable="0">
<mxGeometry x="-0.2444" y="1" relative="1" as="geometry">
<mxPoint x="-4" y="9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-86" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;收到控制指令?&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="190" y="450" width="140" height="60" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-86" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;收到控制指令?&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="200" y="650" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-98" value="控制指令监听" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry x="200" y="390" width="120" height="40" as="geometry" />
<mxCell id="DPG0hEwUPDznWshsaorW-98" value="控制指令监听" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry x="210" y="530" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-98" target="DPG0hEwUPDznWshsaorW-86">
<mxCell id="DPG0hEwUPDznWshsaorW-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-98" target="nnVTWkkhsZWMSzmyXnU6-4" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-105" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="DPG0hEwUPDznWshsaorW-109" source="DPG0hEwUPDznWshsaorW-103" target="DPG0hEwUPDznWshsaorW-98">
<mxCell id="DPG0hEwUPDznWshsaorW-105" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="nnVTWkkhsZWMSzmyXnU6-14" source="DPG0hEwUPDznWshsaorW-103" target="nnVTWkkhsZWMSzmyXnU6-4" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="60" y="660" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-103" value="控制仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" parent="nnVTWkkhsZWMSzmyXnU6-14" vertex="1">
<mxGeometry y="660" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="nnVTWkkhsZWMSzmyXnU6-2" value="构型验证" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" vertex="1" parent="nnVTWkkhsZWMSzmyXnU6-14">
<mxGeometry x="210" y="240" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="nnVTWkkhsZWMSzmyXnU6-4" value="仿真运行状态&lt;div&gt;发布&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#FFFFCC;" vertex="1" parent="nnVTWkkhsZWMSzmyXnU6-14">
<mxGeometry x="210" y="590" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="nnVTWkkhsZWMSzmyXnU6-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="nnVTWkkhsZWMSzmyXnU6-14" source="nnVTWkkhsZWMSzmyXnU6-4" target="DPG0hEwUPDznWshsaorW-86">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-103" value="控制仿真内核" style="rounded=1;whiteSpace=wrap;html=1;absoluteArcSize=1;arcSize=14;strokeWidth=2;fontSize=16;labelBackgroundColor=none;fillColor=#E6FFCC;" vertex="1" parent="DPG0hEwUPDznWshsaorW-109">
<mxGeometry y="460" width="120" height="40" as="geometry" />
<mxCell id="nnVTWkkhsZWMSzmyXnU6-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="nnVTWkkhsZWMSzmyXnU6-14" source="nnVTWkkhsZWMSzmyXnU6-9" target="DPG0hEwUPDznWshsaorW-79">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-110" value="" style="group" vertex="1" connectable="0" parent="1">
<mxGeometry x="40" y="40" width="340" height="140" as="geometry" />
<mxCell id="nnVTWkkhsZWMSzmyXnU6-13" value="N" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="nnVTWkkhsZWMSzmyXnU6-11">
<mxGeometry x="-0.7077" y="1" relative="1" as="geometry">
<mxPoint x="-28" y="-9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-37" value="仿真调度引擎" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#E6FFCC;fontStyle=1;verticalAlign=top;" vertex="1" parent="DPG0hEwUPDznWshsaorW-110">
<mxGeometry width="340" height="140" as="geometry" />
<mxCell id="nnVTWkkhsZWMSzmyXnU6-9" value="&lt;span style=&quot;font-size: 16px;&quot;&gt;验证通过?&lt;/span&gt;" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;labelBackgroundColor=none;fillColor=#FFFFCC;" vertex="1" parent="nnVTWkkhsZWMSzmyXnU6-14">
<mxGeometry x="200" y="300" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-36" value="仿真内核加载及调用" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#CCFF99;" vertex="1" parent="DPG0hEwUPDznWshsaorW-110">
<mxGeometry x="10" y="90" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-38" value="控制指令监听及仿真运行控制" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#CCFF99;" vertex="1" parent="DPG0hEwUPDznWshsaorW-110">
<mxGeometry x="180" y="90" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-107" value="仿真内核预加载" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#CCFF99;" vertex="1" parent="DPG0hEwUPDznWshsaorW-110">
<mxGeometry x="180" y="40" width="150" height="40" as="geometry" />
</mxCell>
<mxCell id="DPG0hEwUPDznWshsaorW-108" value="命令参数解析" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#CCFF99;" vertex="1" parent="DPG0hEwUPDznWshsaorW-110">
<mxGeometry x="10" y="40" width="150" height="40" as="geometry" />
<mxCell id="nnVTWkkhsZWMSzmyXnU6-10" value="Y" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="nnVTWkkhsZWMSzmyXnU6-14" source="nnVTWkkhsZWMSzmyXnU6-9" target="DPG0hEwUPDznWshsaorW-48">
<mxGeometry y="-10" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>

Binary file not shown.

View File

@ -256,8 +256,6 @@ public:
using ThisType = cls; \
using SuperType = sup;
#define XN_UNUSED(x) (void)x
namespace XNSim
{
template <typename T>

View File

@ -28,7 +28,7 @@ public:
/**
* @brief
*/
enum LogLevel { Debug, Info, Warning, Error, Time };
enum LogLevel { Debug, Info, Warning, Error };
/**
* @brief
@ -128,7 +128,7 @@ private:
/**
* @brief
*/
const std::string COLOR_DEBUG = "\033[34m"; // 蓝
const std::string COLOR_DEBUG = "\033[36m"; // 青
/**
* @brief
@ -217,18 +217,20 @@ private:
"A01021002: 单条日志参数数量超过限制详见XNLogger.cppline 216");
std::string result = message;
// 使用初始化列表展开参数包
// 使用折叠表达式展开参数包
int index = 1;
// 使用lambda和std::initializer_list展开参数包
(void)std::initializer_list<int>{(
[&result, &index](const auto &value) {
// 定义替换单个参数的lambda函数
auto replacePlaceholder = [&result, &index](const auto &value) {
std::string placeholder = "%" + std::to_string(index++);
size_t pos = result.find(placeholder);
if (pos != std::string::npos) {
result.replace(pos, placeholder.length(), convertToString(value));
}
}(args),
0)...};
};
// 使用折叠表达式对每个参数调用替换函数
(replacePlaceholder(args), ...);
return result;
}
};
@ -236,19 +238,35 @@ private:
/**
* @brief
*/
#define LOG_DEBUG(message, ...) XNLoggerHelper::log(XNLogger::Debug, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_DEBUG(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Debug, message, args...);
}
/**
* @brief
* @brief
*/
#define LOG_INFO(message, ...) XNLoggerHelper::log(XNLogger::Info, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_INFO(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Info, message, args...);
}
/**
* @brief
* @brief
*/
#define LOG_WARNING(message, ...) XNLoggerHelper::log(XNLogger::Warning, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_WARNING(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Warning, message, args...);
}
/**
* @brief
* @brief
*/
#define LOG_ERROR(message, ...) XNLoggerHelper::log(XNLogger::Error, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_ERROR(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Error, message, args...);
}

View File

@ -4,8 +4,6 @@
#include "TypeDefine.h"
#include "TopicManager.h"
#define THISUNUSED(x) (void)(x)
class XNFramework;
using XNFrameworkPtr = std::shared_ptr<XNFramework>;
@ -40,11 +38,10 @@ public:
_isInitialized = false;
};
virtual void Initialize(XNFrameworkPtr framework, uint32_t modelId, uint32_t DDS_type) override
virtual void Initialize(XNFrameworkPtr framework [[maybe_unused]],
uint32_t modelId [[maybe_unused]],
uint32_t DDS_type [[maybe_unused]]) override
{
THISUNUSED(framework);
THISUNUSED(modelId);
THISUNUSED(DDS_type);
XNDDSErrorCode ret =
TopicManager::Instance()->registerSubscriber<typename T::DDSPubSubType>(
T::topic_name,

9
Release/public_key.pem Normal file
View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxdmYwjqt2Jd7+PW4N/qi
KQALeEd4j6RqIiXMm8zYYYQSe3SSrEuOZYhUKqFcYX9KwEo05SeiJm6oiHJw/ADw
H6Tcn3XoNICrfeMdkpCV1OpAHq9WjaueYtwy3EZgBh7iFx0jOY8a4fpQUL+KeID9
qeAYU+BXbPDIOkGVIu2saDfdwfMW2shR6kaNAto66MhfZMSqcGQfN9NkhmsdXahC
WuulopiM0k95LMr15TM3fqAvOOIvT+Us8l8OnnGYDYWPx6Gva3DILLa6ZvUXsLUE
519inlKdIILYszHCLnfs8hQPPrPk8Fa85v0PVVdSbBORCsQ0r9dN0dBFGJ/yGC8j
FQIDAQAB
-----END PUBLIC KEY-----

View File

@ -256,8 +256,6 @@ public:
using ThisType = cls; \
using SuperType = sup;
#define XN_UNUSED(x) (void)x
namespace XNSim
{
template <typename T>

View File

@ -69,23 +69,16 @@ void XNLogger::log(LogLevel level, const std::string &message)
break;
}
coloredMessage += "\n";
// 控制台输出
if (consoleOutputEnabled[level]) {
if (level == Time) {
// 如果是时间日志,则不换行,回退到该行开始
std::cout << coloredMessage << "\r" << std::flush;
} else {
std::cout << coloredMessage << std::endl;
}
std::cout << coloredMessage;
}
// 文件输出
if (fileOutputEnabled[level] && logFile.is_open()) {
if (level == Time) {
logFile << logMessage << "\r" << std::flush;
} else {
logFile << logMessage << std::endl;
}
logFile << logMessage;
}
}
@ -110,8 +103,6 @@ std::string XNLogger::logLevelToString(LogLevel level) const
return "WARNING";
case Error:
return "ERROR";
case Time:
return "TIME";
default:
return "UNKNOWN";
}

View File

@ -28,7 +28,7 @@ public:
/**
* @brief
*/
enum LogLevel { Debug, Info, Warning, Error, Time };
enum LogLevel { Debug, Info, Warning, Error };
/**
* @brief
@ -128,7 +128,7 @@ private:
/**
* @brief
*/
const std::string COLOR_DEBUG = "\033[34m"; // 蓝
const std::string COLOR_DEBUG = "\033[36m"; // 青
/**
* @brief
@ -217,18 +217,20 @@ private:
"A01021002: 单条日志参数数量超过限制详见XNLogger.cppline 216");
std::string result = message;
// 使用初始化列表展开参数包
// 使用折叠表达式展开参数包
int index = 1;
// 使用lambda和std::initializer_list展开参数包
(void)std::initializer_list<int>{(
[&result, &index](const auto &value) {
// 定义替换单个参数的lambda函数
auto replacePlaceholder = [&result, &index](const auto &value) {
std::string placeholder = "%" + std::to_string(index++);
size_t pos = result.find(placeholder);
if (pos != std::string::npos) {
result.replace(pos, placeholder.length(), convertToString(value));
}
}(args),
0)...};
};
// 使用折叠表达式对每个参数调用替换函数
(replacePlaceholder(args), ...);
return result;
}
};
@ -236,19 +238,35 @@ private:
/**
* @brief
*/
#define LOG_DEBUG(message, ...) XNLoggerHelper::log(XNLogger::Debug, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_DEBUG(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Debug, message, args...);
}
/**
* @brief
* @brief
*/
#define LOG_INFO(message, ...) XNLoggerHelper::log(XNLogger::Info, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_INFO(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Info, message, args...);
}
/**
* @brief
* @brief
*/
#define LOG_WARNING(message, ...) XNLoggerHelper::log(XNLogger::Warning, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_WARNING(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Warning, message, args...);
}
/**
* @brief
* @brief
*/
#define LOG_ERROR(message, ...) XNLoggerHelper::log(XNLogger::Error, message, ##__VA_ARGS__)
template <typename... Args>
inline void LOG_ERROR(const std::string &message, Args &&...args)
{
XNLoggerHelper::log(XNLogger::Error, message, args...);
}

View File

@ -4,8 +4,6 @@
#include "TypeDefine.h"
#include "TopicManager.h"
#define THISUNUSED(x) (void)(x)
class XNFramework;
using XNFrameworkPtr = std::shared_ptr<XNFramework>;
@ -40,11 +38,10 @@ public:
_isInitialized = false;
};
virtual void Initialize(XNFrameworkPtr framework, uint32_t modelId, uint32_t DDS_type) override
virtual void Initialize(XNFrameworkPtr framework [[maybe_unused]],
uint32_t modelId [[maybe_unused]],
uint32_t DDS_type [[maybe_unused]]) override
{
THISUNUSED(framework);
THISUNUSED(modelId);
THISUNUSED(DDS_type);
XNDDSErrorCode ret =
TopicManager::Instance()->registerSubscriber<typename T::DDSPubSubType>(
T::topic_name,

View File

@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 3.16)
project(XNSignature LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#
if(DEFINED ENV{XNCore})
set(XNCore_PATH $ENV{XNCore})
else()
message(FATAL_ERROR "Environment variable XNCore is not set.")
endif()
#
find_package(OpenSSL REQUIRED)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${XNCore_PATH}" CACHE PATH "Install path prefix" FORCE)
endif()
include(GNUInstallDirs)
#
add_executable(XNSignatureKeygen keygen.cpp)
target_link_libraries(XNSignatureKeygen PRIVATE OpenSSL::SSL OpenSSL::Crypto)
#
add_executable(XNSignatureSign sign.cpp)
target_link_libraries(XNSignatureSign PRIVATE OpenSSL::SSL OpenSSL::Crypto)
#
add_library(XNSignatureVerify SHARED
XNSignature_global.h
XNSignatureVerify.h
verify.cpp
)
target_include_directories(XNSignatureVerify PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(XNSignatureVerify PRIVATE OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(XNSignatureVerify PRIVATE XNSIGNATURE_LIBRARY XNSIGNATURE_EXPORTS)
#
add_executable(test_verify test_verify.cpp)
target_link_libraries(test_verify PRIVATE XNSignatureVerify)
target_compile_definitions(test_verify PRIVATE XNSIGNATURE_EXPORTS)
#
add_executable(test_integrity test_integrity.cpp)
target_link_libraries(test_integrity PRIVATE XNSignatureVerify)
target_compile_definitions(test_integrity PRIVATE XNSIGNATURE_EXPORTS)
# -
install(TARGETS XNSignatureVerify
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

164
XNSignature/README.md Normal file
View File

@ -0,0 +1,164 @@
# XNSignature 数字签名工具集
这是一个基于 OpenSSL 的数字签名工具集,包含三个主要组件:
## 项目结构
- **XNSignatureKeygen**: 密钥生成工具(可执行程序)
- **XNSignatureSign**: 文件签名工具(可执行程序)
- **XNSignatureVerify**: 签名验证库(动态库)
## 编译和安装
### 依赖要求
- CMake 3.16+
- OpenSSL 开发库
- C++17 编译器
### 编译步骤
```bash
mkdir build
cd build
cmake ..
make
```
### 安装
```bash
make install
```
## 使用方法
### 1. 生成密钥对
运行密钥生成工具,会在当前目录生成密钥文件:
```bash
./XNSignatureKeygen
```
这将生成:
- `private_key.pem` - 私钥文件
- `public_key.pem` - 公钥文件
### 2. 为文件创建数字签名
有两种使用方式:
#### 方式一:签名所有文件
```bash
./XNSignatureSign
```
这将自动签名当前目录下的所有文件(除了密钥文件和已有的签名文件),每个文件会生成对应的 `.sig` 签名文件。
#### 方式二:签名指定文件
```bash
./XNSignatureSign <文件路径>
```
示例:
```bash
./XNSignatureSign document.txt
./XNSignatureSign important_file.pdf
```
签名工具会使用当前目录下的 `private_key.pem` 私钥文件。
### 3. 验证数字签名
使用验证库验证文件签名:
#### C++ 程序中使用
```cpp
#include "XNSignatureVerify.h"
// 验证签名
int result = verifySignature("document.txt", "public_key.pem", "document.sig");
if (result == 0) {
std::cout << "签名验证成功!" << std::endl;
} else if (result == -1) {
std::cout << "签名验证失败!" << std::endl;
} else {
std::cout << "验证过程中发生错误!" << std::endl;
}
```
#### 测试验证库
```bash
./test_verify
```
## API 函数说明
### 验证库函数
#### `verifySignature`
```cpp
int verifySignature(const char* filePath, const char* publicKeyPath, const char* signaturePath);
```
- **功能**: 验证文件数字签名
- **返回值**: 0=成功, -1=验证失败, -2=其他错误
## 技术特点
- 使用 RSA-2048 算法进行数字签名
- 采用 SHA256 哈希算法
- 支持 PEM 格式的密钥文件
- 提供 C 语言接口,便于集成
- 完整的错误处理和资源管理
## 安全说明
- 私钥文件应妥善保管,不要泄露给他人
- 公钥文件可以公开分发
- 签名文件用于验证文件完整性,防止篡改
- 建议定期更换密钥对
## 示例工作流程
1. 生成密钥对:
```bash
./xn_keygen
```
2. 签名重要文件:
方式一:签名所有文件
```bash
./XNSignatureSign
```
方式二:签名指定文件
```bash
./XNSignatureSign important_document.pdf
```
3. 分发文件时包含:
- `important_document.pdf` (原始文件)
- `important_document.sig` (签名文件)
- `public_key.pem` (公钥文件)
4. 接收方验证文件完整性:
```cpp
int result = verifySignature("important_document.pdf", "public_key.pem", "important_document.sig");
if (result == 0) {
// 文件未被篡改,可以安全使用
}
```

View File

@ -0,0 +1,25 @@
#ifndef XNSIGNATUREVERIFY_H
#define XNSIGNATUREVERIFY_H
#include "XNSignature_global.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief
* @param filePath
* @param publicKeyPath
* @param signaturePath
* @return 0-1-2
*/
XNSIGNATURE_API int verifySignature(const char *filePath, const char *publicKeyPath,
const char *signaturePath);
#ifdef __cplusplus
}
#endif
#endif // XNSIGNATUREVERIFY_H

View File

@ -0,0 +1,10 @@
#ifndef XNSIGNATURE_GLOBAL_H
#define XNSIGNATURE_GLOBAL_H
#ifdef XNSIGNATURE_EXPORTS
# define XNSIGNATURE_API __attribute__((visibility("default")))
#else
# define XNSIGNATURE_API __attribute__((visibility("hidden")))
#endif
#endif // XNSIGNATURE_GLOBAL_H

133
XNSignature/keygen.cpp Normal file
View File

@ -0,0 +1,133 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <iostream>
#include <string>
/**
* @brief RSA密钥对
* @param privateKeyPath
* @param publicKeyPath
* @param keySize 2048
* @return 0-1
*/
int generateRSAKeyPair(const char *privateKeyPath, const char *publicKeyPath, int keySize = 2048)
{
if (!privateKeyPath || !publicKeyPath) {
std::cerr << "错误:密钥路径不能为空" << std::endl;
return -1;
}
// 生成RSA密钥对
EVP_PKEY *pkey = EVP_PKEY_new();
if (!pkey) {
std::cerr << "错误:无法创建密钥对象" << std::endl;
return -1;
}
// 创建RSA密钥生成上下文
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
if (!ctx) {
std::cerr << "错误:无法创建密钥生成上下文" << std::endl;
EVP_PKEY_free(pkey);
return -1;
}
// 初始化密钥生成
if (EVP_PKEY_keygen_init(ctx) <= 0) {
std::cerr << "错误:无法初始化密钥生成" << std::endl;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
// 设置密钥长度
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) <= 0) {
std::cerr << "错误:无法设置密钥长度" << std::endl;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
// 生成密钥对
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
std::cerr << "错误:密钥生成失败" << std::endl;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
// 保存私钥到文件
FILE *privateKeyFile = fopen(privateKeyPath, "w");
if (!privateKeyFile) {
std::cerr << "错误:无法创建私钥文件" << std::endl;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
if (PEM_write_PrivateKey(privateKeyFile, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
std::cerr << "错误:无法写入私钥" << std::endl;
fclose(privateKeyFile);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
fclose(privateKeyFile);
// 保存公钥到文件
FILE *publicKeyFile = fopen(publicKeyPath, "w");
if (!publicKeyFile) {
std::cerr << "错误:无法创建公钥文件" << std::endl;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
if (PEM_write_PUBKEY(publicKeyFile, pkey) != 1) {
std::cerr << "错误:无法写入公钥" << std::endl;
fclose(publicKeyFile);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return -1;
}
fclose(publicKeyFile);
// 清理资源
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
std::cout << "RSA密钥对生成成功" << std::endl;
std::cout << "私钥保存到: " << privateKeyPath << std::endl;
std::cout << "公钥保存到: " << publicKeyPath << std::endl;
return 0;
}
/**
* @brief
*/
int main(int argc, char *argv[])
{
// 固定文件名,生成在程序所在目录
const char *privateKeyPath = "private_key.pem";
const char *publicKeyPath = "public_key.pem";
int keySize = 2048; // 默认密钥长度
std::cout << "=== XNSignature 密钥生成工具 ===" << std::endl;
std::cout << "私钥文件: " << privateKeyPath << std::endl;
std::cout << "公钥文件: " << publicKeyPath << std::endl;
std::cout << "密钥长度: " << keySize << "" << std::endl;
std::cout << "正在生成密钥对..." << std::endl;
int result = generateRSAKeyPair(privateKeyPath, publicKeyPath, keySize);
if (result == 0) {
std::cout << "密钥生成完成!" << std::endl;
return 0;
} else {
std::cerr << "密钥生成失败!" << std::endl;
return -1;
}
}

253
XNSignature/sign.cpp Normal file
View File

@ -0,0 +1,253 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
/**
* @brief SHA256哈希值
* @param filePath
* @param hash 32
* @return 0-1
*/
int calculateFileHash(const char *filePath, unsigned char *hash)
{
if (!filePath || !hash) {
return -1;
}
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "错误:无法打开文件 " << filePath << std::endl;
return -1;
}
SHA256_CTX sha256;
SHA256_Init(&sha256);
char buffer[4096];
while (file) {
file.read(buffer, sizeof(buffer));
std::streamsize bytesRead = file.gcount();
if (bytesRead > 0) {
SHA256_Update(&sha256, buffer, bytesRead);
}
}
SHA256_Final(hash, &sha256);
file.close();
return 0;
}
/**
* @brief
* @param filePath
* @param privateKeyPath
* @param signaturePath
* @return 0-1
*/
int signFile(const char *filePath, const char *privateKeyPath, const char *signaturePath)
{
if (!filePath || !privateKeyPath || !signaturePath) {
std::cerr << "错误:参数不能为空" << std::endl;
return -1;
}
// 加载私钥
FILE *privateKeyFile = fopen(privateKeyPath, "r");
if (!privateKeyFile) {
std::cerr << "错误:无法打开私钥文件" << std::endl;
return -1;
}
EVP_PKEY *privateKey = PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr);
fclose(privateKeyFile);
if (!privateKey) {
std::cerr << "错误:无法读取私钥" << std::endl;
return -1;
}
// 计算文件哈希
unsigned char hash[SHA256_DIGEST_LENGTH];
if (calculateFileHash(filePath, hash) != 0) {
EVP_PKEY_free(privateKey);
return -1;
}
// 创建签名上下文
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
std::cerr << "错误:无法创建签名上下文" << std::endl;
EVP_PKEY_free(privateKey);
return -1;
}
// 初始化签名
if (EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, privateKey) <= 0) {
std::cerr << "错误:无法初始化签名" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
// 计算签名长度
size_t signatureLen;
if (EVP_DigestSign(ctx, nullptr, &signatureLen, hash, SHA256_DIGEST_LENGTH) <= 0) {
std::cerr << "错误:无法计算签名长度" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
// 分配签名缓冲区
std::vector<unsigned char> signature(signatureLen);
// 执行签名
if (EVP_DigestSign(ctx, signature.data(), &signatureLen, hash, SHA256_DIGEST_LENGTH) <= 0) {
std::cerr << "错误:签名失败" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
// 保存签名到文件
std::ofstream signatureFile(signaturePath, std::ios::binary);
if (!signatureFile.is_open()) {
std::cerr << "错误:无法创建签名文件" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
signatureFile.write(reinterpret_cast<const char *>(signature.data()), signatureLen);
signatureFile.close();
// 清理资源
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
std::cout << "文件签名成功!" << std::endl;
std::cout << "签名文件保存到: " << signaturePath << std::endl;
return 0;
}
#include <filesystem>
#include <vector>
#include <string>
/**
* @brief
* @param directory
* @return
*/
std::vector<std::string> getFilesInDirectory(const std::string &directory)
{
std::vector<std::string> files;
try {
for (const auto &entry : std::filesystem::directory_iterator(directory)) {
if (entry.is_regular_file()) {
// 跳过密钥文件和签名文件
std::string filename = entry.path().filename().string();
if (filename != "private_key.pem" && filename != "public_key.pem"
&& filename.find(".sig") == std::string::npos) {
files.push_back(entry.path().string());
}
}
}
} catch (const std::filesystem::filesystem_error &e) {
std::cerr << "错误:无法读取目录 " << directory << ": " << e.what() << std::endl;
}
return files;
}
/**
* @brief 使
*/
void showUsage(const char *programName)
{
std::cout << "用法: " << programName << " [文件路径]" << std::endl;
std::cout << "参数说明:" << std::endl;
std::cout << " 文件路径: 要签名的文件路径(可选)" << std::endl;
std::cout << " 如果不提供参数,将签名当前目录下的所有文件" << std::endl;
std::cout << "示例:" << std::endl;
std::cout << " " << programName << " # 签名所有文件" << std::endl;
std::cout << " " << programName << " document.txt # 签名指定文件" << std::endl;
}
/**
* @brief
*/
int main(int argc, char *argv[])
{
const char *privateKeyPath = "private_key.pem";
std::vector<std::string> filesToSign;
std::cout << "=== XNSignature 文件签名工具 ===" << std::endl;
if (argc == 1) {
// 没有参数,签名目录下所有文件
std::cout << "未指定文件,将签名当前目录下的所有文件..." << std::endl;
filesToSign = getFilesInDirectory(".");
if (filesToSign.empty()) {
std::cout << "当前目录下没有找到可签名的文件" << std::endl;
return 0;
}
std::cout << "找到 " << filesToSign.size() << " 个文件:" << std::endl;
for (const auto &file : filesToSign) {
std::cout << " - " << file << std::endl;
}
} else if (argc == 2) {
// 指定了单个文件
filesToSign.push_back(argv[1]);
std::cout << "将签名指定文件: " << argv[1] << std::endl;
} else {
std::cerr << "错误:参数数量不正确" << std::endl;
showUsage(argv[0]);
return -1;
}
std::cout << "私钥文件: " << privateKeyPath << std::endl;
std::cout << "正在签名文件..." << std::endl;
int successCount = 0;
int totalCount = filesToSign.size();
for (const auto &filePath : filesToSign) {
// 生成签名文件路径
std::string signaturePath = filePath + ".sig";
std::cout << "\n正在签名: " << filePath << std::endl;
std::cout << "签名文件: " << signaturePath << std::endl;
int result = signFile(filePath.c_str(), privateKeyPath, signaturePath.c_str());
if (result == 0) {
std::cout << "✓ 签名成功" << std::endl;
successCount++;
} else {
std::cout << "✗ 签名失败" << std::endl;
}
}
std::cout << "\n=== 签名完成 ===" << std::endl;
std::cout << "成功签名: " << successCount << "/" << totalCount << " 个文件" << std::endl;
if (successCount == totalCount) {
std::cout << "所有文件签名完成!" << std::endl;
return 0;
} else {
std::cerr << "部分文件签名失败!" << std::endl;
return -1;
}
}

View File

@ -0,0 +1,179 @@
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include "XNSignatureVerify.h"
/**
* @brief
*
*/
int main()
{
std::cout << "=== 文件完整性检测测试 ===" << std::endl;
// 创建测试文件
std::string testFile = "test_integrity.txt";
std::ofstream file(testFile);
if (!file.is_open()) {
std::cerr << "错误:无法创建测试文件" << std::endl;
return -1;
}
file << "这是一个测试文件,用于验证数字签名的完整性检测功能。" << std::endl;
file << "任何微小的修改都应该被检测到。" << std::endl;
file.close();
std::cout << "1. 创建测试文件: " << testFile << std::endl;
// 生成密钥对
std::cout << "2. 生成密钥对..." << std::endl;
system("./XNSignatureKeygen");
// 对文件进行签名
std::cout << "3. 对文件进行签名..." << std::endl;
system(("./XNSignatureSign " + testFile).c_str());
// 验证原始签名
std::cout << "4. 验证原始签名..." << std::endl;
int result1 = verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result1 == 0) {
std::cout << "✓ 原始文件签名验证成功" << std::endl;
} else {
std::cout << "✗ 原始文件签名验证失败" << std::endl;
return -1;
}
// 测试1修改文件内容添加一个字符
std::cout << "\n5. 测试1修改文件内容添加字符..." << std::endl;
std::ofstream modFile1(testFile, std::ios::app);
modFile1 << "X"; // 添加一个字符
modFile1.close();
int result2 = verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result2 != 0) {
std::cout << "✓ 检测到文件内容修改" << std::endl;
} else {
std::cout << "✗ 未能检测到文件内容修改" << std::endl;
return -1;
}
// 恢复文件内容
std::ofstream restoreFile1(testFile);
restoreFile1 << "这是一个测试文件,用于验证数字签名的完整性检测功能。" << std::endl;
restoreFile1 << "任何微小的修改都应该被检测到。" << std::endl;
restoreFile1.close();
// 重新签名
system(("./XNSignatureSign " + testFile).c_str());
// 测试2修改文件内容删除一个字符
std::cout << "\n6. 测试2修改文件内容删除字符..." << std::endl;
std::string content;
std::ifstream readFile(testFile);
std::getline(readFile, content);
readFile.close();
if (content.length() > 0) {
content = content.substr(0, content.length() - 1); // 删除最后一个字符
std::ofstream modFile2(testFile);
modFile2 << content << std::endl;
modFile2.close();
int result3 =
verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result3 != 0) {
std::cout << "✓ 检测到文件内容修改" << std::endl;
} else {
std::cout << "✗ 未能检测到文件内容修改" << std::endl;
return -1;
}
}
// 测试3修改文件内容替换一个字符
std::cout << "\n7. 测试3修改文件内容替换字符..." << std::endl;
std::ifstream readFile2(testFile);
std::getline(readFile2, content);
readFile2.close();
if (content.length() > 5) {
content[5] = 'X'; // 替换第6个字符
std::ofstream modFile3(testFile);
modFile3 << content << std::endl;
modFile3.close();
int result4 =
verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result4 != 0) {
std::cout << "✓ 检测到文件内容修改" << std::endl;
} else {
std::cout << "✗ 未能检测到文件内容修改" << std::endl;
return -1;
}
}
// 测试4修改文件内容添加空格
std::cout << "\n8. 测试4修改文件内容添加空格..." << std::endl;
std::ifstream readFile3(testFile);
std::getline(readFile3, content);
readFile3.close();
content.insert(10, " "); // 在第10个位置插入空格
std::ofstream modFile4(testFile);
modFile4 << content << std::endl;
modFile4.close();
int result5 = verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result5 != 0) {
std::cout << "✓ 检测到文件内容修改" << std::endl;
} else {
std::cout << "✗ 未能检测到文件内容修改" << std::endl;
return -1;
}
// 测试5修改文件内容改变换行符
std::cout << "\n9. 测试5修改文件内容改变换行符..." << std::endl;
std::ofstream modFile5(testFile);
modFile5 << "这是一个测试文件,用于验证数字签名的完整性检测功能。\r\n"; // 使用Windows换行符
modFile5 << "任何微小的修改都应该被检测到。\r\n";
modFile5.close();
int result6 = verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result6 != 0) {
std::cout << "✓ 检测到文件内容修改" << std::endl;
} else {
std::cout << "✗ 未能检测到文件内容修改" << std::endl;
return -1;
}
// 测试6修改文件内容添加不可见字符
std::cout << "\n10. 测试6修改文件内容添加不可见字符..." << std::endl;
std::ofstream modFile6(testFile);
modFile6 << "这是一个测试文件,用于验证数字签名的完整性检测功能。" << std::endl;
modFile6 << "任何微小的修改都应该被检测到。" << (char)0x00 << std::endl; // 添加null字符
modFile6.close();
int result7 = verifySignature(testFile.c_str(), "public_key.pem", (testFile + ".sig").c_str());
if (result7 != 0) {
std::cout << "✓ 检测到文件内容修改" << std::endl;
} else {
std::cout << "✗ 未能检测到文件内容修改" << std::endl;
return -1;
}
std::cout << "\n=== 测试完成 ===" << std::endl;
std::cout << "✓ 所有完整性检测测试通过!" << std::endl;
std::cout << "✓ 数字签名能够检测到文件的任何微小变化" << std::endl;
// 清理测试文件
system(("rm -f " + testFile + " " + testFile + ".sig").c_str());
return 0;
}

View File

@ -0,0 +1,51 @@
#include "XNSignatureVerify.h"
#include <iostream>
#include <fstream>
/**
* @brief
* @param filename
* @param content
*/
void createTestFile(const char *filename, const char *content)
{
std::ofstream file(filename);
if (file.is_open()) {
file << content;
file.close();
std::cout << "测试文件创建成功: " << filename << std::endl;
} else {
std::cerr << "无法创建测试文件: " << filename << std::endl;
}
}
/**
* @brief
*/
int main()
{
std::cout << "=== XNSignature 验证库测试程序 ===" << std::endl;
// 测试文件路径
const char *testFile = "test_document.txt";
const char *publicKeyFile = "public_key.pem";
const char *signatureFile = "test_document.txt.sig";
// 创建测试文件
//createTestFile(testFile, "这是一个测试文档,用于验证数字签名功能。\n包含一些重要信息。");
std::cout << "\n1. 验证数字签名..." << std::endl;
int verifyResult = verifySignature(testFile, publicKeyFile, signatureFile);
if (verifyResult == 0) {
std::cout << "签名验证成功!" << std::endl;
} else if (verifyResult == -1) {
std::cout << "签名验证失败!" << std::endl;
} else {
std::cout << "验证过程中发生错误!" << std::endl;
}
std::cout << "\n2. 验证完成" << std::endl;
std::cout << "\n=== 测试完成 ===" << std::endl;
return 0;
}

303
XNSignature/verify.cpp Normal file
View File

@ -0,0 +1,303 @@
#include "XNSignature_global.h"
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
extern "C"
{
/**
* @brief SHA256哈希值
* @param filePath
* @param hash 32
* @return 0-1
*/
int calculateFileHash(const char *filePath, unsigned char *hash)
{
if (!filePath || !hash) {
return -1;
}
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "错误:无法打开文件 " << filePath << std::endl;
return -1;
}
SHA256_CTX sha256;
SHA256_Init(&sha256);
char buffer[4096];
while (file) {
file.read(buffer, sizeof(buffer));
std::streamsize bytesRead = file.gcount();
if (bytesRead > 0) {
SHA256_Update(&sha256, buffer, bytesRead);
}
}
SHA256_Final(hash, &sha256);
file.close();
return 0;
}
/**
* @brief
* @param filePath
* @param publicKeyPath
* @param signaturePath
* @return 0-1-2
*/
XNSIGNATURE_API int verifySignature(const char *filePath, const char *publicKeyPath,
const char *signaturePath)
{
if (!filePath || !publicKeyPath || !signaturePath) {
std::cerr << "错误:参数不能为空" << std::endl;
return -2;
}
// 加载公钥
FILE *publicKeyFile = fopen(publicKeyPath, "r");
if (!publicKeyFile) {
std::cerr << "错误:无法打开公钥文件" << std::endl;
return -2;
}
EVP_PKEY *publicKey = PEM_read_PUBKEY(publicKeyFile, nullptr, nullptr, nullptr);
fclose(publicKeyFile);
if (!publicKey) {
std::cerr << "错误:无法读取公钥" << std::endl;
return -2;
}
// 计算文件哈希
unsigned char hash[SHA256_DIGEST_LENGTH];
if (calculateFileHash(filePath, hash) != 0) {
EVP_PKEY_free(publicKey);
return -2;
}
// 读取签名文件
std::ifstream signatureFile(signaturePath, std::ios::binary);
if (!signatureFile.is_open()) {
std::cerr << "错误:无法打开签名文件" << std::endl;
EVP_PKEY_free(publicKey);
return -2;
}
signatureFile.seekg(0, std::ios::end);
size_t signatureSize = signatureFile.tellg();
signatureFile.seekg(0, std::ios::beg);
std::vector<unsigned char> signature(signatureSize);
signatureFile.read(reinterpret_cast<char *>(signature.data()), signatureSize);
signatureFile.close();
// 创建验证上下文
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
std::cerr << "错误:无法创建验证上下文" << std::endl;
EVP_PKEY_free(publicKey);
return -2;
}
// 初始化验证
if (EVP_DigestVerifyInit(ctx, nullptr, EVP_sha256(), nullptr, publicKey) <= 0) {
std::cerr << "错误:无法初始化验证" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(publicKey);
return -2;
}
// 执行验证
int result =
EVP_DigestVerify(ctx, signature.data(), signature.size(), hash, SHA256_DIGEST_LENGTH);
// 清理资源
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(publicKey);
if (result == 1) {
std::cout << "签名验证成功!文件完整性确认。" << std::endl;
return 0;
} else if (result == 0) {
std::cout << "签名验证失败!文件可能已被篡改。" << std::endl;
return -1;
} else {
std::cerr << "错误:验证过程中发生错误" << std::endl;
return -2;
}
}
/**
* @brief
* @param filePath
* @return 0-1
*/
int showFileHash(const char *filePath)
{
if (!filePath) {
std::cerr << "错误:文件路径不能为空" << std::endl;
return -1;
}
unsigned char hash[SHA256_DIGEST_LENGTH];
if (calculateFileHash(filePath, hash) != 0) {
return -1;
}
std::cout << "文件 " << filePath << " 的SHA256哈希值" << std::endl;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
printf("%02x", hash[i]);
}
std::cout << std::endl;
return 0;
}
/**
* @brief
* @param filePath
* @param hashString 65
* @return 0-1
*/
int getFileHashString(const char *filePath, char *hashString)
{
if (!filePath || !hashString) {
return -1;
}
unsigned char hash[SHA256_DIGEST_LENGTH];
if (calculateFileHash(filePath, hash) != 0) {
return -1;
}
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(hashString + i * 2, "%02x", hash[i]);
}
hashString[64] = '\0'; // 确保字符串结束
return 0;
}
/**
* @brief
* @param filePath
* @param publicKeyPath
* @param signaturePath
* @param resultMessage
* @param messageSize
* @return 0-1-2
*/
int verifySignatureWithMessage(const char *filePath, const char *publicKeyPath,
const char *signaturePath, char *resultMessage, int messageSize)
{
if (!filePath || !publicKeyPath || !signaturePath || !resultMessage) {
if (resultMessage && messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:参数不能为空");
}
return -2;
}
// 加载公钥
FILE *publicKeyFile = fopen(publicKeyPath, "r");
if (!publicKeyFile) {
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:无法打开公钥文件");
}
return -2;
}
EVP_PKEY *publicKey = PEM_read_PUBKEY(publicKeyFile, nullptr, nullptr, nullptr);
fclose(publicKeyFile);
if (!publicKey) {
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:无法读取公钥");
}
return -2;
}
// 计算文件哈希
unsigned char hash[SHA256_DIGEST_LENGTH];
if (calculateFileHash(filePath, hash) != 0) {
EVP_PKEY_free(publicKey);
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:无法计算文件哈希");
}
return -2;
}
// 读取签名文件
std::ifstream signatureFile(signaturePath, std::ios::binary);
if (!signatureFile.is_open()) {
EVP_PKEY_free(publicKey);
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:无法打开签名文件");
}
return -2;
}
signatureFile.seekg(0, std::ios::end);
size_t signatureSize = signatureFile.tellg();
signatureFile.seekg(0, std::ios::beg);
std::vector<unsigned char> signature(signatureSize);
signatureFile.read(reinterpret_cast<char *>(signature.data()), signatureSize);
signatureFile.close();
// 创建验证上下文
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
EVP_PKEY_free(publicKey);
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:无法创建验证上下文");
}
return -2;
}
// 初始化验证
if (EVP_DigestVerifyInit(ctx, nullptr, EVP_sha256(), nullptr, publicKey) <= 0) {
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(publicKey);
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:无法初始化验证");
}
return -2;
}
// 执行验证
int result =
EVP_DigestVerify(ctx, signature.data(), signature.size(), hash, SHA256_DIGEST_LENGTH);
// 清理资源
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(publicKey);
if (result == 1) {
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "签名验证成功!文件完整性确认。");
}
return 0;
} else if (result == 0) {
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "签名验证失败!文件可能已被篡改。");
}
return -1;
} else {
if (messageSize > 0) {
snprintf(resultMessage, messageSize, "错误:验证过程中发生错误");
}
return -2;
}
}
} // extern "C"

28
private_key.pem Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDF2ZjCOq3Yl3v4
9bg3+qIpAAt4R3iPpGoiJcybzNhhhBJ7dJKsS45liFQqoVxhf0rASjTlJ6ImbqiI
cnD8APAfpNyfdeg0gKt94x2SkJXU6kAer1aNq55i3DLcRmAGHuIXHSM5jxrh+lBQ
v4p4gP2p4BhT4Fds8Mg6QZUi7axoN93B8xbayFHqRo0C2jroyF9kxKpwZB8302SG
ax1dqEJa66WimIzST3ksyvXlMzd+oC844i9P5SzyXw6ecZgNhY/Hoa9rcMgstrpm
9RewtQTnX2KeUp0ggtizMcIud+zyFA8+s+TwVrzm/Q9VV1JsE5EKxDSv103R0EUY
n/IYLyMVAgMBAAECggEBAKl1CgWxxJyygphlvXcU0DdVtn06meRN6il9PpZjCSHc
wQfEfKvduwTzk0NAGaPYJuozpMJxA8zvEqJrgqIVG5W+2sgpcM0nN7sG/5k9BVfr
myes/fExgOMjvtwz2qLjaLprVnRCQcAzaP8AT1WPBbSuH6gXikngoV5kNZxI/VX0
oYniHmGUlfOC2LKYXvSpHEmXhEyuZFDLxNqEpUPG2xHot7HUYklJKR4qxhD44CZJ
UvOs5AeXxXlKVUpY0Ue+DGbd8kzNyVD+MChRKCDe+pwdIMP1u5yOwNNLqkveszOh
9RH85l07cFrB68+Qycx+HqhzkNgjafqKZt08PAR6PzECgYEA7SzL3pOtfVUMwPNd
6o1I8dfsSM7PxSWswUFkGF9ULijX4TbsQ3kli6Y3ZZZ4I1g4rEv3LKF1KB98Pv2T
iKID1scEke4cYy8Q69wvXgektPgEf2JDdOOm7mFADAvAh4oIvjHSDXaFeskqnhhZ
Vc3K64/7NNfd7NwT+dk69uNgVQMCgYEA1Y2/i5f2Es7xLAK1+NeoSYuDsKhfK3bn
sWEKmJflIchvQ/GcUthawKuACv2u59xLtDHI8+Jky3ISobVYKREP+otWv2rndSQk
XpfmsBLgIrcmgkBaZF+ebln8qwclqMjMW5hItfRKb/f57RTM+wsoGvNzWAxrtuR1
O27PtrOe8AcCgYEA5x/FWBR/d2h/MjS3K9Ac6phpSRZIwK0TKYzItzuGtCjXH0C/
go03OlxzFYtJbeAV8klhCNwaaEwubs/7iqWfqhhtaqwoe7ss+Tur6Sz3o+chsuUW
KX2Dej/JAzQcnbi1BmtUcAw0zU/mOQQvYn9WJLI9seQ+/wgEa3D2lgtEH/MCgYEA
hXPmfprBOTG/fwxWoaJLVWJtMmmVx7ivw6ZsE73gf8Mc3S3QzejMldjW1IeB1P1T
BdGSze3tpUGtKQcFh+xUuvJ2jHqHGCo03DQ7Ak9ZZ/hihUUn98/VVwq/HjYCL78E
Dj1VOvflyKEDu0ejbUKklmsK6rwgWBPeuvxdq8QGD+MCgYEAjXiRR7Jo+zKPZFmC
P7G4YURBxAXNAneHTS6NXrXqf8l6ST1yPMfy+AoBtW6IkwQuob8e0aR7WiAtK427
OQicnMap9/oDZ+tm2po7O3FQ7EJKiPYdltuCS/H4rYHm70oMiuMvWb5tzlYSbk4Z
2LZ2Omi+NQyZiuHUWhnm8nQaQmc=
-----END PRIVATE KEY-----