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