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.packager;
020
021import org.jpos.iso.Dataset;
022import org.jpos.iso.DatasetFormat;
023import org.jpos.iso.ISODatasetField;
024import org.jpos.iso.ISOComponent;
025import org.jpos.iso.ISODataset;
026import org.jpos.iso.ISOException;
027
028import java.io.IOException;
029import java.io.InputStream;
030
031/**
032 * Special-case packager for DE 055 ICC data, which carries raw BER-TLV without
033 * the standard dataset identifier and length envelope.
034 */
035public class ICCDataPackager extends DatasetPackager {
036    /**
037     * Creates an ICC data packager.
038     *
039     * @throws ISOException on packager initialization errors
040     */
041    public ICCDataPackager() throws ISOException {
042        super();
043    }
044
045    /**
046     * ICC data is encoded as raw BER-TLV, without the standard dataset
047     * identifier and length envelope.
048     *
049     * @return always {@code false}
050     */
051    @Override
052    public boolean hasDatasetEnvelope() {
053        return false;
054    }
055
056    /**
057     * Packs raw ICC BER-TLV bytes without the standard dataset envelope.
058     *
059     * @param m ICC dataset field
060     * @return packed BER-TLV bytes
061     * @throws ISOException on packing errors
062     */
063    @Override
064    public byte[] pack(ISOComponent m) throws ISOException {
065        if (!(m instanceof ISODatasetField)) {
066            throw new ISOException("Can't call ICC data packager on " + (m != null ? m.getClass().getName() : "null"));
067        }
068        ISODatasetField field = (ISODatasetField) m;
069        Dataset dataset = field.getDataset(getFieldNumber());
070        if (dataset == null) {
071            if (field.getDatasets().isEmpty()) {
072                return new byte[0];
073            }
074            dataset = field.getDatasets().get(0);
075        }
076        if (dataset.getFormat() != DatasetFormat.TLV) {
077            throw new ISOException("ICC data is BER-TLV only");
078        }
079        return packDatasetContent(dataset);
080    }
081
082    /**
083     * Unpacks raw ICC BER-TLV bytes into a synthetic dataset keyed by the outer field number.
084     *
085     * @param m destination dataset field
086     * @param b BER-TLV bytes
087     * @return number of bytes consumed
088     * @throws ISOException on unpacking errors
089     */
090    @Override
091    public int unpack(ISOComponent m, byte[] b) throws ISOException {
092        if (!(m instanceof ISODatasetField)) {
093            throw new ISOException("Can't call ICC data packager on " + (m != null ? m.getClass().getName() : "null"));
094        }
095        ISODataset dataset = unpackTLV(getFieldNumber(), b);
096        ((ISODatasetField) m).addDataset(dataset);
097        return b.length;
098    }
099
100    /**
101     * Unpacks raw ICC BER-TLV bytes from a stream.
102     *
103     * @param m destination dataset field
104     * @param in source stream
105     * @throws IOException on stream errors
106     * @throws ISOException on unpacking errors
107     */
108    @Override
109    public void unpack(ISOComponent m, InputStream in) throws IOException, ISOException {
110        unpack(m, in.readAllBytes());
111    }
112}