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/**
026 * Represents POS Data Code flags as defined in jPOS/jCard specifications,
027 * encoding reading method, verification method, POS environment, and security characteristics.
028 */
029@SuppressWarnings("unused")
030public class PosDataCode extends PosFlags implements Loggeable {
031    /**
032     * Enumeration of card/data reading methods used at the POS terminal.
033     */
034    public enum ReadingMethod implements Flag {
035        /** Reading method is unknown. */
036        UNKNOWN                (1, "Unknown"),
037        /** Contactless reading (e.g. RFID); information not taken from card. */
038        CONTACTLESS            (1 << 1, "Information not taken from card"),  // i.e.: RFID
039        /** Physical entry (e.g. manual entry or OCR). */
040        PHYSICAL               (1 << 2, "Physical entry"),                   // i.e.: Manual Entry or OCR
041        /** Bar code reading. */
042        BARCODE                (1 << 3, "Bar code"),
043        /** Magnetic stripe reading. */
044        MAGNETIC_STRIPE        (1 << 4, "Magnetic Stripe"),
045        /** ICC (chip) reading. */
046        ICC                    (1 << 5, "ICC"),
047        /** Data on file (no card present). */
048        DATA_ON_FILE           (1 << 6, "Data on file"),
049        /** ICC was read but the read failed. */
050        ICC_FAILED             (1 << 11, "ICC read but failed"),
051        /** Magnetic stripe was read but the read failed. */
052        MAGNETIC_STRIPE_FAILED (1 << 12, "Magnetic Stripe read but failed"),
053        /** Fallback from preferred reading method. */
054        FALLBACK               (1 << 13, "Fallback"),
055        /** Track 1 data is present (jCard private field). */
056        TRACK1_PRESENT         (1 << 27, "Track1 data present"), // jCard private field
057        /** Track 2 data is present (jCard private field). */
058        TRACK2_PRESENT         (1 << 28, "Track2 data present"); // jCard private field
059
060        /** Integer bitmask value for this reading method. */
061        private int val;
062        /** Human-readable description of this reading method. */
063        private String description;
064        ReadingMethod (int val, String description) {
065            this.val = val;
066            this.description = description;
067        }
068        /** {@inheritDoc} */
069        public int intValue() {
070            return val;
071        }
072        /** {@inheritDoc} */
073        public String toString () {
074            return description;
075        }
076
077        /** Bit offset within the PosDataCode byte array for reading method flags. */
078        public static int OFFSET = 0;
079        /** {@inheritDoc} */
080        @Override
081        public int getOffset() {
082            return OFFSET;
083        }
084    }
085
086    /**
087     * Enumeration of cardholder verification methods used at the POS terminal.
088     */
089    public enum VerificationMethod implements Flag {
090        /** Verification method is unknown. */
091        UNKNOWN                              (1, "Unknown"),
092        /** No verification performed. */
093        NONE                                 (1 << 1, "None"),
094        /** Cardholder verified by manual signature. */
095        MANUAL_SIGNATURE                     (1 << 2, "Manual signature"),
096        /** Cardholder verified by online PIN. */
097        ONLINE_PIN                           (1 << 3, "Online PIN"),
098        /** Cardholder verified by offline PIN in clear. */
099        OFFLINE_PIN_IN_CLEAR                 (1 << 4, "Offline PIN in clear"),
100        /** Cardholder verified by offline encrypted PIN. */
101        OFFLINE_PIN_ENCRYPTED                (1 << 5, "Offline PIN encrypted"),
102        /** Cardholder verified by offline digitized signature analysis. */
103        OFFLINE_DIGITIZED_SIGNATURE_ANALYSIS (1 << 6, "Offline digitized signature analysis"),
104        /** Cardholder verified by offline biometrics. */
105        OFFLINE_BIOMETRICS                   (1 << 7, "Offline biometrics"),
106        /** Cardholder verified by offline manual verification. */
107        OFFLINE_MANUAL_VERIFICATION          (1 << 8, "Offline manual verification"),
108        /** Cardholder verified by offline biographics. */
109        OFFLINE_BIOGRAPHICS                  (1 << 9, "Offline biographics"),
110        /** Cardholder verified by account-based digital signature. */
111        ACCOUNT_BASED_DIGITAL_SIGNATURE      (1 << 10, "Account based digital signature"),
112        /** Cardholder verified by public key-based digital signature. */
113        PUBLIC_KEY_BASED_DIGITAL_SIGNATURE   (1 << 11, "Public key based digital signature");
114
115        /** Integer bitmask value for this verification method. */
116        private int val;
117        /** Human-readable description of this verification method. */
118        private String description;
119        VerificationMethod (int val, String description) {
120            this.val = val;
121            this.description = description;
122        }
123        /** {@inheritDoc} */
124        public int intValue() {
125            return val;
126        }
127        /** {@inheritDoc} */
128        public String toString () {
129            return description;
130        }
131
132        /** Bit offset within the PosDataCode byte array for verification method flags. */
133        public static int OFFSET = 4;
134        /** {@inheritDoc} */
135        @Override
136        public int getOffset() {
137            return OFFSET;
138        }
139    }
140
141    /**
142     * Enumeration of POS terminal environment types.
143     */
144    public enum POSEnvironment implements Flag {
145        /** POS environment is unknown. */
146        UNKNOWN                 (1, "Unknown"),
147        /** Attended POS terminal. */
148        ATTENDED                (1 << 1, "Attended POS"),
149        /** Unattended POS terminal, details unknown. */
150        UNATTENDED              (1 << 2, "Unattended, details unknown"),
151        /** Mail order / telephone order transaction. */
152        MOTO                    (1 << 3, "Mail order / telephone order"),
153        /** E-Commerce transaction. */
154        E_COMMERCE              (1 << 4, "E-Commerce"),
155        /** M-Commerce (mobile commerce) transaction. */
156        M_COMMERCE              (1 << 5, "M-Commerce"),
157        /** Recurring transaction. */
158        RECURRING               (1 << 6, "Recurring transaction"),
159        /** Transaction using stored cardholder details. */
160        STORED_DETAILS          (1 << 7, "Stored details"),
161        /** Cardholder Activated Terminal. */
162        CAT                     (1 << 8, "Cardholder Activated Terminal"),
163        /** ATM located on bank premises. */
164        ATM_ON_BANK             (1 << 9, "ATM on bank premises"),
165        /** ATM located off bank premises. */
166        ATM_OFF_BANK            (1 << 10, "ATM off bank premises"),
167        /** Deferred transaction. */
168        DEFERRED_TRANSACTION    (1 << 11, "Deferred transaction"),
169        /** Installment transaction. */
170        INSTALLMENT_TRANSACTION (1 << 12, "Installment transaction");
171
172        /** Integer bitmask value for this POS environment. */
173        private int val;
174        /** Human-readable description of this POS environment. */
175        private String description;
176        POSEnvironment (int val, String description) {
177            this.val = val;
178            this.description = description;
179        }
180        /** {@inheritDoc} */
181        public int intValue() {
182            return val;
183        }
184        /** {@inheritDoc} */
185        public String toString () {
186            return description;
187        }
188
189
190        /** Bit offset within the PosDataCode byte array for POS environment flags. */
191        public static int OFFSET = 8;
192        /** {@inheritDoc} */
193        @Override
194        public int getOffset() {
195            return OFFSET;
196        }
197    }
198
199    /**
200     * Enumeration of security characteristics for the transaction channel.
201     */
202    public enum SecurityCharacteristic implements Flag {
203        /** Security characteristic is unknown. */
204        UNKNOWN                                      (1, "Unknown"),
205        /** Transaction carried over a private network. */
206        PRIVATE_NETWORK                              (1 << 1, "Private network"),
207        /** Transaction carried over an open network (Internet). */
208        OPEN_NETWORK                                 (1 << 2, "Open network (Internet)"),
209        /** Channel-level MACing applied. */
210        CHANNEL_MACING                               (1 << 3, "Channel MACing"),
211        /** Pass-through MACing applied. */
212        PASS_THROUGH_MACING                          (1 << 4, "Pass through MACing"),
213        /** Channel-level encryption applied. */
214        CHANNEL_ENCRYPTION                           (1 << 5, "Channel encryption"),
215        /** End-to-end encryption applied. */
216        END_TO_END_ENCRYPTION                        (1 << 6, "End-to-end encryption"),
217        /** Private algorithm encryption applied. */
218        PRIVATE_ALG_ENCRYPTION                       (1 << 7, "Private algorithm encryption"),
219        /** PKI encryption applied. */
220        PKI_ENCRYPTION                               (1 << 8, "PKI encryption"),
221        /** Private algorithm MACing applied. */
222        PRIVATE_ALG_MACING                           (1 << 9, "Private algorithm MACing"),
223        /** Standard algorithm MACing applied. */
224        STD_ALG_MACING                               (1 << 10, "Standard algorithm MACing"),
225        /** Cardholder-managed end-to-end encryption applied. */
226        CARDHOLDER_MANAGED_END_TO_END_ENCRYPTION     (1 << 11, "Cardholder managed end-to-end encryption"),
227        /** Cardholder-managed point-to-point encryption applied. */
228        CARDHOLDER_MANAGED_POINT_TO_POINT_ENCRYPTION (1 << 12, "Cardholder managed point-to-point encryption"),
229        /** Merchant-managed end-to-end encryption applied. */
230        MERCHANT_MANAGED_END_TO_END_ENCRYPTION       (1 << 13, "Merchant managed end-to-end encryption"),
231        /** Merchant-managed point-to-point encryption applied. */
232        MERCHANT_MANAGED_POINT_TO_POINT_ENCRYPTION   (1 << 14, "Merchant managed point-to-point encryption"),
233        /** Acquirer-managed end-to-end encryption applied. */
234        ACQUIRER_MANAGED_END_TO_END_ENCRYPTION       (1 << 15, "Acquirer managed end-to-end-encryption"),
235        /** Acquirer-managed point-to-point encryption applied. */
236        ACQUIRER_MANAGED_POINT_TO_POINT_ENCRYPTION   (1 << 16, "Acquirer managed point-to-point encryption");
237
238        /** Integer bitmask value for this security characteristic. */
239        private int val;
240        /** Human-readable description of this security characteristic. */
241        private String description;
242        SecurityCharacteristic (int val, String description) {
243            this.val = val;
244            this.description = description;
245        }
246        /** {@inheritDoc} */
247        public int intValue() {
248            return val;
249        }
250        /** {@inheritDoc} */
251        public String toString () {
252            return description;
253        }
254
255        /** Bit offset within the PosDataCode byte array for security characteristic flags. */
256        public static int OFFSET = 12;
257        /** {@inheritDoc} */
258        @Override
259        public int getOffset() {
260            return OFFSET;
261        }
262    }
263
264    /** Raw 16-byte array holding the four groups of POS data code flags. */
265    private byte[] b = new byte[16];
266
267    /** Default constructor. */
268    public PosDataCode() {
269    }
270
271    /**
272     * Constructs a PosDataCode with the given flag integers for each category.
273     *
274     * @param readingMethod        bitmask of {@link ReadingMethod} values
275     * @param verificationMethod   bitmask of {@link VerificationMethod} values
276     * @param posEnvironment       bitmask of {@link POSEnvironment} values
277     * @param securityCharacteristic bitmask of {@link SecurityCharacteristic} values
278     */
279    public PosDataCode (
280            int readingMethod,
281            int verificationMethod,
282            int posEnvironment,
283            int securityCharacteristic)
284    {
285        super();
286
287        b[0]  = (byte) readingMethod;
288        b[1]  = (byte) (readingMethod >>> 8);
289        b[2]  = (byte) (readingMethod >>> 16);
290        b[3]  = (byte) (readingMethod >>> 24);
291
292        b[4]  = (byte) verificationMethod;
293        b[5]  = (byte) (verificationMethod >>> 8);
294        b[6]  = (byte) (verificationMethod >>> 16);
295        b[7]  = (byte) (verificationMethod >>> 24);
296
297        b[8]  = (byte) posEnvironment;
298        b[9]  = (byte) (posEnvironment >>> 8);
299        b[10] = (byte) (posEnvironment >>> 16);
300        b[11] = (byte) (posEnvironment >>> 24);
301
302        b[12] = (byte) securityCharacteristic;
303        b[13] = (byte) (securityCharacteristic >>> 8);
304        b[14] = (byte) (securityCharacteristic >>> 16);
305        b[15] = (byte) (securityCharacteristic >>> 24);
306    }
307
308    /**
309     * Constructs a PosDataCode from a raw byte array.
310     *
311     * @param b source byte array (up to 16 bytes are copied)
312     */
313    private PosDataCode (byte[] b) {
314        if (b != null) {
315            // will always use our own internal copy of array
316            int copyLen= Math.min(b.length, 16);
317            System.arraycopy(b, 0, this.b, 0, copyLen);
318        }
319    }
320
321    /**
322     * Returns {@code true} if all specified reading method bits are set.
323     *
324     * @param readingMethods bitmask of reading methods to test
325     * @return {@code true} if all specified bits are set
326     */
327    public boolean hasReadingMethods (int readingMethods) {
328        int i = b[3] << 24 | b[2] << 16  & 0xFF0000 | b[1] << 8  & 0xFF00 | b[0] & 0xFF ;
329        return (i & readingMethods) == readingMethods;
330    }
331
332    /**
333     * Returns {@code true} if the given reading method is set.
334     *
335     * @param method the {@link ReadingMethod} to test
336     * @return {@code true} if the reading method bit is set
337     */
338    public boolean hasReadingMethod (ReadingMethod method) {
339        return hasReadingMethods (method.intValue());
340    }
341
342    /**
343     * Returns {@code true} if all specified verification method bits are set.
344     *
345     * @param verificationMethods bitmask of verification methods to test
346     * @return {@code true} if all specified bits are set
347     */
348    public boolean hasVerificationMethods (int verificationMethods) {
349        int i = b[7] << 24 | b[6] << 16 & 0xFF0000 | b[5] << 8  & 0xFF00 | b[4] & 0xFF;
350        return (i & verificationMethods) == verificationMethods;
351    }
352
353    /**
354     * Returns {@code true} if the given verification method is set.
355     *
356     * @param method the {@link VerificationMethod} to test
357     * @return {@code true} if the verification method bit is set
358     */
359    public boolean hasVerificationMethod (VerificationMethod method) {
360        return hasVerificationMethods(method.intValue());
361    }
362
363    /**
364     * Returns {@code true} if all specified POS environment bits are set.
365     *
366     * @param posEnvironments bitmask of POS environments to test
367     * @return {@code true} if all specified bits are set
368     */
369    public boolean hasPosEnvironments (int posEnvironments) {
370        int i = b[11] << 24  | b[10] << 16 & 0xFF0000 | b[9] << 8 & 0xFF00 | b[8] & 0xFF;
371        return (i & posEnvironments) == posEnvironments;
372    }
373
374    /**
375     * Returns {@code true} if the given POS environment is set.
376     *
377     * @param method the {@link POSEnvironment} to test
378     * @return {@code true} if the POS environment bit is set
379     */
380    public boolean hasPosEnvironment (POSEnvironment method) {
381        return hasPosEnvironments(method.intValue());
382    }
383
384    /**
385     * Returns {@code true} if all specified security characteristic bits are set.
386     *
387     * @param securityCharacteristics bitmask of security characteristics to test
388     * @return {@code true} if all specified bits are set
389     */
390    public boolean hasSecurityCharacteristics (int securityCharacteristics) {
391        int i = b[15] << 24 | b[14] << 16 & 0xFF0000 | b[13] << 8  & 0xFF00 | b[12] & 0xFF;
392        return (i & securityCharacteristics) == securityCharacteristics;
393    }
394
395    /**
396     * Returns {@code true} if the given security characteristic is set.
397     *
398     * @param characteristic the {@link SecurityCharacteristic} to test
399     * @return {@code true} if the security characteristic bit is set
400     */
401    public boolean hasSecurityCharacteristic (SecurityCharacteristic characteristic) {
402        return  hasSecurityCharacteristics(characteristic.intValue());
403    }
404
405    /**
406     * Returns the raw 16-byte representation of this PosDataCode.
407     *
408     * @return byte array holding all POS data code flags
409     */
410    public byte[] getBytes() {
411        return b;
412    }
413
414    /**
415     * Returns {@code true} if the transaction used an EMV (ICC or contactless) reading method.
416     *
417     * @return {@code true} if ICC or contactless reading method is set
418     */
419    public boolean isEMV() {
420        return hasReadingMethod(ReadingMethod.ICC) || hasReadingMethod(ReadingMethod.CONTACTLESS);
421    }
422
423    /**
424     * Returns {@code true} if the transaction used manual (physical) entry.
425     *
426     * @return {@code true} if physical reading method is set
427     */
428    public boolean isManualEntry() {
429        return hasReadingMethod(ReadingMethod.PHYSICAL);
430    }
431
432    /**
433     * Returns {@code true} if the transaction used magnetic stripe reading.
434     *
435     * @return {@code true} if magnetic stripe reading method is set
436     */
437    public boolean isSwiped() {
438        return hasReadingMethod(ReadingMethod.MAGNETIC_STRIPE);
439    }
440
441    /**
442     * Returns {@code true} if the transaction is a recurring transaction.
443     *
444     * @return {@code true} if the recurring POS environment flag is set
445     */
446    public boolean isRecurring() {
447        return hasPosEnvironment(POSEnvironment.RECURRING);
448    }
449
450    /**
451     * Returns {@code true} if the transaction is an e-commerce transaction.
452     *
453     * @return {@code true} if the e-commerce POS environment flag is set
454     */
455    public boolean isECommerce() {
456        return hasPosEnvironment(POSEnvironment.E_COMMERCE);
457    }
458
459    /**
460     * Returns {@code true} if the card was not physically present (e-commerce, manual entry, or recurring).
461     *
462     * @return {@code true} if card-not-present conditions are detected
463     */
464    public boolean isCardNotPresent() {
465        return isECommerce() || isManualEntry() || isRecurring();
466    }
467
468    /** {@inheritDoc} */
469    public String toString() {
470        return super.toString() + "[" + ISOUtil.hexString (getBytes())+ "]";
471    }
472
473    /**
474     * Creates a PosDataCode instance from a raw byte array.
475     *
476     * @param b source byte array
477     * @return a new {@link PosDataCode} initialized from {@code b}
478     */
479    public static PosDataCode valueOf (byte[] b) {
480        return new PosDataCode(b);  // we create new objects for now, but may return cached instances in the future
481    }
482
483    /**
484     * Dumps a human-readable representation of this PosDataCode to the given stream.
485     *
486     * @param p      the output stream
487     * @param indent indentation prefix string
488     */
489    public void dump(PrintStream p, String indent) {
490        String inner = indent + "  ";
491        StringBuilder sb = new StringBuilder();
492        p.printf("%s<pdc value='%s'>%s%n", indent, ISOUtil.hexString(getBytes()), sb.toString());
493        for (ReadingMethod m : ReadingMethod.values()) {
494            if (hasReadingMethod(m)) {
495                if (sb.length() > 0)
496                    sb.append(',');
497                sb.append(m.name());
498            }
499        }
500        p.printf ("%srm: %s%n", inner, sb.toString());
501        sb = new StringBuilder();
502        for (VerificationMethod m : VerificationMethod.values()) {
503            if (hasVerificationMethod(m)) {
504                if (sb.length() > 0)
505                    sb.append(',');
506                sb.append(m.name());
507            }
508        }
509        p.printf ("%svm: %s%n", inner, sb.toString());
510        sb = new StringBuilder();
511        for (POSEnvironment m : POSEnvironment.values()) {
512            if (hasPosEnvironment(m)) {
513                if (sb.length() > 0)
514                    sb.append(',');
515                sb.append(m.name());
516            }
517        }
518        p.printf ("%spe: %s%n", inner, sb.toString());
519        sb = new StringBuilder();
520        for (SecurityCharacteristic m : SecurityCharacteristic.values()) {
521            if (hasSecurityCharacteristic(m)) {
522                if (sb.length() > 0)
523                    sb.append(',');
524                sb.append(m.name());
525            }
526        }
527        p.printf ("%ssc: %s%n", inner, sb.toString());
528        p.println("</pdc>");
529    }
530
531    /**
532     * Sets or clears one or more reading methods.
533     *
534     * @param value   {@code true} to set, {@code false} to clear
535     * @param methods the reading methods to modify
536     */
537    public void setReadingMethods(boolean value, ReadingMethod ... methods ){
538        setFlags(value, methods);
539    }
540
541    /**
542     * Clears one or more reading methods.
543     *
544     * @param methods the reading methods to clear
545     */
546    public void unsetReadingMethods(ReadingMethod ... methods ) {
547        setReadingMethods(false, methods);
548    }
549
550    /**
551     * Sets one or more reading methods.
552     *
553     * @param methods the reading methods to set
554     */
555    public void setReadingMethods(ReadingMethod ... methods ) {
556        setReadingMethods(true, methods);
557    }
558
559    /**
560     * Sets or clears one or more verification methods.
561     *
562     * @param value   {@code true} to set, {@code false} to clear
563     * @param methods the verification methods to modify
564     */
565    public void setVerificationMethods(boolean value, VerificationMethod ... methods ){
566        setFlags(value, methods);
567    }
568
569    /**
570     * Clears one or more verification methods.
571     *
572     * @param methods the verification methods to clear
573     */
574    public void unsetVerificationMethods(VerificationMethod ... methods){
575        setVerificationMethods(false, methods);
576    }
577
578    /**
579     * Sets one or more verification methods.
580     *
581     * @param methods the verification methods to set
582     */
583    public void setVerificationMethods(VerificationMethod ... methods){
584        setVerificationMethods(true, methods);
585    }
586
587    /**
588     * Sets or clears one or more POS environment flags.
589     *
590     * @param value {@code true} to set, {@code false} to clear
591     * @param envs  the POS environments to modify
592     */
593    public void setPOSEnvironments(boolean value, POSEnvironment ... envs){
594        setFlags(value, envs);
595    }
596
597    /**
598     * Clears one or more POS environment flags.
599     *
600     * @param envs the POS environments to clear
601     */
602    public void unsetPOSEnvironments(POSEnvironment ... envs){
603        setPOSEnvironments(false, envs);
604    }
605
606    /**
607     * Sets one or more POS environment flags.
608     *
609     * @param envs the POS environments to set
610     */
611    public void setPOSEnvironments(POSEnvironment ... envs){
612        setPOSEnvironments(true, envs);
613    }
614
615    /**
616     * Sets or clears one or more security characteristic flags.
617     *
618     * @param value                  {@code true} to set, {@code false} to clear
619     * @param securityCharacteristics the security characteristics to modify
620     */
621    public void setSecurityCharacteristics(boolean value, SecurityCharacteristic ... securityCharacteristics){
622        setFlags(value, securityCharacteristics);
623    }
624
625    /**
626     * Clears one or more security characteristic flags.
627     *
628     * @param envs the security characteristics to clear
629     */
630    public void unsetSecurityCharacteristics(SecurityCharacteristic ... envs){
631        setSecurityCharacteristics(false, envs);
632    }
633
634    /**
635     * Sets one or more security characteristic flags.
636     *
637     * @param envs the security characteristics to set
638     */
639    public void setSecurityCharacteristics(SecurityCharacteristic ... envs){
640        setSecurityCharacteristics(true, envs);
641    }
642
643
644}