JLChen
2021-10-08 f8457b624a75bf8e41489b74f66009eee6891b8b
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
/*
 * Copyright 2012 ZXing authors
 *
 * 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.
 */
 
#import "ZXGenericGF.h"
#import "ZXGenericGFPoly.h"
#import "ZXIntArray.h"
#import "ZXReedSolomonEncoder.h"
 
@interface ZXReedSolomonEncoder ()
 
@property (nonatomic, strong, readonly) NSMutableArray *cachedGenerators;
@property (nonatomic, strong, readonly) ZXGenericGF *field;
 
@end
 
@implementation ZXReedSolomonEncoder
 
- (id)initWithField:(ZXGenericGF *)field {
  if (self = [super init]) {
    _field = field;
    ZXIntArray *one = [[ZXIntArray alloc] initWithLength:1];
    one.array[0] = 1;
    _cachedGenerators = [NSMutableArray arrayWithObject:[[ZXGenericGFPoly alloc] initWithField:field coefficients:one]];
  }
 
  return self;
}
 
- (ZXGenericGFPoly *)buildGenerator:(int)degree {
  if (degree >= self.cachedGenerators.count) {
    ZXGenericGFPoly *lastGenerator = self.cachedGenerators[[self.cachedGenerators count] - 1];
    for (NSUInteger d = [self.cachedGenerators count]; d <= degree; d++) {
      ZXIntArray *next = [[ZXIntArray alloc] initWithLength:2];
      next.array[0] = 1;
      next.array[1] = [self.field exp:(int)d - 1 + self.field.generatorBase];
      ZXGenericGFPoly *nextGenerator = [lastGenerator multiply:[[ZXGenericGFPoly alloc] initWithField:self.field coefficients:next]];
      [self.cachedGenerators addObject:nextGenerator];
      lastGenerator = nextGenerator;
    }
  }
 
  return (ZXGenericGFPoly *)self.cachedGenerators[degree];
}
 
- (void)encode:(ZXIntArray *)toEncode ecBytes:(int)ecBytes {
  if (ecBytes == 0) {
    @throw [NSException exceptionWithName:NSInvalidArgumentException
                                   reason:@"No error correction bytes"
                                 userInfo:nil];
  }
  int dataBytes = toEncode.length - ecBytes;
  if (dataBytes <= 0) {
    @throw [NSException exceptionWithName:NSInvalidArgumentException
                                   reason:@"No data bytes provided"
                                 userInfo:nil];
  }
  ZXGenericGFPoly *generator = [self buildGenerator:ecBytes];
  ZXIntArray *infoCoefficients = [[ZXIntArray alloc] initWithLength:dataBytes];
  for (int i = 0; i < dataBytes; i++) {
    infoCoefficients.array[i] = toEncode.array[i];
  }
  ZXGenericGFPoly *info = [[ZXGenericGFPoly alloc] initWithField:self.field coefficients:infoCoefficients];
  info = [info multiplyByMonomial:ecBytes coefficient:1];
  ZXGenericGFPoly *remainder = [info divide:generator][1];
  ZXIntArray *coefficients = remainder.coefficients;
  int numZeroCoefficients = ecBytes - coefficients.length;
  for (int i = 0; i < numZeroCoefficients; i++) {
    toEncode.array[dataBytes + i] = 0;
  }
  for (int i = 0; i < coefficients.length; i++) {
    toEncode.array[dataBytes + numZeroCoefficients + i] = coefficients.array[i];
  }
}
 
@end