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;
020import org.jpos.iso.packager.GenericPackagerParams;
021import org.xml.sax.Attributes;
022
023import java.io.IOException;
024import java.io.InputStream;
025
026/** EBCDIC LLLVAR binary field packager with a two-byte tag header. */
027public class IFEP_LLLBINARY extends ISOBinaryFieldPackager implements GenericPackagerParams {
028    Integer fieldId = null;
029
030    private static final int TAG_HEADER_LENGTH = 2;
031    private final int prefixerPackedLength;
032
033    /** Default constructor. */
034    public IFEP_LLLBINARY() {
035        super();
036        prefixerPackedLength = 3;
037    }
038
039    /**
040     * Constructs a packager with the given length and description.
041     * @param length field length
042     * @param description field description
043     */
044    public IFEP_LLLBINARY(int length, String description) {
045        super(length, description, LiteralBinaryInterpreter.INSTANCE, EbcdicPrefixer.LLL);
046        checkLength(length, 999);
047        prefixerPackedLength = EbcdicPrefixer.LLL.getPackedLength();
048    }
049
050    /**
051     * Constructs a packager with custom interpreter and prefixer.
052     * @param length           field length
053     * @param description      field description
054     * @param binaryInterpreter binary interpreter
055     * @param prefixer         length prefixer
056     */
057    public IFEP_LLLBINARY(int length, String description, BinaryInterpreter binaryInterpreter, Prefixer prefixer) {
058        super(length, description, binaryInterpreter, prefixer);
059        checkLength(length, 999);
060        prefixerPackedLength = prefixer.getPackedLength();
061    }
062
063    @Override
064    public void setGenericPackagerParams(Attributes atts) {
065        fieldId = Integer.parseInt(atts.getValue("id"));
066    }
067
068    /**
069     * @param c - a component
070     * @return packed component
071     * @exception ISOException on ISO processing error
072     */
073    public byte[] pack (ISOComponent c) throws ISOException {
074        int len = ((byte[]) c.getValue()).length;
075        String key = fieldId != null ? fieldId.toString() : c.getKey().toString();
076        if (len > getLength())
077            throw new ISOException (
078                "invalid len "+len +" packing IFEP_LLLBINARY field "
079                +c.getKey().toString()
080            );
081
082        byte[] b = new byte[len + prefixerPackedLength + TAG_HEADER_LENGTH];
083        byte[] llltt = 
084            ISOUtil.asciiToEbcdic (
085              ISOUtil.zeropad(Integer.toString(len+ TAG_HEADER_LENGTH), prefixerPackedLength)
086              +ISOUtil.zeropad(key, TAG_HEADER_LENGTH));
087
088        System.arraycopy(llltt, 0, b, 0, TAG_HEADER_LENGTH + prefixerPackedLength);
089        System.arraycopy(c.getValue(), 0, b, TAG_HEADER_LENGTH + prefixerPackedLength, len);
090        return b;
091    }
092
093    /**
094     * @param c - the Component to unpack
095     * @param b - binary image
096     * @param offset - starting offset within the binary image
097     * @return consumed bytes
098     * @exception ISOException on ISO processing error
099     */
100    public int unpack (ISOComponent c, byte[] b, int offset)
101        throws ISOException
102    {
103        int len = Integer.parseInt(ISOUtil.ebcdicToAscii(b, offset, prefixerPackedLength)) - TAG_HEADER_LENGTH;
104        if (!(c instanceof ISOBinaryField))
105            throw new ISOException 
106                (c.getClass().getName() + " is not an ISOBinaryField");
107
108        c.setFieldNumber (
109            Integer.parseInt(ISOUtil.ebcdicToAscii (b, offset+prefixerPackedLength, TAG_HEADER_LENGTH))
110        );
111        byte[] value = new byte[len];
112        System.arraycopy(b, offset + prefixerPackedLength + TAG_HEADER_LENGTH , value, 0, len);
113        c.setValue (value);
114        return len + prefixerPackedLength + TAG_HEADER_LENGTH;
115    }
116    public void unpack (ISOComponent c, InputStream in) 
117        throws IOException, ISOException
118    {
119
120        if (!(c instanceof ISOField))
121            throw new ISOException 
122                (c.getClass().getName() + " is not an ISOField");
123
124        int len   = Integer.parseInt(ISOUtil.ebcdicToAscii(readBytes (in, prefixerPackedLength))) - TAG_HEADER_LENGTH;
125        int fldno = Integer.parseInt(ISOUtil.ebcdicToAscii(readBytes (in, TAG_HEADER_LENGTH)));
126        c.setFieldNumber (fldno);
127        c.setValue (readBytes(in, len));
128    }
129    public int getMaxPackedLength() {
130        return getLength() + prefixerPackedLength + TAG_HEADER_LENGTH;
131    }
132}