rxing/datamatrix/encoder/
x12_encoder.rs

1/*
2 * Copyright 2006-2007 Jeremias Maerki.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::common::Result;
18use crate::Exceptions;
19
20use super::{high_level_encoder, C40Encoder, Encoder, EncoderContext};
21
22pub struct X12Encoder(C40Encoder);
23impl Encoder for X12Encoder {
24    fn getEncodingMode(&self) -> usize {
25        high_level_encoder::X12_ENCODATION
26    }
27
28    fn encode(&self, context: &mut super::EncoderContext) -> Result<()> {
29        //step C
30        let mut buffer = String::new();
31        while context.hasMoreCharacters() {
32            let c = context.getCurrentChar();
33            context.pos += 1;
34
35            Self::encodeChar(c, &mut buffer)?;
36
37            let count = buffer.chars().count();
38            if (count % 3) == 0 {
39                C40Encoder::writeNextTriplet(context, &mut buffer)?;
40
41                let newMode = high_level_encoder::lookAheadTest(
42                    context.getMessage(),
43                    context.pos,
44                    self.getEncodingMode() as u32,
45                );
46                if newMode != self.getEncodingMode() {
47                    // Return to ASCII encodation, which will actually handle latch to new mode
48                    context.signalEncoderChange(high_level_encoder::ASCII_ENCODATION);
49                    break;
50                }
51            }
52        }
53        Self::handleEOD(context, &mut buffer)?;
54        Ok(())
55    }
56}
57impl X12Encoder {
58    pub fn new() -> Self {
59        Self(C40Encoder::new())
60    }
61
62    fn encodeChar(c: char, sb: &mut String) -> Result<u32> {
63        match c {
64            '\r' => sb.push('\0'),
65            '*' => sb.push('\u{1}'),
66            '>' => sb.push('\u{2}'),
67            ' ' => sb.push('\u{3}'),
68            _ => {
69                if c.is_ascii_digit() {
70                    sb.push((c as u8 - 48 + 4) as char);
71                } else if c.is_ascii_uppercase() {
72                    sb.push((c as u8 - 65 + 14) as char);
73                } else {
74                    high_level_encoder::illegalCharacter(c)?;
75                }
76            }
77        }
78        Ok(1)
79    }
80
81    fn handleEOD(context: &mut EncoderContext, buffer: &mut str) -> Result<()> {
82        context.updateSymbolInfo();
83        let available = context
84            .getSymbolInfo()
85            .ok_or(Exceptions::ILLEGAL_STATE)?
86            .getDataCapacity()
87            - context.getCodewordCount() as u32;
88        let count = buffer.chars().count();
89        context.pos -= count as u32;
90        if context.getRemainingCharacters() > 1
91            || available > 1
92            || context.getRemainingCharacters() != available
93        {
94            context.writeCodeword(high_level_encoder::X12_UNLATCH);
95        }
96        if context.getNewEncoding().is_none() {
97            context.signalEncoderChange(high_level_encoder::ASCII_ENCODATION);
98        }
99        Ok(())
100    }
101}
102
103impl Default for X12Encoder {
104    fn default() -> Self {
105        Self::new()
106    }
107}