1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * Copyright 2006-2007 Jeremias Maerki.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::common::Result;
use crate::Exceptions;

use super::{
    high_level_encoder::{self, ASCII_ENCODATION, BASE256_ENCODATION},
    Encoder,
};

pub struct Base256Encoder;
impl Encoder for Base256Encoder {
    fn getEncodingMode(&self) -> usize {
        BASE256_ENCODATION
    }

    fn encode(&self, context: &mut super::EncoderContext) -> Result<()> {
        let mut buffer = String::new();
        buffer.push('\0'); //Initialize length field
        while context.hasMoreCharacters() {
            let c = context.getCurrentChar();
            buffer.push(c);

            context.pos += 1;

            let newMode = high_level_encoder::lookAheadTest(
                context.getMessage(),
                context.pos,
                self.getEncodingMode() as u32,
            );
            if newMode != self.getEncodingMode() {
                // Return to ASCII encodation, which will actually handle latch to new mode
                context.signalEncoderChange(ASCII_ENCODATION);
                break;
            }
        }
        let dataCount = buffer.chars().count() - 1;
        let lengthFieldSize = 1;
        let currentSize = context.getCodewordCount() + dataCount + lengthFieldSize;
        context.updateSymbolInfoWithLength(currentSize);
        let mustPad = (context
            .getSymbolInfo()
            .ok_or(Exceptions::illegalState)?
            .getDataCapacity()
            - currentSize as u32)
            > 0;
        if context.hasMoreCharacters() || mustPad {
            if dataCount <= 249 {
                buffer.replace_range(
                    0..1,
                    &char::from_u32(dataCount as u32)
                        .ok_or(Exceptions::parse)?
                        .to_string(),
                );
            } else if dataCount <= 1555 {
                buffer.replace_range(
                    0..1,
                    &char::from_u32((dataCount as u32 / 250) + 249)
                        .ok_or(Exceptions::parse)?
                        .to_string(),
                );
                let (ci_pos, _) = buffer
                    .char_indices()
                    .nth(1)
                    .ok_or(Exceptions::indexOutOfBounds)?;
                buffer.insert(
                    ci_pos,
                    char::from_u32(dataCount as u32 % 250).ok_or(Exceptions::indexOutOfBounds)?,
                );
            } else {
                return Err(Exceptions::illegalStateWith(format!(
                    "Message length not in valid ranges: {dataCount}"
                )));
            }
        }
        let c = buffer.chars().count();
        for i in 0..c {
            // for (int i = 0, c = buffer.length(); i < c; i++) {
            context.writeCodeword(
                Self::randomize255State(
                    buffer.chars().nth(i).ok_or(Exceptions::indexOutOfBounds)?,
                    context.getCodewordCount() as u32 + 1,
                )
                .ok_or(Exceptions::parse)? as u8,
            );
        }
        Ok(())
    }
}
impl Base256Encoder {
    pub fn new() -> Self {
        Self
    }
    fn randomize255State(ch: char, codewordPosition: u32) -> Option<char> {
        let pseudoRandom = ((149 * codewordPosition) % 255) + 1;
        let tempVariable = ch as u32 + pseudoRandom;
        if tempVariable <= 255 {
            char::from_u32(tempVariable)
        } else {
            char::from_u32(tempVariable - 256)
        }
    }
}

impl Default for Base256Encoder {
    fn default() -> Self {
        Self::new()
    }
}