KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > krysalis > barcode > impl > UPCEANLogicImpl


1 /*
2  * $Id: UPCEANLogicImpl.java,v 1.8 2003/04/19 14:06:06 jmaerki Exp $
3  * ============================================================================
4  * The Krysalis Patchy Software License, Version 1.1_01
5  * Copyright (c) 2002-2003 Nicola Ken Barozzi. All rights reserved.
6  *
7  * This Licence is compatible with the BSD licence as described and
8  * approved by http://www.opensource.org/, and is based on the
9  * Apache Software Licence Version 1.1.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in
20  * the documentation and/or other materials provided with the
21  * distribution.
22  *
23  * 3. The end-user documentation included with the redistribution,
24  * if any, must include the following acknowledgment:
25  * "This product includes software developed for project
26  * Krysalis (http://www.krysalis.org/)."
27  * Alternately, this acknowledgment may appear in the software itself,
28  * if and wherever such third-party acknowledgments normally appear.
29  *
30  * 4. The names "Krysalis" and "Nicola Ken Barozzi" and
31  * "Krysalis Barcode" must not be used to endorse or promote products
32  * derived from this software without prior written permission. For
33  * written permission, please contact nicolaken@krysalis.org.
34  *
35  * 5. Products derived from this software may not be called "Krysalis",
36  * "Krysalis Barcode", nor may "Krysalis" appear in their name,
37  * without prior written permission of Nicola Ken Barozzi.
38  *
39  * 6. This software may contain voluntary contributions made by many
40  * individuals, who decided to donate the code to this project in
41  * respect of this licence, and was originally created by
42  * Jeremias Maerki <jeremias@maerki.org>.
43  *
44  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
45  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47  * DISCLAIMED. IN NO EVENT SHALL THE KRYSALIS PROJECT OR
48  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
51  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
52  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
54  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  * ====================================================================
57  */

58 package org.krysalis.barcode.impl;
59
60 import org.krysalis.barcode.BarGroup;
61 import org.krysalis.barcode.ChecksumMode;
62 import org.krysalis.barcode.ClassicBarcodeLogicHandler;
63
64 /**
65  * This is an abstract base class for UPC and EAN barcodes.
66  *
67  * @author Jeremias Maerki
68  */

69 public abstract class UPCEANLogicImpl {
70
71     /** Left hand A character set */
72     protected static final byte LEFT_HAND_A = 0;
73     /** Left hand B character set */
74     protected static final byte LEFT_HAND_B = 1;
75     /** Right hand character set */
76     protected static final byte RIGHT_HAND = 2;
77     /** Odd parity character set */
78     protected static final byte ODD_PARITY = LEFT_HAND_A;
79     /** Even parity character set */
80     protected static final byte EVEN_PARITY = LEFT_HAND_B;
81
82     private static final byte[][] CHARSET = {{3, 2, 1, 1},
83                                              {2, 2, 2, 1},
84                                              {2, 1, 2, 2},
85                                              {1, 4, 1, 1},
86                                              {1, 1, 3, 2},
87                                              {1, 2, 3, 1},
88                                              {1, 1, 1, 4},
89                                              {1, 3, 1, 2},
90                                              {1, 2, 1, 3},
91                                              {3, 1, 1, 2}};
92         
93     private static final byte O = ODD_PARITY;
94     private static final byte E = EVEN_PARITY;
95     
96     private static final byte[][] SUPP2_PARITY =
97             {{O, O}, {O, E}, {E, O}, {E, E}};
98                                     
99     private static final byte[][] SUPP5_PARITY =
100             {{E, E, O, O, O},
101              {E, O, E, O, O},
102              {E, O, O, E, O},
103              {E, O, O, O, E},
104              {O, E, E, O, O},
105              {O, O, E, E, O},
106              {O, O, O, E, E},
107              {O, E, O, E, O},
108              {O, E, O, O, E},
109              {O, O, E, O, E}};
110                                              
111     private ChecksumMode checksumMode = ChecksumMode.CP_AUTO;
112
113     
114     /**
115      * Main constructor
116      * @param mode the checksum mode
117      */

118     public UPCEANLogicImpl(ChecksumMode mode) {
119         this.checksumMode = mode;
120     }
121
122     /**
123      * Returns the current checksum mode.
124      * @return the checksum mode
125      */

126     public ChecksumMode getChecksumMode() {
127         return this.checksumMode;
128     }
129
130     /**
131      * Validates a UPC/EAN message. The method throws IllegalArgumentExceptions
132      * if an invalid message is passed.
133      * @param msg the message to validate
134      */

135     public static void validateMessage(String JavaDoc msg) {
136         for (int i = 0; i < msg.length(); i++) {
137             final char c = msg.charAt(i);
138             if ((c < '0') || (c > '9')) {
139                 throw new IllegalArgumentException JavaDoc("Invalid characters found. "
140                     + "Valid are 0-9 only. Message: " + msg);
141             }
142         }
143     }
144     
145     /**
146      * Calculates the check character for a given message
147      * @param msg the message
148      * @return char the check character
149      */

150     public static char calcChecksum(String JavaDoc msg) {
151         int oddsum = 0;
152         int evensum = 0;
153         for (int i = msg.length() - 1; i >= 0; i--) {
154             if ((msg.length() - i) % 2 == 0) {
155                 evensum += Character.digit(msg.charAt(i), 10);
156             } else {
157                 oddsum += Character.digit(msg.charAt(i), 10);
158             }
159         }
160         int check = 10 - ((evensum + 3 * oddsum) % 10);
161         if (check >= 10) check = 0;
162         return Character.forDigit(check, 10);
163     }
164     
165     private int widthAt(char ch, int index) {
166         if (Character.isDigit(ch)) {
167             int digit = Character.digit(ch, 10);
168             int width = CHARSET[digit][index];
169             return width;
170         } else {
171             throw new IllegalArgumentException JavaDoc("Invalid character '" + ch + "'. Expected a digit.");
172         }
173     }
174
175     /**
176      * Encodes a character.
177      * @param logic the logic handler to receive generated events
178      * @param c the character to encode
179      * @param charset the character set to use
180      */

181     protected void encodeChar(ClassicBarcodeLogicHandler logic, char c, int charset) {
182         logic.startBarGroup(BarGroup.MSG_CHARACTER, new Character JavaDoc(c).toString());
183         if (charset == LEFT_HAND_B) {
184             for (byte i = 0; i < 4; i++) {
185                 final int width = widthAt(c, 3 - i);
186                 final boolean black = (i % 2 != 0);
187                 logic.addBar(black, width);
188             }
189         } else {
190             for (byte i = 0; i < 4; i++) {
191                 final int width = widthAt(c, i);
192                 final boolean black = ((i % 2 == 0 && charset == RIGHT_HAND)
193                                     || (i % 2 != 0 && charset == LEFT_HAND_A));
194                 logic.addBar(black, width);
195             }
196         }
197         logic.endBarGroup();
198     }
199
200     /**
201      * Generates a side guard.
202      * @param logic the logic handler to receive generated events
203      */

204     protected void drawSideGuard(ClassicBarcodeLogicHandler logic) {
205         //draw guard bars 101
206
logic.startBarGroup(BarGroup.UPC_EAN_GUARD, null);
207         logic.addBar(true, 1);
208         logic.addBar(false, 1);
209         logic.addBar(true, 1);
210         logic.endBarGroup();
211     }
212
213     /**
214      * Generates a center guard.
215      * @param logic the logic handler to receive generated events
216      */

217     protected void drawCenterGuard(ClassicBarcodeLogicHandler logic) {
218         //draw guard bars 01010
219
logic.startBarGroup(BarGroup.UPC_EAN_GUARD, null);
220         logic.addBar(false, 1);
221         logic.addBar(true, 1);
222         logic.addBar(false, 1);
223         logic.addBar(true, 1);
224         logic.addBar(false, 1);
225         logic.endBarGroup();
226     }
227
228     /**
229      * Generates a left guard for a supplemental.
230      * @param logic the logic handler to receive generated events
231      */

232     private void drawSuppLeftGuard(ClassicBarcodeLogicHandler logic) {
233         //draw guard bars 1011
234
logic.startBarGroup(BarGroup.UPC_EAN_GUARD, null);
235         logic.addBar(true, 1);
236         logic.addBar(false, 1);
237         logic.addBar(true, 2);
238         logic.endBarGroup();
239     }
240
241     /**
242      * Generates a supplemental separator.
243      * @param logic the logic handler to receive generated events
244      */

245     private void drawSuppSeparator(ClassicBarcodeLogicHandler logic) {
246         //draw inter-character separator 01
247
logic.startBarGroup(BarGroup.UPC_EAN_GUARD, null);
248         logic.addBar(false, 1);
249         logic.addBar(true, 1);
250         logic.endBarGroup();
251     }
252
253     /**
254      * Generates a 2-character supplemental.
255      * @param logic the logic handler to receive generated events
256      * @param supp the two characters
257      */

258     private void drawSupplemental2(ClassicBarcodeLogicHandler logic, String JavaDoc supp) {
259         int suppValue = Integer.parseInt(supp);
260         int remainder = suppValue % 4;
261         logic.startBarGroup(BarGroup.UPC_EAN_SUPP, supp);
262         drawSuppLeftGuard(logic);
263         encodeChar(logic, supp.charAt(0), SUPP2_PARITY[remainder][0]);
264         drawSuppSeparator(logic);
265         encodeChar(logic, supp.charAt(1), SUPP2_PARITY[remainder][1]);
266         logic.endBarGroup();
267     }
268
269     /**
270      * Generates a 5-character supplemental.
271      * @param logic the logic handler to receive generated events
272      * @param supp the five characters
273      */

274     private void drawSupplemental5(ClassicBarcodeLogicHandler logic, String JavaDoc supp) {
275         int suppValue = Integer.parseInt(supp);
276         int weightedSum =
277               3 * ((suppValue / 10000) % 10)
278             + 9 * ((suppValue / 1000) % 10)
279             + 3 * ((suppValue / 100) % 10)
280             + 9 * ((suppValue / 10) % 10)
281             + 3 * (suppValue % 10);
282         byte checksum = (byte)(weightedSum % 10);
283         logic.startBarGroup(BarGroup.UPC_EAN_SUPP, supp);
284         drawSuppLeftGuard(logic);
285         for (byte i = 0; i < 5; i++) {
286             if (i > 0) {
287                 drawSuppSeparator(logic);
288             }
289             encodeChar(logic, supp.charAt(i), SUPP5_PARITY[checksum][i]);
290         }
291         logic.endBarGroup();
292     }
293
294     /**
295      * Generates events for a supplemental.
296      * @param logic the logic handler to receive generated events
297      * @param supp the supplemental
298      */

299     protected void drawSupplemental(ClassicBarcodeLogicHandler logic, String JavaDoc supp) {
300         if (supp == null) {
301             throw new NullPointerException JavaDoc("Supplemental message must not be null");
302         }
303         if (supp.length() == 2) {
304             drawSupplemental2(logic, supp);
305         } else if (supp.length() == 5) {
306             drawSupplemental5(logic, supp);
307         } else {
308             throw new IllegalArgumentException JavaDoc(
309                 "Only supplemental lengths 2 and 5 are allowed: " + supp.length());
310         }
311     }
312
313     /**
314      * Returns the length of the supplemental part of a UPC/EAN message.
315      * The method throws an IllegalArgumentException if the supplement is
316      * malformed.
317      * @param msg the UPC/EAN message
318      * @return 2 or 5 if there is a supplemental, 0 if there's none.
319      */

320     protected static int getSupplementalLength(String JavaDoc msg) {
321         String JavaDoc supp = retrieveSupplemental(msg);
322         if (supp == null) {
323             return 0;
324         } else if (supp.length() == 2) {
325             return 2;
326         } else if (supp.length() == 5) {
327             return 5;
328         } else {
329             throw new IllegalArgumentException JavaDoc(
330                 "Illegal supplemental length (valid: 2 or 5): " + supp);
331         }
332     }
333
334     /**
335      * Removes an optional supplemental (ex. "+20") from the message.
336      * @param msg a UPC/EAN message
337      * @return the message without the supplemental
338      */

339     protected static String JavaDoc removeSupplemental(String JavaDoc msg) {
340         int pos = msg.indexOf('+');
341         if (pos >= 0) {
342             return msg.substring(0, pos);
343         } else {
344             return msg;
345         }
346     }
347     
348     /**
349      * Returns the supplemental part of a UPC/EAN message if there is one.
350      * Supplementals are added in the form: "+[supplemental]" (ex. "+20").
351      * @param msg a UPC/EAN message
352      * @return the supplemental part, null if there is none
353      */

354     protected static String JavaDoc retrieveSupplemental(String JavaDoc msg) {
355         int pos = msg.indexOf('+');
356         if (pos >= 0) {
357             return msg.substring(pos + 1);
358         } else {
359             return null;
360         }
361     }
362     
363     /**
364      * Generates the barcode logic.
365      * @param logic the logic handler to receive generated events
366      * @param msg the message to encode
367      */

368     public abstract void generateBarcodeLogic(ClassicBarcodeLogicHandler logic, String JavaDoc msg);
369                                              
370 }
371
Popular Tags