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.*;
022import org.jpos.util.LogEvent;
023import org.jpos.util.Logger;
024
025import java.io.ByteArrayOutputStream;
026import java.io.IOException;
027import java.util.BitSet;
028import java.util.Map;
029
030/**
031 * ISO 8583 v1987 BINARY Packager 
032 * customized for VISA Base1 subfields
033 * 
034 *
035 * @author <a href="mailto:eoin.flood@orbiscom.com">Eoin Flood</a>
036 * @version $Id$
037 * @see ISOPackager
038 * @see ISOBasePackager
039 * @see ISOComponent
040 */
041
042@SuppressWarnings("unchecked")
043public class Base1SubFieldPackager extends ISOBasePackager
044{
045    /** Default constructor; no instance state to initialise. */
046    public Base1SubFieldPackager() {}
047    // These methods are identical to ISOBasePackager
048    // except that fld[1] has been replaced with fld[0]
049    // and a secondard bitmap is not allowed
050
051    protected boolean emitBitMap()
052    {
053        return fld[0] instanceof ISOBitMapPackager;
054    }
055
056    protected int getFirstField()
057    {
058        return fld[0] instanceof ISOBitMapPackager ? 1 : 0;
059    }
060
061    protected ISOFieldPackager getBitMapfieldPackager() 
062    {
063        return fld[0];
064    }
065
066    /**
067     * Unpack a packed subfield into
068     * its corresponding ISOComponent
069     */
070
071    public int unpack (ISOComponent m, byte[] b) throws ISOException 
072    {
073        LogEvent evt = new LogEvent (this, "unpack");
074        try 
075        {
076            if (m.getComposite() != m) 
077                throw new ISOException ("Can't call packager on non Composite");
078            if (logger != null)  // save a few CPU cycle if no logger available
079                evt.addMessage (ISOUtil.hexString (b));
080
081            int consumed=0;
082            ISOBitMap bitmap = new ISOBitMap (-1);
083
084            BitSet bmap = null;
085            int maxField = fld.length;
086            if (emitBitMap()) 
087            {
088                consumed += getBitMapfieldPackager().unpack(bitmap,b,consumed);
089                bmap = (BitSet) bitmap.getValue();
090                m.set (bitmap);
091                maxField = bmap.size();
092            }
093            for (int i=getFirstField(); i<maxField && consumed < b.length; i++) 
094            {
095                if (bmap == null || bmap.get(i)) 
096                {
097                    ISOComponent c = fld[i].createComponent(i);
098                    consumed += fld[i].unpack (c, b, consumed);
099                    m.set(c);
100                }
101            }
102            if (b.length != consumed) 
103            {
104                evt.addMessage (
105                "WARNING: unpack len=" +b.length +" consumed=" +consumed);
106            }
107            return consumed;
108        } 
109        catch (ISOException e) 
110        {
111            evt.addMessage (e);
112            throw e;
113        } 
114        finally 
115        {
116            Logger.log (evt);
117        }
118    }
119
120    /**
121     * Pack the subfield into a byte array
122     */
123    @Override
124    public byte[] pack (ISOComponent m) throws ISOException {
125        LogEvent evt = new LogEvent (this, "pack");
126        try (ByteArrayOutputStream bout = new ByteArrayOutputStream(100))
127        {
128            ISOComponent c;
129            Map fields = m.getChildren();
130
131            if (emitBitMap()) 
132            {
133                // BITMAP (-1 in HashTable)
134                c = (ISOComponent) fields.get (-1);
135                byte[] b = getBitMapfieldPackager().pack(c);
136                bout.write(b);
137            }
138
139            for (int i=getFirstField(); i<=m.getMaxField(); i++) 
140            {
141                if ((c = (ISOComponent) fields.get (i)) != null)
142                {
143                    try 
144                    {
145                        byte[] b = fld[i].pack(c);
146                        bout.write(b);
147                    } 
148                    catch (Exception e) 
149                    {
150                        evt.addMessage ("error packing field "+i);
151                        evt.addMessage (c);
152                        evt.addMessage (e);
153                        throw new ISOException (e);
154                    }
155                }
156            }
157
158            byte[] d = bout.toByteArray();
159            if (logger != null)  // save a few CPU cycle if no logger available
160                evt.addMessage (ISOUtil.hexString (d));
161            return d;
162        } catch (ISOException ex) {
163            evt.addMessage(ex);
164            throw ex;
165        } catch (IOException ex) {
166            evt.addMessage(ex);
167            throw new ISOException(ex);
168        } finally {
169            Logger.log(evt);
170        }
171    }
172}
173
174