rxing/datamatrix/encoder/minimal_encoder.rs
1/*
2 * Copyright 2021 ZXing authors
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 std::{fmt, sync::Arc};
18
19use crate::{
20 common::{CharacterSet, ECIInput, Eci, MinimalECIInput, Result},
21 Exceptions,
22};
23
24use super::{high_level_encoder, SymbolShapeHint};
25
26const ISO_8859_1_ENCODER: CharacterSet = CharacterSet::ISO8859_1;
27
28/**
29 * Encoder that encodes minimally
30 *
31 * Algorithm:
32 *
33 * Uses Dijkstra to produce mathematically minimal encodings that are in some cases smaller than the results produced
34 * by the algorithm described in annex S in the specification ISO/IEC 16022:200(E). The biggest improvment of this
35 * algorithm over that one is the case when the algorithm enters the most inefficient mode, the B256 Mode:: The
36 * algorithm from the specification algorithm will exit this mode only if it encounters digits so that arbitrarily
37 * inefficient results can be produced if the postfix contains no digits.
38 *
39 * Multi ECI support and ECI switching:
40 *
41 * For multi language content the algorithm selects the most compact representation using ECI modes. Note that unlike
42 * the compaction algorithm used for QR-Codes, this implementation operates in two stages and therfore is not
43 * mathematically optimal. In the first stage, the input string is encoded minimally as a stream of ECI character set
44 * selectors and bytes encoded in the selected encoding. In this stage the algorithm might for example decide to
45 * encode ocurrences of the characters "\u0150\u015C" (O-double-acute, S-circumflex) in UTF-8 by a single ECI or
46 * alternatively by multiple ECIs that switch between IS0-8859-2 and ISO-8859-3 (e.g. in the case that the input
47 * contains many * characters from ISO-8859-2 (Latin 2) and few from ISO-8859-3 (Latin 3)).
48 * In a second stage this stream of ECIs and bytes is minimally encoded using the various Data Matrix encoding modes.
49 * While both stages encode mathematically minimally it is not ensured that the result is mathematically minimal since
50 * the size growth for inserting an ECI in the first stage can only be approximated as the first stage does not know
51 * in which mode the ECI will occur in the second stage (may, or may not require an extra latch to ASCII depending on
52 * the current mode). The reason for this shortcoming are difficulties in implementing it in a straightforward and
53 * readable manner.
54 *
55 * GS1 support
56 *
57 * FNC1 delimiters can be encoded in the input string by using the FNC1 character specified in the encoding function.
58 * When a FNC1 character is specified then a leading FNC1 will be encoded and all ocurrences of delimiter characters
59 * while result in FNC1 codewords in the symbol.
60 *
61 * @author Alex Geller
62 */
63
64#[derive(Debug, Copy, Clone, PartialEq, Eq)]
65enum Mode {
66 Ascii,
67 C40,
68 Text,
69 X12,
70 Edf,
71 B256,
72}
73
74impl Mode {
75 pub fn ordinal(&self) -> usize {
76 match self {
77 Mode::Ascii => 0,
78 Mode::C40 => 1,
79 Mode::Text => 2,
80 Mode::X12 => 3,
81 Mode::Edf => 4,
82 Mode::B256 => 5,
83 }
84 }
85}
86
87const C40_SHIFT2_CHARS: [char; 27] = [
88 '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=',
89 '>', '?', '@', '[', '\\', ']', '^', '_',
90];
91
92pub fn isExtendedASCII(ch: char, fnc1: Option<char>) -> bool {
93 let is_fnc1 = if let Some(fnc1) = fnc1 {
94 ch != fnc1
95 } else {
96 true
97 };
98 is_fnc1 && ch as u8 >= 128 //&& ch as u8 <= 255
99 // return ch != fnc1 && ch as u8 >= 128 && ch as u8 <= 255;
100}
101
102#[inline]
103fn isInC40Shift1Set(ch: char) -> bool {
104 ch as u8 <= 31
105}
106
107fn isInC40Shift2Set(ch: char, fnc1: Option<char>) -> bool {
108 for c40Shift2Char in C40_SHIFT2_CHARS {
109 // for (char c40Shift2Char : C40_SHIFT2_CHARS) {
110 if c40Shift2Char == ch {
111 return true;
112 }
113 }
114 if let Some(fnc1) = fnc1 {
115 ch == fnc1
116 } else {
117 false
118 }
119 // return ch as u8 as i32 == fnc1;
120}
121
122fn isInTextShift1Set(ch: char) -> bool {
123 isInC40Shift1Set(ch)
124}
125
126fn isInTextShift2Set(ch: char, fnc1: Option<char>) -> bool {
127 isInC40Shift2Set(ch, fnc1)
128}
129
130/**
131 * Performs message encoding of a DataMatrix message
132 *
133 * @param msg the message
134 * @return the encoded message (the char values range from 0 to 255)
135 */
136pub fn encodeHighLevel(msg: &str) -> Result<String> {
137 encodeHighLevelWithDetails(msg, None, None, SymbolShapeHint::FORCE_NONE)
138}
139
140/**
141 * Performs message encoding of a DataMatrix message
142 *
143 * @param msg the message
144 * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
145 * chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
146 * charset to encode any character in the input that can be encoded by it if the charset is among the
147 * supported charsets.
148 * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not a GS1
149 * bar code. If the value is not -1 then a FNC1 is also prepended.
150 * @param shape requested shape.
151 * @return the encoded message (the char values range from 0 to 255)
152 */
153pub fn encodeHighLevelWithDetails(
154 msg: &str,
155 priorityCharset: Option<CharacterSet>,
156 fnc1: Option<char>,
157 shape: SymbolShapeHint,
158) -> Result<String> {
159 let mut msg = msg;
160 let mut macroId = 0;
161 if msg.starts_with(high_level_encoder::MACRO_05_HEADER)
162 && msg.ends_with(high_level_encoder::MACRO_TRAILER)
163 {
164 macroId = 5;
165 // msg = msg.substring(high_level_encoder::MACRO_05_HEADER.len(), msg.len() - 2);
166 msg = &msg[high_level_encoder::MACRO_05_HEADER.chars().count()..(msg.chars().count() - 2)];
167 } else if msg.starts_with(high_level_encoder::MACRO_06_HEADER)
168 && msg.ends_with(high_level_encoder::MACRO_TRAILER)
169 {
170 macroId = 6;
171 // msg = msg.substring(high_level_encoder::MACRO_06_HEADER.len(), msg.len() - 2);
172 msg = &msg[high_level_encoder::MACRO_06_HEADER.chars().count()..(msg.chars().count() - 2)];
173 }
174 Ok(ISO_8859_1_ENCODER
175 .decode(&encode(msg, priorityCharset, fnc1, shape, macroId)?)
176 .expect("should decode"))
177 // return new String(encode(msg, priorityCharset, fnc1, shape, macroId), StandardCharsets.ISO_8859_1);
178}
179
180/**
181 * Encodes input minimally and returns an array of the codewords
182 *
183 * @param input The string to encode
184 * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm
185 * chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority
186 * charset to encode any character in the input that can be encoded by it if the charset is among the
187 * supported charsets.
188 * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not a GS1
189 * bar code. If the value is not -1 then a FNC1 is also prepended.
190 * @param shape requested shape.
191 * @param macroId Prepends the specified macro function in case that a value of 5 or 6 is specified.
192 * @return An array of bytes representing the codewords of a minimal encoding.
193 */
194fn encode(
195 input: &str,
196 priorityCharset: Option<CharacterSet>,
197 fnc1: Option<char>,
198 shape: SymbolShapeHint,
199 macroId: i32,
200) -> Result<Vec<u8>> {
201 Ok(encodeMinimally(Arc::new(Input::new(
202 input,
203 priorityCharset,
204 fnc1,
205 shape,
206 macroId,
207 )))?
208 .getBytes()
209 .to_vec())
210}
211
212fn addEdge(edges: &mut [Vec<Option<Arc<Edge>>>], edge: Arc<Edge>) -> Result<()> {
213 let vertexIndex = (edge.fromPosition + edge.characterLength) as usize;
214 if edges[vertexIndex][edge.getEndMode()?.ordinal()].is_none()
215 || edges[vertexIndex][edge.getEndMode()?.ordinal()]
216 .as_ref()
217 .ok_or(Exceptions::ILLEGAL_STATE)?
218 .cachedTotalSize
219 > edge.cachedTotalSize
220 {
221 edges[vertexIndex][edge.getEndMode()?.ordinal()] = Some(edge.clone());
222 }
223 Ok(())
224}
225
226/** @return the number of words in which the string starting at from can be encoded in c40 or text Mode::
227 * The number of characters encoded is returned in characterLength.
228 * The number of characters encoded is also minimal in the sense that the algorithm stops as soon
229 * as a character encoding fills a C40 word competely (three C40 values). An exception is at the
230 * end of the string where two C40 values are allowed (according to the spec the third c40 value
231 * is filled with 0 (Shift 1) in this case).
232 */
233fn getNumberOfC40Words(
234 input: Arc<Input>,
235 from: u32,
236 c40: bool,
237 characterLength: &mut [u32],
238) -> Result<u32> {
239 let mut thirdsCount = 0;
240 for i in (from as usize)..input.length() {
241 // for (int i = from; i < input.length(); i++) {
242 if input.isECI(i as u32)? {
243 characterLength[0] = 0;
244 return Ok(0);
245 }
246 let ci = input.charAt(i)?;
247 if c40 && high_level_encoder::isNativeC40(ci)
248 || !c40 && high_level_encoder::isNativeText(ci)
249 {
250 thirdsCount += 1; //native
251 } else if !isExtendedASCII(ci, input.getFNC1Character()) {
252 thirdsCount += 2; //shift
253 } else {
254 let asciiValue = ci as u8;
255 if asciiValue >= 128
256 && (c40 && high_level_encoder::isNativeC40((asciiValue - 128) as char)
257 || !c40 && high_level_encoder::isNativeText((asciiValue - 128) as char))
258 {
259 thirdsCount += 3; // shift, Upper shift
260 } else {
261 thirdsCount += 4; // shift, Upper shift, shift
262 }
263 }
264
265 if thirdsCount % 3 == 0 || ((thirdsCount - 2) % 3 == 0 && i + 1 == input.length()) {
266 characterLength[0] = i as u32 - from + 1;
267 // return (int) Math.ceil(((double) thirdsCount) / 3.0);
268 return Ok(((thirdsCount as f64) / 3.0).ceil() as u32);
269 }
270 }
271 characterLength[0] = 0;
272
273 Ok(0)
274}
275
276fn addEdges(
277 input: Arc<Input>,
278 edges: &mut [Vec<Option<Arc<Edge>>>],
279 from: u32,
280 previous: Option<Arc<Edge>>,
281) -> Result<()> {
282 if input.isECI(from)? {
283 addEdge(
284 edges,
285 Arc::new(Edge::new(input, Mode::Ascii, from, 1, previous)?),
286 )?;
287 return Ok(());
288 }
289
290 let ch = input.charAt(from as usize)?;
291 if previous.is_none() || previous.as_ref().unwrap().getEndMode()? != Mode::Edf {
292 //not possible to unlatch a full EDF edge to something
293 //else
294 if high_level_encoder::isDigit(ch)
295 && input.haveNCharacters(from as usize, 2)?
296 && high_level_encoder::isDigit(input.charAt(from as usize + 1)?)
297 {
298 // two digits ASCII encoded
299 addEdge(
300 edges,
301 Arc::new(Edge::new(
302 input.clone(),
303 Mode::Ascii,
304 from,
305 2,
306 previous.clone(),
307 )?),
308 )?;
309 } else {
310 // one ASCII encoded character or an extended character via Upper Shift
311 addEdge(
312 edges,
313 Arc::new(Edge::new(
314 input.clone(),
315 Mode::Ascii,
316 from,
317 1,
318 previous.clone(),
319 )?),
320 )?;
321 }
322
323 let modes = [Mode::C40, Mode::Text];
324 for mode in modes {
325 // for (Mode mode : modes) {
326 let mut characterLength = [0u32; 1];
327 if getNumberOfC40Words(input.clone(), from, mode == Mode::C40, &mut characterLength)?
328 > 0
329 {
330 addEdge(
331 edges,
332 Arc::new(Edge::new(
333 input.clone(),
334 mode,
335 from,
336 characterLength[0],
337 previous.clone(),
338 )?),
339 )?;
340 }
341 }
342
343 if input.haveNCharacters(from as usize, 3)?
344 && high_level_encoder::isNativeX12(input.charAt(from as usize)?)
345 && high_level_encoder::isNativeX12(input.charAt(from as usize + 1)?)
346 && high_level_encoder::isNativeX12(input.charAt(from as usize + 2)?)
347 {
348 addEdge(
349 edges,
350 Arc::new(Edge::new(
351 input.clone(),
352 Mode::X12,
353 from,
354 3,
355 previous.clone(),
356 )?),
357 )?;
358 }
359
360 addEdge(
361 edges,
362 Arc::new(Edge::new(
363 input.clone(),
364 Mode::B256,
365 from,
366 1,
367 previous.clone(),
368 )?),
369 )?;
370 }
371
372 //We create 4 EDF edges, with 1, 2 3 or 4 characters length. The fourth normally doesn't have a latch to ASCII
373 //unless it is 2 characters away from the end of the input.
374 let mut i: u32 = 0;
375 while i < 3 {
376 // for (i = 0; i < 3; i++) {
377 let pos = from + i;
378 if input.haveNCharacters(pos as usize, 1)?
379 && high_level_encoder::isNativeEDIFACT(input.charAt(pos as usize)?)
380 {
381 addEdge(
382 edges,
383 Arc::new(Edge::new(
384 input.clone(),
385 Mode::Edf,
386 from,
387 i + 1,
388 previous.clone(),
389 )?),
390 )?;
391 } else {
392 break;
393 }
394 i += 1;
395 }
396 if i == 3
397 && input.haveNCharacters(from as usize, 4)?
398 && high_level_encoder::isNativeEDIFACT(input.charAt(from as usize + 3)?)
399 {
400 addEdge(
401 edges,
402 Arc::new(Edge::new(input, Mode::Edf, from, 4, previous)?),
403 )?;
404 }
405 Ok(())
406}
407
408fn encodeMinimally(input: Arc<Input>) -> Result<RXingResult> {
409 // @SuppressWarnings("checkstyle:lineLength")
410 /* The minimal encoding is computed by Dijkstra. The acyclic graph is modeled as follows:
411 * A vertex represents a combination of a position in the input and an encoding mode where position 0
412 * denotes the position left of the first character, 1 the position left of the second character and so on.
413 * Likewise the end vertices are located after the last character at position input.length().
414 * For any position there might be up to six vertices, one for each of the encoding types ASCII, C40, TEXT, X12,
415 * EDF and B256.
416 *
417 * As an example consider the input string "ABC123" then at position 0 there is only one vertex with the default
418 * ASCII encodation. At position 3 there might be vertices for the types ASCII, C40, X12, EDF and B256.
419 *
420 * An edge leading to such a vertex encodes one or more of the characters left of the position that the vertex
421 * represents. It encodes the characters in the encoding mode of the vertex that it ends on. In other words,
422 * all edges leading to a particular vertex encode the same characters (the length of the suffix can vary) using the same
423 * encoding Mode::
424 * As an example consider the input string "ABC123" and the vertex (4,EDF). Possible edges leading to this vertex
425 * are:
426 * (0,ASCII) --EDF(ABC1)--> (4,EDF)
427 * (1,ASCII) --EDF(BC1)--> (4,EDF)
428 * (1,B256) --EDF(BC1)--> (4,EDF)
429 * (1,EDF) --EDF(BC1)--> (4,EDF)
430 * (2,ASCII) --EDF(C1)--> (4,EDF)
431 * (2,B256) --EDF(C1)--> (4,EDF)
432 * (2,EDF) --EDF(C1)--> (4,EDF)
433 * (3,ASCII) --EDF(1)--> (4,EDF)
434 * (3,B256) --EDF(1)--> (4,EDF)
435 * (3,EDF) --EDF(1)--> (4,EDF)
436 * (3,C40) --EDF(1)--> (4,EDF)
437 * (3,X12) --EDF(1)--> (4,EDF)
438 *
439 * The edges leading to a vertex are stored in such a way that there is a fast way to enumerate the edges ending
440 * on a particular vertex.
441 *
442 * The algorithm processes the vertices in order of their position thereby performing the following:
443 *
444 * For every vertex at position i the algorithm enumerates the edges ending on the vertex and removes all but the
445 * shortest from that list.
446 * Then it processes the vertices for the position i+1. If i+1 == input.length() then the algorithm ends
447 * and chooses the the edge with the smallest size from any of the edges leading to vertices at this position.
448 * Otherwise the algorithm computes all possible outgoing edges for the vertices at the position i+1
449 *
450 * Examples:
451 * The process is illustrated by showing the graph (edges) after each iteration from left to right over the input:
452 * An edge is drawn as follows "(" + fromVertex + ") -- " + encodingMode + "(" + encodedInput + ") (" +
453 * accumulatedSize + ") --> (" + toVertex + ")"
454 *
455 * Example 1 encoding the string "ABCDEFG":
456 *
457 *
458 * Situation after adding edges to the start vertex (0,ASCII)
459 * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
460 * (0,ASCII) B256(A) (3) --> (1,B256)
461 * (0,ASCII) EDF(AB) (4) --> (2,EDF)
462 * (0,ASCII) C40(ABC) (3) --> (3,C40)
463 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
464 * (0,ASCII) X12(ABC) (3) --> (3,X12)
465 * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
466 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
467 *
468 * Situation after adding edges to vertices at position 1
469 * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
470 * (0,ASCII) B256(A) (3) --> (1,B256)
471 * (0,ASCII) EDF(AB) (4) --> (2,EDF)
472 * (0,ASCII) C40(ABC) (3) --> (3,C40)
473 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
474 * (0,ASCII) X12(ABC) (3) --> (3,X12)
475 * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
476 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
477 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII)
478 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) B256(B) (4) --> (2,B256)
479 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BC) (5) --> (3,EDF)
480 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40)
481 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT)
482 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12)
483 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCD) (5) --> (4,EDF)
484 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF)
485 * (0,ASCII) B256(A) (3) --> (1,B256) ASCII(B) (4) --> (2,ASCII)
486 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256)
487 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BC) (6) --> (3,EDF)
488 * (0,ASCII) B256(A) (3) --> (1,B256) C40(BCD) (5) --> (4,C40)
489 * (0,ASCII) B256(A) (3) --> (1,B256) TEXT(BCD) (7) --> (4,TEXT)
490 * (0,ASCII) B256(A) (3) --> (1,B256) X12(BCD) (5) --> (4,X12)
491 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCD) (6) --> (4,EDF)
492 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCDE) (6) --> (5,EDF)
493 *
494 * Edge "(1,ASCII) ASCII(B) (2) --> (2,ASCII)" is minimal for the vertex (2,ASCII) so that edge "(1,B256) ASCII(B) (4) --> (2,ASCII)" is removed.
495 * Edge "(1,B256) B256(B) (3) --> (2,B256)" is minimal for the vertext (2,B256) so that the edge "(1,ASCII) B256(B) (4) --> (2,B256)" is removed.
496 *
497 * Situation after adding edges to vertices at position 2
498 * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
499 * (0,ASCII) B256(A) (3) --> (1,B256)
500 * (0,ASCII) EDF(AB) (4) --> (2,EDF)
501 * (0,ASCII) C40(ABC) (3) --> (3,C40)
502 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
503 * (0,ASCII) X12(ABC) (3) --> (3,X12)
504 * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
505 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
506 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII)
507 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BC) (5) --> (3,EDF)
508 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40)
509 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT)
510 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12)
511 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCD) (5) --> (4,EDF)
512 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF)
513 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256)
514 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BC) (6) --> (3,EDF)
515 * (0,ASCII) B256(A) (3) --> (1,B256) C40(BCD) (5) --> (4,C40)
516 * (0,ASCII) B256(A) (3) --> (1,B256) TEXT(BCD) (7) --> (4,TEXT)
517 * (0,ASCII) B256(A) (3) --> (1,B256) X12(BCD) (5) --> (4,X12)
518 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCD) (6) --> (4,EDF)
519 * (0,ASCII) B256(A) (3) --> (1,B256) EDF(BCDE) (6) --> (5,EDF)
520 * (0,ASCII) EDF(AB) (4) --> (2,EDF) ASCII(C) (5) --> (3,ASCII)
521 * (0,ASCII) EDF(AB) (4) --> (2,EDF) B256(C) (6) --> (3,B256)
522 * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CD) (7) --> (4,EDF)
523 * (0,ASCII) EDF(AB) (4) --> (2,EDF) C40(CDE) (6) --> (5,C40)
524 * (0,ASCII) EDF(AB) (4) --> (2,EDF) TEXT(CDE) (8) --> (5,TEXT)
525 * (0,ASCII) EDF(AB) (4) --> (2,EDF) X12(CDE) (6) --> (5,X12)
526 * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CDE) (7) --> (5,EDF)
527 * (0,ASCII) EDF(AB) (4) --> (2,EDF) EDF(CDEF) (7) --> (6,EDF)
528 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII)
529 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) B256(C) (5) --> (3,B256)
530 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CD) (6) --> (4,EDF)
531 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) C40(CDE) (5) --> (5,C40)
532 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) TEXT(CDE) (7) --> (5,TEXT)
533 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) X12(CDE) (5) --> (5,X12)
534 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDE) (6) --> (5,EDF)
535 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDEF) (6) --> (6,EDF)
536 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) ASCII(C) (4) --> (3,ASCII)
537 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256)
538 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CD) (6) --> (4,EDF)
539 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) C40(CDE) (5) --> (5,C40)
540 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) TEXT(CDE) (7) --> (5,TEXT)
541 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) X12(CDE) (5) --> (5,X12)
542 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CDE) (6) --> (5,EDF)
543 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) EDF(CDEF) (6) --> (6,EDF)
544 *
545 * Edge "(2,ASCII) ASCII(C) (3) --> (3,ASCII)" is minimal for the vertex (3,ASCII) so that edges "(2,EDF) ASCII(C) (5) --> (3,ASCII)"
546 * and "(2,B256) ASCII(C) (4) --> (3,ASCII)" can be removed.
547 * Edge "(0,ASCII) EDF(ABC) (4) --> (3,EDF)" is minimal for the vertex (3,EDF) so that edges "(1,ASCII) EDF(BC) (5) --> (3,EDF)"
548 * and "(1,B256) EDF(BC) (6) --> (3,EDF)" can be removed.
549 * Edge "(2,B256) B256(C) (4) --> (3,B256)" is minimal for the vertex (3,B256) so that edges "(2,ASCII) B256(C) (5) --> (3,B256)"
550 * and "(2,EDF) B256(C) (6) --> (3,B256)" can be removed.
551 *
552 * This continues for vertices 3 thru 7
553 *
554 * Situation after adding edges to vertices at position 7
555 * (0,ASCII) ASCII(A) (1) --> (1,ASCII)
556 * (0,ASCII) B256(A) (3) --> (1,B256)
557 * (0,ASCII) EDF(AB) (4) --> (2,EDF)
558 * (0,ASCII) C40(ABC) (3) --> (3,C40)
559 * (0,ASCII) TEXT(ABC) (5) --> (3,TEXT)
560 * (0,ASCII) X12(ABC) (3) --> (3,X12)
561 * (0,ASCII) EDF(ABC) (4) --> (3,EDF)
562 * (0,ASCII) EDF(ABCD) (4) --> (4,EDF)
563 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII)
564 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40)
565 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) TEXT(BCD) (6) --> (4,TEXT)
566 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12)
567 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) EDF(BCDE) (5) --> (5,EDF)
568 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256)
569 * (0,ASCII) C40(ABC) (3) --> (3,C40) C40(DEF) (5) --> (6,C40)
570 * (0,ASCII) X12(ABC) (3) --> (3,X12) X12(DEF) (5) --> (6,X12)
571 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII)
572 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) C40(CDE) (5) --> (5,C40)
573 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) TEXT(CDE) (7) --> (5,TEXT)
574 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) X12(CDE) (5) --> (5,X12)
575 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) EDF(CDEF) (6) --> (6,EDF)
576 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) C40(BCD) (4) --> (4,C40) C40(EFG) (6) --> (7,C40) //Solution 1
577 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) X12(BCD) (4) --> (4,X12) X12(EFG) (6) --> (7,X12) //Solution 2
578 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256)
579 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII)
580 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) TEXT(DEF) (8) --> (6,TEXT)
581 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) EDF(DEFG) (7) --> (7,EDF)
582 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256)
583 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII)
584 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) TEXT(EFG) (9) --> (7,TEXT)
585 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256)
586 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) ASCII(F) (6) --> (6,ASCII)
587 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) B256(F) (7) --> (6,B256)
588 * (0,ASCII) ASCII(A) (1) --> (1,ASCII) ASCII(B) (2) --> (2,ASCII) ASCII(C) (3) --> (3,ASCII) ASCII(D) (4) --> (4,ASCII) ASCII(E) (5) --> (5,ASCII) ASCII(F) (6) --> (6,ASCII) ASCII(G) (7) --> (7,ASCII)
589 * (0,ASCII) B256(A) (3) --> (1,B256) B256(B) (3) --> (2,B256) B256(C) (4) --> (3,B256) B256(D) (5) --> (4,B256) B256(E) (6) --> (5,B256) B256(F) (7) --> (6,B256) B256(G) (8) --> (7,B256)
590 *
591 * Hence a minimal encoding of "ABCDEFG" is either ASCII(A),C40(BCDEFG) or ASCII(A), X12(BCDEFG) with a size of 5 bytes.
592 */
593
594 let inputLength = input.length();
595
596 // Array that represents vertices. There is a vertex for every character and Mode::
597 // The last dimension in the array below encodes the 6 modes ASCII, C40, TEXT, X12, EDF and B256
598 // let edges = new Edge[inputLength + 1][6];
599 let mut edges = vec![vec![None; 6]; inputLength + 1];
600 addEdges(input.clone(), &mut edges, 0, None)?;
601
602 for i in 1..=inputLength {
603 for j in 0..6 {
604 if edges[i][j].is_some() && i < inputLength {
605 let edge = edges[i][j].clone();
606 addEdges(input.clone(), &mut edges, i as u32, edge)?;
607 }
608 }
609 //optimize memory by removing edges that have been passed.
610 edges[i - 1][..6].fill(None);
611 }
612
613 let mut minimalJ: i32 = -1;
614 let mut minimalSize = i32::MAX;
615 for j in 0..6 {
616 if let Some(edge) = &edges[inputLength][j] {
617 // if edges[inputLength][j].is_some() {
618 // let edge = edges[inputLength][j].as_ref().unwrap();
619 let size = if (1..=3).contains(&j) {
620 edge.cachedTotalSize + 1
621 } else {
622 edge.cachedTotalSize
623 }; //C40, TEXT and X12 need an
624 // extra unlatch at the end
625 if (size as i32) < minimalSize {
626 minimalSize = size as i32;
627 minimalJ = j as i32;
628 }
629 }
630 }
631
632 if minimalJ < 0 {
633 return Err(Exceptions::illegal_state_with(format!(
634 "Internal error: failed to encode \"{input}\""
635 )));
636 }
637 RXingResult::new(edges[inputLength][minimalJ as usize].clone())
638}
639
640const ALL_CODEWORD_CAPACITIES: [u32; 28] = [
641 3, 5, 8, 10, 12, 16, 18, 22, 30, 32, 36, 44, 49, 62, 86, 114, 144, 174, 204, 280, 368, 456,
642 576, 696, 816, 1050, 1304, 1558,
643];
644const SQUARE_CODEWORD_CAPACITIES: [u32; 24] = [
645 3, 5, 8, 12, 18, 22, 30, 36, 44, 62, 86, 114, 144, 174, 204, 280, 368, 456, 576, 696, 816,
646 1050, 1304, 1558,
647];
648const RECTANGULAR_CODEWORD_CAPACITIES: [u32; 6] = [5, 10, 16, 33, 32, 49];
649
650struct Edge {
651 input: Arc<Input>,
652 mode: Mode, //the mode at the start of this edge.
653 fromPosition: u32,
654 characterLength: u32,
655 previous: Option<Arc<Edge>>,
656 cachedTotalSize: u32,
657}
658impl Edge {
659 fn new(
660 input: Arc<Input>,
661 mode: Mode,
662 fromPosition: u32,
663 characterLength: u32,
664 previous: Option<Arc<Edge>>,
665 ) -> Result<Self> {
666 if fromPosition + characterLength > input.length() as u32 {
667 return Err(Exceptions::FORMAT);
668 }
669
670 let mut size = if let Some(previous) = previous.clone() {
671 previous.cachedTotalSize
672 } else {
673 0
674 };
675
676 let previousMode = Self::getPreviousMode(previous.clone())?;
677
678 /*
679 * Switching modes
680 * ASCII -> C40: latch 230
681 * ASCII -> TEXT: latch 239
682 * ASCII -> X12: latch 238
683 * ASCII -> EDF: latch 240
684 * ASCII -> B256: latch 231
685 * C40 -> ASCII: word(c1,c2,c3), 254
686 * TEXT -> ASCII: word(c1,c2,c3), 254
687 * X12 -> ASCII: word(c1,c2,c3), 254
688 * EDIFACT -> ASCII: Unlatch character,0,0,0 or c1,Unlatch character,0,0 or c1,c2,Unlatch character,0 or
689 * c1,c2,c3,Unlatch character
690 * B256 -> ASCII: without latch after n bytes
691 */
692 match mode {
693 Mode::Ascii => {
694 size += 1;
695 if input.isECI(fromPosition)?
696 || isExtendedASCII(
697 input.charAt(fromPosition as usize)?,
698 input.getFNC1Character(),
699 )
700 {
701 size += 1;
702 }
703 if previousMode == Mode::C40
704 || previousMode == Mode::Text
705 || previousMode == Mode::X12
706 {
707 size += 1; // unlatch 254 to ASCII
708 }
709 }
710 Mode::B256 => {
711 size += 1;
712 if previousMode != Mode::B256 || Self::getB256Size(mode, previous.clone()) == 250 {
713 size += 1; //byte count
714 }
715 // } else if Self::getB256Size(mode, previous.clone()) == 250 {
716 // size += 1; //extra byte count
717 // }
718 if previousMode == Mode::Ascii {
719 size += 1; //latch to B256
720 } else if previousMode == Mode::C40
721 || previousMode == Mode::Text
722 || previousMode == Mode::X12
723 {
724 size += 2; //unlatch to ASCII, latch to B256
725 }
726 }
727 Mode::C40 | Mode::Text | Mode::X12 => {
728 if mode == Mode::X12 {
729 size += 2;
730 } else {
731 let mut charLen = [0u32; 1];
732 size += getNumberOfC40Words(
733 input.clone(),
734 fromPosition,
735 mode == Mode::C40,
736 &mut charLen,
737 )? * 2;
738 }
739
740 if previousMode == Mode::Ascii || previousMode == Mode::B256 {
741 size += 1; //additional byte for latch from ASCII to this mode
742 } else if previousMode != mode
743 && (previousMode == Mode::C40
744 || previousMode == Mode::Text
745 || previousMode == Mode::X12)
746 {
747 size += 2; //unlatch 254 to ASCII followed by latch to this mode
748 }
749 }
750 Mode::Edf => {
751 size += 3;
752 if previousMode == Mode::Ascii || previousMode == Mode::B256 {
753 size += 1; //additional byte for latch from ASCII to this mode
754 } else if previousMode == Mode::C40
755 || previousMode == Mode::Text
756 || previousMode == Mode::X12
757 {
758 size += 2; //unlatch 254 to ASCII followed by latch to this mode
759 }
760 }
761 }
762 Ok(Self {
763 input,
764 mode,
765 fromPosition,
766 characterLength,
767 previous,
768 cachedTotalSize: size,
769 })
770 // cachedTotalSize = size;
771 }
772
773 // does not count beyond 250
774 pub fn getB256Size(mode: Mode, previous: Option<Arc<Edge>>) -> u32 {
775 if mode != Mode::B256 {
776 return 0;
777 }
778 let mut cnt = 1;
779 let mut current = previous;
780 while current.is_some() && current.as_ref().unwrap().mode == Mode::B256 && cnt <= 250 {
781 cnt += 1;
782 current.clone_from(¤t.clone().as_ref().unwrap().previous);
783 }
784 // let cnt = 0;
785 // Edge current = this;
786 // while (current != null && current.mode == Mode::B256 && cnt <= 250) {
787 // cnt+=1;
788 // current = current.previous;
789 // }
790 cnt
791 }
792
793 pub fn getPreviousStartMode(previous: Option<Arc<Edge>>) -> Mode {
794 if let Some(prev) = previous {
795 prev.mode
796 } else {
797 Mode::Ascii
798 }
799 // if previous.is_none() { Mode::ASCII} else {previous.as_ref().unwrap().mode}
800 }
801
802 pub fn getPreviousMode(previous: Option<Arc<Edge>>) -> Result<Mode> {
803 if let Some(prev) = previous {
804 prev.getEndMode()
805 } else {
806 Ok(Mode::Ascii)
807 }
808 // return previous == null ? Mode::ASCII : previous.getEndMode();
809 }
810
811 /** Returns Mode::ASCII in case that:
812 * - Mode is EDIFACT and characterLength is less than 4 or the remaining characters can be encoded in at most 2
813 * ASCII bytes.
814 * - Mode is C40, TEXT or X12 and the remaining characters can be encoded in at most 1 ASCII byte.
815 *
816 * Returns mode in all other cases.
817 * */
818 pub fn getEndMode(&self) -> Result<Mode> {
819 let mode = self.mode;
820 if mode == Mode::Edf {
821 if self.characterLength < 4 {
822 return Ok(Mode::Ascii);
823 }
824 let lastASCII = Self::getLastASCII(self)?; // see 5.2.8.2 EDIFACT encodation Rules
825 if lastASCII > 0
826 && self.getCodewordsRemaining(self.cachedTotalSize + lastASCII) <= 2 - lastASCII
827 {
828 return Ok(Mode::Ascii);
829 }
830 }
831 if mode == Mode::C40 || mode == Mode::Text || mode == Mode::X12 {
832 // see 5.2.5.2 C40 encodation rules and 5.2.7.2 ANSI X12 encodation rules
833 if self.fromPosition + self.characterLength >= self.input.length() as u32
834 && self.getCodewordsRemaining(self.cachedTotalSize) == 0
835 {
836 return Ok(Mode::Ascii);
837 }
838 let lastASCII = Self::getLastASCII(self)?;
839 if lastASCII == 1 && self.getCodewordsRemaining(self.cachedTotalSize + 1) == 0 {
840 return Ok(Mode::Ascii);
841 }
842 }
843
844 Ok(mode)
845 }
846
847 pub fn getMode(&self) -> Mode {
848 self.mode
849 }
850
851 /** Peeks ahead and returns 1 if the postfix consists of exactly two digits, 2 if the postfix consists of exactly
852 * two consecutive digits and a non extended character or of 4 digits.
853 * Returns 0 in any other case
854 **/
855 pub fn getLastASCII(&self) -> Result<u32> {
856 let length = self.input.length() as u32;
857 let from = self.fromPosition + self.characterLength;
858 if length - from > 4 || from >= length {
859 return Ok(0);
860 }
861 if length - from == 1 {
862 if isExtendedASCII(
863 self.input.charAt(from as usize)?,
864 self.input.getFNC1Character(),
865 ) {
866 return Ok(0);
867 }
868 return Ok(1);
869 }
870 if length - from == 2 {
871 if isExtendedASCII(
872 self.input.charAt(from as usize)?,
873 self.input.getFNC1Character(),
874 ) || isExtendedASCII(
875 self.input.charAt(from as usize + 1)?,
876 self.input.getFNC1Character(),
877 ) {
878 return Ok(0);
879 }
880 if high_level_encoder::isDigit(self.input.charAt(from as usize)?)
881 && high_level_encoder::isDigit(self.input.charAt(from as usize + 1)?)
882 {
883 return Ok(1);
884 }
885 return Ok(2);
886 }
887 if length - from == 3 {
888 if high_level_encoder::isDigit(self.input.charAt(from as usize)?)
889 && high_level_encoder::isDigit(self.input.charAt(from as usize + 1)?)
890 && !isExtendedASCII(
891 self.input.charAt(from as usize + 2)?,
892 self.input.getFNC1Character(),
893 )
894 {
895 return Ok(2);
896 }
897 if high_level_encoder::isDigit(self.input.charAt(from as usize + 1)?)
898 && high_level_encoder::isDigit(self.input.charAt(from as usize + 2)?)
899 && !isExtendedASCII(
900 self.input.charAt(from as usize)?,
901 self.input.getFNC1Character(),
902 )
903 {
904 return Ok(2);
905 }
906 return Ok(0);
907 }
908 if high_level_encoder::isDigit(self.input.charAt(from as usize)?)
909 && high_level_encoder::isDigit(self.input.charAt(from as usize + 1)?)
910 && high_level_encoder::isDigit(self.input.charAt(from as usize + 2)?)
911 && high_level_encoder::isDigit(self.input.charAt(from as usize + 3)?)
912 {
913 return Ok(2);
914 }
915
916 Ok(0)
917 }
918
919 /** Returns the capacity in codewords of the smallest symbol that has enough capacity to fit the given minimal
920 * number of codewords.
921 **/
922 pub fn getMinSymbolSize(&self, minimum: u32) -> u32 {
923 match self.input.getShapeHint() {
924 SymbolShapeHint::FORCE_SQUARE => {
925 for capacity in SQUARE_CODEWORD_CAPACITIES {
926 // for (int capacity : squareCodewordCapacities) {
927 if capacity >= minimum {
928 return capacity;
929 }
930 }
931 }
932 SymbolShapeHint::FORCE_RECTANGLE => {
933 for capacity in RECTANGULAR_CODEWORD_CAPACITIES {
934 // for (int capacity : rectangularCodewordCapacities) {
935 if capacity >= minimum {
936 return capacity;
937 }
938 }
939 }
940 _ => {}
941 }
942 for capacity in ALL_CODEWORD_CAPACITIES {
943 // for (int capacity : allCodewordCapacities) {
944 if capacity >= minimum {
945 return capacity;
946 }
947 }
948
949 ALL_CODEWORD_CAPACITIES[ALL_CODEWORD_CAPACITIES.len() - 1]
950 }
951
952 /** Returns the remaining capacity in codewords of the smallest symbol that has enough capacity to fit the given
953 * minimal number of codewords.
954 **/
955 pub fn getCodewordsRemaining(&self, minimum: u32) -> u32 {
956 Self::getMinSymbolSize(self, minimum) - minimum
957 }
958
959 #[inline]
960 pub fn getBytes1(c: u32) -> Vec<u8> {
961 // let result = vec![0u8;1];
962 // result[0] = c as u8;
963 // result
964 vec![c as u8]
965 }
966
967 #[inline]
968 pub fn getBytes2(c1: u32, c2: u32) -> Vec<u8> {
969 // byte[] result = new byte[2];
970 // result[0] = (byte) c1;
971 // result[1] = (byte) c2;
972 // return result;
973 vec![c1 as u8, c2 as u8]
974 }
975
976 pub fn setC40Word(bytes: &mut [u8], offset: u32, c1: u32, c2: u32, c3: u32) {
977 let val16 = (1600 * (c1 & 0xff)) + (40 * (c2 & 0xff)) + (c3 & 0xff) + 1;
978 bytes[offset as usize] = (val16 / 256) as u8;
979 bytes[offset as usize + 1] = (val16 % 256) as u8;
980 }
981
982 fn getX12Value(c: char) -> u32 {
983 let c = c as u32;
984 if c == 13 {
985 0
986 } else if c == 42 {
987 1
988 } else if c == 62 {
989 2
990 } else if c == 32 {
991 3
992 } else if (48..=57).contains(&c) {
993 c - 44
994 } else if (65..=90).contains(&c) {
995 c - 51
996 } else {
997 c
998 }
999 }
1000
1001 pub fn getX12Words(&self) -> Result<Vec<u8>> {
1002 assert!(self.characterLength % 3 == 0);
1003 let mut result = vec![0u8; self.characterLength as usize / 3 * 2];
1004 let mut i = 0;
1005 while i < result.len() {
1006 // for (int i = 0; i < result.length; i += 2) {
1007 Self::setC40Word(
1008 &mut result,
1009 i as u32,
1010 Self::getX12Value(self.input.charAt(self.fromPosition as usize + i / 2 * 3)?),
1011 Self::getX12Value(
1012 self.input
1013 .charAt(self.fromPosition as usize + i / 2 * 3 + 1)?,
1014 ),
1015 Self::getX12Value(
1016 self.input
1017 .charAt(self.fromPosition as usize + i / 2 * 3 + 2)?,
1018 ),
1019 );
1020 i += 2;
1021 }
1022 Ok(result)
1023 }
1024
1025 pub fn getShiftValue(c: char, c40: bool, fnc1: Option<char>) -> u32 {
1026 if c40 && isInC40Shift1Set(c) || !c40 && isInTextShift1Set(c) {
1027 0
1028 } else if c40 && isInC40Shift2Set(c, fnc1) || !c40 && isInTextShift2Set(c, fnc1) {
1029 1
1030 } else {
1031 2
1032 }
1033 }
1034
1035 fn getC40Value(c40: bool, setIndex: u32, c: char, fnc1: Option<char>) -> u32 {
1036 if let Some(fnc1_char) = fnc1 {
1037 if c == fnc1_char {
1038 assert!(setIndex == 2);
1039 return 27;
1040 }
1041 }
1042 if c40 {
1043 let c = c as u32;
1044 if c <= 31 {
1045 c
1046 } else if c == 32 {
1047 3
1048 } else if c <= 47 {
1049 c - 33
1050 } else if c <= 57 {
1051 c - 44
1052 } else if c <= 64 {
1053 c - 43
1054 } else if c <= 90 {
1055 c - 51
1056 } else if c <= 95 {
1057 c - 69
1058 } else if c <= 127 {
1059 c - 96
1060 } else {
1061 c
1062 }
1063 } else {
1064 let c = c as u32;
1065 if c == 0 {
1066 0
1067 } else if setIndex == 0 && c <= 3 {
1068 c - 1
1069 } else if
1070 //is this a bug in the spec?
1071 setIndex == 1 && c <= 31 {
1072 c
1073 } else if c == 32 {
1074 3
1075 } else if (33..=47).contains(&c) {
1076 c - 33
1077 } else if (48..=57).contains(&c) {
1078 c - 44
1079 } else if (58..=64).contains(&c) {
1080 c - 43
1081 } else if (65..=90).contains(&c) {
1082 c - 64
1083 } else if (91..=95).contains(&c) {
1084 c - 69
1085 } else if c == 96 {
1086 0
1087 } else if (97..=122).contains(&c) {
1088 c - 83
1089 } else if (123..=127).contains(&c) {
1090 c - 96
1091 } else {
1092 c
1093 }
1094 }
1095 }
1096
1097 pub fn getC40Words(&self, c40: bool, fnc1: Option<char>) -> Result<Vec<u8>> {
1098 let mut c40Values: Vec<u8> = Vec::new();
1099 let fromPosition = self.fromPosition as usize;
1100 for i in 0..self.characterLength as usize {
1101 // for (int i = 0; i < characterLength; i++) {
1102 let ci = self.input.charAt(fromPosition + i)?;
1103 if c40 && high_level_encoder::isNativeC40(ci)
1104 || !c40 && high_level_encoder::isNativeText(ci)
1105 {
1106 c40Values.push(Self::getC40Value(c40, 0, ci, fnc1) as u8);
1107 } else if !isExtendedASCII(ci, fnc1) {
1108 let shiftValue = Self::getShiftValue(ci, c40, fnc1);
1109 c40Values.push(shiftValue as u8); //Shift[123]
1110 c40Values.push(Self::getC40Value(c40, shiftValue, ci, fnc1) as u8);
1111 } else {
1112 let asciiValue = (ci as u8 - 128) as char;
1113 if c40 && high_level_encoder::isNativeC40(asciiValue)
1114 || !c40 && high_level_encoder::isNativeText(asciiValue)
1115 {
1116 c40Values.push(1); //Shift 2
1117 c40Values.push(30); //Upper Shift
1118 c40Values.push(Self::getC40Value(c40, 0, asciiValue, fnc1) as u8);
1119 } else {
1120 c40Values.push(1); //Shift 2
1121 c40Values.push(30); //Upper Shift
1122 let shiftValue = Self::getShiftValue(asciiValue, c40, fnc1);
1123 c40Values.push(shiftValue as u8); // Shift[123]
1124 c40Values.push(Self::getC40Value(c40, shiftValue, asciiValue, fnc1) as u8);
1125 }
1126 }
1127 }
1128
1129 if (c40Values.len() % 3) != 0 {
1130 assert!(
1131 (c40Values.len() - 2) % 3 == 0
1132 && fromPosition + self.characterLength as usize == self.input.length()
1133 );
1134 c40Values.push(0); // pad with 0 (Shift 1)
1135 }
1136
1137 let mut result = vec![0u8; c40Values.len() / 3 * 2];
1138 let mut byteIndex = 0;
1139 let mut i = 0;
1140 while i < c40Values.len() {
1141 // for (int i = 0; i < c40Values.size(); i += 3) {
1142 Self::setC40Word(
1143 &mut result,
1144 byteIndex,
1145 c40Values[i] as u32,
1146 c40Values[i + 1] as u32,
1147 c40Values[i + 2] as u32,
1148 );
1149 byteIndex += 2;
1150
1151 i += 3;
1152 }
1153
1154 Ok(result)
1155 }
1156
1157 pub fn getEDFBytes(&self) -> Result<Vec<u8>> {
1158 let numberOfThirds = (self.characterLength as f32 / 4.0).ceil() as usize;
1159 let mut result = vec![0u8; numberOfThirds * 3];
1160 let mut pos = self.fromPosition as usize;
1161 let endPos = (self.fromPosition as usize + self.characterLength as usize - 1)
1162 .min(self.input.length() - 1);
1163 let mut i = 0;
1164 while i < numberOfThirds {
1165 // for (int i = 0; i < numberOfThirds; i += 3) {
1166 let mut edfValues = [0u32; 4];
1167 for edfValue in &mut edfValues {
1168 // for j in 0..4 {
1169 // for (int j = 0; j < 4; j++) {
1170 if pos <= endPos {
1171 *edfValue = self.input.charAt(pos)? as u32 & 0x3f;
1172 pos += 1;
1173 } else {
1174 *edfValue = if pos == endPos + 1 { 0x1f } else { 0 };
1175 }
1176 }
1177 let mut val24 = edfValues[0] << 18;
1178 val24 |= edfValues[1] << 12;
1179 val24 |= edfValues[2] << 6;
1180 val24 |= edfValues[3];
1181 result[i] = ((val24 >> 16) & 0xff) as u8;
1182 result[i + 1] = ((val24 >> 8) & 0xff) as u8;
1183 result[i + 2] = (val24 & 0xff) as u8;
1184
1185 i += 3;
1186 }
1187
1188 Ok(result)
1189 }
1190
1191 pub fn getLatchBytes(&self) -> Result<Vec<u8>> {
1192 match Self::getPreviousMode(self.previous.clone())? {
1193 Mode::Ascii | Mode::B256 =>
1194 //after B256 ends (via length) we are back to ASCII
1195 {
1196 match self.mode {
1197 Mode::B256 => return Ok(Self::getBytes1(231)),
1198 Mode::C40 => return Ok(Self::getBytes1(230)),
1199 Mode::Text => return Ok(Self::getBytes1(239)),
1200 Mode::X12 => return Ok(Self::getBytes1(238)),
1201 Mode::Edf => return Ok(Self::getBytes1(240)),
1202 _ => {}
1203 }
1204 }
1205 Mode::C40 | Mode::Text | Mode::X12
1206 if self.mode != Self::getPreviousMode(self.previous.clone())? =>
1207 {
1208 match self.mode {
1209 Mode::Ascii => return Ok(Self::getBytes1(254)),
1210 Mode::B256 => return Ok(Self::getBytes2(254, 231)),
1211 Mode::C40 => return Ok(Self::getBytes2(254, 230)),
1212 Mode::Text => return Ok(Self::getBytes2(254, 239)),
1213 Mode::X12 => return Ok(Self::getBytes2(254, 238)),
1214 Mode::Edf => return Ok(Self::getBytes2(254, 240)),
1215 }
1216 }
1217 Mode::C40 | Mode::Text | Mode::X12 => {}
1218 Mode::Edf => assert!(self.mode == Mode::Edf), //The rightmost EDIFACT edge always contains an unlatch character
1219 }
1220
1221 Ok(Vec::new())
1222 }
1223
1224 // Important: The function does not return the length bytes (one or two) in case of B256 encoding
1225 pub fn getDataBytes(&self) -> Result<Vec<u8>> {
1226 match self.mode {
1227 Mode::Ascii => {
1228 if self.input.isECI(self.fromPosition)? {
1229 Ok(Self::getBytes2(
1230 241,
1231 self.input.getECIValue(self.fromPosition as usize)? as u32 + 1,
1232 ))
1233 } else if isExtendedASCII(
1234 self.input.charAt(self.fromPosition as usize)?,
1235 self.input.getFNC1Character(),
1236 ) {
1237 Ok(Self::getBytes2(
1238 235,
1239 self.input.charAt(self.fromPosition as usize)? as u32 - 127,
1240 ))
1241 } else if self.characterLength == 2 {
1242 Ok(Self::getBytes1(
1243 (self.input.charAt(self.fromPosition as usize)? as u32 - b'0' as u32) * 10
1244 + self.input.charAt(self.fromPosition as usize + 1)? as u32
1245 - b'0' as u32
1246 + 130,
1247 ))
1248 } else if self.input.isFNC1(self.fromPosition as usize)? {
1249 Ok(Self::getBytes1(232))
1250 } else {
1251 Ok(Self::getBytes1(
1252 self.input.charAt(self.fromPosition as usize)? as u32 + 1,
1253 ))
1254 }
1255 }
1256 Mode::B256 => Ok(Self::getBytes1(
1257 self.input.charAt(self.fromPosition as usize)? as u32,
1258 )),
1259 Mode::C40 => self.getC40Words(true, self.input.getFNC1Character()),
1260 Mode::Text => self.getC40Words(false, self.input.getFNC1Character()),
1261 Mode::X12 => self.getX12Words(),
1262 Mode::Edf => self.getEDFBytes(),
1263 }
1264 // assert!( false);
1265 // Ok(vec![0])
1266 }
1267}
1268
1269struct RXingResult {
1270 bytes: Vec<u8>,
1271}
1272impl RXingResult {
1273 pub fn new(solution: Option<Arc<Edge>>) -> Result<Self> {
1274 let solution = if let Some(edge) = solution {
1275 edge
1276 } else {
1277 return Err(Exceptions::ILLEGAL_ARGUMENT);
1278 };
1279 let input = solution.input.clone();
1280 let mut size = 0;
1281 let mut bytesAL = Vec::new(); //new ArrayList<>();
1282 let mut randomizePostfixLength = Vec::new(); //new ArrayList<>();
1283 let mut randomizeLengths = Vec::new(); //new ArrayList<>();
1284 if (solution.mode == Mode::C40 || solution.mode == Mode::Text || solution.mode == Mode::X12)
1285 && solution.getEndMode()? != Mode::Ascii
1286 {
1287 size += Self::prepend(&Edge::getBytes1(254), &mut bytesAL);
1288 }
1289 let mut hold_current = Some(solution.clone());
1290 while let Some(current) = hold_current {
1291 // Fails on i = 77 should be 151 is 144
1292 size += Self::prepend(¤t.getDataBytes()?, &mut bytesAL);
1293
1294 if current.previous.is_none()
1295 || Edge::getPreviousStartMode(current.previous.clone()) != current.getMode()
1296 {
1297 if current.getMode() == Mode::B256 {
1298 if size <= 249 {
1299 bytesAL.insert(0, size as u8);
1300 size += 1;
1301 } else {
1302 bytesAL.insert(0, (size % 250) as u8);
1303 bytesAL.insert(0, (size / 250 + 249) as u8);
1304 size += 2;
1305 }
1306 randomizePostfixLength.push(bytesAL.len());
1307 randomizeLengths.push(size);
1308 }
1309 Self::prepend(¤t.getLatchBytes()?, &mut bytesAL);
1310 size = 0;
1311 }
1312
1313 hold_current = current.previous.clone();
1314 }
1315 if input.getMacroId() == 5 {
1316 _ = Self::prepend(&Edge::getBytes1(236), &mut bytesAL);
1317 } else if input.getMacroId() == 6 {
1318 _ = Self::prepend(&Edge::getBytes1(237), &mut bytesAL);
1319 }
1320
1321 if input.getFNC1Character().is_some() {
1322 _ = Self::prepend(&Edge::getBytes1(232), &mut bytesAL);
1323 }
1324 for i in 0..randomizePostfixLength.len() {
1325 // for (int i = 0; i < randomizePostfixLength.size(); i++) {
1326 let bytes_al_len = bytesAL.len() as u32;
1327 Self::applyRandomPattern(
1328 &mut bytesAL,
1329 bytes_al_len - *randomizePostfixLength.get(i).unwrap() as u32,
1330 *randomizeLengths.get(i).unwrap() as u32,
1331 );
1332 }
1333 //add padding
1334 let capacity = solution.getMinSymbolSize(bytesAL.len() as u32);
1335 if bytesAL.len() < capacity as usize {
1336 bytesAL.push(129);
1337 }
1338 while bytesAL.len() < capacity as usize {
1339 bytesAL.push(Self::randomize253State(bytesAL.len() as u32 + 1) as u8);
1340 }
1341
1342 let mut bytes = vec![0u8; bytesAL.len()];
1343 // for (i, byte) in bytes.iter_mut().enumerate() {
1344 // // for (int i = 0; i < bytes.length; i++) {
1345 // *byte = *bytesAL.get(i).unwrap();
1346 // }
1347 bytes[..].copy_from_slice(&bytesAL[..]);
1348
1349 Ok(Self { bytes })
1350 }
1351
1352 pub fn prepend(bytes: &[u8], into: &mut Vec<u8>) -> usize {
1353 for byte in bytes.iter().rev() {
1354 into.insert(0, *byte);
1355 }
1356 bytes.len()
1357 }
1358
1359 #[inline]
1360 fn randomize253State(codewordPosition: u32) -> u32 {
1361 let pseudoRandom = ((149 * codewordPosition) % 253) + 1;
1362 let tempVariable = 129 + pseudoRandom;
1363 if tempVariable <= 254 {
1364 tempVariable
1365 } else {
1366 tempVariable - 254
1367 }
1368 }
1369
1370 pub fn applyRandomPattern(bytesAL: &mut [u8], startPosition: u32, length: u32) {
1371 for i in 0..length as usize {
1372 //See "B.1 253-state algorithm
1373 let Pad_codeword_position = startPosition as usize + i;
1374 let Pad_codeword_value = bytesAL.get(Pad_codeword_position).unwrap_or(&0);
1375 let pseudo_random_number = ((149 * (Pad_codeword_position + 1)) % 255) + 1;
1376 let temp_variable: u16 = *Pad_codeword_value as u16 + pseudo_random_number as u16;
1377 bytesAL[Pad_codeword_position] = if temp_variable <= 255 {
1378 temp_variable as u8
1379 } else {
1380 (temp_variable - 256) as u8
1381 };
1382 }
1383 }
1384
1385 pub fn getBytes(&self) -> &[u8] {
1386 &self.bytes
1387 }
1388}
1389
1390struct Input {
1391 shape: SymbolShapeHint,
1392 macroId: i32,
1393 internal: MinimalECIInput,
1394}
1395
1396impl Input {
1397 pub fn new(
1398 stringToEncode: &str,
1399 priorityCharset: Option<CharacterSet>,
1400 fnc1: Option<char>,
1401 shape: SymbolShapeHint,
1402 macroId: i32,
1403 ) -> Self {
1404 let z = fnc1.unwrap_or_default().to_string();
1405 let v = if fnc1.is_some() {
1406 Some(z.as_str())
1407 } else {
1408 None
1409 };
1410 Self {
1411 shape,
1412 macroId,
1413 internal: MinimalECIInput::new(stringToEncode, priorityCharset, v),
1414 }
1415 }
1416
1417 pub fn getMacroId(&self) -> i32 {
1418 self.macroId
1419 }
1420
1421 pub fn getShapeHint(&self) -> SymbolShapeHint {
1422 self.shape
1423 }
1424
1425 pub fn length(&self) -> usize {
1426 self.internal.length()
1427 }
1428 pub fn isECI(&self, index: u32) -> Result<bool> {
1429 self.internal.isECI(index)
1430 }
1431 pub fn charAt(&self, index: usize) -> Result<char> {
1432 self.internal.charAt(index)
1433 }
1434 pub fn getFNC1Character(&self) -> Option<char> {
1435 if self.internal.getFNC1Character() == 1000 {
1436 None
1437 } else {
1438 Some(self.internal.getFNC1Character() as u8 as char)
1439 }
1440 }
1441 fn haveNCharacters(&self, index: usize, n: usize) -> Result<bool> {
1442 self.internal.haveNCharacters(index, n)
1443 }
1444 fn isFNC1(&self, index: usize) -> Result<bool> {
1445 self.internal.isFNC1(index)
1446 }
1447 fn getECIValue(&self, index: usize) -> Result<Eci> {
1448 self.internal.getECIValue(index)
1449 }
1450}
1451
1452impl fmt::Display for Input {
1453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1454 self.internal.fmt(f)
1455 }
1456}