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.IOException;
022import java.io.InputStream;
023
024/**
025 * Wraps a regular binary field packager so its payload can be exposed as an
026 * {@link ISODatasetField}.
027 */
028public class DatasetFieldPackager extends ISOFieldPackager {
029    /** Inner packager that handles the dataset payload (TLV/DBM). */
030    protected ISODatasetPackager datasetPackager;
031    /** Outer field packager handling length and transport encoding. */
032    protected ISOFieldPackager fieldPackager;
033
034    /**
035     * Creates a dataset-aware field packager.
036     *
037     * @param fieldPackager outer field packager used for length and transport encoding
038     * @param datasetPackager inner dataset payload packager
039     */
040    public DatasetFieldPackager(ISOFieldPackager fieldPackager, ISODatasetPackager datasetPackager) {
041        super(fieldPackager.getLength(), fieldPackager.getDescription());
042        this.datasetPackager = datasetPackager;
043        this.fieldPackager = fieldPackager;
044    }
045
046    /**
047     * Packs a dataset field by first encoding the inner dataset payload and
048     * then delegating the outer field framing to the wrapped field packager.
049     *
050     * @param c field component to pack
051     * @return packed field bytes
052     * @throws ISOException on packing errors
053     */
054    @Override
055    public byte[] pack(ISOComponent c) throws ISOException {
056        if (c instanceof ISODatasetField) {
057            ISODatasetField datasetField = (ISODatasetField) c;
058            int fieldNumber = datasetField.getFieldNumber() >= 0 ? datasetField.getFieldNumber() : 0;
059            ISOBinaryField field = new ISOBinaryField(fieldNumber, datasetPackager.pack(datasetField));
060            if (datasetPackager.getFieldNumber() > -1) {
061                field.setFieldNumber(datasetPackager.getFieldNumber());
062            }
063            return fieldPackager.pack(field);
064        }
065        return fieldPackager.pack(c);
066    }
067
068    /**
069     * Unpacks a dataset field from a byte array.
070     *
071     * @param c destination component
072     * @param b source buffer
073     * @param offset starting offset
074     * @return number of bytes consumed from the outer field
075     * @throws ISOException on unpacking errors
076     */
077    @Override
078    public int unpack(ISOComponent c, byte[] b, int offset) throws ISOException {
079        ISOBinaryField field = new ISOBinaryField(0);
080        if (datasetPackager.getFieldNumber() > -1) {
081            field.setFieldNumber(datasetPackager.getFieldNumber());
082        }
083        int consumed = fieldPackager.unpack(field, b, offset);
084        if (field.getValue() != null && c instanceof ISODatasetField) {
085            datasetPackager.unpack(c, (byte[]) field.getValue());
086        }
087        return consumed;
088    }
089
090    /**
091     * Unpacks a dataset field from a stream.
092     *
093     * @param c destination component
094     * @param in source stream
095     * @throws IOException on stream errors
096     * @throws ISOException on unpacking errors
097     */
098    @Override
099    public void unpack(ISOComponent c, InputStream in) throws IOException, ISOException {
100        ISOBinaryField field = new ISOBinaryField(0);
101        if (datasetPackager.getFieldNumber() > -1) {
102            field.setFieldNumber(datasetPackager.getFieldNumber());
103        }
104        fieldPackager.unpack(field, in);
105        if (field.getValue() != null && c instanceof ISODatasetField) {
106            datasetPackager.unpack(c, (byte[]) field.getValue());
107        }
108    }
109
110    /**
111     * Creates an {@link ISODatasetField} for the supplied field number.
112     *
113     * @param fieldNumber outer field number
114     * @return dataset field component
115     */
116    @Override
117    public ISOComponent createComponent(int fieldNumber) {
118        return new ISODatasetField(fieldNumber);
119    }
120
121    /**
122     * Returns the maximum packed length of the outer field.
123     *
124     * @return maximum packed length
125     */
126    @Override
127    public int getMaxPackedLength() {
128        return fieldPackager.getLength();
129    }
130
131    /**
132     * Returns the inner dataset payload packager.
133     *
134     * @return dataset packager
135     */
136    public ISODatasetPackager getISODatasetPackager() {
137        return datasetPackager;
138    }
139
140    /**
141     * Returns the wrapped outer field packager.
142     *
143     * @return outer field packager
144     */
145    public ISOFieldPackager getISOFieldPackager() {
146        return fieldPackager;
147    }
148}