iso8583_parser/
lib.rs

1//! # String Manipulation Module
2//!
3//! This module provides utilities for string manipulation.
4//!
5//! ## Examples
6//!
7//! ```
8//! use iso8583_parser::{StringManipulation, Mode};
9//!
10//! let mut s = String::from("48656C6C6F2C576F726C64"); // "Hello, World" in hex
11//!
12//! // Convert hex to ASCII
13//! let ascii_result = s.hex_to_ascii();
14//! assert_eq!(ascii_result.unwrap(), "Hello,World");
15//! 
16//! // Get a slice of the string until a specified length
17//! let slice = s.get_slice_until(5);
18//! assert_eq!(slice, "48656");
19//! 
20//! // Get another slice of the string until a specified length
21//! let slice = s.get_slice_until(5);
22//! assert_eq!(slice, "C6C6F");
23//! 
24//!let mode_instance = Mode { enabled_private_tlv: false, enabled_private_ltv: false };
25//! // Process a field based on field number, length, and name
26//! s.process_field(1, 12, "test", &mode_instance);
27//!
28//! use iso8583_parser::positions_of_set_bits;
29//!
30//! let bitmap: Vec<u32> = positions_of_set_bits(u64::from_str_radix("3038058020C19201", 16).unwrap());
31//! assert_eq!(bitmap, vec![3, 4, 11, 12, 13, 22, 24, 25, 35, 41, 42, 48, 49, 52, 55, 64]);
32//! 
33//! let mut s = String::from("1101303830303539313535301002322E362E31352E3332020330022231021532"); // LTV format in hex
34//!
35//! // Parse LTV (Length, Tag, Value) format
36//! let ltvs = s.parse_private_ltv().unwrap();
37//!
38//! for ltv in ltvs {
39//!     println!("{}", ltv);
40//! }
41//! ```
42
43use emv_tlv_parser::parse_tlv;
44use std::error;
45pub mod gui; // Make the gui module public
46
47#[derive(Debug)]
48pub struct  LTV {
49    pub length: usize,
50    pub tag: u8,
51    pub value: String,
52}
53pub struct  PrivateTlv {
54    pub tag: String,
55    pub length: usize,
56    pub value: String,
57}
58
59pub struct Mode {
60    pub enabled_private_tlv: bool,
61    pub enabled_private_ltv: bool,
62}
63
64/// Returns the positions of set bits in a binary number.
65pub fn positions_of_set_bits(n: u64) -> Vec<u32> {
66    (0..64).filter(|&bit| 1 & (n >> (63 - bit)) != 0).map(|bit| bit + 1).collect()
67}
68
69/// Trait for string manipulation operations.
70pub trait StringManipulation {
71    /// Get a slice of the string until a specified length.
72    fn get_slice_until(&mut self, length: usize) -> String;
73
74    /// Convert a hex string to ASCII.
75    fn hex_to_ascii(&mut self) -> Result<String, hex::FromHexError>;
76
77    /// Process a field based on field number, length, and name.
78    fn process_field(&mut self, field_number: u32, length: u32, name: &str, mode: &Mode) -> String;
79
80    /// Parse LTV (Length, Tag, Value) format.
81    fn parse_private_ltv(&mut self) -> Result<Vec<LTV>, Box<dyn error::Error>>;
82
83    /// Parse Private TLV format
84    fn parse_private_tlv(&mut self) -> Result<Vec<PrivateTlv>, Box<dyn error::Error>>;
85}
86
87impl StringManipulation for String {
88    /// Get a slice of the string until a specified length.
89    fn get_slice_until(&mut self, length: usize) -> String {
90        self.drain(..length).collect::<String>()
91    }
92
93    /// Convert a hex string to ASCII.
94    fn hex_to_ascii(&mut self) -> Result<String, hex::FromHexError> {
95        let hex_bytes = hex::decode(self)?;
96        let ascii_chars: String = hex_bytes.iter().map(|&byte| byte as char).collect();
97        Ok(ascii_chars)
98    }
99
100    /// Process a field based on field number, length, and name.
101    fn process_field(&mut self, field_number: u32, length: u32, name: &str, mode: &Mode) -> String {
102        // Check if there's enough data to process
103        if self.len() == 0 {
104            return format!(
105                "Field {:3} | Length: {:3}| {:25} | Error: No data available\n",
106                field_number,
107                length,
108                name
109            );
110        }
111
112        let padded_length = if length % 2 == 1 {
113            length + 1
114        } else {
115            length
116        };
117
118        // Check if there's enough data for the field
119        if self.len() < padded_length as usize {
120            return format!(
121                "Field {:3} | Length: {:3}| {:25} | Error: Insufficient data (needed {} bytes, had {} bytes)\n",
122                field_number,
123                length,
124                name,
125                padded_length,
126                self.len()
127            );
128        }
129
130        let mut field_value = if field_number == 35 {
131            self.get_slice_until(38.min(self.len()))
132        } else {
133            self.get_slice_until(padded_length as usize)
134        };
135
136        let value_to_print = if matches!(field_number, 37 | 38 | 41 | 42 | 44 | 49 | 50 | 51 | 62 | 116 | 122) {
137            field_value.hex_to_ascii().unwrap()
138        } else {
139            field_value.to_string()
140        };
141    
142        let mut result = format!(
143            "Field {:3} | Length: {:3}| {:25} | {}\n",
144            field_number,
145            length,
146            name,
147            value_to_print.chars().take(length as usize).collect::<String>()
148        );
149    
150        if field_number == 55 {
151            match parse_tlv(value_to_print) {
152                Ok(tags) => {
153                    for tag in tags {
154                        result.push_str(&format!("{}\n", tag));
155                    }
156                }
157                Err(e) => result.push_str(&format!("Error parsing TLV: {}\n", e)),
158            }
159        } else if field_number == 48 || field_number == 121 {
160            if mode.enabled_private_tlv {
161                let mut tlv_private_value = value_to_print;
162                match tlv_private_value.parse_private_tlv() {
163                    Ok(tlvs_p) => {
164                        for tlv_p in tlvs_p {
165                            result.push_str(&format!("{}\n", tlv_p));
166                        }
167                    }
168                    Err(e) => result.push_str(&format!("Error parsing private tlv: {:?}\n", e)),
169                }
170            } else if mode.enabled_private_ltv {
171                let mut ltv_value = value_to_print;
172                match ltv_value.parse_private_ltv() {
173                    Ok(ltvs) => {
174                        for ltv in ltvs {
175                            result.push_str(&format!("{}\n", ltv));
176                        }
177                    }
178                    Err(e) => result.push_str(&format!("Error parsing LTV: {:?}\n", e)),
179                }
180            }
181        }
182    
183        result
184    }
185
186
187    fn parse_private_ltv(&mut self) -> Result<Vec<LTV>, Box<dyn error::Error>> {
188    let mut ltvs = Vec::new();
189        while self.len() > 0 {
190            let length =  self.drain(..2).collect::<String>().parse::<usize>()?;
191            let tag =  self.drain(..2).collect::<String>().parse::<u8>()?;
192            let byte_length  = (length - 1) * 2;
193            let value = self.drain(..byte_length).collect::<String>();
194            let ltv = LTV { length, tag, value};
195            ltvs.push(ltv);
196        }
197    Ok(ltvs)
198    }
199
200    fn parse_private_tlv(&mut self) -> Result<Vec<PrivateTlv>, Box<dyn error::Error>> {
201        let mut private_tlvs = Vec::new();
202            while self.len() > 0 {
203                let tag =  self.drain(..4).collect::<String>().hex_to_ascii().unwrap();
204                let length_hex_string =  self.drain(..4).collect::<String>().hex_to_ascii().unwrap();
205                let length = usize::from_str_radix(length_hex_string.as_str(), 16)?;
206                let byte_length  = length * 2;
207                let value = self.drain(..byte_length).collect::<String>().hex_to_ascii().unwrap();
208                let private_tlv = PrivateTlv { tag, length, value};
209                private_tlvs.push(private_tlv);
210            }
211        Ok(private_tlvs)
212    }
213
214}
215
216use std::fmt;
217impl fmt::Display for LTV {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        let value_string = match self.value.clone().hex_to_ascii() {
220            Ok(ascii) => format!("-> {}", ascii),
221            Err(e) => e.to_string(), // Handle the error case, you might want to log or handle it differently
222        };
223        write!(
224            f,
225            "\tLen: {:3} | Tag: {:3} | Val: {} {}",
226            self.length,
227            self.tag,
228            self.value,
229            value_string,
230        )
231    }
232}
233
234impl fmt::Display for PrivateTlv {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        write!(
237            f,
238            "\tTag: {:3} | Len: {:3} | Val: {}",
239            self.tag,
240            self.length,
241            self.value,
242        )
243    }
244}
245
246#[derive(Debug)]
247pub struct ParserResult {
248    pub message_length: Option<u32>,
249    pub header: Option<String>,
250    pub mti: String,
251    pub bitmap: Vec<u32>,
252    pub fields: Vec<String>,  // Added this field to store the processed fields
253    pub unparsed: String,
254}
255
256pub fn parse_iso8583(message: &str, including_header_length: bool, tlv_private: bool, ltv_private: bool) -> Result<ParserResult, Box<dyn error::Error>> {
257    let mut result = ParserResult {
258        message_length: None,
259        header: None,
260        mti: String::new(),
261        bitmap: Vec::new(),
262        fields: Vec::new(),
263        unparsed: String::new(),
264    };
265
266    let mut s = message.replace("\"", "").replace(" ", "");
267    
268    if including_header_length {
269        let message_len = u32::from_str_radix(&s.get_slice_until(4), 16)? * 2;
270        result.message_length = Some(message_len);
271        
272        if s.len() != message_len as usize {
273            return Err(format!("Error: Incorrect message len. The expected length is {} but The actual is {}", message_len, s.len()).into());
274        }
275        result.header = Some(s.get_slice_until(10).to_string());
276    }
277
278    result.mti = s.get_slice_until(4).to_string();
279    
280    let mut bitmap: Vec<u32> = positions_of_set_bits(u64::from_str_radix(&s.get_slice_until(16), 16)?);
281    if bitmap.contains(&1) {
282        let mut positions = positions_of_set_bits(u64::from_str_radix(&s.get_slice_until(16), 16)?);
283        positions.iter_mut().for_each(|num| *num += 64);
284        bitmap.append(&mut positions);
285        bitmap.retain(|&x| x != 1);
286    }
287    result.bitmap = bitmap;
288
289    let mode = Mode {
290        enabled_private_tlv: tlv_private,
291        enabled_private_ltv: ltv_private,
292    };
293    
294    for &bit in &result.bitmap {
295        let field_info = match bit {
296            2 => {
297                let pan_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap();
298                Some((bit, pan_len, "PAN"))
299            }
300            3 => Some((bit, 6, "Process Code")),
301            4 => Some((bit, 12, "Transaction Amount")),
302            5 => Some((bit, 12, "Settlement Amount")),
303            6 => Some((bit, 12, "Cardholder Billing Amount")),
304            7 => Some((bit, 10, "Transaction Date and Time")),
305            9 => Some((bit, 8, "Conversion rate, settlement")),
306            10 => Some((bit, 8, "Conversion rate, cardholder billing")),
307            11 => Some((bit, 6, "Trace")),
308            12 => Some((bit, 6, "Time")),
309            13 => Some((bit, 4, "Date")),
310            14 => Some((bit, 4, "Card EXpiration Date")),
311            15 => Some((bit, 4, "Settlement Date")),
312            18 => Some((bit, 4, "Merchant Category Code")),
313            19 => Some((bit, 3, "Acquirer Country Code")),
314            22 => Some((bit, 4, "POS Entry Mode")),
315            23 => Some((bit, 3, "Card Sequence Number")),
316            24 => Some((bit, 4, "")),
317            25 => Some((bit, 2, "")),
318            32 => {
319                let field32_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap();
320                Some((bit, field32_len, "Institution Identification Code Acquiring"))
321            }
322            35 => {
323                let track2_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap() * 2;
324                Some((bit, track2_len, "Track2"))
325            }
326            37 => Some((bit, 24, "Retrieval Ref #")),
327            38 => Some((bit, 12, "Authorization Code")),
328            39 => Some((bit, 4, "Response Code")),
329            41 => Some((bit, 16, "Terminal")),
330            42 => Some((bit, 30, "Acceptor")),
331            43 => Some((bit, 40, "Card Acceptor Name/Location")),
332            44 => {
333                let field44_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap() * 2;
334                Some((bit, field44_len, "Additional response data"))
335            }
336            45 => {
337                let track1_len: u32 = s.get_slice_until(2).parse::<u32>().unwrap();
338                Some((bit, track1_len, "Track 1 Data"))
339            }
340            48 => {
341                let field48_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
342                Some((bit, field48_len, "Aditional Data"))
343            }
344            49 => Some((bit, 6, "Transaction Currency Code")),
345            50 => Some((bit, 6, "Settlement Currency Code")),
346            51 => Some((bit, 6, "Billing Currency Code")),
347            52 => Some((bit, 16, "PinBlock")),
348            54 => {
349                let field54_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
350                Some((bit, field54_len, "Amount"))
351            }
352            55 => {
353                let field55_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
354                Some((bit, field55_len, ""))
355            }
356            60 => {
357                let field60_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
358                Some((bit, field60_len, ""))
359            }
360            62 => {
361                let field62_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
362                Some((bit, field62_len, "Private"))
363            }
364            64 => Some((bit, 16, "MAC")),
365            70 => Some((bit, 4, "")),
366            116 => {
367                let field116_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
368                Some((bit, field116_len, ""))
369            }
370            121 => {
371                let field121_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
372                Some((bit, field121_len, "Additional Data"))
373            }
374            122 => {
375                let field122_len = s.get_slice_until(4).parse::<u32>().unwrap() * 2;
376                Some((bit, field122_len, "Additional Data"))
377            }
378            128 => Some((bit, 16, "MAC")),
379            _ => return Err(format!("Field {} is not implemented", bit).into()),
380        };
381
382        if let Some((field_number, length, name)) = field_info {
383            let field_data = s.process_field(field_number, length, name, &mode);
384            result.fields.push(field_data);
385        }
386    }
387
388    result.unparsed = s;
389    Ok(result)
390}
391
392#[cfg(test)]
393mod tests {
394      use crate::StringManipulation;
395    #[test]
396    fn test_parse_ltv_single() {
397        let mut s = String::from("061148656C6C6F");
398        let mut ltvs = s.parse_private_ltv().unwrap();
399
400        assert_eq!(ltvs.len(), 1);
401
402        let ltv = &mut ltvs[0];
403        assert_eq!(ltv.length, 6);
404        assert_eq!(ltv.tag, 11);
405        assert_eq!(ltv.value.hex_to_ascii().unwrap(), "Hello");
406    }
407
408    #[test]
409    fn test_parse_ltv_multiple() {
410        let mut s = String::from("031148690622576F726C64");
411        let mut ltvs = s.parse_private_ltv().unwrap();
412
413        assert_eq!(ltvs.len(), 2);
414
415        let ltv1 = &mut ltvs[0];
416        assert_eq!(ltv1.length, 3);
417        assert_eq!(ltv1.tag, 11);
418        assert_eq!(ltv1.value.hex_to_ascii().unwrap(), "Hi");
419
420        let ltv2 = &mut ltvs[1];
421        assert_eq!(ltv2.length, 6);
422        assert_eq!(ltv2.tag, 22);
423        assert_eq!(ltv2.value.hex_to_ascii().unwrap(), "World");
424    }
425
426    #[test]
427    fn test_parse_ltv_empty() {
428        let mut s = String::new();
429        let ltvs = s.parse_private_ltv();
430
431        assert!(ltvs.is_ok());
432        assert!(ltvs.unwrap().is_empty());
433    }
434
435    #[test]
436    fn error_test() {
437        let mut s = String::from("T31148690622576F726C64");
438        let ltvs = s.parse_private_ltv();
439        assert!(ltvs.is_err());
440        assert_eq!(ltvs.err().unwrap().to_string().as_str(), "invalid digit found in string");
441    }
442
443}