1use crate::{
28 BarcodeFormat, Binarizer, DecodeHints, Exceptions, RXingResult, RXingResultMetadataType,
29 RXingResultMetadataValue, Reader,
30 common::{BitArray, Result},
31 oned::{
32 OneDReader, record_pattern, record_pattern_in_reverse,
33 rss::{
34 AbstractRSSReaderTrait, DataCharacter, DataCharacterTrait, FinderPattern, rss_utils,
35 },
36 },
37};
38
39use super::{ExpandedPair, ExpandedRow, bit_array_builder, decoders::abstract_expanded_decoder};
40
41const FINDER_PAT_A: u32 = 0;
42const FINDER_PAT_B: u32 = 1;
43const FINDER_PAT_C: u32 = 2;
44const FINDER_PAT_D: u32 = 3;
45const FINDER_PAT_E: u32 = 4;
46const FINDER_PAT_F: u32 = 5;
47
48const FINDER_PATTERN_SEQUENCES: [&[u32]; 10] = [
49 &[FINDER_PAT_A, FINDER_PAT_A],
50 &[FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B],
51 &[FINDER_PAT_A, FINDER_PAT_C, FINDER_PAT_B, FINDER_PAT_D],
52 &[
53 FINDER_PAT_A,
54 FINDER_PAT_E,
55 FINDER_PAT_B,
56 FINDER_PAT_D,
57 FINDER_PAT_C,
58 ],
59 &[
60 FINDER_PAT_A,
61 FINDER_PAT_E,
62 FINDER_PAT_B,
63 FINDER_PAT_D,
64 FINDER_PAT_D,
65 FINDER_PAT_F,
66 ],
67 &[
68 FINDER_PAT_A,
69 FINDER_PAT_E,
70 FINDER_PAT_B,
71 FINDER_PAT_D,
72 FINDER_PAT_E,
73 FINDER_PAT_F,
74 FINDER_PAT_F,
75 ],
76 &[
77 FINDER_PAT_A,
78 FINDER_PAT_A,
79 FINDER_PAT_B,
80 FINDER_PAT_B,
81 FINDER_PAT_C,
82 FINDER_PAT_C,
83 FINDER_PAT_D,
84 FINDER_PAT_D,
85 ],
86 &[
87 FINDER_PAT_A,
88 FINDER_PAT_A,
89 FINDER_PAT_B,
90 FINDER_PAT_B,
91 FINDER_PAT_C,
92 FINDER_PAT_C,
93 FINDER_PAT_D,
94 FINDER_PAT_E,
95 FINDER_PAT_E,
96 ],
97 &[
98 FINDER_PAT_A,
99 FINDER_PAT_A,
100 FINDER_PAT_B,
101 FINDER_PAT_B,
102 FINDER_PAT_C,
103 FINDER_PAT_C,
104 FINDER_PAT_D,
105 FINDER_PAT_E,
106 FINDER_PAT_F,
107 FINDER_PAT_F,
108 ],
109 &[
110 FINDER_PAT_A,
111 FINDER_PAT_A,
112 FINDER_PAT_B,
113 FINDER_PAT_B,
114 FINDER_PAT_C,
115 FINDER_PAT_D,
116 FINDER_PAT_D,
117 FINDER_PAT_E,
118 FINDER_PAT_E,
119 FINDER_PAT_F,
120 FINDER_PAT_F,
121 ],
122];
123
124#[derive(Default)]
129pub struct RSSExpandedReader {
130 decodeFinderCounters: [u32; 4],
131 dataCharacterCounters: [u32; 8],
132 oddRoundingErrors: [f32; 4],
133 evenRoundingErrors: [f32; 4],
134 oddCounts: [u32; 4],
135 evenCounts: [u32; 4],
136
137 pub(super) pairs: Vec<ExpandedPair>,
138 pub(super) rows: Vec<ExpandedRow>,
139 startEnd: [u32; 2],
140 startFromEven: bool,
141}
142impl AbstractRSSReaderTrait for RSSExpandedReader {}
143impl OneDReader for RSSExpandedReader {
144 fn decode_row(
145 &mut self,
146 rowNumber: u32,
147 row: &crate::common::BitArray,
148 _hints: &DecodeHints,
149 ) -> Result<crate::RXingResult> {
150 self.pairs.clear();
153 self.startFromEven = false;
154 if let Ok(decoded_two_pairs) = self.decodeRow2pairs(rowNumber, row) {
155 if let Ok(possible_result) = Self::constructRXingResult(&decoded_two_pairs) {
156 return Ok(possible_result);
157 }
158 }
159
160 self.pairs.clear();
161 self.startFromEven = true;
162 Self::constructRXingResult(&self.decodeRow2pairs(rowNumber, row)?)
163 }
164}
165impl Reader for RSSExpandedReader {
166 fn decode<B: Binarizer>(&mut self, image: &mut crate::BinaryBitmap<B>) -> Result<RXingResult> {
167 self.decode_with_hints(image, &DecodeHints::default())
168 }
169
170 fn decode_with_hints<B: Binarizer>(
172 &mut self,
173 image: &mut crate::BinaryBitmap<B>,
174 hints: &DecodeHints,
175 ) -> Result<crate::RXingResult> {
176 if let Ok(res) = self._do_decode(image, hints) {
177 Ok(res)
178 } else {
179 let tryHarder = hints.TryHarder.unwrap_or(false);
180 if tryHarder && image.is_rotate_supported() {
181 let mut rotatedImage = image.rotate_counter_clockwise();
182 let mut result = self._do_decode(&mut rotatedImage, hints)?;
183 let metadata = result.getRXingResultMetadata();
185 let mut orientation = 270;
186 if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) {
187 orientation = (orientation
189 + if let Some(crate::RXingResultMetadataValue::Orientation(or)) =
190 metadata.get(&RXingResultMetadataType::ORIENTATION)
191 {
192 *or
193 } else {
194 0
195 })
196 % 360;
197 }
198 result.putMetadata(
199 RXingResultMetadataType::ORIENTATION,
200 RXingResultMetadataValue::Orientation(orientation),
201 );
202 let height = rotatedImage.get_height();
204
205 let total_points = result.getPoints().len();
206 let points = result.getPointsMut();
207 for point in points.iter_mut().take(total_points) {
208 std::mem::swap(&mut point.x, &mut point.y);
209 point.x = height as f32 - point.x - 1.0;
210 }
211
212 Ok(result)
213 } else {
214 Err(Exceptions::NOT_FOUND)
215 }
216 }
217 }
218
219 fn reset(&mut self) {
220 self.pairs.clear();
221 self.rows.clear();
222 }
223}
224
225impl RSSExpandedReader {
226 pub fn new() -> Self {
227 Self::default()
228 }
229 const SYMBOL_WIDEST: [u32; 5] = [7, 5, 4, 3, 1];
230 const EVEN_TOTAL_SUBSET: [u32; 5] = [4, 20, 52, 104, 204];
231 const GSUM: [u32; 5] = [0, 348, 1388, 2948, 3988];
232
233 const FINDER_PATTERNS: [[u32; 4]; 6] = [
234 [1, 8, 4, 1], [3, 6, 4, 1], [3, 4, 6, 1], [3, 2, 8, 1], [2, 6, 5, 1], [2, 2, 9, 1], ];
241
242 const WEIGHTS: [[u32; 8]; 23] = [
243 [1, 3, 9, 27, 81, 32, 96, 77],
244 [20, 60, 180, 118, 143, 7, 21, 63],
245 [189, 145, 13, 39, 117, 140, 209, 205],
246 [193, 157, 49, 147, 19, 57, 171, 91],
247 [62, 186, 136, 197, 169, 85, 44, 132],
248 [185, 133, 188, 142, 4, 12, 36, 108],
249 [113, 128, 173, 97, 80, 29, 87, 50],
250 [150, 28, 84, 41, 123, 158, 52, 156],
251 [46, 138, 203, 187, 139, 206, 196, 166],
252 [76, 17, 51, 153, 37, 111, 122, 155],
253 [43, 129, 176, 106, 107, 110, 119, 146],
254 [16, 48, 144, 10, 30, 90, 59, 177],
255 [109, 116, 137, 200, 178, 112, 125, 164],
256 [70, 210, 208, 202, 184, 130, 179, 115],
257 [134, 191, 151, 31, 93, 68, 204, 190],
258 [148, 22, 66, 198, 172, 94, 71, 2],
259 [6, 18, 54, 162, 64, 192, 154, 40],
260 [120, 149, 25, 75, 14, 42, 126, 167],
261 [79, 26, 78, 23, 69, 207, 199, 175],
262 [103, 98, 83, 38, 114, 131, 182, 124],
263 [161, 61, 183, 127, 170, 88, 53, 159],
264 [55, 165, 73, 8, 24, 72, 5, 15],
265 [45, 135, 194, 160, 58, 174, 100, 89],
266 ];
267
268 #[allow(dead_code)]
269 const MAX_PAIRS: usize = 11;
270
271 pub(super) fn decodeRow2pairs(
273 &mut self,
274 rowNumber: u32,
275 row: &BitArray,
276 ) -> Result<Vec<ExpandedPair>> {
277 let mut done = false;
278 while !done {
279 let previousPairs = self.pairs.clone();
280 let to_add_res = self.retrieveNextPair(row, &previousPairs, rowNumber);
281 if let Ok(to_add) = to_add_res {
282 self.pairs.push(to_add);
283 } else if self.pairs.is_empty() {
284 return Err(to_add_res.err().unwrap_or(Exceptions::ILLEGAL_STATE));
285 } else {
286 done = true;
288 }
289 }
290
291 if self.checkChecksum() {
293 return Ok(self.pairs.clone());
294 }
295
296 let tryStackedDecode = !self.rows.is_empty();
297 self.storeRow(rowNumber); if tryStackedDecode {
299 let ps = self.checkRows(false).or(self.checkRows(true));
302 if let Some(ps) = ps {
303 return Ok(ps);
304 }
305
306 }
315
316 Err(Exceptions::NOT_FOUND)
317 }
318
319 fn checkRows(&mut self, reverse: bool) -> Option<Vec<ExpandedPair>> {
320 if self.rows.len() > 25 {
324 self.rows.clear(); return None;
326 }
327
328 self.pairs.clear();
329 if reverse {
330 self.rows.reverse();
331 }
332
333 let mut c_rows = Vec::new();
334 let ps = self.checkRowsDetails(&mut c_rows, 0).ok();
335 if reverse {
345 self.rows.reverse();
346 }
347
348 ps
349 }
350
351 fn checkRowsDetails(
354 &mut self,
355 collectedRows: &mut Vec<ExpandedRow>,
356 currentRow: usize,
357 ) -> Result<Vec<ExpandedPair>> {
358 for i in currentRow..self.rows.len() {
359 let row = self.rows.get(i).ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?;
361
362 self.pairs.extend_from_slice(row.getPairs());
363
364 let addSize = row.getPairs().len();
365
366 if Self::isValidSequence(&self.pairs) {
367 if self.checkChecksum() {
368 return Ok(self.pairs.clone());
369 }
370
371 collectedRows.push(row.clone());
372
373 if let Ok(cr) = self.checkRowsDetails(collectedRows, i + 1) {
375 return Ok(cr);
376 } else {
377 collectedRows.truncate(collectedRows.len() - 1);
379 self.pairs.truncate(self.pairs.len() - addSize);
380 }
381 } else {
382 self.pairs.truncate(self.pairs.len() - addSize);
383 }
384 }
385
386 Err(Exceptions::NOT_FOUND)
387 }
388
389 fn isValidSequence(pairs: &[ExpandedPair]) -> bool {
394 for sequence in FINDER_PATTERN_SEQUENCES.iter() {
395 if pairs.len() <= sequence.len() {
400 let stop = sequence
401 .iter()
402 .enumerate()
403 .take(pairs.len())
404 .all(|(j, seq)| {
405 pairs
406 .get(j)
407 .unwrap()
408 .getFinderPattern()
409 .as_ref()
410 .unwrap()
411 .getValue()
412 == *seq
413 });
414
415 if stop {
433 return true;
434 }
435 }
436 }
437
438 false
439 }
440
441 fn storeRow(&mut self, rowNumber: u32) {
442 let mut insertPos = 0;
444 let mut prevIsSame = false;
445 let mut nextIsSame = false;
446 while insertPos < self.rows.len() {
447 if let Some(erow) = self.rows.get(insertPos) {
448 if erow.getRowNumber() > rowNumber {
449 nextIsSame = erow.isEquivalent(&self.pairs);
450 break;
451 }
452 prevIsSame = erow.isEquivalent(&self.pairs);
453 insertPos += 1;
454 }
455 }
456 if nextIsSame || prevIsSame {
457 return;
458 }
459
460 if Self::isPartialRow(&self.pairs, &self.rows) {
466 return;
467 }
468
469 self.rows
470 .insert(insertPos, ExpandedRow::new(self.pairs.clone(), rowNumber));
471
472 Self::removePartialRows(&self.pairs, &mut self.rows);
473 }
474
475 fn removePartialRows(pairs: &[ExpandedPair], rows: &mut Vec<ExpandedRow>) {
477 rows.retain(|row| {
478 if row.getPairs().len() != pairs.len() {
480 !row.getPairs().iter().all(|p| pairs.contains(p))
481 } else {
489 true
490 }
491 });
492 }
493
494 fn isPartialRow(pairs: &[ExpandedPair], rows: &[ExpandedRow]) -> bool {
496 rows.iter()
497 .any(|r| !pairs.iter().any(|p| !r.getPairs().contains(p)))
498 }
522
523 #[cfg(test)]
525 #[allow(dead_code)]
526 pub(crate) fn getRowsMut(&mut self) -> &mut [ExpandedRow] {
527 &mut self.rows
528 }
529 #[cfg(test)]
530 pub(crate) fn getRows(&self) -> &[ExpandedRow] {
531 &self.rows
532 }
533
534 pub(crate) fn constructRXingResult(pairs: &[ExpandedPair]) -> Result<RXingResult> {
536 let binary = bit_array_builder::buildBitArray(pairs).ok_or(Exceptions::ILLEGAL_STATE)?;
537
538 let mut decoder = abstract_expanded_decoder::createDecoder(&binary)?;
539 let resultingString = decoder.parseInformation()?;
540
541 let firstPoints = pairs
542 .first()
543 .ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?
544 .getFinderPattern()
545 .as_ref()
546 .ok_or(Exceptions::ILLEGAL_STATE)?
547 .getPoints();
548 let lastPoints = pairs
549 .last()
550 .ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?
551 .getFinderPattern()
552 .as_ref()
553 .ok_or(Exceptions::ILLEGAL_STATE)?
554 .getPoints();
555
556 let mut result = RXingResult::new(
557 &resultingString,
558 Vec::new(),
559 vec![firstPoints[0], firstPoints[1], lastPoints[0], lastPoints[1]],
560 BarcodeFormat::RSS_EXPANDED,
561 );
562
563 result.putMetadata(
564 RXingResultMetadataType::SYMBOLOGY_IDENTIFIER,
565 RXingResultMetadataValue::SymbologyIdentifier("]e0".to_owned()),
566 );
567
568 Ok(result)
569 }
570
571 fn checkChecksum(&self) -> bool {
572 let Some(firstPair) = self.pairs.first() else {
573 return false;
574 };
575 let checkCharacter = firstPair.getLeftChar();
576 let Some(firstCharacter) = firstPair.getRightChar() else {
577 return false;
578 };
579
580 let mut checksum = firstCharacter.getChecksumPortion();
581 let mut s = 2;
582
583 for currentPair in self.pairs.iter().skip(1) {
584 let Some(currentPairLeftChar) = currentPair.getLeftChar() else {
585 return false;
586 };
587 checksum += currentPairLeftChar.getChecksumPortion();
588 s += 1;
589 if let Some(currentRightChar) = currentPair.getRightChar() {
590 checksum += currentRightChar.getChecksumPortion();
591 s += 1;
592 }
593 }
594
595 checksum %= 211;
596
597 let checkCharacterValue = (211 * (s as i64 - 4) + checksum as i64) as u32;
598
599 if let Some(checkCharacter) = checkCharacter {
600 checkCharacterValue == checkCharacter.getValue()
601 } else {
602 false
603 }
604 }
605
606 fn getNextSecondBar(row: &BitArray, initialPos: usize) -> usize {
607 let mut currentPos;
608 if row.get(initialPos) {
609 currentPos = row.getNextUnset(initialPos);
610 currentPos = row.getNextSet(currentPos);
611 } else {
612 currentPos = row.getNextSet(initialPos);
613 currentPos = row.getNextUnset(currentPos);
614 }
615 currentPos
616 }
617
618 pub(super) fn retrieveNextPair(
620 &mut self,
621 row: &BitArray,
622 previousPairs: &[ExpandedPair],
623 rowNumber: u32,
624 ) -> Result<ExpandedPair> {
625 let mut isOddPattern = previousPairs.len() % 2 == 0;
626 if self.startFromEven {
627 isOddPattern = !isOddPattern;
628 }
629
630 let mut pattern;
631
632 let mut keepFinding = true;
633 let mut forcedOffset = -1_i32;
634 loop {
635 self.findNextPair(row, previousPairs, forcedOffset)?;
636 pattern = self.parseFoundFinderPattern(row, rowNumber, isOddPattern);
637 if pattern.is_none() {
638 forcedOffset = Self::getNextSecondBar(row, self.startEnd[0] as usize) as i32;
639 } else {
640 keepFinding = false;
641 }
642 if !keepFinding {
643 break;
644 }
645 }
646
647 let leftChar = self.decodeDataCharacter(
651 row,
652 pattern.as_ref().ok_or(Exceptions::NOT_FOUND)?,
653 isOddPattern,
654 true,
655 )?;
656
657 if !previousPairs.is_empty()
658 && previousPairs
659 .last()
660 .ok_or(Exceptions::NOT_FOUND)?
661 .mustBeLast()
662 {
663 return Err(Exceptions::NOT_FOUND);
664 }
665
666 let rightChar = self
667 .decodeDataCharacter(
668 row,
669 pattern.as_ref().ok_or(Exceptions::NOT_FOUND)?,
670 isOddPattern,
671 false,
672 )
673 .ok();
674
675 Ok(ExpandedPair::new(Some(leftChar), rightChar, pattern))
676 }
677
678 fn findNextPair(
679 &mut self,
680 row: &BitArray,
681 previousPairs: &[ExpandedPair],
682 forcedOffset: i32,
683 ) -> Result<()> {
684 let counters = &mut self.decodeFinderCounters;
685 counters.fill(0);
686 let width = row.get_size();
692
693 let mut rowOffset;
694 if forcedOffset >= 0 {
695 rowOffset = forcedOffset;
696 } else if previousPairs.is_empty() {
697 rowOffset = 0;
698 } else {
699 let lastPair = previousPairs
700 .last()
701 .ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?;
702 rowOffset = lastPair
703 .getFinderPattern()
704 .as_ref()
705 .ok_or(Exceptions::ILLEGAL_STATE)?
706 .getStartEnd()[1] as i32;
707 }
708 let mut searchingEvenPair = previousPairs.len() % 2 != 0;
709 if self.startFromEven {
710 searchingEvenPair = !searchingEvenPair;
711 }
712
713 let mut isWhite = false;
714 while rowOffset < width as i32 {
715 isWhite = !row.get(rowOffset as usize);
716 if !isWhite {
717 break;
718 }
719 rowOffset += 1;
720 }
721
722 let mut counterPosition = 0;
723 let mut patternStart = rowOffset;
724 for x in rowOffset..width as i32 {
725 if row.get(x as usize) != isWhite {
727 counters[counterPosition] += 1;
728 } else {
729 if counterPosition == 3 {
730 if searchingEvenPair {
731 Self::reverseCounters(counters);
732 }
733
734 if Self::isFinderPattern(counters) {
735 self.startEnd[0] = patternStart as u32;
736 self.startEnd[1] = x as u32;
737 return Ok(());
738 }
739
740 if searchingEvenPair {
741 Self::reverseCounters(counters);
742 }
743
744 patternStart += (counters[0] + counters[1]) as i32;
745 counters[0] = counters[2];
746 counters[1] = counters[3];
747 counters[2] = 0;
748 counters[3] = 0;
749 counterPosition -= 1;
750 } else {
751 counterPosition += 1;
752 }
753 counters[counterPosition] = 1;
754 isWhite = !isWhite;
755 }
756 }
757 Err(Exceptions::NOT_FOUND)
758 }
759
760 fn reverseCounters<const N: usize>(counters: &mut [u32; N]) {
761 counters.reverse();
762 }
763
764 fn parseFoundFinderPattern(
765 &self,
766 row: &BitArray,
767 rowNumber: u32,
768 oddPattern: bool,
769 ) -> Option<FinderPattern> {
770 let firstCounter;
772 let start;
773 let end;
774
775 if oddPattern {
776 let mut firstElementStart = self.startEnd[0] as i32 - 1;
779 while firstElementStart >= 0 && !row.get(firstElementStart as usize) {
781 firstElementStart -= 1;
782 }
783
784 firstElementStart += 1;
785 firstCounter = self.startEnd[0] as i32 - firstElementStart;
786 start = firstElementStart;
787 end = self.startEnd[1];
788 } else {
789 start = self.startEnd[0] as i32;
792
793 end = row.getNextUnset(self.startEnd[1] as usize + 1) as u32;
794 firstCounter = end as i32 - self.startEnd[1] as i32;
795 }
796
797 let mut counters = self.decodeFinderCounters;
799 let counters_len = counters.len();
800 counters.copy_within(..counters_len - 1, 1);
801 counters[0] = firstCounter as u32;
804 let value = Self::parseFinderValue(&counters, &Self::FINDER_PATTERNS).ok()?;
805
806 Some(FinderPattern::new(
807 value,
808 [start as usize, end as usize],
809 start as usize,
810 end as usize,
811 rowNumber,
812 ))
813 }
814
815 pub(super) fn decodeDataCharacter(
816 &mut self,
817 row: &BitArray,
818 pattern: &FinderPattern,
819 isOddPattern: bool,
820 leftChar: bool,
821 ) -> Result<DataCharacter> {
822 let counters = &mut self.dataCharacterCounters;
823 counters.fill(0);
824
825 if leftChar {
826 record_pattern_in_reverse(row, pattern.getStartEnd()[0], counters)?;
827 } else {
828 record_pattern(row, pattern.getStartEnd()[1], counters)?;
829 counters.reverse();
831 } let numModules = 17;
835
836 let elementWidth: f32 = (counters.iter().sum::<u32>() as f32) / numModules as f32;
837
838 let expectedElementWidth: f32 =
840 (pattern.getStartEnd()[1] - pattern.getStartEnd()[0]) as f32 / 15.0;
841 if (elementWidth - expectedElementWidth).abs() / expectedElementWidth > 0.3 {
842 return Err(Exceptions::NOT_FOUND);
843 }
844
845 for (i, counter) in counters.iter().enumerate() {
846 let value: f32 = 1.0 * (*counter as f32) / elementWidth;
848 let mut count = (value + 0.5) as i32; if count < 1 {
850 if value < 0.3 {
851 return Err(Exceptions::NOT_FOUND);
852 }
853 count = 1;
854 } else if count > 8 {
855 if value > 8.7 {
856 return Err(Exceptions::NOT_FOUND);
857 }
858 count = 8;
859 }
860 let offset = i / 2;
861 if (i & 0x01) == 0 {
862 self.oddCounts[offset] = count as u32;
863 self.oddRoundingErrors[offset] = value - count as f32;
864 } else {
865 self.evenCounts[offset] = count as u32;
866 self.evenRoundingErrors[offset] = value - count as f32;
867 }
868 }
869
870 self.adjustOddEvenCounts(numModules as u32)?;
871
872 let weightRowNumber = (4 * pattern.getValue() as isize
873 + (if isOddPattern { 0 } else { 2 })
874 + isize::from(!leftChar)
875 - 1) as usize;
876
877 let mut oddSum = 0;
878 let mut oddChecksumPortion = 0;
879 for i in (0..self.oddCounts.len()).rev() {
880 if Self::isNotA1left(pattern, isOddPattern, leftChar) {
881 let weight = Self::WEIGHTS[weightRowNumber][2 * i];
882 oddChecksumPortion += self.oddCounts[i] * weight;
883 }
884 oddSum += self.oddCounts[i];
885 }
886 let mut evenChecksumPortion = 0;
887 for i in (0..self.evenCounts.len()).rev() {
888 if Self::isNotA1left(pattern, isOddPattern, leftChar) {
889 let weight = Self::WEIGHTS[weightRowNumber][2 * i + 1];
890 evenChecksumPortion += self.evenCounts[i] * weight;
891 }
892 }
893 let checksumPortion = oddChecksumPortion + evenChecksumPortion;
894
895 if (oddSum & 0x01) != 0 || !(4..=13).contains(&oddSum) {
896 return Err(Exceptions::NOT_FOUND);
897 }
898
899 let group = ((13 - oddSum) / 2) as usize;
900 let oddWidest = Self::SYMBOL_WIDEST[group];
901 let evenWidest = 9 - oddWidest;
902 let vOdd = rss_utils::getRSSvalue(&self.oddCounts, oddWidest, true);
903 let vEven = rss_utils::getRSSvalue(&self.evenCounts, evenWidest, false);
904 let tEven = Self::EVEN_TOTAL_SUBSET[group];
905 let gSum = Self::GSUM[group];
906 let value = vOdd * tEven + vEven + gSum;
907
908 Ok(DataCharacter::new(value, checksumPortion))
909 }
910
911 #[inline(always)]
912 fn isNotA1left(pattern: &FinderPattern, isOddPattern: bool, leftChar: bool) -> bool {
913 !(pattern.getValue() == 0 && isOddPattern && leftChar)
915 }
916
917 fn adjustOddEvenCounts(&mut self, numModules: u32) -> Result<()> {
918 let oddSum = self.oddCounts.iter().sum::<u32>();
919 let evenSum = self.evenCounts.iter().sum::<u32>();
920
921 let mut incrementOdd = false;
922 let mut decrementOdd = false;
923
924 if oddSum > 13 {
925 decrementOdd = true;
926 } else if oddSum < 4 {
927 incrementOdd = true;
928 }
929 let mut incrementEven = false;
930 let mut decrementEven = false;
931 if evenSum > 13 {
932 decrementEven = true;
933 } else if evenSum < 4 {
934 incrementEven = true;
935 }
936
937 let mismatch = oddSum as isize + evenSum as isize - numModules as isize;
938 let oddParityBad = (oddSum & 0x01) == 1;
939 let evenParityBad = (evenSum & 0x01) == 0;
940 match mismatch {
941 1 => {
942 if oddParityBad {
943 if evenParityBad {
944 return Err(Exceptions::NOT_FOUND);
945 }
946 decrementOdd = true;
947 } else {
948 if !evenParityBad {
949 return Err(Exceptions::NOT_FOUND);
950 }
951 decrementEven = true;
952 }
953 }
954 -1 => {
955 if oddParityBad {
956 if evenParityBad {
957 return Err(Exceptions::NOT_FOUND);
958 }
959 incrementOdd = true;
960 } else {
961 if !evenParityBad {
962 return Err(Exceptions::NOT_FOUND);
963 }
964 incrementEven = true;
965 }
966 }
967 0 => {
968 if oddParityBad {
969 if !evenParityBad {
970 return Err(Exceptions::NOT_FOUND);
971 }
972 if oddSum < evenSum {
974 incrementOdd = true;
975 decrementEven = true;
976 } else {
977 decrementOdd = true;
978 incrementEven = true;
979 }
980 } else if evenParityBad {
981 return Err(Exceptions::NOT_FOUND);
982 }
983 }
984
985 _ => return Err(Exceptions::NOT_FOUND),
986 }
987
988 if incrementOdd {
989 if decrementOdd {
990 return Err(Exceptions::NOT_FOUND);
991 }
992 Self::increment(&mut self.oddCounts, &self.oddRoundingErrors);
993 }
994 if decrementOdd {
995 Self::decrement(&mut self.oddCounts, &self.oddRoundingErrors);
996 }
997 if incrementEven {
998 if decrementEven {
999 return Err(Exceptions::NOT_FOUND);
1000 }
1001 Self::increment(&mut self.evenCounts, &self.oddRoundingErrors);
1002 }
1003 if decrementEven {
1004 Self::decrement(&mut self.evenCounts, &self.evenRoundingErrors);
1005 }
1006
1007 Ok(())
1008 }
1009}