001    /* JAPI - (Yet another (hopefully) useful) Java API
002     *
003     * Copyright (C) 2006 Christian Hujer
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License as
007     * published by the Free Software Foundation; either version 2 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful, but
011     * WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013     * General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018     * 02111-1307, USA.
019     */
020    
021    package net.sf.japi.io;
022    
023    /** A class with methods for converting BCD data from and to Binary data.
024     * Currently only int is supported.
025     * Probably <code>net.sf.japi.io</code> is not the ideal package for this class, yet it seems most appropriate.
026     * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
027     */
028    public final class BCD {
029    
030        /** Private constructor - no instances needed. */
031        private BCD() {
032        }
033    
034        /** Convert a BCD value to an int value.
035         * @param bcd BCD value
036         * @return int value for bcd value
037         */
038        public static int bcd2int(final int bcd) {
039            int ret = 0;
040            for (int i = 0; i < 8; i++) {
041                ret += (0xF & bcd >> 4 * i) * base10(i);
042            }
043            return ret;
044        }
045    
046        /** Convert an int value to a BCD value.
047         * @param val int value
048         * @return bcd value for int value
049         */
050        public static int int2bcd(final int val) {
051            int bcd = 0;
052            int work = val;
053            for (int i = 0; i < 8; i++) {
054                final int nibble = work % 10;
055                work /= 10;
056                bcd += nibble * (1 << 4 * i);
057            }
058            return bcd;
059        }
060    
061        /** Check wether a BCD value is correct.
062         * If the supplied value contains a nibble with a value &gt;= 10, it will throw an IllegalArgumentException.
063         * Otherwise it will simply return.
064         * @param bcd number to check
065         */
066        public static void check(final int bcd) {
067            for (int i = 0; i < 8; i++) {
068                if ((0xF & bcd >> 4 * i) >= 10) {
069                    throw new IllegalArgumentException();
070                }
071            }
072        }
073    
074        /** Check wether a BCD value is correct.
075         * @param bcd bcd value to check
076         * @return <code>true</code> if supplied value is bcd, otherwise <code>false</code>
077         */
078        public static boolean isBcd(final int bcd) {
079            for (int i = 0; i < 8; i++) {
080                if ((0xF & bcd >> 4 * i) >= 10) {
081                    return false;
082                }
083            }
084            return true;
085        }
086    
087        /** Return the 10 base (10^n).
088         * @param n power
089         * @return <code>10^<var>n</var></code>
090         */
091        public static int base10(final int n) {
092            int ret = 1;
093            for (int i = 0; i < n; i++) {
094                ret *= 10;
095            }
096            return ret;
097        }
098    
099        /** Perform a BCD correction.
100         * For each nibble that contains a value greater than or equal 10, the next nibble will be incremented.
101         * Any overflow is added to the low byte, so an overflow bcd value will toggle even/odd.
102         * @param bcd bcd value to correct
103         * @return corrected bcd value
104         */
105        public static int correct(final int bcd) {
106            int newBcd = bcd;
107            for (int i = 0; i < 8; i++) {
108                if ((0xF & bcd >> 4 * i) >= 10) {
109                    newBcd -= 10 << 4 * i;
110                    newBcd += 1 << 4 * (i + 1);
111                }
112            }
113            assert isBcd(newBcd);
114            return newBcd;
115        }
116    
117    } // class BCD