/* * 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