Compare commits
	
		
			3 Commits
		
	
	
		
			5269dd7789
			...
			760a9cd92c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						760a9cd92c
	
				 | 
					
					
						|||
| 
						
						
							
						
						3f476c3114
	
				 | 
					
					
						|||
| 
						
						
							
						
						d44c561427
	
				 | 
					
					
						
@@ -10,6 +10,7 @@ axum = "0.7.5"
 | 
				
			|||||||
listenfd = "1.0.1"
 | 
					listenfd = "1.0.1"
 | 
				
			||||||
notify = "6.1.1"
 | 
					notify = "6.1.1"
 | 
				
			||||||
serde = { version = "1.0.204", features = ["derive"] }
 | 
					serde = { version = "1.0.204", features = ["derive"] }
 | 
				
			||||||
 | 
					thiserror = "1.0.63"
 | 
				
			||||||
tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
 | 
					tokio = { version = "1.39.1", features = ["macros", "rt-multi-thread"] }
 | 
				
			||||||
tower-http = { version = "0.5.2", features = ["fs"] }
 | 
					tower-http = { version = "0.5.2", features = ["fs"] }
 | 
				
			||||||
tower-livereload = "0.9.3"
 | 
					tower-livereload = "0.9.3"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,23 @@ use axum::body::Body;
 | 
				
			|||||||
use axum::http::Request;
 | 
					use axum::http::Request;
 | 
				
			||||||
use listenfd::ListenFd;
 | 
					use listenfd::ListenFd;
 | 
				
			||||||
use notify::Watcher;
 | 
					use notify::Watcher;
 | 
				
			||||||
use std::env;
 | 
					 | 
				
			||||||
use std::path::Path;
 | 
					use std::path::Path;
 | 
				
			||||||
 | 
					use std::{env, io};
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
use tokio::net::TcpListener;
 | 
					use tokio::net::TcpListener;
 | 
				
			||||||
use tower_livereload::predicate::Predicate;
 | 
					use tower_livereload::predicate::Predicate;
 | 
				
			||||||
use tower_livereload::LiveReloadLayer;
 | 
					use tower_livereload::LiveReloadLayer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Error, Debug)]
 | 
				
			||||||
 | 
					pub enum AppError {
 | 
				
			||||||
 | 
					    #[error("Unable to bind to TCP listener")]
 | 
				
			||||||
 | 
					    TCPListener(#[from] std::io::Error),
 | 
				
			||||||
 | 
					    #[error("Error with the notify watcher")]
 | 
				
			||||||
 | 
					    NotifyWatcher(#[from] notify::Error),
 | 
				
			||||||
 | 
					    #[error("Missing environment variable {var}")]
 | 
				
			||||||
 | 
					    MissingEnvVar { var: &'static str },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Nous filtrons les requêtes de `htmx` pour ne pas inclure le script _JS_ qui gère le rechargement
 | 
					/// Nous filtrons les requêtes de `htmx` pour ne pas inclure le script _JS_ qui gère le rechargement
 | 
				
			||||||
/// Voir https://github.com/leotaku/tower-livereload/pull/3
 | 
					/// Voir https://github.com/leotaku/tower-livereload/pull/3
 | 
				
			||||||
#[derive(Copy, Clone)]
 | 
					#[derive(Copy, Clone)]
 | 
				
			||||||
@@ -20,44 +31,47 @@ impl<T> Predicate<Request<T>> for NotHtmxPredicate {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DEFAULT_LISTENER: &str = "localhost:3000";
 | 
					const DEFAULT_LISTENER: &str = "localhost:3000";
 | 
				
			||||||
async fn get_tcp_listener() -> TcpListener {
 | 
					async fn get_tcp_listener() -> Result<TcpListener, io::Error> {
 | 
				
			||||||
    let mut listenfd = ListenFd::from_env();
 | 
					    let mut listenfd = ListenFd::from_env();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match listenfd.take_tcp_listener(0).unwrap() {
 | 
					    match listenfd.take_tcp_listener(0)? {
 | 
				
			||||||
        // if we are given a tcp listener on listen fd 0, we use that one
 | 
					        // if we are given a tcp listener on listen fd 0, we use that one
 | 
				
			||||||
        Some(listener) => {
 | 
					        Some(listener) => {
 | 
				
			||||||
            listener.set_nonblocking(true).unwrap();
 | 
					            listener.set_nonblocking(true)?;
 | 
				
			||||||
            TcpListener::from_std(listener).unwrap()
 | 
					            Ok(TcpListener::from_std(listener)?)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // otherwise fall back to local listening
 | 
					        // otherwise fall back to local listening
 | 
				
			||||||
        None => TcpListener::bind(DEFAULT_LISTENER).await.unwrap(),
 | 
					        None => Ok(TcpListener::bind(DEFAULT_LISTENER).await?),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_livereload_layer(templates_path: &Path) -> LiveReloadLayer<NotHtmxPredicate> {
 | 
					fn get_livereload_layer(
 | 
				
			||||||
 | 
					    templates_path: &Path,
 | 
				
			||||||
 | 
					) -> Result<LiveReloadLayer<NotHtmxPredicate>, notify::Error> {
 | 
				
			||||||
    let livereload = LiveReloadLayer::new();
 | 
					    let livereload = LiveReloadLayer::new();
 | 
				
			||||||
    let reloader = livereload.reloader();
 | 
					    let reloader = livereload.reloader();
 | 
				
			||||||
    let mut watcher = notify::recommended_watcher(move |_| reloader.reload()).unwrap();
 | 
					    let mut watcher = notify::recommended_watcher(move |_| reloader.reload())?;
 | 
				
			||||||
    watcher
 | 
					    watcher.watch(templates_path, notify::RecursiveMode::Recursive)?;
 | 
				
			||||||
        .watch(templates_path, notify::RecursiveMode::Recursive)
 | 
					    Ok(livereload.request_predicate::<Body, NotHtmxPredicate>(NotHtmxPredicate))
 | 
				
			||||||
        .unwrap();
 | 
					 | 
				
			||||||
    livereload.request_predicate::<Body, NotHtmxPredicate>(NotHtmxPredicate)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::main]
 | 
					#[tokio::main]
 | 
				
			||||||
async fn main() {
 | 
					async fn main() -> Result<(), AppError> {
 | 
				
			||||||
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
 | 
					    let manifest_dir = env::var("CARGO_MANIFEST_DIR").map_err(|_| AppError::MissingEnvVar {
 | 
				
			||||||
 | 
					        var: "CARGO_MANIFEST_DIR",
 | 
				
			||||||
 | 
					    })?;
 | 
				
			||||||
    let assets_path = Path::new(&manifest_dir).join("assets");
 | 
					    let assets_path = Path::new(&manifest_dir).join("assets");
 | 
				
			||||||
    let templates_path = Path::new(&manifest_dir).join("templates");
 | 
					    let templates_path = Path::new(&manifest_dir).join("templates");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let livereload_layer = get_livereload_layer(&templates_path);
 | 
					    let livereload_layer =
 | 
				
			||||||
 | 
					        get_livereload_layer(&templates_path).map_err(AppError::NotifyWatcher)?;
 | 
				
			||||||
    let router = get_router(assets_path.as_path()).layer(livereload_layer);
 | 
					    let router = get_router(assets_path.as_path()).layer(livereload_layer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let listener: TcpListener = get_tcp_listener().await;
 | 
					    let listener: TcpListener = get_tcp_listener().await.map_err(AppError::TCPListener)?;
 | 
				
			||||||
    println!("Listening on: http://{}", listener.local_addr().unwrap());
 | 
					    let local_addr = listener.local_addr().map_err(AppError::TCPListener)?;
 | 
				
			||||||
 | 
					    println!("Listening on: http://{}", local_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Run the server with the router
 | 
					    // Run the server with the router
 | 
				
			||||||
    axum::serve(listener, router.into_make_service())
 | 
					    axum::serve(listener, router.into_make_service()).await?;
 | 
				
			||||||
        .await
 | 
					    Ok(())
 | 
				
			||||||
        .unwrap();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,4 +21,5 @@ tokio = "1.39.1"
 | 
				
			|||||||
app = { path = "../app" }
 | 
					app = { path = "../app" }
 | 
				
			||||||
http = "1.1.0"
 | 
					http = "1.1.0"
 | 
				
			||||||
bytes = "1.6.1"
 | 
					bytes = "1.6.1"
 | 
				
			||||||
 | 
					thiserror = "1.0.63"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,30 @@
 | 
				
			|||||||
 | 
					use axum::body::{to_bytes, Body};
 | 
				
			||||||
 | 
					use axum::Router;
 | 
				
			||||||
use bytes::Bytes;
 | 
					use bytes::Bytes;
 | 
				
			||||||
use http::{request, response, Request, Response};
 | 
					use http::{request, response, Request, Response};
 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::sync::Arc;
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					 | 
				
			||||||
use axum::body::{to_bytes, Body};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use axum::Router;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use tauri::path::BaseDirectory;
 | 
					use tauri::path::BaseDirectory;
 | 
				
			||||||
use tauri::Manager;
 | 
					use tauri::Manager;
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
use tokio::sync::{Mutex, MutexGuard};
 | 
					use tokio::sync::{Mutex, MutexGuard};
 | 
				
			||||||
use tower::{Service, ServiceExt};
 | 
					use tower::{Service, ServiceExt};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Error, Debug)]
 | 
				
			||||||
 | 
					pub enum DesktopError {
 | 
				
			||||||
 | 
					    #[error("Axum error:\n{0}")]
 | 
				
			||||||
 | 
					    Axum(#[from] axum::Error),
 | 
				
			||||||
 | 
					    #[error("Infallible error")]
 | 
				
			||||||
 | 
					    Infallible(#[from] std::convert::Infallible),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Process requests sent to Tauri (with the `axum://` protocol) and handle them with Axum
 | 
				
			||||||
 | 
					/// When an error occurs, this function is expected to panic, which should result in a 500 error
 | 
				
			||||||
 | 
					/// being sent to the client, so we let the client handle the error recovering
 | 
				
			||||||
async fn process_tauri_request(
 | 
					async fn process_tauri_request(
 | 
				
			||||||
    tauri_request: Request<Vec<u8>>,
 | 
					    tauri_request: Request<Vec<u8>>,
 | 
				
			||||||
    mut router: MutexGuard<'_, Router>,
 | 
					    mut router: MutexGuard<'_, Router>,
 | 
				
			||||||
) -> Response<Vec<u8>> {
 | 
					) -> Result<Response<Vec<u8>>, DesktopError> {
 | 
				
			||||||
    let (parts, body): (request::Parts, Vec<u8>) = tauri_request.into_parts();
 | 
					    let (parts, body): (request::Parts, Vec<u8>) = tauri_request.into_parts();
 | 
				
			||||||
    let axum_request: Request<Body> = Request::from_parts(parts, body.into());
 | 
					    let axum_request: Request<Body> = Request::from_parts(parts, body.into());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,17 +32,16 @@ async fn process_tauri_request(
 | 
				
			|||||||
        .as_service()
 | 
					        .as_service()
 | 
				
			||||||
        .ready()
 | 
					        .ready()
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .expect("Failed to get ready service from router")
 | 
					        .map_err(DesktopError::Infallible)?
 | 
				
			||||||
        .call(axum_request)
 | 
					        .call(axum_request)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .expect("Could not get response from router");
 | 
					        .map_err(DesktopError::Infallible)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (parts, body): (response::Parts, Body) = axum_response.into_parts();
 | 
					    let (parts, body): (response::Parts, Body) = axum_response.into_parts();
 | 
				
			||||||
    let body: Bytes = to_bytes(body, usize::MAX).await.unwrap_or_default();
 | 
					    let body: Bytes = to_bytes(body, usize::MAX).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let tauri_response: Response<Vec<u8>> = Response::from_parts(parts, body.into());
 | 
					    let tauri_response: Response<Vec<u8>> = Response::from_parts(parts, body.into());
 | 
				
			||||||
 | 
					    Ok(tauri_response)
 | 
				
			||||||
    tauri_response
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
 | 
					#[cfg_attr(mobile, tauri::mobile_entry_point)]
 | 
				
			||||||
@@ -43,7 +51,7 @@ pub fn run() {
 | 
				
			|||||||
            let assets_path: PathBuf = app
 | 
					            let assets_path: PathBuf = app
 | 
				
			||||||
                .path()
 | 
					                .path()
 | 
				
			||||||
                .resolve("assets", BaseDirectory::Resource)
 | 
					                .resolve("assets", BaseDirectory::Resource)
 | 
				
			||||||
                .expect("Path should be resolvable");
 | 
					                .expect("Assets path should be resolvable");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Adds Axum router to application state
 | 
					            // Adds Axum router to application state
 | 
				
			||||||
            // This makes it so we can retrieve it from any app instance (see bellow)
 | 
					            // This makes it so we can retrieve it from any app instance (see bellow)
 | 
				
			||||||
@@ -60,8 +68,19 @@ pub fn run() {
 | 
				
			|||||||
            // Spawn a new async task to process the request
 | 
					            // Spawn a new async task to process the request
 | 
				
			||||||
            tauri::async_runtime::spawn(async move {
 | 
					            tauri::async_runtime::spawn(async move {
 | 
				
			||||||
                let router = router.lock().await;
 | 
					                let router = router.lock().await;
 | 
				
			||||||
                let response = process_tauri_request(request, router).await;
 | 
					                match process_tauri_request(request, router).await {
 | 
				
			||||||
                responder.respond(response);
 | 
					                    Ok(response) => responder.respond(response),
 | 
				
			||||||
 | 
					                    Err(err) => {
 | 
				
			||||||
 | 
					                        let body = format!("Failed to process an axum:// request:\n{}", err);
 | 
				
			||||||
 | 
					                        responder.respond(
 | 
				
			||||||
 | 
					                            http::Response::builder()
 | 
				
			||||||
 | 
					                                .status(http::StatusCode::BAD_REQUEST)
 | 
				
			||||||
 | 
					                                .header(http::header::CONTENT_TYPE, "text/plain")
 | 
				
			||||||
 | 
					                                .body::<Vec<u8>>(body.into())
 | 
				
			||||||
 | 
					                                .expect("BAD_REQUEST response should be valid"),
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .run(tauri::generate_context!())
 | 
					        .run(tauri::generate_context!())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,10 @@ version = "0.1.0"
 | 
				
			|||||||
edition = "2021"
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
 | 
					anyhow = "1.0.86"
 | 
				
			||||||
dotenv = "0.15"
 | 
					dotenv = "0.15"
 | 
				
			||||||
libc = "0.2"
 | 
					libc = "0.2"
 | 
				
			||||||
 | 
					thiserror = "1.0.63"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[build-dependencies]
 | 
					[build-dependencies]
 | 
				
			||||||
dotenv = "0.15"
 | 
					dotenv = "0.15"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ use std::path::PathBuf;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    // Load the .env.build file for build-time environment variables
 | 
					    // Load the .env.build file for build-time environment variables
 | 
				
			||||||
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
 | 
					    let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
 | 
				
			||||||
    let manifest_path = PathBuf::from(manifest_dir);
 | 
					    let manifest_path = PathBuf::from(manifest_dir);
 | 
				
			||||||
    dotenv::from_path(manifest_path.join(".env.build")).ok();
 | 
					    dotenv::from_path(manifest_path.join(".env.build")).ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,12 +22,13 @@ fn main() {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Add the SESAM_FSV_LIB_PATH to the linker search path
 | 
					    // Add the SESAM_FSV_LIB_PATH to the linker search path
 | 
				
			||||||
    let fsv_lib_path = PathBuf::from(env::var("SESAM_FSV_LIB_PATH").unwrap());
 | 
					    let fsv_lib_path =
 | 
				
			||||||
 | 
					        PathBuf::from(env::var("SESAM_FSV_LIB_PATH").expect("SESAM_FSV_LIB_PATH must be set"));
 | 
				
			||||||
    println!("cargo::rustc-link-search=native={}", fsv_lib_path.display());
 | 
					    println!("cargo::rustc-link-search=native={}", fsv_lib_path.display());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Add the SESAM_FSV_LIB_PATH to the PATH environment variable
 | 
					    // Add the SESAM_FSV_LIB_PATH to the PATH environment variable
 | 
				
			||||||
    if cfg!(target_os = "windows") {
 | 
					    if cfg!(target_os = "windows") {
 | 
				
			||||||
        let path = env::var("PATH").unwrap_or(String::new());
 | 
					        let path = env::var("PATH").unwrap_or_default();
 | 
				
			||||||
        println!("cargo:rustc-env=PATH={};{}", fsv_lib_path.display(), path);
 | 
					        println!("cargo:rustc-env=PATH={};{}", fsv_lib_path.display(), path);
 | 
				
			||||||
    } else if cfg!(target_os = "linux") {
 | 
					    } else if cfg!(target_os = "linux") {
 | 
				
			||||||
        println!("cargo:rustc-env=LD_LIBRARY_PATH={}", fsv_lib_path.display());
 | 
					        println!("cargo:rustc-env=LD_LIBRARY_PATH={}", fsv_lib_path.display());
 | 
				
			||||||
@@ -36,7 +37,7 @@ fn main() {
 | 
				
			|||||||
    // Link the SESAM_FSV_SSVLIB dynamic library
 | 
					    // Link the SESAM_FSV_SSVLIB dynamic library
 | 
				
			||||||
    println!(
 | 
					    println!(
 | 
				
			||||||
        "cargo::rustc-link-lib=dylib={}",
 | 
					        "cargo::rustc-link-lib=dylib={}",
 | 
				
			||||||
        env::var("SESAM_FSV_SSVLIB").unwrap()
 | 
					        env::var("SESAM_FSV_SSVLIB").expect("SESAM_FSV_SSVLIB must be set")
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    // TODO : try `raw-dylib` instead of `dylib` on Windows to avoid the need of the `lib` headers compiled from the `def`
 | 
					    // TODO : try `raw-dylib` instead of `dylib` on Windows to avoid the need of the `lib` headers compiled from the `def`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,24 @@
 | 
				
			|||||||
use libc::{c_void, size_t};
 | 
					use libc::{c_void, size_t};
 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
use std::ptr;
 | 
					use std::ptr;
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::libssv::SSV_LireCartePS;
 | 
					use crate::libssv::{self, SSV_LireCartePS};
 | 
				
			||||||
use crate::ssv_memory::{decode_ssv_memory, Block};
 | 
					use crate::ssv_memory::{decode_ssv_memory, Block, SSVMemoryError};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Error, Debug)]
 | 
				
			||||||
 | 
					pub enum CartePSError {
 | 
				
			||||||
 | 
					    #[error("Unknown (group, field) pair: ({group}, {field})")]
 | 
				
			||||||
 | 
					    UnknownGroupFieldPair { group: u16, field: u16 },
 | 
				
			||||||
 | 
					    #[error("CString creation error: {0}")]
 | 
				
			||||||
 | 
					    CString(#[from] std::ffi::NulError),
 | 
				
			||||||
 | 
					    #[error("Unable to get the last situation while parsing a CartePS")]
 | 
				
			||||||
 | 
					    InvalidLastSituation,
 | 
				
			||||||
 | 
					    #[error(transparent)]
 | 
				
			||||||
 | 
					    SSVMemory(#[from] SSVMemoryError),
 | 
				
			||||||
 | 
					    #[error(transparent)]
 | 
				
			||||||
 | 
					    SSVLibErrorCode(#[from] libssv::LibSSVError),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Default)]
 | 
					#[derive(Debug, Default)]
 | 
				
			||||||
pub struct CartePS {
 | 
					pub struct CartePS {
 | 
				
			||||||
@@ -52,10 +67,10 @@ struct SituationPS {
 | 
				
			|||||||
    habilitation_à_signer_un_lot: String,
 | 
					    habilitation_à_signer_un_lot: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn lire_carte(code_pin: &str, lecteur: &str) -> Result<CartePS, String> {
 | 
					pub fn lire_carte(code_pin: &str, lecteur: &str) -> Result<CartePS, CartePSError> {
 | 
				
			||||||
    let resource_ps = CString::new(lecteur).expect("CString::new failed");
 | 
					    let resource_ps = CString::new(lecteur)?;
 | 
				
			||||||
    let resource_reader = CString::new("").expect("CString::new failed");
 | 
					    let resource_reader = CString::new("")?;
 | 
				
			||||||
    let card_number = CString::new(code_pin).expect("CString::new failed");
 | 
					    let card_number = CString::new(code_pin)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut buffer: *mut c_void = ptr::null_mut();
 | 
					    let mut buffer: *mut c_void = ptr::null_mut();
 | 
				
			||||||
    let mut size: size_t = 0;
 | 
					    let mut size: size_t = 0;
 | 
				
			||||||
@@ -69,17 +84,32 @@ pub fn lire_carte(code_pin: &str, lecteur: &str) -> Result<CartePS, String> {
 | 
				
			|||||||
            &mut size,
 | 
					            &mut size,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        println!("SSV_LireCartePS result: {}", result);
 | 
					        println!("SSV_LireCartePS result: {}", result);
 | 
				
			||||||
 | 
					        if result != 0 {
 | 
				
			||||||
 | 
					            return Err(libssv::LibSSVError::StandardErrorCode {
 | 
				
			||||||
 | 
					                code: result,
 | 
				
			||||||
 | 
					                function: "SSV_LireCartePS",
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !buffer.is_null() {
 | 
					        if !buffer.is_null() {
 | 
				
			||||||
            hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
 | 
					            hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
 | 
				
			||||||
            libc::free(buffer);
 | 
					            libc::free(buffer);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let groups = decode_ssv_memory(hex_values, hex_values.len());
 | 
					    let groups =
 | 
				
			||||||
 | 
					        decode_ssv_memory(hex_values, hex_values.len()).map_err(CartePSError::SSVMemory)?;
 | 
				
			||||||
    decode_carte_ps(groups)
 | 
					    decode_carte_ps(groups)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn decode_carte_ps(groups: Vec<Block>) -> Result<CartePS, String> {
 | 
					fn get_last_mut_situation(carte_ps: &mut CartePS) -> Result<&mut SituationPS, CartePSError> {
 | 
				
			||||||
 | 
					    carte_ps
 | 
				
			||||||
 | 
					        .situations
 | 
				
			||||||
 | 
					        .last_mut()
 | 
				
			||||||
 | 
					        .ok_or(CartePSError::InvalidLastSituation)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn decode_carte_ps(groups: Vec<Block>) -> Result<CartePS, CartePSError> {
 | 
				
			||||||
    let mut carte_ps = CartePS::default();
 | 
					    let mut carte_ps = CartePS::default();
 | 
				
			||||||
    for group in groups {
 | 
					    for group in groups {
 | 
				
			||||||
        for field in group.content {
 | 
					        for field in group.content {
 | 
				
			||||||
@@ -118,137 +148,99 @@ fn decode_carte_ps(groups: Vec<Block>) -> Result<CartePS, String> {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 1) => {
 | 
					                (2..=16, 1) => {
 | 
				
			||||||
                    carte_ps.situations.push(SituationPS::default());
 | 
					                    carte_ps.situations.push(SituationPS::default());
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .numero_logique_de_la_situation_de_facturation_du_ps = field.content[0];
 | 
					                        .numero_logique_de_la_situation_de_facturation_du_ps = field.content[0];
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 2) => {
 | 
					                (2..=16, 2) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().mode_d_exercice =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.mode_d_exercice =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 3) => {
 | 
					                (2..=16, 3) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().statut_d_exercice =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.statut_d_exercice =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 4) => {
 | 
					                (2..=16, 4) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().secteur_d_activite =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.secteur_d_activite =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 5) => {
 | 
					                (2..=16, 5) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?.type_d_identification_structure =
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .type_d_identification_structure =
 | 
					 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 6) => {
 | 
					                (2..=16, 6) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?.numero_d_identification_structure =
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .numero_d_identification_structure =
 | 
					 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 7) => {
 | 
					                (2..=16, 7) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .cle_du_numero_d_identification_structure =
 | 
					                        .cle_du_numero_d_identification_structure =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 8) => {
 | 
					                (2..=16, 8) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?.raison_sociale_structure =
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .raison_sociale_structure =
 | 
					 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 9) => {
 | 
					                (2..=16, 9) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .numero_d_identification_de_facturation_du_ps =
 | 
					                        .numero_d_identification_de_facturation_du_ps =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 10) => {
 | 
					                (2..=16, 10) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .cle_du_numero_d_identification_de_facturation_du_ps =
 | 
					                        .cle_du_numero_d_identification_de_facturation_du_ps =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 11) => {
 | 
					                (2..=16, 11) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .numero_d_identification_du_ps_remplaçant =
 | 
					                        .numero_d_identification_du_ps_remplaçant =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 12) => {
 | 
					                (2..=16, 12) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .cle_du_numero_d_identification_du_ps_remplaçant =
 | 
					                        .cle_du_numero_d_identification_du_ps_remplaçant =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 13) => {
 | 
					                (2..=16, 13) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_conventionnel =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_conventionnel =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 14) => {
 | 
					                (2..=16, 14) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_specialite =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_specialite =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 15) => {
 | 
					                (2..=16, 15) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_zone_tarifaire =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_zone_tarifaire =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 16) => {
 | 
					                (2..=16, 16) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_zone_ik =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_zone_ik =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 17) => {
 | 
					                (2..=16, 17) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_agrement_1 =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_agrement_1 =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 18) => {
 | 
					                (2..=16, 18) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_agrement_2 =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_agrement_2 =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 19) => {
 | 
					                (2..=16, 19) => {
 | 
				
			||||||
                    carte_ps.situations.last_mut().unwrap().code_agrement_3 =
 | 
					                    get_last_mut_situation(&mut carte_ps)?.code_agrement_3 =
 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 20) => {
 | 
					                (2..=16, 20) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?.habilitation_à_signer_une_facture =
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .habilitation_à_signer_une_facture =
 | 
					 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                (2..=16, 21) => {
 | 
					                (2..=16, 21) => {
 | 
				
			||||||
                    carte_ps
 | 
					                    get_last_mut_situation(&mut carte_ps)?.habilitation_à_signer_un_lot =
 | 
				
			||||||
                        .situations
 | 
					 | 
				
			||||||
                        .last_mut()
 | 
					 | 
				
			||||||
                        .unwrap()
 | 
					 | 
				
			||||||
                        .habilitation_à_signer_un_lot =
 | 
					 | 
				
			||||||
                        String::from_utf8_lossy(field.content).to_string();
 | 
					                        String::from_utf8_lossy(field.content).to_string();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                _ => {
 | 
					                _ => {
 | 
				
			||||||
                    return Err(format!(
 | 
					                    return Err(CartePSError::UnknownGroupFieldPair {
 | 
				
			||||||
                        "Unknown (group, field) pair: ({}, {})",
 | 
					                        group: group.id,
 | 
				
			||||||
                        group.id, field.id
 | 
					                        field: field.id,
 | 
				
			||||||
                    ))
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -279,7 +271,7 @@ mod test_decode_carte_ps {
 | 
				
			|||||||
            57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
 | 
					            57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
 | 
				
			||||||
            48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
					            48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        let blocks = decode_ssv_memory(bytes, bytes.len());
 | 
					        let blocks = decode_ssv_memory(bytes, bytes.len()).unwrap();
 | 
				
			||||||
        let carte_ps = decode_carte_ps(blocks).unwrap();
 | 
					        let carte_ps = decode_carte_ps(blocks).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(carte_ps.titulaire.type_de_carte_ps, "0");
 | 
					        assert_eq!(carte_ps.titulaire.type_de_carte_ps, "0");
 | 
				
			||||||
@@ -370,7 +362,7 @@ mod test_decode_carte_ps {
 | 
				
			|||||||
            57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
 | 
					            57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53, 48, 2, 49,
 | 
				
			||||||
            48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
					            48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        let blocks = decode_ssv_memory(bytes, bytes.len());
 | 
					        let blocks = decode_ssv_memory(bytes, bytes.len()).unwrap();
 | 
				
			||||||
        let carte_ps = decode_carte_ps(blocks).unwrap();
 | 
					        let carte_ps = decode_carte_ps(blocks).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(carte_ps.situations.len(), 3);
 | 
					        assert_eq!(carte_ps.situations.len(), 3);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,13 @@
 | 
				
			|||||||
/// Low level bindings to the SSVLIB dynamic library.
 | 
					/// Low level bindings to the SSVLIB dynamic library.
 | 
				
			||||||
// TODO : look for creating a dedicated *-sys crate : https://kornel.ski/rust-sys-crate
 | 
					// TODO : look for creating a dedicated *-sys crate : https://kornel.ski/rust-sys-crate
 | 
				
			||||||
use libc::{c_char, c_ushort, c_void, size_t};
 | 
					use libc::{c_char, c_ushort, c_void, size_t};
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub enum LibSSVError {
 | 
				
			||||||
 | 
					    #[error("SSV library error in {function}: {code}")]
 | 
				
			||||||
 | 
					    StandardErrorCode { code: u16, function: &'static str },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg_attr(target_os = "linux", link(name = "ssvlux64"))]
 | 
					#[cfg_attr(target_os = "linux", link(name = "ssvlux64"))]
 | 
				
			||||||
#[cfg_attr(target_os = "windows", link(name = "ssvw64"))]
 | 
					#[cfg_attr(target_os = "windows", link(name = "ssvw64"))]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@ mod libssv;
 | 
				
			|||||||
mod ssv_memory;
 | 
					mod ssv_memory;
 | 
				
			||||||
mod ssvlib_demo;
 | 
					mod ssvlib_demo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					use anyhow::{Context, Result};
 | 
				
			||||||
    ssvlib_demo::demo();
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<()> {
 | 
				
			||||||
 | 
					    ssvlib_demo::demo().context("Error while running the SSV library demo")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,33 @@
 | 
				
			|||||||
/// # SSV Memory
 | 
					/// # SSV Memory
 | 
				
			||||||
/// Provide functions to manipulate raw memory from SSV library.
 | 
					/// Provide functions to manipulate raw memory from SSV library.
 | 
				
			||||||
use std::convert::TryFrom;
 | 
					use std::convert::TryFrom;
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub enum BytesReadingError {
 | 
				
			||||||
 | 
					    #[error("Empty bytes input")]
 | 
				
			||||||
 | 
					    EmptyBytes,
 | 
				
			||||||
 | 
					    #[error("Invalid memory: not enough bytes ({actual}) to read the expected size ({expected})")]
 | 
				
			||||||
 | 
					    InvalidSize { expected: usize, actual: usize },
 | 
				
			||||||
 | 
					    #[error("Invalid memory: size ({actual}) is expected to be less than {expected} bytes")]
 | 
				
			||||||
 | 
					    SizeTooBig { expected: usize, actual: usize },
 | 
				
			||||||
 | 
					    #[error("Invalid memory: not enough bytes to read the block id")]
 | 
				
			||||||
 | 
					    InvalidBlockId(#[from] std::array::TryFromSliceError),
 | 
				
			||||||
 | 
					    #[error("Error while reading field at offset {offset}")]
 | 
				
			||||||
 | 
					    InvalidField {
 | 
				
			||||||
 | 
					        source: Box<BytesReadingError>,
 | 
				
			||||||
 | 
					        offset: usize,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub enum SSVMemoryError {
 | 
				
			||||||
 | 
					    #[error("Error while parsing block at offset {offset}")]
 | 
				
			||||||
 | 
					    BlockParsing {
 | 
				
			||||||
 | 
					        source: BytesReadingError,
 | 
				
			||||||
 | 
					        offset: usize,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(PartialEq, Debug)]
 | 
					#[derive(PartialEq, Debug)]
 | 
				
			||||||
struct ElementSize {
 | 
					struct ElementSize {
 | 
				
			||||||
@@ -9,13 +36,12 @@ struct ElementSize {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO : Est-ce qu'on pourrait/devrait définir un type custom pour représenter les tableaux de bytes ?
 | 
					// TODO : Est-ce qu'on pourrait/devrait définir un type custom pour représenter les tableaux de bytes ?
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl TryFrom<&[u8]> for ElementSize {
 | 
					impl TryFrom<&[u8]> for ElementSize {
 | 
				
			||||||
    type Error = &'static str;
 | 
					    type Error = BytesReadingError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
 | 
					    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
 | 
				
			||||||
        if bytes.is_empty() {
 | 
					        if bytes.is_empty() {
 | 
				
			||||||
            return Err("Empty bytes input");
 | 
					            return Err(BytesReadingError::EmptyBytes);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut element_size = ElementSize { size: 0, pad: 1 };
 | 
					        let mut element_size = ElementSize { size: 0, pad: 1 };
 | 
				
			||||||
@@ -30,9 +56,15 @@ impl TryFrom<&[u8]> for ElementSize {
 | 
				
			|||||||
            // N are the 7 lower bits of the first byte
 | 
					            // N are the 7 lower bits of the first byte
 | 
				
			||||||
            let size_bytes_len = (bytes[0] & 0b0111_1111) as usize;
 | 
					            let size_bytes_len = (bytes[0] & 0b0111_1111) as usize;
 | 
				
			||||||
            if size_bytes_len > bytes.len() - 1 {
 | 
					            if size_bytes_len > bytes.len() - 1 {
 | 
				
			||||||
                return Err("Invalid memory: not enough bytes to read the size");
 | 
					                return Err(BytesReadingError::InvalidSize {
 | 
				
			||||||
 | 
					                    expected: size_bytes_len,
 | 
				
			||||||
 | 
					                    actual: bytes.len() - 1,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
            } else if size_bytes_len > 4 {
 | 
					            } else if size_bytes_len > 4 {
 | 
				
			||||||
                return Err("Invalid memory: size is too big");
 | 
					                return Err(BytesReadingError::SizeTooBig {
 | 
				
			||||||
 | 
					                    expected: 4,
 | 
				
			||||||
 | 
					                    actual: size_bytes_len,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            let size_bytes = &bytes[1..1 + size_bytes_len];
 | 
					            let size_bytes = &bytes[1..1 + size_bytes_len];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,15 +86,21 @@ pub struct Block<'a> {
 | 
				
			|||||||
    pub content: Vec<Field<'a>>,
 | 
					    pub content: Vec<Field<'a>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> From<&'a [u8]> for Block<'a> {
 | 
					impl<'a> TryFrom<&'a [u8]> for Block<'a> {
 | 
				
			||||||
    fn from(bytes: &'a [u8]) -> Self {
 | 
					    type Error = BytesReadingError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
 | 
				
			||||||
        let mut offset = 0;
 | 
					        let mut offset = 0;
 | 
				
			||||||
        let id = u16::from_be_bytes(bytes[..2].try_into().unwrap());
 | 
					        let id = u16::from_be_bytes(
 | 
				
			||||||
 | 
					            bytes[..2]
 | 
				
			||||||
 | 
					                .try_into()
 | 
				
			||||||
 | 
					                .map_err(BytesReadingError::InvalidBlockId)?,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        offset += 2;
 | 
					        offset += 2;
 | 
				
			||||||
        let ElementSize {
 | 
					        let ElementSize {
 | 
				
			||||||
            size: block_size,
 | 
					            size: block_size,
 | 
				
			||||||
            pad,
 | 
					            pad,
 | 
				
			||||||
        } = bytes[2..].try_into().unwrap();
 | 
					        } = bytes[2..].try_into()?;
 | 
				
			||||||
        offset += pad;
 | 
					        offset += pad;
 | 
				
			||||||
        let raw_content = &bytes[offset..];
 | 
					        let raw_content = &bytes[offset..];
 | 
				
			||||||
        let mut field_offset = 0;
 | 
					        let mut field_offset = 0;
 | 
				
			||||||
@@ -70,17 +108,22 @@ impl<'a> From<&'a [u8]> for Block<'a> {
 | 
				
			|||||||
        let mut content = Vec::new();
 | 
					        let mut content = Vec::new();
 | 
				
			||||||
        let mut field_id = 1;
 | 
					        let mut field_id = 1;
 | 
				
			||||||
        while field_offset < block_size {
 | 
					        while field_offset < block_size {
 | 
				
			||||||
            let mut field: Field<'a> = raw_content[field_offset..].into();
 | 
					            let mut field: Field<'a> = raw_content[field_offset..].try_into().map_err(|err| {
 | 
				
			||||||
 | 
					                BytesReadingError::InvalidField {
 | 
				
			||||||
 | 
					                    source: Box::new(err),
 | 
				
			||||||
 | 
					                    offset: field_offset,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })?;
 | 
				
			||||||
            field.id = field_id;
 | 
					            field.id = field_id;
 | 
				
			||||||
            field_offset += field.size;
 | 
					            field_offset += field.size;
 | 
				
			||||||
            field_id += 1;
 | 
					            field_id += 1;
 | 
				
			||||||
            content.push(field);
 | 
					            content.push(field);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Block {
 | 
					        Ok(Block {
 | 
				
			||||||
            id,
 | 
					            id,
 | 
				
			||||||
            size: offset + block_size,
 | 
					            size: offset + block_size,
 | 
				
			||||||
            content,
 | 
					            content,
 | 
				
			||||||
        }
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,31 +134,41 @@ pub struct Field<'a> {
 | 
				
			|||||||
    pub content: &'a [u8],
 | 
					    pub content: &'a [u8],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> From<&'a [u8]> for Field<'a> {
 | 
					impl<'a> TryFrom<&'a [u8]> for Field<'a> {
 | 
				
			||||||
    fn from(bytes: &'a [u8]) -> Self {
 | 
					    type Error = BytesReadingError;
 | 
				
			||||||
        let ElementSize { size, pad } = bytes.try_into().unwrap();
 | 
					
 | 
				
			||||||
 | 
					    fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
 | 
				
			||||||
 | 
					        let ElementSize { size, pad } = bytes.try_into()?;
 | 
				
			||||||
        let contenu = &bytes[pad..pad + size];
 | 
					        let contenu = &bytes[pad..pad + size];
 | 
				
			||||||
        Field {
 | 
					        Ok(Field {
 | 
				
			||||||
            id: 0,
 | 
					            id: 0,
 | 
				
			||||||
            size: pad + size,
 | 
					            size: pad + size,
 | 
				
			||||||
            content: contenu,
 | 
					            content: contenu,
 | 
				
			||||||
        }
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn decode_ssv_memory(bytes: &[u8], size: usize) -> Vec<Block> {
 | 
					pub fn decode_ssv_memory(bytes: &[u8], size: usize) -> Result<Vec<Block>, SSVMemoryError> {
 | 
				
			||||||
    let mut blocks: Vec<Block> = Vec::new();
 | 
					    let mut blocks: Vec<Block> = Vec::new();
 | 
				
			||||||
    let mut offset = 0;
 | 
					    let mut offset = 0;
 | 
				
			||||||
    while offset < size {
 | 
					    while offset < size {
 | 
				
			||||||
        let block: Block = bytes[offset..].into();
 | 
					        let block: Block =
 | 
				
			||||||
 | 
					            bytes[offset..]
 | 
				
			||||||
 | 
					                .try_into()
 | 
				
			||||||
 | 
					                .map_err(|err| SSVMemoryError::BlockParsing {
 | 
				
			||||||
 | 
					                    source: err,
 | 
				
			||||||
 | 
					                    offset,
 | 
				
			||||||
 | 
					                })?;
 | 
				
			||||||
        offset += block.size;
 | 
					        offset += block.size;
 | 
				
			||||||
        blocks.push(block);
 | 
					        blocks.push(block);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    blocks
 | 
					    Ok(blocks)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test_element_size {
 | 
					mod test_element_size {
 | 
				
			||||||
 | 
					    use std::any::Any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -142,29 +195,51 @@ mod test_element_size {
 | 
				
			|||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn null_size() {
 | 
					    fn null_size() {
 | 
				
			||||||
        let bytes: &[u8] = &[];
 | 
					        let bytes: &[u8] = &[];
 | 
				
			||||||
        let result: Result<ElementSize, &str> = bytes.try_into();
 | 
					        let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
 | 
				
			||||||
        assert_eq!(result, Err("Empty bytes input"),);
 | 
					        assert!(result.is_err());
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            result.unwrap_err().type_id(),
 | 
				
			||||||
 | 
					            BytesReadingError::EmptyBytes.type_id()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn invalid_memory() {
 | 
					    fn invalid_memory() {
 | 
				
			||||||
        let bytes: &[u8] = &[0b_1000_0001_u8];
 | 
					        let bytes: &[u8] = &[0b_1000_0001_u8];
 | 
				
			||||||
        let result: Result<ElementSize, &str> = bytes.try_into();
 | 
					        let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
 | 
				
			||||||
 | 
					        assert!(result.is_err());
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            result,
 | 
					            result.unwrap_err().to_string(),
 | 
				
			||||||
            Err("Invalid memory: not enough bytes to read the size"),
 | 
					            BytesReadingError::InvalidSize {
 | 
				
			||||||
 | 
					                expected: 1,
 | 
				
			||||||
 | 
					                actual: 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let bytes: &[u8] = &[0b_1000_0010_u8, 1];
 | 
					        let bytes: &[u8] = &[0b_1000_0010_u8, 1];
 | 
				
			||||||
        let result: Result<ElementSize, &str> = bytes.try_into();
 | 
					        let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
 | 
				
			||||||
 | 
					        assert!(result.is_err());
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            result,
 | 
					            result.unwrap_err().to_string(),
 | 
				
			||||||
            Err("Invalid memory: not enough bytes to read the size"),
 | 
					            BytesReadingError::InvalidSize {
 | 
				
			||||||
 | 
					                expected: 2,
 | 
				
			||||||
 | 
					                actual: 1
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let bytes: &[u8] = &[0b_1000_0101_u8, 1, 1, 1, 1, 1];
 | 
					        let bytes: &[u8] = &[0b_1000_0101_u8, 1, 1, 1, 1, 1];
 | 
				
			||||||
        let result: Result<ElementSize, &str> = bytes.try_into();
 | 
					        let result: Result<ElementSize, BytesReadingError> = bytes.try_into();
 | 
				
			||||||
        assert_eq!(result, Err("Invalid memory: size is too big"),);
 | 
					        assert!(result.is_err());
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            result.unwrap_err().to_string(),
 | 
				
			||||||
 | 
					            BytesReadingError::SizeTooBig {
 | 
				
			||||||
 | 
					                expected: 4,
 | 
				
			||||||
 | 
					                actual: 5
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .to_string()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -179,7 +254,7 @@ mod test_field {
 | 
				
			|||||||
            80, 72, 65, 82, 77, 65, 67, 73, 69, 78, 48, 48, 53, 50, 52, 49, 57, 9, 70, 82, 65, 78,
 | 
					            80, 72, 65, 82, 77, 65, 67, 73, 69, 78, 48, 48, 53, 50, 52, 49, 57, 9, 70, 82, 65, 78,
 | 
				
			||||||
            67, 79, 73, 83, 69, 1, 84,
 | 
					            67, 79, 73, 83, 69, 1, 84,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        let element: Field = bytes.into();
 | 
					        let element: Field = bytes.try_into().unwrap();
 | 
				
			||||||
        assert_eq!(element.size, 52);
 | 
					        assert_eq!(element.size, 52);
 | 
				
			||||||
        assert_eq!(element.content[..5], [1, 48, 1, 56, 11]);
 | 
					        assert_eq!(element.content[..5], [1, 48, 1, 56, 11]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -194,7 +269,7 @@ mod test_field {
 | 
				
			|||||||
        // Add 256 bytes to the content
 | 
					        // Add 256 bytes to the content
 | 
				
			||||||
        bytes_vec.append(&mut vec![1; 256]);
 | 
					        bytes_vec.append(&mut vec![1; 256]);
 | 
				
			||||||
        let bytes: &[u8] = &bytes_vec;
 | 
					        let bytes: &[u8] = &bytes_vec;
 | 
				
			||||||
        let element: Field = bytes.into();
 | 
					        let element: Field = bytes.try_into().unwrap();
 | 
				
			||||||
        assert_eq!(element.size, 259);
 | 
					        assert_eq!(element.size, 259);
 | 
				
			||||||
        assert_eq!(element.content.len(), 256);
 | 
					        assert_eq!(element.content.len(), 256);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -208,15 +283,15 @@ mod test_block {
 | 
				
			|||||||
    fn test_francoise_pharmacien0052419_partial_block_1() {
 | 
					    fn test_francoise_pharmacien0052419_partial_block_1() {
 | 
				
			||||||
        let bytes: &[u8] = &[1, 48, 1, 56, 11, 57, 57, 55, 48, 48, 53, 50, 52, 49, 57, 52];
 | 
					        let bytes: &[u8] = &[1, 48, 1, 56, 11, 57, 57, 55, 48, 48, 53, 50, 52, 49, 57, 52];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let field1: Field = bytes.into();
 | 
					        let field1: Field = bytes.try_into().unwrap();
 | 
				
			||||||
        assert_eq!(field1.size, 2);
 | 
					        assert_eq!(field1.size, 2);
 | 
				
			||||||
        assert_eq!(field1.content, &[48]);
 | 
					        assert_eq!(field1.content, &[48]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let field2: Field = bytes[field1.size..].into();
 | 
					        let field2: Field = bytes[field1.size..].try_into().unwrap();
 | 
				
			||||||
        assert_eq!(field2.size, 2);
 | 
					        assert_eq!(field2.size, 2);
 | 
				
			||||||
        assert_eq!(field2.content, &[56]);
 | 
					        assert_eq!(field2.content, &[56]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let field3: Field = bytes[field1.size + field2.size..].into();
 | 
					        let field3: Field = bytes[field1.size + field2.size..].try_into().unwrap();
 | 
				
			||||||
        assert_eq!(field3.size, 12);
 | 
					        assert_eq!(field3.size, 12);
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            field3.content,
 | 
					            field3.content,
 | 
				
			||||||
@@ -243,12 +318,12 @@ mod test_block {
 | 
				
			|||||||
            48, 2, 49, 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
					            48, 2, 49, 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let first_block: Block = bytes.into();
 | 
					        let first_block: Block = bytes.try_into().unwrap();
 | 
				
			||||||
        assert_eq!(first_block.id, 1);
 | 
					        assert_eq!(first_block.id, 1);
 | 
				
			||||||
        assert_eq!(first_block.size, 54);
 | 
					        assert_eq!(first_block.size, 54);
 | 
				
			||||||
        assert_eq!(first_block.content.len(), 8);
 | 
					        assert_eq!(first_block.content.len(), 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let second_block: Block = bytes[first_block.size..].into();
 | 
					        let second_block: Block = bytes[first_block.size..].try_into().unwrap();
 | 
				
			||||||
        assert_eq!(second_block.id, 2);
 | 
					        assert_eq!(second_block.id, 2);
 | 
				
			||||||
        assert_eq!(second_block.size, 86);
 | 
					        assert_eq!(second_block.size, 86);
 | 
				
			||||||
        assert_eq!(second_block.content.len(), 21);
 | 
					        assert_eq!(second_block.content.len(), 21);
 | 
				
			||||||
@@ -277,7 +352,7 @@ mod test_decode_ssv_memory {
 | 
				
			|||||||
            50, 50, 49, 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53,
 | 
					            50, 50, 49, 57, 53, 8, 48, 48, 50, 48, 50, 52, 49, 57, 1, 56, 0, 1, 48, 1, 49, 2, 53,
 | 
				
			||||||
            48, 2, 49, 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
					            48, 2, 49, 48, 2, 48, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
        let blocks = decode_ssv_memory(bytes, bytes.len());
 | 
					        let blocks = decode_ssv_memory(bytes, bytes.len()).unwrap();
 | 
				
			||||||
        assert_eq!(blocks.len(), 2);
 | 
					        assert_eq!(blocks.len(), 2);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,25 +6,49 @@ use std::env;
 | 
				
			|||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::ptr;
 | 
					use std::ptr;
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::cps::lire_carte;
 | 
					use crate::cps::lire_carte;
 | 
				
			||||||
use crate::libssv::{SSV_InitLIB2, SSV_LireConfig};
 | 
					use crate::libssv::{SSV_InitLIB2, SSV_LireConfig};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn ssv_init_lib_2() {
 | 
					#[derive(Error, Debug)]
 | 
				
			||||||
 | 
					pub enum SSVDemoError {
 | 
				
			||||||
 | 
					    #[error(transparent)]
 | 
				
			||||||
 | 
					    CartePSReading(#[from] crate::cps::CartePSError),
 | 
				
			||||||
 | 
					    #[error(transparent)]
 | 
				
			||||||
 | 
					    SSVLibErrorCode(#[from] crate::libssv::LibSSVError),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn ssv_init_lib_2() -> Result<(), SSVDemoError> {
 | 
				
			||||||
    let ini_str = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set");
 | 
					    let ini_str = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set");
 | 
				
			||||||
    let ini = CString::new(ini_str).expect("CString::new failed");
 | 
					    let ini = CString::new(ini_str).expect("CString::new failed");
 | 
				
			||||||
    unsafe {
 | 
					    unsafe {
 | 
				
			||||||
        let result = SSV_InitLIB2(ini.as_ptr());
 | 
					        let result = SSV_InitLIB2(ini.as_ptr());
 | 
				
			||||||
        println!("SSV_InitLIB2 result: {}", result);
 | 
					        println!("SSV_InitLIB2 result: {}", result);
 | 
				
			||||||
 | 
					        if result != 0 {
 | 
				
			||||||
 | 
					            return Err(crate::libssv::LibSSVError::StandardErrorCode {
 | 
				
			||||||
 | 
					                code: result,
 | 
				
			||||||
 | 
					                function: "SSV_InitLIB2",
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            .into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn ssv_lire_config() {
 | 
					fn ssv_lire_config() -> Result<(), SSVDemoError> {
 | 
				
			||||||
    let mut buffer: *mut c_void = ptr::null_mut();
 | 
					    let mut buffer: *mut c_void = ptr::null_mut();
 | 
				
			||||||
    let mut size: size_t = 0;
 | 
					    let mut size: size_t = 0;
 | 
				
			||||||
    unsafe {
 | 
					    unsafe {
 | 
				
			||||||
        let result = SSV_LireConfig(&mut buffer, &mut size);
 | 
					        let result = SSV_LireConfig(&mut buffer, &mut size);
 | 
				
			||||||
        println!("SSV_LireConfig result: {}", result);
 | 
					        println!("SSV_LireConfig result: {}", result);
 | 
				
			||||||
 | 
					        if result != 0 {
 | 
				
			||||||
 | 
					            return Err(crate::libssv::LibSSVError::StandardErrorCode {
 | 
				
			||||||
 | 
					                code: result,
 | 
				
			||||||
 | 
					                function: "SSV_LireConfig",
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !buffer.is_null() {
 | 
					        if !buffer.is_null() {
 | 
				
			||||||
            let hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
 | 
					            let hex_values = std::slice::from_raw_parts(buffer as *const u8, size);
 | 
				
			||||||
@@ -36,25 +60,27 @@ fn ssv_lire_config() {
 | 
				
			|||||||
            libc::free(buffer);
 | 
					            libc::free(buffer);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn demo() {
 | 
					pub fn demo() -> Result<(), SSVDemoError> {
 | 
				
			||||||
    // TODO : this is probably not working on release, because I'm not sure it exists a CARGO_MANIFEST_DIR and so it can find the `.env`
 | 
					    // TODO : this is probably not working on release, because I'm not sure it exists a CARGO_MANIFEST_DIR and so it can find the `.env`
 | 
				
			||||||
    // Maybe we could use a system standard config path to store a config file
 | 
					    // Maybe we could use a system standard config path to store a config file
 | 
				
			||||||
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
 | 
					    let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
 | 
				
			||||||
    let manifest_path = PathBuf::from(manifest_dir);
 | 
					    let manifest_path = PathBuf::from(manifest_dir);
 | 
				
			||||||
    dotenv::from_path(manifest_path.join(".env")).ok();
 | 
					    dotenv::from_path(manifest_path.join(".env")).ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    println!("------- Demo for the SSV library --------");
 | 
					    println!("------- Demo for the SSV library --------");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ssv_init_lib_2();
 | 
					    ssv_init_lib_2()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let code_pin = "1234";
 | 
					    let code_pin = "1234";
 | 
				
			||||||
    let lecteur = "HID Global OMNIKEY 3x21 Smart Card Reader 0";
 | 
					    let lecteur = "HID Global OMNIKEY 3x21 Smart Card Reader 0";
 | 
				
			||||||
    let carte_ps = lire_carte(code_pin, lecteur).unwrap();
 | 
					    let carte_ps = lire_carte(code_pin, lecteur)?;
 | 
				
			||||||
    println!("CartePS: {:#?}", carte_ps);
 | 
					    println!("CartePS: {:#?}", carte_ps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ssv_lire_config();
 | 
					    ssv_lire_config()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    println!("-----------------------------------------");
 | 
					    println!("-----------------------------------------");
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user