From 5897d50feddd6d31d480c4fa3c5d3b2596ff0ff6 Mon Sep 17 00:00:00 2001 From: Igor Skljar <39621064+it240884sii@users.noreply.github.com> Date: Fri, 11 Sep 2026 21:23:14 +0300 Subject: [PATCH 1/2] Remove redundant isofield with id 96 Removed redundant ISO field definition for id 96. --- jpos/src/main/resources/packager/cmf.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/jpos/src/main/resources/packager/cmf.xml b/jpos/src/main/resources/packager/cmf.xml index 5b6d8fbf82..a83f7502e9 100644 --- a/jpos/src/main/resources/packager/cmf.xml +++ b/jpos/src/main/resources/packager/cmf.xml @@ -763,11 +763,6 @@ name="Reserved for ISO use" pad="false" class="org.jpos.iso.IFB_LLLLBINARY"/> - Date: Fri, 11 Sep 2026 16:41:42 -0300 Subject: [PATCH 2/2] Fix reserved field 91 in CMF packagers --- jpos/src/main/resources/packager/cmf-858.xml | 2 +- jpos/src/main/resources/packager/cmf.xml | 5 + jpos/src/main/resources/packager/cmfv3.xml | 8 +- .../iso/packager/CMFFieldDefinitionsTest.java | 103 ++++++++++++++++++ 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 jpos/src/test/java/org/jpos/iso/packager/CMFFieldDefinitionsTest.java diff --git a/jpos/src/main/resources/packager/cmf-858.xml b/jpos/src/main/resources/packager/cmf-858.xml index fdf67d2a55..e6b4db859a 100644 --- a/jpos/src/main/resources/packager/cmf-858.xml +++ b/jpos/src/main/resources/packager/cmf-858.xml @@ -763,7 +763,7 @@ name="Reserved for ISO use" pad="false" class="org.jpos.iso.IFB_LLLLBINARY"/> - + - + class="org.jpos.iso.IFB_LLLLBINARY"/> . + */ + +package org.jpos.iso.packager; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.jpos.iso.IFB_LLLBINARY; +import org.jpos.iso.IFB_LLLLBINARY; +import org.jpos.iso.ISOBinaryField; +import org.jpos.iso.ISOFieldPackager; +import org.jpos.iso.ISOMsg; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CMFFieldDefinitionsTest { + @ParameterizedTest + @ValueSource(strings = {"cmf.xml", "cmfv3.xml", "cmf-858.xml"}) + void topLevelFieldIdsAreUnique(String resource) throws Exception { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + try (InputStream input = resource(resource)) { + Element root = factory.newDocumentBuilder().parse(input).getDocumentElement(); + Set ids = new HashSet<>(); + for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child instanceof Element field && field.hasAttribute("id")) + assertTrue(ids.add(field.getAttribute("id")), + resource + ": duplicate field " + field.getAttribute("id")); + } + } + } + + @ParameterizedTest + @ValueSource(strings = {"cmf.xml", "cmfv3.xml", "cmf-858.xml"}) + void reservedAndKeyManagementFieldsRoundTripAtTheirLimits(String resource) throws Exception { + GenericPackager packager; + try (InputStream input = resource(resource)) { + packager = new GenericPackager(input); + } + ISOFieldPackager reserved = packager.getFieldPackager(91); + ISOFieldPackager keys = packager.getFieldPackager(96); + assertInstanceOf(IFB_LLLLBINARY.class, reserved); + assertEquals(9999, reserved.getLength()); + assertInstanceOf(IFB_LLLBINARY.class, keys); + assertEquals(999, keys.getLength()); + + byte[] reservedData = new byte[9999]; + byte[] keyData = new byte[999]; + Arrays.fill(reservedData, (byte) 0xA5); + Arrays.fill(keyData, (byte) 0x5A); + assertArrayEquals(new byte[] {(byte) 0x99, (byte) 0x99}, + Arrays.copyOf(reserved.pack(new ISOBinaryField(91, reservedData)), 2)); + assertArrayEquals(new byte[] {0x09, (byte) 0x99}, + Arrays.copyOf(keys.pack(new ISOBinaryField(96, keyData)), 2)); + + ISOMsg message = new ISOMsg(); + message.setPackager(packager); + message.setMTI("1200"); + message.set(91, reservedData); + message.set(96, keyData); + byte[] packed = message.pack(); + ISOMsg unpacked = new ISOMsg(); + unpacked.setPackager(packager); + assertEquals(packed.length, unpacked.unpack(packed)); + assertArrayEquals(reservedData, unpacked.getBytes(91)); + assertArrayEquals(keyData, unpacked.getBytes(96)); + } + + private InputStream resource(String name) { + InputStream input = getClass().getResourceAsStream("/packager/" + name); + assertNotNull(input, name); + return input; + } +}