001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 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,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.iso;
020
021import java.io.PrintStream;
022
023import org.jpos.util.Loggeable;
024
025@SuppressWarnings("unused")
026public class PosCapability extends PosFlags implements Loggeable {
027    public enum ReadingCapability implements Flag {
028        UNKNOWN                (1,      "Unknown"),
029        CONTACTLESS            (1 << 1, "Information not taken from card"),  // i.e.: RFID
030        PHYSICAL               (1 << 2, "Physical entry"),                   // i.e.: Manual Entry or OCR
031        BARCODE                (1 << 3, "Bar code"),
032        MAGNETIC_STRIPE        (1 << 4, "Magnetic Stripe"),
033        ICC                    (1 << 5, "ICC"),
034        DATA_ON_FILE           (1 << 6, "Data on file"),
035        ICC_FAILED             (1 << 11, "ICC read but failed"),
036        MAGNETIC_STRIPE_FAILED (1 << 12, "Magnetic Stripe read but failed"),
037        FALLBACK               (1 << 13, "Fallback"),
038        TRACK1_PRESENT         (1 << 27, "Track1 data present"), // jCard private field
039        TRACK2_PRESENT         (1 << 28, "Track2 data present"); // jCard private field
040
041        private int val;
042        private String description;
043        ReadingCapability (int val, String description) {
044            this.val = val;
045            this.description = description;
046        }
047        public int intValue() {
048            return val;
049        }
050        public String toString () {
051            return description;
052        }
053
054        public static int OFFSET = 0;
055        @Override
056        public int getOffset() {
057            return OFFSET;
058        }
059    }
060
061    public enum VerificationCapability implements Flag {
062        UNKNOWN                              (1, "Unknown"),
063        NONE                                 (1 << 1, "None"),
064        MANUAL_SIGNATURE                     (1 << 2, "Manual signature"),
065        ONLINE_PIN                           (1 << 3, "Online PIN"),
066        OFFLINE_PIN_IN_CLEAR                 (1 << 4, "Offline PIN in clear"),
067        OFFLINE_PIN_ENCRYPTED                (1 << 5, "Offline PIN encrypted"),
068        OFFLINE_DIGITIZED_SIGNATURE_ANALYSIS (1 << 6, "Offline digitized signature analysis"),
069        OFFLINE_BIOMETRICS                   (1 << 7, "Offline biometrics"),
070        OFFLINE_MANUAL_VERIFICATION          (1 << 8, "Offline manual verification"),
071        OFFLINE_BIOGRAPHICS                  (1 << 9, "Offline biographics"),
072        ACCOUNT_BASED_DIGITAL_SIGNATURE      (1 << 10, "Account based digital signature"),
073        PUBLIC_KEY_BASED_DIGITAL_SIGNATURE   (1 << 11, "Public key based digital signature");
074
075        private int val;
076        private String description;
077        VerificationCapability (int val, String description) {
078            this.val = val;
079            this.description = description;
080        }
081        public int intValue() {
082            return val;
083        }
084        public String toString () {
085            return description;
086        }
087
088        public static int OFFSET = 0;
089        @Override
090        public int getOffset() {
091            return OFFSET;
092        }
093    }
094
095    private byte[] b = new byte[8];
096
097    public PosCapability() {}
098
099    public PosCapability (
100            int readingCapability,
101            int verificationCapability)
102    {
103        super();
104
105        b[0]  = (byte) readingCapability;
106        b[1]  = (byte) (readingCapability >>> 8);
107        b[2]  = (byte) (readingCapability >>> 16);
108        b[3]  = (byte) (readingCapability >>> 24);
109
110        b[4]  = (byte) verificationCapability;
111        b[5]  = (byte) (verificationCapability >>> 8);
112        b[6]  = (byte) (verificationCapability >>> 16);
113        b[7]  = (byte) (verificationCapability >>> 24);
114    }
115
116    private PosCapability (byte[] b) {
117        if (b != null) {
118            // will always use our own internal copy of array
119            int copyLen= Math.min(b.length, 16);
120            System.arraycopy(b, 0, this.b, 0, copyLen);
121        }
122    }
123
124    public boolean hasReadingCapability (int readingMethods) {
125        int i = b[3] << 24 | b[2] << 16  & 0xFF0000 | b[1] << 8  & 0xFF00 | b[0] & 0xFF ;
126        return (i & readingMethods) == readingMethods;
127    }
128    public boolean hasReadingCapability (ReadingCapability method) {
129        return hasReadingCapability (method.intValue());
130    }
131    public boolean hasVerificationCapability (int verificationMethods) {
132        int i = b[7] << 24 | b[6] << 16 & 0xFF0000 | b[5] << 8  & 0xFF00 | b[4] & 0xFF;
133        return (i & verificationMethods) == verificationMethods;
134    }
135    public boolean hasVerificationCapability (VerificationCapability method) {
136        return hasVerificationCapability(method.intValue());
137    }
138    public byte[] getBytes() {
139        return b;
140    }
141    public boolean canEMV() {
142        return hasReadingCapability(ReadingCapability.ICC) || hasReadingCapability(ReadingCapability.CONTACTLESS);
143    }
144    public boolean canManualEntry() {
145        return hasReadingCapability(ReadingCapability.PHYSICAL);
146    }
147    public boolean isSwiped() {
148        return hasReadingCapability(ReadingCapability.MAGNETIC_STRIPE);
149    }
150    public String toString() {
151        return super.toString() + "[" + ISOUtil.hexString (getBytes())+ "]";
152    }
153
154    public static PosCapability valueOf (byte[] b) {
155        return new PosCapability(b);  // we create new objects for now, but may return cached instances in the future
156    }
157
158    public void dump(PrintStream p, String indent) {
159        String inner = indent + "  ";
160        StringBuilder sb = new StringBuilder();
161        p.printf("%s<pvc value='%s'>%n", indent, ISOUtil.hexString(getBytes()));
162        for (ReadingCapability m : ReadingCapability.values()) {
163            if (hasReadingCapability(m)) {
164                if (sb.length() > 0)
165                    sb.append(',');
166                sb.append(m.name());
167            }
168        }
169        p.printf ("%src: %s%n", inner, sb);
170        sb = new StringBuilder();
171        for (VerificationCapability m : VerificationCapability.values()) {
172            if (hasVerificationCapability(m)) {
173                if (sb.length() > 0)
174                    sb.append(',');
175                sb.append(m.name());
176            }
177        }
178        p.printf ("%svc: %s%n", inner, sb);
179        p.println("</pvc>");
180    }
181
182    public void setReadingCapabilities(boolean value, ReadingCapability ... capabilities ){
183        setFlags(value, capabilities);
184    }
185
186    public void unsetReadingCapabilities(ReadingCapability ... capabilities) {
187        setReadingCapabilities(false, capabilities);
188    }
189
190    public void setReadingCapabilities(ReadingCapability ... capabilities) {
191        setReadingCapabilities(true, capabilities);
192    }
193
194    public void setVerificationCapabilities(boolean value, VerificationCapability ... capabilities){
195        setFlags(value, capabilities);
196    }
197
198    public void unsetVerificationCapabilities(VerificationCapability ... capabilities) {
199        setVerificationCapabilities(false, capabilities);
200    }
201
202    public void setVerificationCapabilities(VerificationCapability ... capabilities) {
203        setVerificationCapabilities(true, capabilities);
204    }
205}