| extern crate base64; | 
 | extern crate hex; | 
 |  | 
 | #[cfg(test)] | 
 | mod tests { | 
 |     #[test] | 
 |     fn it_works() { | 
 |         assert_eq!(2 + 2, 4); | 
 |     } | 
 |  | 
 |     #[test] | 
 |     fn test_key() { | 
 |         let key = "wDp3/3NPEi+R0peokVv010GkDk1mRTp3tUB/lCEVRAA="; | 
 |         let key_buffer = base64::decode_config(key, base64::STANDARD).unwrap(); | 
 |         let s = hex::encode(key_buffer.as_slice()); | 
 |         let key_string = hex::decode(format!("{}{:04x}{:02x}", s, 5, 3)).unwrap(); | 
 |         println!( | 
 |             "key : {}", | 
 |             base64::encode_config(key_string, base64::URL_SAFE) | 
 |         ); | 
 |     } | 
 | } | 
 |  | 
 | // use std::ffi::{CStr, CString}; | 
 | // use std::os::raw::{c_char, c_uchar, c_ulong}; | 
 |  | 
 | // #[no_mangle] | 
 | // pub extern "C" fn dlsmk_decode( | 
 | //     key: *const c_uchar, | 
 | //     qrcode: *const c_uchar, | 
 | //     qrlen: c_ulong, | 
 | // ) -> *mut c_char { | 
 | //     CString::new("Hello ".to_owned()).unwrap().into_raw() | 
 | // } | 
 |  | 
 | #[cfg(any(target_family = "unix", target_os = "android"))] | 
 | #[allow(non_snake_case)] | 
 | pub mod android { | 
 |     extern crate base64; | 
 |     extern crate jni; | 
 |  | 
 |     use self::jni::objects::{JClass, JMap, JObject, JString}; | 
 |     use self::jni::sys::{jboolean, jint, jlong, JNI_FALSE, JNI_TRUE}; | 
 |     use self::jni::JNIEnv; | 
 |     // use super::*; | 
 |     use libc; | 
 |     use std::slice; | 
 |  | 
 |     use log::debug; | 
 |  | 
 |     use dlqrcode::DaliQrCode; | 
 |  | 
 |     fn put_data(env: &JNIEnv, map: &JMap, key: &str, value: &str) { | 
 |         map.put( | 
 |             *env.new_string(key).unwrap(), | 
 |             *env.new_string(value).unwrap(), | 
 |         ) | 
 |         .unwrap(); | 
 |     } | 
 |  | 
 |     #[no_mangle] | 
 |     pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_decode( | 
 |         env: JNIEnv, | 
 |         _: JClass, | 
 |         key_hex: JString, | 
 |         qrcode: JString, | 
 |         offset: jlong, | 
 |         result: JObject, | 
 |     ) -> jboolean { | 
 |         let key = { | 
 |             let s = env | 
 |                 .get_string(key_hex) | 
 |                 .expect("invalid key string") | 
 |                 .as_ptr(); | 
 |             let keylen = libc::strlen(s); | 
 |             let mut k = Vec::new(); | 
 |             k.extend_from_slice(slice::from_raw_parts(s as *const u8, keylen)); | 
 |             k | 
 |         }; | 
 |  | 
 |         let qrcode = { | 
 |             let s = env | 
 |                 .get_string(qrcode) | 
 |                 .expect("invalid qrcode string") | 
 |                 .as_ptr(); | 
 |             let qrlen = libc::strlen(s); | 
 |             let mut q = Vec::new(); | 
 |             q.extend_from_slice(slice::from_raw_parts(s as *const u8, qrlen)); | 
 |             q | 
 |         }; | 
 |  | 
 |         let qrdata = env.get_map(result).expect("invalid qrdata map"); | 
 |  | 
 |         let (key, step, skew) = { | 
 |             let mut k = [0u8; 32]; | 
 |             if let Ok(v) = base64::decode_config(key.as_slice(), base64::URL_SAFE) { | 
 |                 if v.len() != 35 { | 
 |                     put_data(&env, &qrdata, "error", "key format error"); | 
 |                     return JNI_FALSE; | 
 |                 } | 
 |                 k.clone_from_slice(&v.as_slice()[..32]); | 
 |                 let step = ((v[32] as u64) << 8) | (v[33] as u64); | 
 |                 let skew = v[34] as u8; | 
 |                 (k, step, skew) | 
 |             } else { | 
 |                 put_data( | 
 |                     &env, | 
 |                     &qrdata, | 
 |                     "error", | 
 |                     "key must be hex format and 64 characters", | 
 |                 ); | 
 |                 return JNI_FALSE; | 
 |             } | 
 |         }; | 
 |  | 
 |         debug!("TOTP step <{}> , skew <{}>", step, skew); | 
 |         let decoder = match DaliQrCode::new(key, None, Some(step), Some(skew), None) { | 
 |             Ok(d) => d, | 
 |             Err(e) => { | 
 |                 let s = format!("invalid input parameter {:?}", e); | 
 |                 put_data(&env, &qrdata, "error", &s); | 
 |                 return JNI_FALSE; | 
 |             } | 
 |         }; | 
 |  | 
 |         match decoder.decode(qrcode.as_ptr(), qrcode.len(), offset as i32) { | 
 |             Ok(d) => { | 
 |                 put_data(&env, &qrdata, "cardno", &d.cardno); | 
 |                 put_data(&env, &qrdata, "cardtype", &d.cardtype); | 
 |                 put_data(&env, &qrdata, "uid", &d.uid); | 
 |                 let sign = dlqrcode::transaction_sign(&d); | 
 |                 put_data(&env, &qrdata, "sign", &sign); | 
 |                 return JNI_TRUE; | 
 |             } | 
 |             Err(e) => { | 
 |                 let s = format!("{:?}", e); | 
 |                 put_data(&env, &qrdata, "error", &s); | 
 |                 return JNI_FALSE; | 
 |             } | 
 |         }; | 
 |     } | 
 |  | 
 |     #[no_mangle] | 
 |     pub unsafe extern "C" fn Java_com_supwisdom_dlsmk_DLSMKQrCode_genTac( | 
 |         env: JNIEnv, | 
 |         _: JClass, | 
 |         qrsign: JString, | 
 |         cardno: JString, | 
 |         amount: jint, | 
 |         termDatetime: JString, | 
 |         result: JObject, | 
 |     ) -> jboolean { | 
 |         let qrsign = { | 
 |             let s = env.get_string(qrsign).expect("invalid key string").as_ptr(); | 
 |             let keylen = libc::strlen(s); | 
 |             String::from_raw_parts(s as *mut u8, keylen, keylen) | 
 |         }; | 
 |         let cardno = { | 
 |             let s = env | 
 |                 .get_string(cardno) | 
 |                 .expect("invalid cardno string") | 
 |                 .as_ptr(); | 
 |             let len = libc::strlen(s); | 
 |             String::from_raw_parts(s as *mut u8, len, len) | 
 |         }; | 
 |  | 
 |         let termDatetime = { | 
 |             let s = env | 
 |                 .get_string(termDatetime) | 
 |                 .expect("invalid datetime") | 
 |                 .as_ptr(); | 
 |             let len = libc::strlen(s); | 
 |             String::from_raw_parts(s as *mut u8, len, len) | 
 |         }; | 
 |  | 
 |         let result = env.get_map(result).expect("invalid qrdata map"); | 
 |  | 
 |         if termDatetime.len() != 14 { | 
 |             put_data(&env, &result, "error", "term datetime must be 14 chars"); | 
 |             return JNI_FALSE; | 
 |         } | 
 |  | 
 |         match dlqrcode::transaction_tac(&cardno, amount, &termDatetime, &qrsign) { | 
 |             Ok(tac) => { | 
 |                 put_data(&env, &result, "tac", &tac); | 
 |                 JNI_TRUE | 
 |             } | 
 |             Err(e) => { | 
 |                 put_data(&env, &result, "error", &format!("{:?}", e)); | 
 |                 JNI_FALSE | 
 |             } | 
 |         } | 
 |     } | 
 | } |