Check-in [8050fa743a]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Work in progress of QR code image generation
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:8050fa743afaa971ae3621a18bfe3fe4722888f7
User & Date: xiekevin 2018-01-22 05:12:58
Context
2018-01-25
17:11
QR code work in progress Leaf check-in: c43811222b user: xiekevin tags: trunk
2018-01-22
05:12
Work in progress of QR code image generation check-in: 8050fa743a user: xiekevin tags: trunk
2018-01-15
03:12
UPC and CODE128 generation done; See Barcode.jara check-in: 90124aac60 user: xiekevin tags: trunk
Changes

Changes to src/fanxi/barcode/Barcode.java.

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
		return this;
	}
	
	protected abstract void computeDimensions();
	
	// check if the input code is a sequence of number, optionally of specific length (length=0 means
	// it can be variable length, char 48 is digit '0', char 57 is digit '9'
	public static boolean isNumbers(char[] code) {
		boolean retval = true;
		if( code==null ) return false;
		for(int i=0; i<code.length; i++) {
			if( code[i]<48 || code[i]>57 ) {
				retval = false;
				break;
			}







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
		return this;
	}
	
	protected abstract void computeDimensions();
	
	// check if the input code is a sequence of number, optionally of specific length (length=0 means
	// it can be variable length, char 48 is digit '0', char 57 is digit '9'
	public static boolean isNumeric(char[] code) {
		boolean retval = true;
		if( code==null ) return false;
		for(int i=0; i<code.length; i++) {
			if( code[i]<48 || code[i]>57 ) {
				retval = false;
				break;
			}

Added src/fanxi/barcode/BitStream.java.

























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
package fanxi.barcode;

import java.util.BitSet;

public class BitStream extends BitSet {

	private static final long serialVersionUID = 1L;
	
	private int segmentSize = 8;
	
	public BitStream() {
		super();
	}

	public BitStream(int bits) {
		super(bits);
	}

	public void and(int offset, String bits) throws Exception {
		if( bits==null ) throw new Exception("Null input");
		int len = bits.length();
		int endIdx = offset + len;
		for(int i=offset; i<endIdx; i++) {
			if( bits.charAt(i)=='1' ) { 
				this.set(i, true);
			}else if( bits.charAt(i)=='0' ) {
				this.set(i, false);
			}else{
				throw new Exception("Wrong format, a bitset string should contain only '1' or '0' characters");
			}
		}
	}
	
	public void and(int offset, int bits, int numBits) throws Exception {
		int endIdx = offset + numBits;
		int mask = 0x01;
		boolean value;
		for(int i=offset; i<endIdx; i++) {
			numBits--;
			value = (((bits & (mask<<numBits)) >> numBits)==1);
			this.set(i, value);
		}
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		int len = this.length();
		for(int i=0; i<len; i++) {
			if( i>0 && ((i)%this.segmentSize)==0 ) sb.append(' ');
			if( this.get(i) ) {
				sb.append('1');
			}else{
				sb.append('0');
			}
		}
		
		return sb.toString();
	}
	
	// a codeword is a 8 bits from the stream, converted to integer big-endian
	public int[] toCodewords(int offset, int length) {
		int[] retval = new int[length/8 + (length%8==0? 0 : 1)];
		int v = 0;
		int shift = 7;
		for( int i=1; i<=length; i++) {
			v = v + (this.get(i+offset-1)? 1<<shift : 0);
			shift--;
			if( i%8==0 ) {
				retval[(i-1)/8] = v;
				v = 0;
				shift = 7;
			}
		}
		if( length%8!=0 ) {
			retval[length/8] = v;
		}
		
		return retval;
	}
	
	public String toStringDecimal(int offset) {
		return this.toStringDecimal(offset, this.size());
	}
	public String toStringDecimal(int offset, int length) {
		StringBuilder sb = new StringBuilder();
		int[] codewords = this.toCodewords(offset, length);
		for( int i=0; i<codewords.length; i++ ) {
			sb.append(codewords[i] + " ");
		}
		
		return sb.toString();
	}

	public String toString(int length) {
		StringBuilder sb = new StringBuilder();
		int len = Math.max(length, this.length());
		for(int i=0; i<len; i++) {
			if( i>0 && ((i)%this.segmentSize)==0 ) sb.append(' ');
			if( this.get(i) ) {
				sb.append('1');
			}else{
				sb.append('0');
			}
		}
		
		return sb.toString();
	}
}

Added src/fanxi/barcode/Poly.java.





















































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
package fanxi.barcode;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

public class Poly {
	
	private TreeMap<Integer, Term>	terms = new TreeMap<>();
	
	public Poly() {
		
	};
	
	public int numberOfTerms() {
		return this.terms.size();
	}
	
	public int[] coefficient() {
		int[] retval = new int[this.terms.size()];
		Iterator<Integer> itr = this.terms.descendingKeySet().iterator();
		Term term = null;
		int i = 0;
		while( itr.hasNext() ) {
			term = this.terms.get(itr.next());
			retval[i++] = term.coefficient.value;
		}
		return retval;
	}

	public Term leadTerm() {
		Iterator<Integer> itr = this.terms.descendingKeySet().iterator();
		Term term = null;
		if( itr.hasNext() ) {
			term = this.terms.get(itr.next());
		}
		return term;
	}
	
	public Poly addTerm(Term term) {
		if( term==null ) return this;
		return this.addTerm(term.coefficient, term.exponent);
	}
	
	public Poly addTerm(int coefficient, int exponent) throws Exception {
		Gf256 coef = Gf256.getByValue(coefficient);
		return this.addTerm(coef, exponent);
	}
	
	public Poly addTerm(Gf256 coefficient, int exponent) {
		Term t = this.terms.get(exponent);
		if( t==null ) {
			this.terms.put(exponent, new Term(coefficient, exponent));
		}else{
			t.coefficient = t.coefficient.xor(coefficient);
		}
		return this;
	}

	public Poly multiply(Term term) {
		for(Term t : this.terms.values()) {
			t.coefficient = Gf256.getByExponent(t.coefficient.exponent + term.coefficient.exponent);
			t.exponent = t.exponent + term.exponent;
		}
		return this;
	}
	
	private final static Map<Integer, Poly>	GENERATOR_POLY	= new HashMap<>();
	
	public static Poly multiply(Poly p1, Poly p2) {
		Poly retval = new Poly();
		Term	newTerm;
		Gf256	newCoef;
		int		newExponent;
		for(Term t1 : p1.terms.values()) {
			for(Term t2 : p2.terms.values()) {
				newCoef = Gf256.getByExponent(t1.coefficient.exponent + t2.coefficient.exponent);
				newExponent = t1.exponent + t2.exponent;
				newTerm = new Term(newCoef, newExponent);
				retval.addTerm(newTerm);
			}
		}
		return retval;
	}
	
	// dividend/divisor, return the remainder, divisor is always the generator poly
	// NOTE: the returned remainder is modified from the same object of dividend
	public static Poly longDivision(Poly dividend, Poly divisor) {
		// multiply divisor by coefficent of the lead term of dividend, and also bring
		// the exponent of divisor lead term to the same as that of dividend
		Term leadTermDividend = dividend.leadTerm();
		Term leadTermDivisor = divisor.leadTerm();
		int exponentDiff = leadTermDividend.exponent - leadTermDivisor.exponent;
		Poly tmpPoly = new Poly().addTerm(new Term(leadTermDividend.coefficient, exponentDiff));
		divisor = Poly.multiply(divisor, tmpPoly);
		
		// dividend xor divsor
		dividend.xor(divisor);
		
		return dividend;
	}
	
	// this is basically add
	public Poly xor(Poly poly) {
		int exp;
		Term term;
		Iterator<Integer> itr; 
		
		// add (xor) all terms in poly to this object
		itr = poly.terms.descendingKeySet().iterator();
		while(itr.hasNext()) {
			exp = itr.next();
			term = poly.terms.get(exp);
			this.addTerm(term);
		}

		// remove 0 coefficent terms
		itr = this.terms.descendingKeySet().iterator();
		while(itr.hasNext()) {
			exp = itr.next();
			term = this.terms.get(exp);
			if( term.coefficient.value==0 ) {
				itr.remove();
			}
		}
		
		return this;
	}
	
	public static Poly computeGeneratorPoly(int n) {
		Poly retval = Poly.GENERATOR_POLY.get(n);
		if( retval!=null ) return retval;
		if( n==2 ) {
			retval = new Poly();
			retval.addTerm(Gf256.getByExponent(0), 2)
				.addTerm(Gf256.getByExponent(25), 1)
				.addTerm(Gf256.getByExponent(1), 0);
		}else{
			Poly nPoly = new Poly().addTerm(Gf256.getByExponent(0), 1)
					.addTerm(Gf256.getByExponent(n-1), 0);
			Poly prevPoly = Poly.computeGeneratorPoly(n-1);
			retval = Poly.multiply(nPoly, prevPoly);
		}
		Poly.GENERATOR_POLY.put(n, retval);
		return retval;
	}
	
	public String toString() {
		StringBuilder sb = new StringBuilder();
		Iterator<Integer> itr = this.terms.descendingKeySet().iterator();
		int exp;
		Term term;
		if( itr.hasNext() ) {
			exp = itr.next();
			term = this.terms.get(exp);
			sb.append(term);
		}
		while(itr.hasNext()) {
			exp = itr.next();
			term = this.terms.get(exp);
			sb.append(" + " + term);
		}
		return sb.toString();
	}

	public String toStringDecimal() {
		StringBuilder sb = new StringBuilder();
		Iterator<Integer> itr = this.terms.descendingKeySet().iterator();
		int exp;
		Term term;
		if( itr.hasNext() ) {
			exp = itr.next();
			term = this.terms.get(exp);
			sb.append(term.toStringDecimal());
		}
		while(itr.hasNext()) {
			exp = itr.next();
			term = this.terms.get(exp);
			sb.append(" + " + term.toStringDecimal());
		}
		return sb.toString();
	}

	public String toStringExponent() {
		StringBuilder sb = new StringBuilder();
		Iterator<Integer> itr = this.terms.descendingKeySet().iterator();
		int exp;
		Term term;
		while(itr.hasNext()) {
			exp = itr.next();
			term = this.terms.get(exp);
			sb.append(term.toString() + " ");
		}
		return sb.toString();
	}

	public static class Term {
		private int		exponent;
		private Gf256	coefficient;
		
		public Term(Gf256 coef, int expo) {
			this.coefficient = coef;
			this.exponent = expo;
		}
		
		public String toStringDecimal() {
			if( this.coefficient.value==0 ) {
				return "0";
			}
			if( this.coefficient.value==1 ) {
				return "x" + this.exponent;
			}
			return this.coefficient.value + "x" + (this.exponent==1? "" : this.exponent);
		}		
		
		public String toString() {
			if( this.coefficient.exponent==0 && this.exponent==0 ) {
				return "1";
			}
			if( this.coefficient.exponent==0 ) {
				return "x" + this.exponent;
			}
			if( this.exponent==0 ) {
				return "a" + this.coefficient.exponent;
			}
			return "a" + this.coefficient.exponent + "x" + (this.exponent==1? "" : this.exponent);
		}

		public String toStringExponent() {
			return this.coefficient.exponent + "." + this.exponent;
		}
		
		public int exponent() {
			return this.exponent;
		}
		
		public Gf256 coefficient() {
			return this.coefficient;
		}
	}
	
	// the Galois 256 Field table for QR code specification
	public static class Gf256 {
		public static final int base = 2;

		private final int value;
		private final int exponent;
		
		private Gf256(int value, int exponent) {
			if( exponent>255 ) exponent = (exponent % 255);
			this.exponent = exponent;
			this.value = value;
		}
		
		public static int computeValue(int exponent) {
			if(exponent<0) return 0;
			if( exponent>255 ) exponent = (exponent % 255);
			if( exponent<8) return (int)Math.pow(Gf256.base, exponent);
			if( exponent==8 ) return 256 ^ 285;
			int retval = 0; 
			retval = 2 * Gf256.computeValue(exponent-1);
			if(retval>=256) retval = retval ^ 285;
			return retval;
		}
		
		private final static Gf256		V0		= new Gf256(0, 0);
		private final static Gf256		E255	= new Gf256(1, 255);
		// index by value, value=0 special, it's implemented as Gf256(0,0)
		private final static Gf256[]	TABLE	= new Gf256[256];
		
		static {
			Gf256 gf256;
			for( int i=0; i<255; i++) {
				gf256 = new Gf256(Gf256.computeValue(i), i);
				Gf256.TABLE[gf256.value] = gf256;
			}
			Gf256.TABLE[0] = Gf256.V0;
		}
		
		public int value() {
			return this.value;
		}
		
		public int exponent() {
			return this.exponent;
		}
		
		// this both add and substraction
		public Gf256 xor(Gf256 gf256) {
			return Gf256.TABLE[this.value ^ gf256.value];
		}
		
		public static Gf256 getByValue(int value) throws Exception {
			if( value==0 ) return Gf256.V0;
			if( value<0 || value>255 ) throw new Exception("Galois Field 256 range is [0,255]");
			return Gf256.TABLE[value];
		}

		public static Gf256 getByExponent(int exponent) {
			if(exponent==255) return Gf256.E255; // Gf256 is cyclic
			return Gf256.TABLE[Gf256.computeValue(exponent)];
		}
		
		public String toString() {
			return "Integer " + this.value + " <-> Exponent " + exponent;
		}
	}
	
	public static void main(String[] args) {
		Poly poly = Poly.computeGeneratorPoly(30);
		System.out.println(poly);
	}
}

Added src/fanxi/barcode/Qr.java.



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
package fanxi.barcode;

import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;

public class Qr {

	public short modulePixes = 3;
	
	protected final String				code;
	protected final Mode				mode;
	protected ErrorCorrectionLevel		level	= ErrorCorrectionLevel.Q; // 25% error correction
	protected final int					version;
	protected final LevelVersionData	lvData;
	
	protected final BitStream		dataBitStream;
	protected int 					dataOffset		= 0;
	
	protected final BitStream		finalBitStream; 

	//[numBlocks[data/ec codewords]
	protected int[][][]				codewords;

	public static final String UTF_8_BOM = new String( new char[] {0xEF,0xBB,0xBF} );
	
	// bits is bit string in literal format, ie, 10110101...
	public static BitSet getBitSet(String bits) throws Exception {
		if( bits==null ) throw new Exception("Null input");
		int len = bits.length();
		BitSet bSet = new BitSet(len);
		for(int i=0; i<len; i++) {
			if( bits.charAt(i)=='1' ) { 
				bSet.set(i);
			}else if( bits.charAt(i)=='0' ) {
				bSet.clear(i);
			}else{
				throw new Exception("Wrong format, a bitset string should contain only '1' or '0' characters");
			}
		}
		return bSet;
	}
	
	// default error correction level M (15% recovery)
	public Qr(String code) throws Exception {
		this(code, ErrorCorrectionLevel.Q);
	}
	
	public Qr(String code, ErrorCorrectionLevel level) throws Exception {
		this(code, level, 0);
	}

	public Qr(String code, ErrorCorrectionLevel level, int version) throws Exception {
		if( code==null || code.length()<1 ) throw new Exception("null or empty string!");
		this.code = code;
		char[] charArray = this.code.toCharArray();
		Mode mode = Mode.BYTE;
		if( Barcode.isNumeric(charArray) ) {
			mode = Mode.NUMERIC;
		}else if( Qr.isAlphanumeric(charArray) ){
			mode = Mode.ALPHANUMERIC;
		}
		this.mode = mode;
		this.level = level;
		this.version = (version==0? this.computeVersion() : version);
		this.lvData = Qr.VERSION_LEVEL_DATA[this.level.ordinal()][this.version-1];
		this.dataBitStream = new BitStream(this.lvData.numDataCw*8);
		this.finalBitStream = new BitStream(this.lvData.numTotalCodewords*8);
		this.codewords = new int[this.lvData.numBlocksG1 + this.lvData.numBlocksG2][2][];
		
		// input data with padding will be saved in this.dataBitStream
		this.computeBitStream();
		
		// data codewords and error correction codewords will be saved in this.codewords
		this.computeErrorCorrectCodewords();
		
		// data will be save to this.finalBitStream
		this.interleaveCodewords();
		
		System.out.println("Bit Stream:\n" + this.dataBitStream.toString(this.dataOffset));
		System.out.println("Decimal Stream:\n" + this.dataBitStream.toStringDecimal(0, this.dataOffset));
	}
	
	public static boolean isAlphanumeric(char[] code) {
		boolean retval = true;
		
		for(char c : code) {
			// 0-9
			if( c>=48 && c<=57 ) {
				continue;
			}
			// A-Z
			if( c>=65 && c<=90 ) {
				continue;
			}
			// space $ % * + - . / : 
			if( c==32 || c==36 || c==37 || c==42 || c==43 || c==45 || c==46 || c==47 || c==58 ) {
				continue;
			}
			retval = false;
			break;
		}
		return retval;
	}
	
	// when the level is not specified, need to use this function to
	// compute the level
	protected int computeVersion() 
			throws Exception 
	{
		int version = 0;
		int len = code.length();
		short[] capacity = Qr.CAPACITY[this.mode.ordinal()][this.level.ordinal()];
		for(int i=0; i<capacity.length; i++) {
			if( capacity[i]>=len ) {
				version = i+1;
				break;
			}
		}
		if( version==0 ) {
			throw new Exception("Message too long for QR code with mode " + mode 
					+ " and error correction level " + level);
		}
		return version;
	}
	
	protected void computeBitStream() throws Exception {
		this.dataOffset = 0;
		this.addModeIndicator();
		this.addCharacterCountIndicator();
		this.encode();
		this.padding();
	}
	
	protected void computeErrorCorrectCodewords() throws Exception {
		int block;
		int[] dataCodework;
		int[] ecCodework;
		int offset;
		int blockIdx = 0;
		for( block=0; block<this.lvData.numBlocksG1; block++) {
			offset = block * this.lvData.numDataCwPerBlocksG1;
			dataCodework = this.dataBitStream.toCodewords(offset*8, 8*this.lvData.numDataCwPerBlocksG1);
			ecCodework = this.computeErrorCorrectCodewords(dataCodework);
			this.codewords[blockIdx][0] = dataCodework;
			this.codewords[blockIdx][1] = ecCodework;
			blockIdx++;
		}
		for( block=0; block<this.lvData.numBlocksG2; block++) {
			offset = block * this.lvData.numDataCwPerBlocksG2;
			dataCodework = this.dataBitStream.toCodewords(offset*8, 8*this.lvData.numDataCwPerBlocksG1);
			ecCodework =this.computeErrorCorrectCodewords(dataCodework);
			this.codewords[blockIdx][0] = dataCodework;
			this.codewords[blockIdx][1] = ecCodework;
			blockIdx++;
		}
	}
	
	protected void interleaveCodewords() throws Exception {
		int dataOffset = 0, ecOffset = this.lvData.numDataCodewords*8;
		int[] dataCodewords, ecCodewords;
		int idx = 0;
		boolean ttl = false;
		while(!ttl) {
			ttl = true;
			for(int i=0; i<this.codewords.length; i++) {
				dataCodewords = this.codewords[i][0];
				if( idx<dataCodewords.length ) {
					this.finalBitStream.and(dataOffset, dataCodewords[idx], 8);
					dataOffset = dataOffset + 8;
					ttl = false;
				}
				ecCodewords = this.codewords[i][1];
				if( idx<ecCodewords.length ) {
					this.finalBitStream.and(ecOffset, ecCodewords[idx], 8);
					ecOffset = ecOffset + 8;
					ttl = false;
				}
			}
			idx++;
		}
		System.out.println(this.finalBitStream.toStringDecimal(0));
	}
	
	protected int[] computeErrorCorrectCodewords(int[] dataCodeword) throws Exception {
		int[] ecCodeword = null;
		Poly msgPoly = new Poly();
		for( int i=0; i<dataCodeword.length; i++ ) {
			msgPoly.addTerm(dataCodeword[i], dataCodeword.length - i - 1 + this.lvData.numEcCwPerBlock);
		}
		Poly genPoly = Poly.computeGeneratorPoly(this.lvData.numEcCwPerBlock);
		Poly remainder = msgPoly;
		for( int i=0; i<dataCodeword.length; i++ ) {
			Poly.longDivision(remainder, genPoly);
		}
		ecCodeword = remainder.coefficient();
		return ecCodeword;
	}

	protected void padding() throws Exception {
		// codeword padding
		int numCodewords = this.lvData.numDataCw;
		int numBits = numCodewords*8;
		int numPads = numBits - this.dataOffset;
		if( numPads>4) numPads = 4;
		if( numPads>0 ) this.dataBitStream.and(this.dataOffset, 0, numPads);
		this.dataOffset = this.dataOffset + numPads;
		
		// multiple of 8 padding
		numPads = 8 - (this.dataOffset % 8);
		if( numPads>0 ) this.dataBitStream.and(this.dataOffset, 0, numPads);
		this.dataOffset = this.dataOffset + numPads;
		
		// fill up to max capacity
		int numBytes = (numCodewords*8 - this.dataOffset)/8;
		for( int i=0; i<numBytes; i++) {
			if( i%2 == 0 ) {
				this.dataBitStream.and(this.dataOffset, 236, 8);// 236 = 11101100
			}else{
				this.dataBitStream.and(this.dataOffset, 17, 8);	// 17 = 00010001		
			}
			this.dataOffset = this.dataOffset + 8;
		}
	}	
	
	protected void encode() throws Exception {
		switch(this.mode) {
		case NUMERIC:
			break;
		case ALPHANUMERIC:
			this.encodeAlphanumeric();
			break;
		case BYTE:
			break;
		default:
			throw new Exception("Unsupported mode " + this.mode);	
		}		
	}
	
	protected void encodeNumeric() throws Exception {
	}
	
	protected void encodeAlphanumeric() throws Exception {
		int i=0;
		int len = this.code.length() - 1;
		int value = 0;
		for(i=0; i<len; i=i+2) {
			value = Qr.VALUE_ALPHANUMERIC.get(this.code.charAt(i)) * 45;
			value = value + Qr.VALUE_ALPHANUMERIC.get(this.code.charAt(i+1));
			this.dataBitStream.and(this.dataOffset, value, 11);
			this.dataOffset = this.dataOffset + 11;
		}
		if( len==i ) { // it's odd-number string
			value = Qr.VALUE_ALPHANUMERIC.get(this.code.charAt(len));
			this.dataBitStream.and(this.dataOffset, value, 6);
			this.dataOffset = this.dataOffset + 6;
		}
	}
	
	protected void encodeByte() throws Exception {
	}
	
	protected void addModeIndicator() throws Exception {
		switch(this.mode) {
		case NUMERIC:
			this.dataBitStream.and(0,"0001");
			break;
		case ALPHANUMERIC:
			this.dataBitStream.and(0,"0010");
			break;
		case BYTE:
			this.dataBitStream.and(0, "0100");
			break;
		default:
			throw new Exception("Unsupported mode " + this.mode);	
		}
		this.dataOffset = this.dataOffset + 4;
	}
	
	protected void addCharacterCountIndicator() throws Exception {
		int count = this.code.length();
		int numBits = 0;
		switch(this.mode) {
		case NUMERIC:
			if( this.version<10 )		numBits = 10;	
			else if( this.version<27 )	numBits = 12;
			else						numBits = 14;
			break;
		case ALPHANUMERIC:
			if( this.version<10 )		numBits = 9;	
			else if( this.version<27 )	numBits = 11;
			else						numBits = 13;
			break;
		case BYTE:
			if( this.version<10 )		numBits = 8;	
			else if( this.version<27 )	numBits = 16;
			else						numBits = 16;
			break;
		default:
			throw new Exception("Unsupported mode " + this.mode);	
		}
		this.dataBitStream.and(4, count, numBits);
		this.dataOffset = this.dataOffset + numBits;
	}

	public static enum Mode {
		NUMERIC,
		ALPHANUMERIC,
		BYTE
	}
	
	public static enum ErrorCorrectionLevel {
		L,	// Recovers 7% of data
		M,	// Recovers 15% of data
		Q,	// Recovers 25% of data
		H,	// Recovers 30% of data
	}
	

	// capacity table [mode][level][version] = capacity
	private static short CAPACITY[][][] = new short[][][] {
	{	// mode NUMERIC
		{	// level L
			41, 77, 127, 187, 255, 322, 370, 461, 552, 652, 772, 883, 1022, 1101, 1250, 1408, 1548, 1725, 1903,
			2061, 2232, 2409, 2620, 2812, 3057, 3283, 3517, 3669, 3909, 4158, 4417, 4686, 4965, 5253, 5529,
			5836, 6153, 6479, 6743, 7089 
		},
		{	// level M
			34, 63, 101, 149, 202, 255, 293, 365, 432, 513, 604, 691, 796, 871, 991, 1082, 1212, 1346, 1500,
			1600, 1708, 1872, 2059, 2188, 2395, 2544, 2701, 2857, 3035, 3289, 3486, 3693, 3909, 4134,
			4343, 4588, 4775, 5039, 5313, 5596 
		},
		{	// level Q
			27, 48, 77, 111, 144, 178, 207, 259, 312, 364, 427, 489, 580, 621, 703, 775, 876, 948, 1063, 1159,
			1224, 1358, 1468, 1588, 1718, 1804, 1933, 2085, 2181, 2358, 2473, 2670, 2805, 2949, 3081,
			3244, 3417, 3599, 3791, 3993 
		},
		{	// level H
			17, 34, 58, 82, 106, 139, 154, 202, 235, 288, 331, 374, 427, 468, 530, 602, 674, 746, 813, 919,
			969, 1056, 1108, 1228, 1286, 1425, 1501, 1581, 1677, 1782, 1897, 2022, 2157, 2301, 2361,
			2524, 2625, 2735, 2927, 3057 
		} 
	},
	{	// mode ALPHANUMERIC
		{	// level L
			25, 47, 77, 114, 154, 195, 224, 279, 335, 395, 468, 535, 619, 667, 758, 854, 938, 1046, 1153, 1249,
			1352, 1460, 1588, 1704, 1853, 1990, 2132, 2223, 2369, 2520, 2677, 2840, 3009, 3183, 3351, 3537,
			3729, 3927, 4087, 4296 
		},
		{	// level M
			20, 38, 61, 90, 122, 154, 178, 221, 262, 311, 366, 419, 483, 528, 600, 656, 734, 816, 909, 970,
			1035, 1134, 1248, 1326, 1451, 1542, 1637, 1732, 1839, 1994, 2113, 2238, 2369, 2506, 2632,
			2780, 2894, 3054, 3220, 3391 
		},
		{	// level Q
			16, 29, 47, 67, 87, 108, 125, 157, 189, 221, 259, 296, 352, 376, 426, 470, 531, 574, 644, 702,
			742, 823, 890, 963, 1041, 1094, 1172, 1263, 1322, 1429, 1499, 1618, 1700, 1787, 1867, 1966,
			2071, 2181, 2298, 2420 
		},
		{	// level H
			10, 20, 35, 50, 64, 84, 93, 122, 143, 174, 200, 227, 259, 283, 321, 365, 408, 452, 493, 557, 587,
			640, 672, 744, 779, 864, 910, 958, 1016, 1080, 1150, 1226, 1307, 1394, 1431, 1530, 1591,
			1658, 1774, 1852 
		}
	}, 
	{	// mode BYTE
		{ 	// level L
			17, 32, 53, 78, 106, 134, 154, 192, 230, 271, 321, 367, 425, 458, 520, 586, 644, 718, 792,
			858, 929, 1003, 1091, 1171, 1273, 1367, 1465, 1528, 1628, 1732, 1840, 1952, 2068, 2188,
			2303, 2431, 2563, 2699, 2809, 2953 
		},
		{	// level M
			14, 26, 42, 62, 84, 106, 122, 152, 180, 213, 251, 287, 331, 362, 412, 450, 504, 560, 624, 666,
			711, 779, 857, 911, 997, 1059, 1125, 1190, 1264, 1370, 1452, 1538, 1628, 1722, 1809, 1911,
			1989, 2099, 2213, 2331 
		},
		{	// level Q
			11, 20, 32, 46, 60, 74, 86, 108, 130, 151, 177, 203, 241, 258, 292, 322, 364, 394, 442, 482, 509,
			565, 611, 661, 715, 751, 805, 868, 908, 982, 1030, 1112, 1168, 1228, 1283, 1351, 1423, 1499,
			1579, 1663 
		},
		{	// level H
			7, 14, 24, 34, 44, 58, 64, 84, 98, 119, 137, 155, 177, 194, 220, 250, 280, 310, 338, 382, 403,
			439, 461, 511, 535, 593, 625, 658, 698, 742, 790, 842, 898, 958, 983, 1051, 1093, 1139,
			1219, 1273 
		}
	}};
	
	public String toString() {
		return "Mode = " + this.mode + "; Error Correction Level = " + this.level + "; Version = " + this.version;
	}
	
	private static final Map<Character,Integer> VALUE_ALPHANUMERIC = new HashMap<>();
	static {
		Qr.VALUE_ALPHANUMERIC.put('0', 0 );
		Qr.VALUE_ALPHANUMERIC.put('1', 1 );
		Qr.VALUE_ALPHANUMERIC.put('2', 2 );
		Qr.VALUE_ALPHANUMERIC.put('3', 3 );
		Qr.VALUE_ALPHANUMERIC.put('4', 4 );
		Qr.VALUE_ALPHANUMERIC.put('5', 5 );
		Qr.VALUE_ALPHANUMERIC.put('6', 6 );
		Qr.VALUE_ALPHANUMERIC.put('7', 7 );
		Qr.VALUE_ALPHANUMERIC.put('8', 8 );
		Qr.VALUE_ALPHANUMERIC.put('9', 9 );
		Qr.VALUE_ALPHANUMERIC.put('A', 10);
		Qr.VALUE_ALPHANUMERIC.put('B', 11);
		Qr.VALUE_ALPHANUMERIC.put('C', 12);
		Qr.VALUE_ALPHANUMERIC.put('D', 13);
		Qr.VALUE_ALPHANUMERIC.put('E', 14);
		Qr.VALUE_ALPHANUMERIC.put('F', 15);
		Qr.VALUE_ALPHANUMERIC.put('G', 16);
		Qr.VALUE_ALPHANUMERIC.put('H', 17);
		Qr.VALUE_ALPHANUMERIC.put('I', 18);
		Qr.VALUE_ALPHANUMERIC.put('J', 19);
		Qr.VALUE_ALPHANUMERIC.put('K', 20);
		Qr.VALUE_ALPHANUMERIC.put('L', 21);
		Qr.VALUE_ALPHANUMERIC.put('M', 22);
		Qr.VALUE_ALPHANUMERIC.put('N', 23);
		Qr.VALUE_ALPHANUMERIC.put('O', 24);
		Qr.VALUE_ALPHANUMERIC.put('P', 25);
		Qr.VALUE_ALPHANUMERIC.put('Q', 26);
		Qr.VALUE_ALPHANUMERIC.put('R', 27);
		Qr.VALUE_ALPHANUMERIC.put('S', 28);
		Qr.VALUE_ALPHANUMERIC.put('T', 29);
		Qr.VALUE_ALPHANUMERIC.put('U', 30);
		Qr.VALUE_ALPHANUMERIC.put('V', 31);
		Qr.VALUE_ALPHANUMERIC.put('W', 32);
		Qr.VALUE_ALPHANUMERIC.put('X', 33);
		Qr.VALUE_ALPHANUMERIC.put('Y', 34);
		Qr.VALUE_ALPHANUMERIC.put('Z', 35);
		Qr.VALUE_ALPHANUMERIC.put(' ', 36);
		Qr.VALUE_ALPHANUMERIC.put('$', 37);
		Qr.VALUE_ALPHANUMERIC.put('%', 38);
		Qr.VALUE_ALPHANUMERIC.put('*', 39);
		Qr.VALUE_ALPHANUMERIC.put('+', 40);
		Qr.VALUE_ALPHANUMERIC.put('-', 41);
		Qr.VALUE_ALPHANUMERIC.put('.', 42);
		Qr.VALUE_ALPHANUMERIC.put('/', 43);
		Qr.VALUE_ALPHANUMERIC.put(':', 44);		
	};
	
	private static final LevelVersionData[][] VERSION_LEVEL_DATA = new LevelVersionData[4][40];
	static {
		Qr.VERSION_LEVEL_DATA[0][0] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 0, 19, 7, 1, 19, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][1] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 1, 34, 10, 1, 34, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][2] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 2, 55, 15, 1, 55, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][3] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 3, 80, 20, 1, 80, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][4] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 4, 108, 26, 1, 108, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][5] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 5, 136, 18, 2, 68, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][6] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 6, 156, 20, 2, 78, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][7] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 7, 194, 24, 2, 97, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][8] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 8, 232, 30, 2, 116, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][9] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 9, 274, 18, 2, 68, 2, 69);
		Qr.VERSION_LEVEL_DATA[0][10] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 10, 324, 20, 4, 81, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][11] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 11, 370, 24, 2, 92, 2, 93);
		Qr.VERSION_LEVEL_DATA[0][12] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 12, 428, 26, 4, 107, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][13] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 13, 461, 30, 3, 115, 1, 116);
		Qr.VERSION_LEVEL_DATA[0][14] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 14, 523, 22, 5, 87, 1, 88);
		Qr.VERSION_LEVEL_DATA[0][15] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 15, 589, 24, 5, 98, 1, 99);
		Qr.VERSION_LEVEL_DATA[0][16] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 16, 647, 28, 1, 107, 5, 108);
		Qr.VERSION_LEVEL_DATA[0][17] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 17, 721, 30, 5, 120, 1, 121);
		Qr.VERSION_LEVEL_DATA[0][18] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 18, 795, 28, 3, 113, 4, 114);
		Qr.VERSION_LEVEL_DATA[0][19] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 19, 861, 28, 3, 107, 5, 108);
		Qr.VERSION_LEVEL_DATA[0][20] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 20, 932, 28, 4, 116, 4, 117);
		Qr.VERSION_LEVEL_DATA[0][21] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 21, 1006, 28, 2, 111, 7, 112);
		Qr.VERSION_LEVEL_DATA[0][22] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 22, 1094, 30, 4, 121, 5, 122);
		Qr.VERSION_LEVEL_DATA[0][23] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 23, 1174, 30, 6, 117, 4, 118);
		Qr.VERSION_LEVEL_DATA[0][24] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 24, 1276, 26, 8, 106, 4, 107);
		Qr.VERSION_LEVEL_DATA[0][25] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 25, 1370, 28, 10, 114, 2, 115);
		Qr.VERSION_LEVEL_DATA[0][26] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 26, 1468, 30, 8, 122, 4, 123);
		Qr.VERSION_LEVEL_DATA[0][27] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 27, 1531, 30, 3, 117, 10, 118);
		Qr.VERSION_LEVEL_DATA[0][28] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 28, 1631, 30, 7, 116, 7, 117);
		Qr.VERSION_LEVEL_DATA[0][29] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 29, 1735, 30, 5, 115, 10, 116);
		Qr.VERSION_LEVEL_DATA[0][30] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 30, 1843, 30, 13, 115, 3, 116);
		Qr.VERSION_LEVEL_DATA[0][31] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 31, 1955, 30, 17, 115, 0, 0);
		Qr.VERSION_LEVEL_DATA[0][32] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 32, 2071, 30, 17, 115, 1, 116);
		Qr.VERSION_LEVEL_DATA[0][33] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 33, 2191, 30, 13, 115, 6, 116);
		Qr.VERSION_LEVEL_DATA[0][34] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 34, 2306, 30, 12, 121, 7, 122);
		Qr.VERSION_LEVEL_DATA[0][35] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 35, 2434, 30, 6, 121, 14, 122);
		Qr.VERSION_LEVEL_DATA[0][36] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 36, 2566, 30, 17, 122, 4, 123);
		Qr.VERSION_LEVEL_DATA[0][37] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 37, 2702, 30, 4, 122, 18, 123);
		Qr.VERSION_LEVEL_DATA[0][38] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 38, 2812, 30, 20, 117, 4, 118);
		Qr.VERSION_LEVEL_DATA[0][39] = new Qr.LevelVersionData(ErrorCorrectionLevel.L, 39, 2956, 30, 19, 118, 6, 119);
		Qr.VERSION_LEVEL_DATA[1][0] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 0, 16, 10, 1, 16, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][1] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 1, 28, 16, 1, 28, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][2] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 2, 44, 26, 1, 44, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][3] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 3, 64, 18, 2, 32, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][4] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 4, 86, 24, 2, 43, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][5] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 5, 108, 16, 4, 27, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][6] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 6, 124, 18, 4, 31, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][7] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 7, 154, 22, 2, 38, 2, 39);
		Qr.VERSION_LEVEL_DATA[1][8] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 8, 182, 22, 3, 36, 2, 37);
		Qr.VERSION_LEVEL_DATA[1][9] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 9, 216, 26, 4, 43, 1, 44);
		Qr.VERSION_LEVEL_DATA[1][10] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 10, 254, 30, 1, 50, 4, 51);
		Qr.VERSION_LEVEL_DATA[1][11] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 11, 290, 22, 6, 36, 2, 37);
		Qr.VERSION_LEVEL_DATA[1][12] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 12, 334, 22, 8, 37, 1, 38);
		Qr.VERSION_LEVEL_DATA[1][13] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 13, 365, 24, 4, 40, 5, 41);
		Qr.VERSION_LEVEL_DATA[1][14] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 14, 415, 24, 5, 41, 5, 42);
		Qr.VERSION_LEVEL_DATA[1][15] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 15, 453, 28, 7, 45, 3, 46);
		Qr.VERSION_LEVEL_DATA[1][16] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 16, 507, 28, 10, 46, 1, 47);
		Qr.VERSION_LEVEL_DATA[1][17] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 17, 563, 26, 9, 43, 4, 44);
		Qr.VERSION_LEVEL_DATA[1][18] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 18, 627, 26, 3, 44, 11, 45);
		Qr.VERSION_LEVEL_DATA[1][19] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 19, 669, 26, 3, 41, 13, 42);
		Qr.VERSION_LEVEL_DATA[1][20] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 20, 714, 26, 17, 42, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][21] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 21, 782, 28, 17, 46, 0, 0);
		Qr.VERSION_LEVEL_DATA[1][22] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 22, 860, 28, 4, 47, 14, 48);
		Qr.VERSION_LEVEL_DATA[1][23] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 23, 914, 28, 6, 45, 14, 46);
		Qr.VERSION_LEVEL_DATA[1][24] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 24, 1000, 28, 8, 47, 13, 48);
		Qr.VERSION_LEVEL_DATA[1][25] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 25, 1062, 28, 19, 46, 4, 47);
		Qr.VERSION_LEVEL_DATA[1][26] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 26, 1128, 28, 22, 45, 3, 46);
		Qr.VERSION_LEVEL_DATA[1][27] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 27, 1193, 28, 3, 45, 23, 46);
		Qr.VERSION_LEVEL_DATA[1][28] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 28, 1267, 28, 21, 45, 7, 46);
		Qr.VERSION_LEVEL_DATA[1][29] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 29, 1373, 28, 19, 47, 10, 48);
		Qr.VERSION_LEVEL_DATA[1][30] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 30, 1455, 28, 2, 46, 29, 47);
		Qr.VERSION_LEVEL_DATA[1][31] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 31, 1541, 28, 10, 46, 23, 47);
		Qr.VERSION_LEVEL_DATA[1][32] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 32, 1631, 28, 14, 46, 21, 47);
		Qr.VERSION_LEVEL_DATA[1][33] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 33, 1725, 28, 14, 46, 23, 47);
		Qr.VERSION_LEVEL_DATA[1][34] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 34, 1812, 28, 12, 47, 26, 48);
		Qr.VERSION_LEVEL_DATA[1][35] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 35, 1914, 28, 6, 47, 34, 48);
		Qr.VERSION_LEVEL_DATA[1][36] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 36, 1992, 28, 29, 46, 14, 47);
		Qr.VERSION_LEVEL_DATA[1][37] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 37, 2102, 28, 13, 46, 32, 47);
		Qr.VERSION_LEVEL_DATA[1][38] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 38, 2216, 28, 40, 47, 7, 48);
		Qr.VERSION_LEVEL_DATA[1][39] = new Qr.LevelVersionData(ErrorCorrectionLevel.M, 39, 2334, 28, 18, 47, 31, 48);
		Qr.VERSION_LEVEL_DATA[2][0] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 0, 13, 13, 1, 13, 0, 0);
		Qr.VERSION_LEVEL_DATA[2][1] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 1, 22, 22, 1, 22, 0, 0);
		Qr.VERSION_LEVEL_DATA[2][2] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 2, 34, 18, 2, 17, 0, 0);
		Qr.VERSION_LEVEL_DATA[2][3] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 3, 48, 26, 2, 24, 0, 0);
		Qr.VERSION_LEVEL_DATA[2][4] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 4, 62, 18, 2, 15, 2, 16);
		Qr.VERSION_LEVEL_DATA[2][5] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 5, 76, 24, 4, 19, 0, 0);
		Qr.VERSION_LEVEL_DATA[2][6] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 6, 88, 18, 2, 14, 4, 15);
		Qr.VERSION_LEVEL_DATA[2][7] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 7, 110, 22, 4, 18, 2, 19);
		Qr.VERSION_LEVEL_DATA[2][8] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 8, 132, 20, 4, 16, 4, 17);
		Qr.VERSION_LEVEL_DATA[2][9] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 9, 154, 24, 6, 19, 2, 20);
		Qr.VERSION_LEVEL_DATA[2][10] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 10, 180, 28, 4, 22, 4, 23);
		Qr.VERSION_LEVEL_DATA[2][11] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 11, 206, 26, 4, 20, 6, 21);
		Qr.VERSION_LEVEL_DATA[2][12] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 12, 244, 24, 8, 20, 4, 21);
		Qr.VERSION_LEVEL_DATA[2][13] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 13, 261, 20, 11, 16, 5, 17);
		Qr.VERSION_LEVEL_DATA[2][14] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 14, 295, 30, 5, 24, 7, 25);
		Qr.VERSION_LEVEL_DATA[2][15] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 15, 325, 24, 15, 19, 2, 20);
		Qr.VERSION_LEVEL_DATA[2][16] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 16, 367, 28, 1, 22, 15, 23);
		Qr.VERSION_LEVEL_DATA[2][17] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 17, 397, 28, 17, 22, 1, 23);
		Qr.VERSION_LEVEL_DATA[2][18] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 18, 445, 26, 17, 21, 4, 22);
		Qr.VERSION_LEVEL_DATA[2][19] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 19, 485, 30, 15, 24, 5, 25);
		Qr.VERSION_LEVEL_DATA[2][20] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 20, 512, 28, 17, 22, 6, 23);
		Qr.VERSION_LEVEL_DATA[2][21] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 21, 568, 30, 7, 24, 16, 25);
		Qr.VERSION_LEVEL_DATA[2][22] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 22, 614, 30, 11, 24, 14, 25);
		Qr.VERSION_LEVEL_DATA[2][23] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 23, 664, 30, 11, 24, 16, 25);
		Qr.VERSION_LEVEL_DATA[2][24] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 24, 718, 30, 7, 24, 22, 25);
		Qr.VERSION_LEVEL_DATA[2][25] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 25, 754, 28, 28, 22, 6, 23);
		Qr.VERSION_LEVEL_DATA[2][26] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 26, 808, 30, 8, 23, 26, 24);
		Qr.VERSION_LEVEL_DATA[2][27] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 27, 871, 30, 4, 24, 31, 25);
		Qr.VERSION_LEVEL_DATA[2][28] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 28, 911, 30, 1, 23, 37, 24);
		Qr.VERSION_LEVEL_DATA[2][29] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 29, 985, 30, 15, 24, 25, 25);
		Qr.VERSION_LEVEL_DATA[2][30] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 30, 1033, 30, 42, 24, 1, 25);
		Qr.VERSION_LEVEL_DATA[2][31] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 31, 1115, 30, 10, 24, 35, 25);
		Qr.VERSION_LEVEL_DATA[2][32] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 32, 1171, 30, 29, 24, 19, 25);
		Qr.VERSION_LEVEL_DATA[2][33] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 33, 1231, 30, 44, 24, 7, 25);
		Qr.VERSION_LEVEL_DATA[2][34] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 34, 1286, 30, 39, 24, 14, 25);
		Qr.VERSION_LEVEL_DATA[2][35] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 35, 1354, 30, 46, 24, 10, 25);
		Qr.VERSION_LEVEL_DATA[2][36] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 36, 1426, 30, 49, 24, 10, 25);
		Qr.VERSION_LEVEL_DATA[2][37] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 37, 1502, 30, 48, 24, 14, 25);
		Qr.VERSION_LEVEL_DATA[2][38] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 38, 1582, 30, 43, 24, 22, 25);
		Qr.VERSION_LEVEL_DATA[2][39] = new Qr.LevelVersionData(ErrorCorrectionLevel.Q, 39, 1666, 30, 34, 24, 34, 25);
		Qr.VERSION_LEVEL_DATA[3][0] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 0, 9, 17, 1, 9, 0, 0);
		Qr.VERSION_LEVEL_DATA[3][1] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 1, 16, 28, 1, 16, 0, 0);
		Qr.VERSION_LEVEL_DATA[3][2] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 2, 26, 22, 2, 13, 0, 0);
		Qr.VERSION_LEVEL_DATA[3][3] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 3, 36, 16, 4, 9, 0, 0);
		Qr.VERSION_LEVEL_DATA[3][4] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 4, 46, 22, 2, 11, 2, 12);
		Qr.VERSION_LEVEL_DATA[3][5] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 5, 60, 28, 4, 15, 0, 0);
		Qr.VERSION_LEVEL_DATA[3][6] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 6, 66, 26, 4, 13, 1, 14);
		Qr.VERSION_LEVEL_DATA[3][7] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 7, 86, 26, 4, 14, 2, 15);
		Qr.VERSION_LEVEL_DATA[3][8] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 8, 100, 24, 4, 12, 4, 13);
		Qr.VERSION_LEVEL_DATA[3][9] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 9, 122, 28, 6, 15, 2, 16);
		Qr.VERSION_LEVEL_DATA[3][10] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 10, 140, 24, 3, 12, 8, 13);
		Qr.VERSION_LEVEL_DATA[3][11] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 11, 158, 28, 7, 14, 4, 15);
		Qr.VERSION_LEVEL_DATA[3][12] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 12, 180, 22, 12, 11, 4, 12);
		Qr.VERSION_LEVEL_DATA[3][13] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 13, 197, 24, 11, 12, 5, 13);
		Qr.VERSION_LEVEL_DATA[3][14] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 14, 223, 24, 11, 12, 7, 13);
		Qr.VERSION_LEVEL_DATA[3][15] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 15, 253, 30, 3, 15, 13, 16);
		Qr.VERSION_LEVEL_DATA[3][16] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 16, 283, 28, 2, 14, 17, 15);
		Qr.VERSION_LEVEL_DATA[3][17] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 17, 313, 28, 2, 14, 19, 15);
		Qr.VERSION_LEVEL_DATA[3][18] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 18, 341, 26, 9, 13, 16, 14);
		Qr.VERSION_LEVEL_DATA[3][19] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 19, 385, 28, 15, 15, 10, 16);
		Qr.VERSION_LEVEL_DATA[3][20] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 20, 406, 30, 19, 16, 6, 17);
		Qr.VERSION_LEVEL_DATA[3][21] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 21, 442, 24, 34, 13, 0, 0);
		Qr.VERSION_LEVEL_DATA[3][22] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 22, 464, 30, 16, 15, 14, 16);
		Qr.VERSION_LEVEL_DATA[3][23] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 23, 514, 30, 30, 16, 2, 17);
		Qr.VERSION_LEVEL_DATA[3][24] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 24, 538, 30, 22, 15, 13, 16);
		Qr.VERSION_LEVEL_DATA[3][25] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 25, 596, 30, 33, 16, 4, 17);
		Qr.VERSION_LEVEL_DATA[3][26] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 26, 628, 30, 12, 15, 28, 16);
		Qr.VERSION_LEVEL_DATA[3][27] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 27, 661, 30, 11, 15, 31, 16);
		Qr.VERSION_LEVEL_DATA[3][28] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 28, 701, 30, 19, 15, 26, 16);
		Qr.VERSION_LEVEL_DATA[3][29] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 29, 745, 30, 23, 15, 25, 16);
		Qr.VERSION_LEVEL_DATA[3][30] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 30, 793, 30, 23, 15, 28, 16);
		Qr.VERSION_LEVEL_DATA[3][31] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 31, 845, 30, 19, 15, 35, 16);
		Qr.VERSION_LEVEL_DATA[3][32] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 32, 901, 30, 11, 15, 46, 16);
		Qr.VERSION_LEVEL_DATA[3][33] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 33, 961, 30, 59, 16, 1, 17);
		Qr.VERSION_LEVEL_DATA[3][34] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 34, 986, 30, 22, 15, 41, 16);
		Qr.VERSION_LEVEL_DATA[3][35] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 35, 1054, 30, 2, 15, 64, 16);
		Qr.VERSION_LEVEL_DATA[3][36] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 36, 1096, 30, 24, 15, 46, 16);
		Qr.VERSION_LEVEL_DATA[3][37] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 37, 1142, 30, 42, 15, 32, 16);
		Qr.VERSION_LEVEL_DATA[3][38] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 38, 1222, 30, 10, 15, 67, 16);
		Qr.VERSION_LEVEL_DATA[3][39] = new Qr.LevelVersionData(ErrorCorrectionLevel.H, 39, 1276, 30, 20, 15, 61, 16);
	}
	
	public static class LevelVersionData {
		public final int	version;
		public final ErrorCorrectionLevel	level;
		public final int	numDataCw;
		public final int	numEcCwPerBlock;
		public final int 	numBlocksG1;
		public final int 	numDataCwPerBlocksG1;
		public final int	numBlocksG2;
		public final int 	numDataCwPerBlocksG2;
		public final int	numTotalCodewords;
		public final int	numDataCodewords;
		public final int	numEcCodewords;
		public LevelVersionData(ErrorCorrectionLevel level, int version, int nDataCw, int nEcCwPerBlock, 
				int nBlockG1, int nDataCwG1, int nBlockG2, int nDataCwG2) 
		{
			this.version = version;
			this.level = level;
			this.numDataCw = nDataCw;
			this.numEcCwPerBlock = nEcCwPerBlock;
			this.numBlocksG1 = nBlockG1;
			this.numDataCwPerBlocksG1 = nDataCwG1;
			this.numBlocksG2 = nBlockG2;
			this.numDataCwPerBlocksG2 = nDataCwG2;
			this.numDataCodewords = this.numBlocksG1*this.numDataCwPerBlocksG1 
					+ this.numBlocksG2*this.numDataCwPerBlocksG2;
			this.numEcCodewords = (this.numBlocksG1 + this.numBlocksG2)*this.numEcCwPerBlock;
			this.numTotalCodewords = this.numDataCodewords + this.numEcCodewords;
		}
	}
	
	public static void main(String[] args) throws Exception {
		Qr qr;
		qr = new Qr("HELLO WORLD", Qr.ErrorCorrectionLevel.M);
		System.out.println(qr);
	}
}

Changes to src/fanxi/barcode/Upc.java.

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
	public Barcode.Type type() {
		return Barcode.Type.UPC;
	}
	
	// compute checksum and fill this.barcode[] array
	private void computeBarcode(char[] code) throws Exception {
		
		if( !Barcode.isNumbers(code) ) {
			throw new Exception("UPC code must be all digit numbers");
		}

		if( code.length!=11 && code.length!=12 ) {
			throw new Exception(
				"UPC code must be 11 digit number (without checksum) or "
					+ "12 digit number (with checksum)");







|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
	public Barcode.Type type() {
		return Barcode.Type.UPC;
	}
	
	// compute checksum and fill this.barcode[] array
	private void computeBarcode(char[] code) throws Exception {
		
		if( !Barcode.isNumeric(code) ) {
			throw new Exception("UPC code must be all digit numbers");
		}

		if( code.length!=11 && code.length!=12 ) {
			throw new Exception(
				"UPC code must be 11 digit number (without checksum) or "
					+ "12 digit number (with checksum)");