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 * ISOMsgFieldPackager is a packager able to pack compound ISOMsgs
026 * (one message inside another one, and so on...)
027 *
028 * @author apr@cs.com.uy
029 * @version $Id$
030 * @see org.jpos.iso.packager.PostPackager
031 */
032public class ISOMsgFieldPackager extends ISOFieldPackager {
033    /** The message-level packager. */
034    protected ISOPackager msgPackager;
035    /** The field-level packager. */
036    protected ISOFieldPackager fieldPackager;
037
038    /**
039     * Constructs a packager with the given field packager and message packager.
040     * @param fieldPackager low level field packager
041     * @param msgPackager ISOMsgField default packager
042     */
043    public ISOMsgFieldPackager (
044            ISOFieldPackager fieldPackager,
045            ISOPackager msgPackager)
046    {
047        super(fieldPackager.getLength(), fieldPackager.getDescription());
048        this.msgPackager = msgPackager;
049        this.fieldPackager = fieldPackager;
050    }
051    /**
052     * @param c - a component
053     * @return packed component
054     * @exception ISOException on ISO processing error
055     */
056    @Override
057    public byte[] pack (ISOComponent c) throws ISOException {
058        if (c instanceof ISOMsg) {
059            ISOMsg m = (ISOMsg) c;
060            m.recalcBitMap();
061
062            // honor ISOMsg's current position in hierarchy
063            int mfn = m.getFieldNumber() >= 0 ? m.getFieldNumber() : 0;
064            ISOBinaryField f = new ISOBinaryField(mfn, msgPackager.pack(m));
065
066            if (msgPackager instanceof ISOSubFieldPackager) {
067                ISOSubFieldPackager sfp = (ISOSubFieldPackager) msgPackager;
068
069                // If this ISOMsg needs to be packed as part of some non-bitmapped tagged format
070                // (not all types covered here), or if the ISOSubFieldPackager has been configured
071                // with a specific field number, overriding the one in the ISOMsg.
072                if (fieldPackager instanceof TaggedFieldPackagerBase    ||
073                    fieldPackager instanceof TaggedFieldPackager        ||
074                    fieldPackager instanceof ISOTagStringFieldPackager  ||
075                    fieldPackager instanceof ISOTagBinaryFieldPackager  ||
076                    sfp.getFieldNumber() > -1)
077                {
078                    f.setFieldNumber(sfp.getFieldNumber());
079                }
080            }
081
082            return fieldPackager.pack(f);
083        }
084        return fieldPackager.pack(c);
085    }
086
087    /**
088     * @param c - the Component to unpack
089     * @param b - binary image
090     * @param offset - starting offset within the binary image
091     * @return consumed bytes
092     * @exception ISOException on ISO processing error
093     */
094    @Override
095    public int unpack (ISOComponent c, byte[] b, int offset)
096        throws ISOException
097    {
098        ISOBinaryField f = new ISOBinaryField(0);
099        if(msgPackager instanceof ISOSubFieldPackager) {
100            ISOSubFieldPackager sfp = (ISOSubFieldPackager) msgPackager;
101            f.setFieldNumber(sfp.getFieldNumber());
102        }
103        int consumed = fieldPackager.unpack(f, b, offset);
104        if (f.getValue() != null && c instanceof ISOMsg)
105            msgPackager.unpack(c, (byte[]) f.getValue());
106        return consumed;
107    }
108
109    /**
110     * @param c  - the Component to unpack
111     * @param in - input stream
112     * @throws org.jpos.iso.ISOException on pack/unpack error
113     * @throws java.io.IOException on I/O error
114     */
115    @Override
116    public void unpack (ISOComponent c, InputStream in)
117        throws IOException, ISOException
118    {
119        ISOBinaryField f = new ISOBinaryField(0);
120        if(msgPackager instanceof ISOSubFieldPackager) {
121            ISOSubFieldPackager sfp = (ISOSubFieldPackager) msgPackager;
122            f.setFieldNumber(sfp.getFieldNumber());
123        }
124        fieldPackager.unpack (f, in);
125        if (f.getValue() != null && c instanceof ISOMsg)
126            msgPackager.unpack(c, (byte[]) f.getValue());
127    }
128
129    @Override
130    public ISOComponent createComponent(int fieldNumber) {
131        ISOMsg m = new ISOMsg(fieldNumber);
132        m.setPackager(msgPackager);
133        return m;
134    }
135
136    @Override
137    public int getMaxPackedLength() {
138        return fieldPackager.getLength();
139    }
140    /** Returns the ISO message packager.
141     * @return the message packager
142     */
143    public ISOPackager getISOMsgPackager() {
144        return msgPackager;
145    }
146    /** Returns the ISO field packager.
147     * @return the field packager
148     */
149    public ISOFieldPackager getISOFieldPackager() {
150        return fieldPackager;
151    }
152}