1use crate::bitmap::Bitmap;
7use crate::error::{ISO8583Error, Result};
8use crate::field::{Field, FieldDefinition, FieldLength, FieldType, FieldValue};
9use crate::mti::MessageType;
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct ISO8583Message {
15 pub mti: MessageType,
17 fields: HashMap<u8, FieldValue>,
19 bitmap: Bitmap,
21}
22
23impl ISO8583Message {
24 pub fn new(mti: MessageType) -> Self {
26 Self {
27 mti,
28 fields: HashMap::new(),
29 bitmap: Bitmap::new(),
30 }
31 }
32
33 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
40 if bytes.len() < 12 {
41 return Err(ISO8583Error::message_too_short(12, bytes.len()));
43 }
44
45 let mut offset = 0;
46
47 let mti = MessageType::from_bytes(&bytes[offset..offset + 4])?;
49 offset += 4;
50
51 let bitmap_hex = hex::encode(&bytes[offset..offset + 8]);
53 let mut bitmap = Bitmap::from_hex(&bitmap_hex)?;
54 offset += 8;
55
56 if bitmap.is_set(1) {
58 if bytes.len() < offset + 8 {
59 return Err(ISO8583Error::message_too_short(offset + 8, bytes.len()));
60 }
61 let secondary_hex = hex::encode(&bytes[offset..offset + 8]);
62 let secondary_bitmap = Bitmap::from_hex(&secondary_hex)?;
63
64 for field_num in 65..=128 {
66 if secondary_bitmap.is_set(field_num) {
67 bitmap.set(field_num)?;
68 }
69 }
70 offset += 8;
71 }
72
73 let mut fields = HashMap::new();
75 let (field_array, field_count) = bitmap.get_set_fields();
76
77 for item in field_array.iter().take(field_count) {
78 let field_num = *item;
79 if field_num == 1 || field_num == 65 {
80 continue; }
82
83 let field = Field::from_number(field_num)?;
84 let def = field.definition();
85
86 let (value, bytes_consumed) = Self::parse_field(&bytes[offset..], &def)?;
88 fields.insert(field_num, value);
89 offset += bytes_consumed;
90 }
91
92 Ok(Self {
93 mti,
94 fields,
95 bitmap,
96 })
97 }
98
99 fn parse_field(bytes: &[u8], def: &FieldDefinition) -> Result<(FieldValue, usize)> {
101 if bytes.is_empty() {
103 return Err(ISO8583Error::message_too_short(1, 0));
104 }
105
106 match def.length {
107 FieldLength::Fixed(len) => {
108 if bytes.len() < len {
110 return Err(ISO8583Error::field_length_mismatch(
111 def.number,
112 len,
113 bytes.len(),
114 ));
115 }
116
117 let value = match def.field_type {
118 FieldType::Binary => FieldValue::from_binary(bytes[..len].to_vec()),
119 _ => {
120 let s = std::str::from_utf8(&bytes[..len]).map_err(|e| {
121 ISO8583Error::EncodingError(format!(
122 "Invalid UTF-8 in field {}: {}",
123 def.number, e
124 ))
125 })?;
126 FieldValue::from_string(s.to_string())
127 }
128 };
129
130 Ok((value, len))
131 }
132 FieldLength::LLVar(max_len) => {
133 if bytes.len() < 2 {
135 return Err(ISO8583Error::message_too_short(2, bytes.len()));
136 }
137
138 let length_str = std::str::from_utf8(&bytes[..2]).map_err(|e| {
139 ISO8583Error::EncodingError(format!(
140 "Invalid length indicator for field {}: {}",
141 def.number, e
142 ))
143 })?;
144 let length: usize = length_str.parse().map_err(|e| {
145 ISO8583Error::EncodingError(format!(
146 "Invalid length value for field {}: {}",
147 def.number, e
148 ))
149 })?;
150
151 if length > max_len {
152 return Err(ISO8583Error::invalid_field_value(
153 def.number,
154 format!(
155 "Length {} exceeds maximum {} for field {}",
156 length, max_len, def.number
157 ),
158 ));
159 }
160
161 if bytes.len() < 2 + length {
163 return Err(ISO8583Error::message_too_short(2 + length, bytes.len()));
164 }
165
166 let value = match def.field_type {
167 FieldType::Binary => FieldValue::from_binary(bytes[2..2 + length].to_vec()),
168 _ => {
169 let s = std::str::from_utf8(&bytes[2..2 + length]).map_err(|e| {
170 ISO8583Error::EncodingError(format!(
171 "Invalid UTF-8 in field {}: {}",
172 def.number, e
173 ))
174 })?;
175 FieldValue::from_string(s.to_string())
176 }
177 };
178
179 Ok((value, 2 + length))
180 }
181 FieldLength::LLLVar(max_len) => {
182 if bytes.len() < 3 {
184 return Err(ISO8583Error::message_too_short(3, bytes.len()));
185 }
186
187 let length_str = std::str::from_utf8(&bytes[..3]).map_err(|e| {
188 ISO8583Error::EncodingError(format!(
189 "Invalid length indicator for field {}: {}",
190 def.number, e
191 ))
192 })?;
193 let length: usize = length_str.parse().map_err(|e| {
194 ISO8583Error::EncodingError(format!(
195 "Invalid length value for field {}: {}",
196 def.number, e
197 ))
198 })?;
199
200 if length > max_len {
201 return Err(ISO8583Error::invalid_field_value(
202 def.number,
203 format!(
204 "Length {} exceeds maximum {} for field {}",
205 length, max_len, def.number
206 ),
207 ));
208 }
209
210 if bytes.len() < 3 + length {
212 return Err(ISO8583Error::message_too_short(3 + length, bytes.len()));
213 }
214
215 let value = match def.field_type {
216 FieldType::Binary => FieldValue::from_binary(bytes[3..3 + length].to_vec()),
217 _ => {
218 let s = std::str::from_utf8(&bytes[3..3 + length]).map_err(|e| {
219 ISO8583Error::EncodingError(format!(
220 "Invalid UTF-8 in field {}: {}",
221 def.number, e
222 ))
223 })?;
224 FieldValue::from_string(s.to_string())
225 }
226 };
227
228 Ok((value, 3 + length))
229 }
230 }
231 }
232
233 pub fn to_bytes(&self) -> Vec<u8> {
235 let mut bytes = Vec::new();
236
237 bytes.extend_from_slice(&self.mti.to_bytes());
239
240 let (bitmap_bytes, bitmap_len) = self.bitmap.to_bytes();
242 bytes.extend_from_slice(&bitmap_bytes[..bitmap_len]);
243
244 let mut field_numbers: Vec<u8> = self.fields.keys().copied().collect();
246 field_numbers.sort();
247
248 for field_num in field_numbers {
249 if field_num == 1 || field_num == 65 {
250 continue; }
252
253 if let Some(value) = self.fields.get(&field_num) {
254 let field = Field::from_number(field_num).unwrap();
255 let field_bytes = Self::generate_field(&field, value);
256 bytes.extend_from_slice(&field_bytes);
257 }
258 }
259
260 bytes
261 }
262
263 fn generate_field(field: &Field, value: &FieldValue) -> Vec<u8> {
265 let def = field.definition();
266 let mut bytes = Vec::new();
267
268 match def.length {
269 FieldLength::Fixed(len) => {
270 match value {
272 FieldValue::String(s) => {
273 let mut field_str = s.clone();
274 if field_str.len() < len {
276 match def.field_type {
278 FieldType::Numeric => {
279 field_str = format!("{:0>width$}", field_str, width = len);
280 }
281 _ => {
282 field_str = format!("{:<width$}", field_str, width = len);
283 }
284 }
285 } else if field_str.len() > len {
286 field_str.truncate(len);
287 }
288 bytes.extend_from_slice(field_str.as_bytes());
289 }
290 FieldValue::Binary(b) => {
291 let mut bin = b.clone();
292 bin.resize(len, 0); bytes.extend_from_slice(&bin);
294 }
295 }
296 }
297 FieldLength::LLVar(_max_len) => {
298 match value {
300 FieldValue::String(s) => {
301 let length = format!("{:02}", s.len());
302 bytes.extend_from_slice(length.as_bytes());
303 bytes.extend_from_slice(s.as_bytes());
304 }
305 FieldValue::Binary(b) => {
306 let length = format!("{:02}", b.len());
307 bytes.extend_from_slice(length.as_bytes());
308 bytes.extend_from_slice(b);
309 }
310 }
311 }
312 FieldLength::LLLVar(_max_len) => {
313 match value {
315 FieldValue::String(s) => {
316 let length = format!("{:03}", s.len());
317 bytes.extend_from_slice(length.as_bytes());
318 bytes.extend_from_slice(s.as_bytes());
319 }
320 FieldValue::Binary(b) => {
321 let length = format!("{:03}", b.len());
322 bytes.extend_from_slice(length.as_bytes());
323 bytes.extend_from_slice(b);
324 }
325 }
326 }
327 }
328
329 bytes
330 }
331
332 pub fn get_field(&self, field: Field) -> Option<&FieldValue> {
334 self.fields.get(&field.number())
335 }
336
337 pub fn set_field(&mut self, field: Field, value: FieldValue) -> Result<()> {
339 let field_num = field.number();
340
341 self.bitmap.set(field_num)?;
343
344 self.fields.insert(field_num, value);
346
347 Ok(())
348 }
349
350 pub fn remove_field(&mut self, field: Field) -> Result<()> {
352 let field_num = field.number();
353
354 self.bitmap.clear(field_num)?;
356
357 self.fields.remove(&field_num);
359
360 Ok(())
361 }
362
363 pub fn has_field(&self, field: Field) -> bool {
365 self.fields.contains_key(&field.number())
366 }
367
368 pub fn get_field_numbers(&self) -> Vec<u8> {
370 let mut numbers: Vec<u8> = self.fields.keys().copied().collect();
371 numbers.sort();
372 numbers
373 }
374
375 pub fn bitmap(&self) -> &Bitmap {
377 &self.bitmap
378 }
379
380 pub fn builder() -> MessageBuilder {
382 MessageBuilder::new()
383 }
384}
385
386#[derive(Debug)]
388pub struct MessageBuilder {
389 message: ISO8583Message,
390}
391
392impl MessageBuilder {
393 pub fn new() -> Self {
395 Self {
396 message: ISO8583Message::new(MessageType::AUTHORIZATION_REQUEST),
397 }
398 }
399
400 pub fn mti(mut self, mti: MessageType) -> Self {
402 self.message.mti = mti;
403 self
404 }
405
406 pub fn field<S: Into<String>>(mut self, field: Field, value: S) -> Self {
408 let _ = self
409 .message
410 .set_field(field, FieldValue::from_string(value.into()));
411 self
412 }
413
414 pub fn binary_field(mut self, field: Field, value: Vec<u8>) -> Self {
416 let _ = self
417 .message
418 .set_field(field, FieldValue::from_binary(value));
419 self
420 }
421
422 pub fn build(self) -> Result<ISO8583Message> {
424 crate::validation::Validator::validate_required_fields(&self.message)?;
426
427 Ok(self.message)
428 }
429}
430
431impl Default for MessageBuilder {
432 fn default() -> Self {
433 Self::new()
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn test_message_creation() {
443 let msg = ISO8583Message::new(MessageType::AUTHORIZATION_REQUEST);
444 assert_eq!(msg.mti, MessageType::AUTHORIZATION_REQUEST);
445 assert_eq!(msg.get_field_numbers().len(), 0);
446 }
447
448 #[test]
449 fn test_set_and_get_field() {
450 let mut msg = ISO8583Message::new(MessageType::AUTHORIZATION_REQUEST);
451
452 msg.set_field(
453 Field::PrimaryAccountNumber,
454 FieldValue::from_string("4111111111111111"),
455 )
456 .unwrap();
457
458 assert!(msg.has_field(Field::PrimaryAccountNumber));
459 let value = msg.get_field(Field::PrimaryAccountNumber).unwrap();
460 assert_eq!(value.as_string(), Some("4111111111111111"));
461 }
462
463 #[test]
464 fn test_remove_field() {
465 let mut msg = ISO8583Message::new(MessageType::AUTHORIZATION_REQUEST);
466
467 msg.set_field(
468 Field::PrimaryAccountNumber,
469 FieldValue::from_string("4111111111111111"),
470 )
471 .unwrap();
472
473 assert!(msg.has_field(Field::PrimaryAccountNumber));
474
475 msg.remove_field(Field::PrimaryAccountNumber).unwrap();
476
477 assert!(!msg.has_field(Field::PrimaryAccountNumber));
478 }
479
480 #[test]
481 fn test_builder() {
482 let msg = ISO8583Message::builder()
483 .mti(MessageType::FINANCIAL_REQUEST)
484 .field(Field::ProcessingCode, "000000")
485 .field(Field::SystemTraceAuditNumber, "123456")
486 .field(Field::LocalTransactionTime, "120000")
487 .field(Field::LocalTransactionDate, "0101");
488
489 assert!(msg.build().is_err());
492 }
493}