1 /***********************************************************************************************************************
2 * Copyright (c) 2004, International Barcode Consortium
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of
11 * conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 * Neither the name of the International Barcode Consortium nor the names of any contributors may be used to endorse
14 * or promote products derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 ***********************************************************************************************************************/
26
27 package net.sourceforge.barbecue.linear.ean;
28
29 import net.sourceforge.barbecue.BlankModule;
30 import net.sourceforge.barbecue.Module;
31 import net.sourceforge.barbecue.linear.upc.ModuleFactory;
32
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37
38 /**
39 * The EAN 13 barcode module definitions.
40 *
41 * @author <a href="mailto:james@metalskin.com">James Jenner</a>
42 */
43 final class EAN13ModuleFactory extends ModuleFactory {
44
45 protected static final List KEYS_LEFT_ODD = new ArrayList();
46 protected static final List KEYS_LEFT_EVEN = new ArrayList();
47
48 protected static final Map SET_LEFT_ODD = new HashMap();
49 protected static final Map SET_LEFT_EVEN = new HashMap();
50
51 protected static final Module RIGHT_MARGIN = new BlankModule(7);
52
53 protected static final Map PARITY_TABLE = new HashMap();
54
55 protected static final int ODD = 0;
56 protected static final int EVEN = 1;
57
58 public static final int LEFT_WIDTH = 7;
59 public static final int GUARD_CHAR_SIZE = 0;
60
61 static {
62 initBaseSet();
63 }
64
65 /**
66 * Cannot construct.
67 */
68 protected EAN13ModuleFactory() {
69 }
70
71 /**
72 * Initialise the module definitions.
73 */
74 protected static void initBaseSet() {
75 initRightSet();
76
77 initLeftOddSet();
78 initLeftEvenSet();
79
80
81
82
83
84 PARITY_TABLE.put("0", new int[]{ODD, ODD, ODD, ODD, ODD, ODD});
85 PARITY_TABLE.put("1", new int[]{ODD, ODD, EVEN, ODD, EVEN, EVEN});
86 PARITY_TABLE.put("2", new int[]{ODD, ODD, EVEN, EVEN, ODD, EVEN});
87 PARITY_TABLE.put("3", new int[]{ODD, ODD, EVEN, EVEN, EVEN, ODD});
88 PARITY_TABLE.put("4", new int[]{ODD, EVEN, ODD, ODD, EVEN, EVEN});
89 PARITY_TABLE.put("5", new int[]{ODD, EVEN, EVEN, ODD, ODD, EVEN});
90 PARITY_TABLE.put("6", new int[]{ODD, EVEN, EVEN, EVEN, ODD, ODD});
91 PARITY_TABLE.put("7", new int[]{ODD, EVEN, ODD, EVEN, ODD, EVEN});
92 PARITY_TABLE.put("8", new int[]{ODD, EVEN, ODD, EVEN, EVEN, ODD});
93 PARITY_TABLE.put("9", new int[]{ODD, EVEN, EVEN, ODD, EVEN, ODD});
94 }
95
96 protected static void initLeftOddSet() {
97
98 KEYS_LEFT_ODD.add("0");
99 SET_LEFT_ODD.put("0", new Module(new int[]{0, 3, 2, 1, 1}));
100 KEYS_LEFT_ODD.add("1");
101 SET_LEFT_ODD.put("1", new Module(new int[]{0, 2, 2, 2, 1}));
102 KEYS_LEFT_ODD.add("2");
103 SET_LEFT_ODD.put("2", new Module(new int[]{0, 2, 1, 2, 2}));
104 KEYS_LEFT_ODD.add("3");
105 SET_LEFT_ODD.put("3", new Module(new int[]{0, 1, 4, 1, 1}));
106 KEYS_LEFT_ODD.add("4");
107 SET_LEFT_ODD.put("4", new Module(new int[]{0, 1, 1, 3, 2}));
108 KEYS_LEFT_ODD.add("5");
109 SET_LEFT_ODD.put("5", new Module(new int[]{0, 1, 2, 3, 1}));
110 KEYS_LEFT_ODD.add("6");
111 SET_LEFT_ODD.put("6", new Module(new int[]{0, 1, 1, 1, 4}));
112 KEYS_LEFT_ODD.add("7");
113 SET_LEFT_ODD.put("7", new Module(new int[]{0, 1, 3, 1, 2}));
114 KEYS_LEFT_ODD.add("8");
115 SET_LEFT_ODD.put("8", new Module(new int[]{0, 1, 2, 1, 3}));
116 KEYS_LEFT_ODD.add("9");
117 SET_LEFT_ODD.put("9", new Module(new int[]{0, 3, 1, 1, 2}));
118 }
119
120 protected static void initLeftEvenSet() {
121
122 KEYS_LEFT_EVEN.add("0");
123 SET_LEFT_EVEN.put("0", new Module(new int[]{0, 1, 1, 2, 3}));
124 KEYS_LEFT_EVEN.add("1");
125 SET_LEFT_EVEN.put("1", new Module(new int[]{0, 1, 2, 2, 2}));
126 KEYS_LEFT_EVEN.add("2");
127 SET_LEFT_EVEN.put("2", new Module(new int[]{0, 2, 2, 1, 2}));
128 KEYS_LEFT_EVEN.add("3");
129 SET_LEFT_EVEN.put("3", new Module(new int[]{0, 1, 1, 4, 1}));
130 KEYS_LEFT_EVEN.add("4");
131 SET_LEFT_EVEN.put("4", new Module(new int[]{0, 2, 3, 1, 1}));
132 KEYS_LEFT_EVEN.add("5");
133 SET_LEFT_EVEN.put("5", new Module(new int[]{0, 1, 3, 2, 1}));
134 KEYS_LEFT_EVEN.add("6");
135 SET_LEFT_EVEN.put("6", new Module(new int[]{0, 4, 1, 1, 1}));
136 KEYS_LEFT_EVEN.add("7");
137 SET_LEFT_EVEN.put("7", new Module(new int[]{0, 2, 1, 3, 1}));
138 KEYS_LEFT_EVEN.add("8");
139 SET_LEFT_EVEN.put("8", new Module(new int[]{0, 3, 1, 2, 1}));
140 KEYS_LEFT_EVEN.add("9");
141 SET_LEFT_EVEN.put("9", new Module(new int[]{0, 2, 1, 1, 3}));
142 }
143
144 /**
145 * Returns the module that represents the specified character.
146 *
147 * @param key The data character to get the encoding module for
148 * @param position The position of the data character, starts at 0
149 * @return The module that encodes the given char
150 */
151 public static Module getModule(String firstChar, String key, int position) {
152 Module module = null;
153
154
155
156
157
158
159
160 if (position + 1 > LEFT_WIDTH) {
161 module = (Module) SET_RIGHT.get(key);
162 } else {
163 int[] parityRef = (int[]) PARITY_TABLE.get(firstChar);
164
165 if (parityRef[position - 1] == ODD) {
166 module = (Module) SET_LEFT_ODD.get(key);
167 } else {
168 module = (Module) SET_LEFT_EVEN.get(key);
169 }
170 }
171
172 module.setSymbol(key);
173 return module;
174 }
175
176 /**
177 * Indicates whether the given key is represented in the default encoding
178 * table that this module factory contains.
179 *
180 * @return True if the key has a direct module encoding, false if not
181 */
182 public static boolean hasModule(String key) {
183 if (KEYS_RIGHT.indexOf(key) > -1) {
184 return true;
185 }
186
187 if (KEYS_LEFT_ODD.indexOf(key) > -1) {
188 return true;
189 }
190
191 if (KEYS_LEFT_EVEN.indexOf(key) > -1) {
192 return true;
193 }
194
195 return false;
196 }
197
198 /**
199 * Returns the encoded module at the given index position. This is used to
200 * get the encoded checksum character.
201 *
202 * @param index The index of the module required
203 * @return The module at the specified index
204 */
205 public static Module getModuleForIndex(String firstChar, int index) {
206 if (index + 1 > LEFT_WIDTH) {
207 return getModule((String) KEYS_RIGHT.get(index), index);
208 } else {
209 int[] parityRef = (int[]) PARITY_TABLE.get(firstChar);
210
211 if (parityRef[index - 1] == ODD) {
212 return getModule((String) KEYS_LEFT_ODD.get(index), index);
213 } else {
214 return getModule((String) KEYS_LEFT_EVEN.get(index), index);
215 }
216 }
217 }
218
219 /**
220 * Indicates whether the given character is valid for this barcode or not.
221 * This basically just checks to see whether the key is in the list of
222 * encoded characters.
223 *
224 * @param key The key to check for validity
225 * @return True if the key is valid, false otherwise
226 */
227 public static boolean isValid(String key) {
228 if (KEYS_RIGHT.indexOf(key) > -1) {
229 return true;
230 }
231
232 if (KEYS_LEFT_ODD.indexOf(key) > -1) {
233 return true;
234 }
235
236 if (KEYS_LEFT_EVEN.indexOf(key) > -1) {
237 return true;
238 }
239
240 return false;
241 }
242 }