From e295d2b38502d8145c30f6ce13f5c3acc7ecc1d9 Mon Sep 17 00:00:00 2001 From: Maxime Date: Fri, 25 Aug 2017 08:55:47 +0200 Subject: [PATCH 1/4] Allow settings to passed programmatically. The use case is to not necessarily rely on the properties file, as within one process run, different copybooks may require different settings. By default, the behavior is the same as before. --- src/main/java/net/sf/cb2java/Settings.java | 143 ++++++++++-------- .../cb2java/copybook/CobolPreprocessor.java | 6 +- .../net/sf/cb2java/copybook/Copybook.java | 73 +-------- .../sf/cb2java/copybook/CopybookAnalyzer.java | 15 +- .../sf/cb2java/copybook/CopybookParser.java | 20 ++- .../java/net/sf/cb2java/copybook/Item.java | 16 +- .../java/net/sf/cb2java/types/Binary.java | 4 +- .../java/net/sf/cb2java/types/Element.java | 8 +- 8 files changed, 130 insertions(+), 155 deletions(-) mode change 100644 => 100755 src/main/java/net/sf/cb2java/Settings.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/copybook/CobolPreprocessor.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/copybook/Copybook.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/copybook/CopybookAnalyzer.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/copybook/CopybookParser.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/copybook/Item.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/types/Binary.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/types/Element.java diff --git a/src/main/java/net/sf/cb2java/Settings.java b/src/main/java/net/sf/cb2java/Settings.java old mode 100644 new mode 100755 index b73793e..8a1af6b --- a/src/main/java/net/sf/cb2java/Settings.java +++ b/src/main/java/net/sf/cb2java/Settings.java @@ -23,33 +23,20 @@ import java.util.Properties; import net.sf.cb2java.types.SignPosition; -public interface Settings { - static Settings DEFAULT = new Default(); - - String getEncoding(); - - Values getValues(); - - boolean getLittleEndian(); - - String getFloatConversion(); - - SignPosition getSignPosition(); - - int getColumnStart(); - - int getColumnEnd(); - - static class Default implements Settings { - private static final String DEFAULT_ENCODING; - private static final boolean DEFAULT_LITTLE_ENDIAN; - private static final String DEFAULT_FLOAT_CONVERSION; - private static final SignPosition DEFAULT_SIGN_POSITION; - private static final Values DEFAULT_VALUES = new Values(); - private static final int DEFAULT_COLUMN_START; - private static final int DEFAULT_COLUMN_END; - - static { +public class Settings { + + String encoding = System.getProperty("file.encoding"); + boolean littleEndian = false; + String floatConversion = "net.sf.cb2java.copybook.floating.IEEE754"; + SignPosition signPosition = SignPosition.TRAILING; + int columnStart = 6; + int columnEnd = 72; + Values values = new Values(); + + static Settings DEFAULT; + static public Settings DEFAULT() { + if(DEFAULT == null) { + DEFAULT = new Settings(); Properties props = new Properties(); try (InputStream is = Settings.class.getResourceAsStream("/copybook.props")) { @@ -63,52 +50,80 @@ static class Default implements Settings { System.out.println("Could not load 'copybook.props' file, reverting to defaults."); } - DEFAULT_ENCODING = getSetting("encoding", System.getProperty("file.encoding"), props); - DEFAULT_LITTLE_ENDIAN = "false".equals(getSetting("little-endian", "false", props)); - DEFAULT_FLOAT_CONVERSION = getSetting("float-conversion", "net.sf.cb2java.copybook.floating.IEEE754", - props); - DEFAULT_SIGN_POSITION = "leading".equalsIgnoreCase(getSetting("default-sign-position", "trailing", props)) - ? SignPosition.LEADING : SignPosition.TRAILING; - DEFAULT_COLUMN_START = Integer.parseInt(getSetting("column.start", "6", props)); - DEFAULT_COLUMN_END = Integer.parseInt(getSetting("column.end", "72", props)); + DEFAULT.setEncoding(getSetting("encoding", DEFAULT.getEncoding(), props)); + DEFAULT.setLittleEndian("false".equals(getSetting("little-endian", DEFAULT.isLittleEndian() + "", props))); + DEFAULT.setFloatConversion(getSetting("float-conversion", DEFAULT.getFloatConversion(), props)); + DEFAULT.setSignPosition("leading".equalsIgnoreCase(getSetting("default-sign-position", "trailing", props)) + ? SignPosition.LEADING : SignPosition.TRAILING); + DEFAULT.setColumnStart(Integer.parseInt(getSetting("column.start", DEFAULT.getColumnStart() + "", props))); + DEFAULT.setColumnEnd(Integer.parseInt(getSetting("column.end", DEFAULT.getColumnEnd() + "", props))); } + return DEFAULT; + } - private static String getSetting(String name, String defaultValue, Properties props) { - String result = defaultValue; - try { - result = System.getProperty("cb2java." + name, result); - result = props.getProperty(name, result); - } catch (RuntimeException e) { - } - return result; - } + public String getEncoding() { + return encoding; + } - public String getEncoding() { - return DEFAULT_ENCODING; - } + public void setEncoding(String encoding) { + this.encoding = encoding; + } - public String getFloatConversion() { - return DEFAULT_FLOAT_CONVERSION; - } + public boolean isLittleEndian() { + return littleEndian; + } - public boolean getLittleEndian() { - return DEFAULT_LITTLE_ENDIAN; - } + public void setLittleEndian(boolean littleEndian) { + this.littleEndian = littleEndian; + } - public Values getValues() { - return DEFAULT_VALUES; - } + public String getFloatConversion() { + return floatConversion; + } - public SignPosition getSignPosition() { - return DEFAULT_SIGN_POSITION; - } + public void setFloatConversion(String floatConversion) { + this.floatConversion = floatConversion; + } - public int getColumnStart() { - return DEFAULT_COLUMN_START; - } + public SignPosition getSignPosition() { + return signPosition; + } + + public void setSignPosition(SignPosition signPosition) { + this.signPosition = signPosition; + } + + public int getColumnStart() { + return columnStart; + } + + public void setColumnStart(int columnStart) { + this.columnStart = columnStart; + } + + public int getColumnEnd() { + return columnEnd; + } + + public void setColumnEnd(int columnEnd) { + this.columnEnd = columnEnd; + } + + public Values getValues() { + return values; + } + + public void setValues(Values values) { + this.values = values; + } - public int getColumnEnd() { - return DEFAULT_COLUMN_END; + static private String getSetting(String name, String defaultValue, Properties props) { + String result = defaultValue; + try { + result = System.getProperty("cb2java." + name, result); + result = props.getProperty(name, result); + } catch (RuntimeException e) { } + return result; } } diff --git a/src/main/java/net/sf/cb2java/copybook/CobolPreprocessor.java b/src/main/java/net/sf/cb2java/copybook/CobolPreprocessor.java old mode 100644 new mode 100755 index e1b94a9..33b7f97 --- a/src/main/java/net/sf/cb2java/copybook/CobolPreprocessor.java +++ b/src/main/java/net/sf/cb2java/copybook/CobolPreprocessor.java @@ -38,10 +38,10 @@ public class CobolPreprocessor { private CobolPreprocessor() { } - public static String preProcess(Reader reader) { + public static String preProcess(Reader reader, Settings settings) { // TODO: figure out a way to pass copybook specific settings for non-default margins treated as comment. - int columnStart = Settings.DEFAULT.getColumnStart(); - int columnEnd = Settings.DEFAULT.getColumnEnd(); + int columnStart = settings.getColumnStart(); + int columnEnd = settings.getColumnEnd(); StringBuffer sb = new StringBuffer(); diff --git a/src/main/java/net/sf/cb2java/copybook/Copybook.java b/src/main/java/net/sf/cb2java/copybook/Copybook.java old mode 100644 new mode 100755 index 231e1cf..11f964f --- a/src/main/java/net/sf/cb2java/copybook/Copybook.java +++ b/src/main/java/net/sf/cb2java/copybook/Copybook.java @@ -40,13 +40,8 @@ * * @author James Watson */ -public class Copybook extends Group implements Settings +public class Copybook extends Group //implements Settings { - private String encoding = Settings.DEFAULT.getEncoding(); - private boolean littleEndian = Settings.DEFAULT.getLittleEndian(); - private String floatConversion = Settings.DEFAULT.getFloatConversion(); - private SignPosition signPosition = Settings.DEFAULT.getSignPosition(); - private Map redefines = new HashMap(); private final Values values; @@ -56,12 +51,13 @@ public class Copybook extends Group implements Settings * * @param name the name of the copybook */ - Copybook(String name, Values values) + Copybook(String name, Values values, Settings settings) { super(name, 0, 0); this.values = values; - this.values.setEncoding(encoding); + this.setSettings(settings); + this.values.setEncoding(settings.getEncoding()); } public Values getValues() @@ -126,67 +122,6 @@ public List parseData(InputStream stream) throws IOException return list; } - - /** - * Sets the encoding for the copybook instance, used for parsing - * and writing of data - * - * @param encoding the encoding for the system - */ - public void setEncoding(String encoding) - { - this.encoding = encoding; - } - - /** - * retrieves the current encoding for text - * - * @return the encoding for text - */ - public String getEncoding() - { - return encoding; - } - - public void setLittleEndian(boolean littleEndian) - { - this.littleEndian = littleEndian; - } - - public boolean getLittleEndian() - { - return littleEndian; - } - - public void setFloatConversion(String className) - { - this.floatConversion = className; - } - - public String getFloatConversion() - { - return floatConversion; - } - - public void setSignPosition(SignPosition position) - { - this.signPosition = position; - } - - public SignPosition getSignPosition() - { - return signPosition; - } - - @Override - public int getColumnStart() { - return Settings.DEFAULT.getColumnStart(); - } - - @Override - public int getColumnEnd() { - return Settings.DEFAULT.getColumnEnd(); - } /** * a helper class for buffering the data as it is processed diff --git a/src/main/java/net/sf/cb2java/copybook/CopybookAnalyzer.java b/src/main/java/net/sf/cb2java/copybook/CopybookAnalyzer.java old mode 100644 new mode 100755 index 63b508b..1497a8d --- a/src/main/java/net/sf/cb2java/copybook/CopybookAnalyzer.java +++ b/src/main/java/net/sf/cb2java/copybook/CopybookAnalyzer.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.StringTokenizer; +import net.sf.cb2java.Settings; import net.sf.cb2java.Values; import net.sf.cb2java.types.Element; import net.sf.cb2java.types.Group; @@ -84,6 +85,7 @@ class CopybookAnalyzer extends DepthFirstAdapter private Parser parser; private Item document; private Item current; + private Settings settings; /** * Creates a new instance with the given parser and @@ -92,12 +94,13 @@ class CopybookAnalyzer extends DepthFirstAdapter * @param copyBookName the name to give this copybook * @param parser sablecc parser instance */ - CopybookAnalyzer(String copyBookName, Parser parser) + CopybookAnalyzer(String copyBookName, Parser parser, Settings settings) { - document = new Item(values, true); + document = new Item(values, true, settings); document.name = copyBookName; current = document; this.parser = parser; + this.settings = settings; } /** @@ -127,7 +130,7 @@ public void outARecordDescription(ARecordDescription node) private void walkTree(Item item) { - item.getElement().setSettings((Copybook) document.getElement()); + item.getElement().setSettings(document.getElement().getSettings()); for (Iterator i = item.children.iterator(); i.hasNext();) { Item child = (Item) i.next(); @@ -176,7 +179,7 @@ public void checkForComments(Token node) public void inAItem(AItem node) { Item prevItem = current; - current = new Item(values, false); + current = new Item(values, false, settings); current.level = Integer.parseInt(node.getNumberNot88().toString().trim()); current.name = node.getDataNameOrFiller().toString().trim(); @@ -265,12 +268,12 @@ public void inASignClause(ASignClause node) public void inALeadingLeadingOrTrailing(ALeadingLeadingOrTrailing node) { - current.signPosition = SignPosition.LEADING; + current.getSettings().setSignPosition(SignPosition.LEADING); } public void inATrailimngLeadingOrTrailing(ALeadingLeadingOrTrailing node) { - current.signPosition = SignPosition.TRAILING; + current.getSettings().setSignPosition(SignPosition.TRAILING); } //======================= USAGE CLAUSE ========================== diff --git a/src/main/java/net/sf/cb2java/copybook/CopybookParser.java b/src/main/java/net/sf/cb2java/copybook/CopybookParser.java old mode 100644 new mode 100755 index 2e84dcb..f44cfc8 --- a/src/main/java/net/sf/cb2java/copybook/CopybookParser.java +++ b/src/main/java/net/sf/cb2java/copybook/CopybookParser.java @@ -25,6 +25,7 @@ import java.io.Reader; import java.io.StringReader; +import net.sf.cb2java.Settings; import net.sf.cb2xml.sablecc.lexer.Lexer; import net.sf.cb2xml.sablecc.lexer.LexerException; import net.sf.cb2xml.sablecc.node.Start; @@ -58,7 +59,12 @@ public static Copybook parse(String name, InputStream stream) { return parse(name, new InputStreamReader(stream)); } - + + public static Copybook parse(Settings settings, String name, InputStream stream) + { + return parse(settings, name, new InputStreamReader(stream)); + } + /** * Parses a copybook definition and returns a Copybook instance * @@ -67,16 +73,16 @@ public static Copybook parse(String name, InputStream stream) * * @return a copybook instance containing the parse tree for the definition */ - public static Copybook parse(String name, Reader reader) + public static Copybook parse(Settings settings, String name, Reader reader) { - String preProcessed = CobolPreprocessor.preProcess(reader); + String preProcessed = CobolPreprocessor.preProcess(reader, settings); StringReader sr = new StringReader(preProcessed); PushbackReader pbr = new PushbackReader(sr, 1000); Lexer lexer = debug ? new DebugLexer(pbr) : new Lexer(pbr); Parser parser = new Parser(lexer); - CopybookAnalyzer copyBookAnalyzer = new CopybookAnalyzer(name, parser); + CopybookAnalyzer copyBookAnalyzer = new CopybookAnalyzer(name, parser, settings); Start ast; try { ast = parser.parse(); @@ -91,4 +97,10 @@ public static Copybook parse(String name, Reader reader) return copyBookAnalyzer.getDocument(); } + + public static Copybook parse(String name, Reader reader) { + + return parse(Settings.DEFAULT(), name, reader); + } + } \ No newline at end of file diff --git a/src/main/java/net/sf/cb2java/copybook/Item.java b/src/main/java/net/sf/cb2java/copybook/Item.java old mode 100644 new mode 100755 index d08ad87..b6d81c6 --- a/src/main/java/net/sf/cb2java/copybook/Item.java +++ b/src/main/java/net/sf/cb2java/copybook/Item.java @@ -20,6 +20,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Set; + import net.sf.cb2java.Settings; import net.sf.cb2java.Value; import net.sf.cb2java.Values; @@ -42,14 +44,22 @@ class Item final boolean document; final Values values; + + public Settings getSettings() { + return settings; + } + + final Settings settings; /** * @param analyzer */ - Item(final Values values, final boolean document) + Item(final Values values, final boolean document, Settings settings) { this.values = values; this.document = document; + this.settings = settings; + signPosition = settings.getSignPosition(); } String name; @@ -66,7 +76,7 @@ class Item boolean isAlpha; boolean signSeparate; - SignPosition signPosition = Settings.DEFAULT.getSignPosition(); + SignPosition signPosition; String picture; Value value; @@ -128,7 +138,7 @@ void createElement() private void createDocument() { - element = new Copybook(name, values); + element = new Copybook(name, values, settings); } private void createGroup() diff --git a/src/main/java/net/sf/cb2java/types/Binary.java b/src/main/java/net/sf/cb2java/types/Binary.java old mode 100644 new mode 100755 index b302a9b..2b4af87 --- a/src/main/java/net/sf/cb2java/types/Binary.java +++ b/src/main/java/net/sf/cb2java/types/Binary.java @@ -122,12 +122,12 @@ public Native(String name, int level, int occurs, String picture) { @Override public byte[] toBytes(Object data) { byte[] bytes = super.toBytes(data); - return getSettings().getLittleEndian() ? reverse(bytes) : bytes; + return getSettings().isLittleEndian() ? reverse(bytes) : bytes; } @Override public Data parse(byte[] input) { - return super.parse(getSettings().getLittleEndian() ? reverse(input) : input); + return super.parse(getSettings().isLittleEndian() ? reverse(input) : input); } } } \ No newline at end of file diff --git a/src/main/java/net/sf/cb2java/types/Element.java b/src/main/java/net/sf/cb2java/types/Element.java old mode 100644 new mode 100755 index be36e5e..b6f28b6 --- a/src/main/java/net/sf/cb2java/types/Element.java +++ b/src/main/java/net/sf/cb2java/types/Element.java @@ -42,7 +42,7 @@ public abstract class Element { /** the absolute position of the where this item starts in data */ private int position; /** the instance that represents the data that defines this element */ - private Settings settings = Settings.DEFAULT; + private Settings settings; /** the default value of this element */ private Value value; /** the parent of this element */ @@ -219,7 +219,7 @@ public void setSettings(Settings settings) { * * @return the parent of this element */ - private Group getParent(){ + public Group getParent(){ return parent; } @@ -237,13 +237,13 @@ public void setParent(Group parent){ * * @return the settings for this element */ - protected Settings getSettings() { + public Settings getSettings() { if (settings != null) { return settings; } else if (getParent() != null) { return getParent().getSettings(); } else { - return null; + return Settings.DEFAULT(); } } From 8a20562501b81502044e2305aa122730169bd9b7 Mon Sep 17 00:00:00 2001 From: Maxime Date: Fri, 25 Aug 2017 09:48:47 +0200 Subject: [PATCH 2/4] Add resilient option, to allow parsing of record data that has issues, and not crash, but instead have Data with null values, or if the record size is shorter than the definition, consider as 0s --- src/main/java/net/sf/cb2java/Settings.java | 10 +++ .../java/net/sf/cb2java/types/Decimal.java | 78 ++++++++++--------- src/main/java/net/sf/cb2java/types/Group.java | 7 +- 3 files changed, 59 insertions(+), 36 deletions(-) mode change 100644 => 100755 src/main/java/net/sf/cb2java/types/Decimal.java mode change 100644 => 100755 src/main/java/net/sf/cb2java/types/Group.java diff --git a/src/main/java/net/sf/cb2java/Settings.java b/src/main/java/net/sf/cb2java/Settings.java index 8a1af6b..b0e7bb4 100755 --- a/src/main/java/net/sf/cb2java/Settings.java +++ b/src/main/java/net/sf/cb2java/Settings.java @@ -32,6 +32,7 @@ public class Settings { int columnStart = 6; int columnEnd = 72; Values values = new Values(); + boolean resiliant = false; static Settings DEFAULT; static public Settings DEFAULT() { @@ -57,6 +58,7 @@ static public Settings DEFAULT() { ? SignPosition.LEADING : SignPosition.TRAILING); DEFAULT.setColumnStart(Integer.parseInt(getSetting("column.start", DEFAULT.getColumnStart() + "", props))); DEFAULT.setColumnEnd(Integer.parseInt(getSetting("column.end", DEFAULT.getColumnEnd() + "", props))); + DEFAULT.setResiliant("false".equals(getSetting("resilient", DEFAULT.isResiliant() + "", props))); } return DEFAULT; } @@ -117,6 +119,14 @@ public void setValues(Values values) { this.values = values; } + public boolean isResiliant() { + return resiliant; + } + + public void setResiliant(boolean resiliant) { + this.resiliant = resiliant; + } + static private String getSetting(String name, String defaultValue, Properties props) { String result = defaultValue; try { diff --git a/src/main/java/net/sf/cb2java/types/Decimal.java b/src/main/java/net/sf/cb2java/types/Decimal.java old mode 100644 new mode 100755 index 00e823f..d0a7fb9 --- a/src/main/java/net/sf/cb2java/types/Decimal.java +++ b/src/main/java/net/sf/cb2java/types/Decimal.java @@ -186,41 +186,49 @@ private char getNumber(char overpunched) { @Override public Data parse(byte[] bytes) { - String input = getString(bytes).trim(); - String s = input; - - if (input.length() < 1) { - s = null; - } else if (signed()) { - if (getSignPosition() == SignPosition.LEADING) { - char c = input.charAt(0); - s = (isPositive(c) ? "" : "-") + getNumber(c) - + (input.length() > 1 ? input.substring(1) : ""); - } else if (getSignPosition() == SignPosition.TRAILING) { - int last = input.length() - 1; - char c = input.charAt(last); - s = (isPositive(c) ? "" : "-") - + (input.length() > 1 ? input.substring(0, last) : "") + getNumber(c); - } else { - throw new IllegalStateException("undefined sign position"); - } - } - BigInteger big = s == null ? null : new BigInteger(s); - Data data = create(); - - if (data instanceof DecimalData) { - DecimalData dData = (DecimalData) data; - BigDecimal bigD = big == null ? null : new BigDecimal(big, decimalPlaces()); - - dData.setValue(bigD); - - return data; - } else { - IntegerData iData = (IntegerData) data; - - iData.setValue(big); - - return data; + try { + String input = getString(bytes).trim(); + String s = input; + + if (input.length() < 1) { + s = null; + } else if (signed()) { + if (getSignPosition() == SignPosition.LEADING) { + char c = input.charAt(0); + s = (isPositive(c) ? "" : "-") + getNumber(c) + + (input.length() > 1 ? input.substring(1) : ""); + } else if (getSignPosition() == SignPosition.TRAILING) { + int last = input.length() - 1; + char c = input.charAt(last); + s = (isPositive(c) ? "" : "-") + + (input.length() > 1 ? input.substring(0, last) : "") + getNumber(c); + } else { + throw new IllegalStateException("undefined sign position"); + } + } + BigInteger big = s == null ? null : new BigInteger(s); + Data data = create(); + + if (data instanceof DecimalData) { + DecimalData dData = (DecimalData) data; + BigDecimal bigD = big == null ? null : new BigDecimal(big, decimalPlaces()); + + dData.setValue(bigD); + + return data; + } else { + IntegerData iData = (IntegerData) data; + + iData.setValue(big); + + return data; + } + } catch (RuntimeException e) { + if(getSettings().isResiliant()) { + return create(); + } else { + throw(e); + } } } diff --git a/src/main/java/net/sf/cb2java/types/Group.java b/src/main/java/net/sf/cb2java/types/Group.java old mode 100644 new mode 100755 index 3685def..d33bcca --- a/src/main/java/net/sf/cb2java/types/Group.java +++ b/src/main/java/net/sf/cb2java/types/Group.java @@ -109,7 +109,12 @@ public Data parse(final byte[] bytes) { private byte[] sub(byte[] in, int start, int end) { byte[] out = new byte[end - start]; - System.arraycopy(in, start, out, 0, out.length); + if(!getSettings().isResiliant() || start < in.length) { + // if resilient, allow for the input to be shorter compared to the copybook definition + // and then consider that the values are 0's + System.arraycopy(in, start, out, 0, + getSettings().isResiliant() ? Math.min(in.length - start, out.length) : out.length); + } return out; } From c149a72c4e65b6566c79334b529c9cecbe8fdd2e Mon Sep 17 00:00:00 2001 From: Maxime Date: Thu, 21 Sep 2017 17:20:00 +0200 Subject: [PATCH 3/4] Add option to trim string data --- src/main/java/net/sf/cb2java/Settings.java | 10 ++++++++++ src/main/java/net/sf/cb2java/types/Element.java | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/sf/cb2java/Settings.java b/src/main/java/net/sf/cb2java/Settings.java index b0e7bb4..3754ba2 100755 --- a/src/main/java/net/sf/cb2java/Settings.java +++ b/src/main/java/net/sf/cb2java/Settings.java @@ -33,6 +33,7 @@ public class Settings { int columnEnd = 72; Values values = new Values(); boolean resiliant = false; + boolean trimStrings = false; static Settings DEFAULT; static public Settings DEFAULT() { @@ -59,6 +60,7 @@ static public Settings DEFAULT() { DEFAULT.setColumnStart(Integer.parseInt(getSetting("column.start", DEFAULT.getColumnStart() + "", props))); DEFAULT.setColumnEnd(Integer.parseInt(getSetting("column.end", DEFAULT.getColumnEnd() + "", props))); DEFAULT.setResiliant("false".equals(getSetting("resilient", DEFAULT.isResiliant() + "", props))); + DEFAULT.setTrimStrings("true".equals(getSetting("trim", DEFAULT.getTrimStrings() + "", props))); } return DEFAULT; } @@ -127,6 +129,14 @@ public void setResiliant(boolean resiliant) { this.resiliant = resiliant; } + public boolean getTrimStrings() { + return trimStrings; + } + + public void setTrimStrings(boolean trimStrings) { + this.trimStrings = trimStrings; + } + static private String getSetting(String name, String defaultValue, Properties props) { String result = defaultValue; try { diff --git a/src/main/java/net/sf/cb2java/types/Element.java b/src/main/java/net/sf/cb2java/types/Element.java index b6f28b6..661ad0e 100755 --- a/src/main/java/net/sf/cb2java/types/Element.java +++ b/src/main/java/net/sf/cb2java/types/Element.java @@ -185,7 +185,12 @@ public final void write(OutputStream stream, Object data) throws IOException { */ public final String getString(byte[] data) { try { - return new String(data, getSettings().getEncoding()); + String value = new String(data, getSettings().getEncoding()); + if(getSettings().getTrimStrings()) { + return value.trim(); + } else { + return value; + } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } From 735c0dc93cd1a40be08965f359becea473e11ff4 Mon Sep 17 00:00:00 2001 From: Maxime Date: Thu, 12 Oct 2017 10:20:11 +0200 Subject: [PATCH 4/4] Start support for EBCDIC variants --- src/main/java/net/sf/cb2java/Settings.java | 11 +++++++++++ src/main/java/net/sf/cb2java/types/Decimal.java | 14 +++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/sf/cb2java/Settings.java b/src/main/java/net/sf/cb2java/Settings.java index 3754ba2..4bfb793 100755 --- a/src/main/java/net/sf/cb2java/Settings.java +++ b/src/main/java/net/sf/cb2java/Settings.java @@ -34,6 +34,7 @@ public class Settings { Values values = new Values(); boolean resiliant = false; boolean trimStrings = false; + String EBCDICVariant = ""; static Settings DEFAULT; static public Settings DEFAULT() { @@ -61,6 +62,7 @@ static public Settings DEFAULT() { DEFAULT.setColumnEnd(Integer.parseInt(getSetting("column.end", DEFAULT.getColumnEnd() + "", props))); DEFAULT.setResiliant("false".equals(getSetting("resilient", DEFAULT.isResiliant() + "", props))); DEFAULT.setTrimStrings("true".equals(getSetting("trim", DEFAULT.getTrimStrings() + "", props))); + DEFAULT.setEBCDICVariant(getSetting("EBCDIC-variant", DEFAULT.getEBCDICVariant(), props)); } return DEFAULT; } @@ -137,6 +139,15 @@ public void setTrimStrings(boolean trimStrings) { this.trimStrings = trimStrings; } + public String getEBCDICVariant() { + return EBCDICVariant; + } + + public void setEBCDICVariant(String EBCDICVariant) { + this.EBCDICVariant = EBCDICVariant; + } + + static private String getSetting(String name, String defaultValue, Properties props) { String result = defaultValue; try { diff --git a/src/main/java/net/sf/cb2java/types/Decimal.java b/src/main/java/net/sf/cb2java/types/Decimal.java index d0a7fb9..db4df5d 100755 --- a/src/main/java/net/sf/cb2java/types/Decimal.java +++ b/src/main/java/net/sf/cb2java/types/Decimal.java @@ -49,7 +49,7 @@ private char getChar(boolean positive, char overpunch) { return overpunch; } else if (positive) { switch(overpunch) { - case '0': return '{'; + case '0': return getSettings().getEBCDICVariant().contains("297") ? 'é' : '{'; case '1': return 'A'; case '2': return 'B'; case '3': return 'C'; @@ -71,7 +71,7 @@ private char getChar(boolean positive, char overpunch) { case '3': return 'L'; case '2': return 'K'; case '1': return 'J'; - case '0': return '}'; + case '0': return getSettings().getEBCDICVariant().contains("297") ? 'è' : '}'; } } @@ -98,6 +98,7 @@ private boolean isPositive(char overpunched) { case '7': case '8': case '9': + case 'é': case '{': case 'A': case 'B': @@ -110,6 +111,7 @@ private boolean isPositive(char overpunched) { case 'I': return true; case '0': + case 'è': case '}': case 'J': case 'K': @@ -174,9 +176,11 @@ private char getNumber(char overpunched) { case 'J': case 'A': return '1'; - case '0': - case '}': - case '{': + case '0': + case '}': + case '{': + case 'é': + case 'è': return '0'; } }