
com.legstar.coxb.convert.simple.CobolStringSimpleConverter Maven / Gradle / Ivy
Show all versions of legstar-distribution
/*******************************************************************************
* Copyright (c) 2011 LegSem.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* LegSem - initial API and implementation
******************************************************************************/
package com.legstar.coxb.convert.simple;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.legstar.coxb.CobolContext;
import com.legstar.coxb.ICobolArrayStringBinding;
import com.legstar.coxb.ICobolStringBinding;
import com.legstar.coxb.convert.CobolConversionException;
import com.legstar.coxb.convert.ICobolStringConverter;
import com.legstar.coxb.host.HostData;
import com.legstar.coxb.host.HostException;
/**
* This is a concrete implementation of marshal/unmarshal operations of java
* strings to cobol character strings.
*
* @author Fady Moussallam
*
*/
public class CobolStringSimpleConverter extends CobolSimpleConverter implements
ICobolStringConverter {
/** Detects a string content as binary data. */
private static final Pattern BINARY_CONTENT_PATTERN = Pattern
.compile("0x[\\da-fA-F]+");
/**
* @param cobolContext the Cobol compiler parameters in effect
*/
public CobolStringSimpleConverter(final CobolContext cobolContext) {
super(cobolContext);
}
/** {@inheritDoc} */
public int toHost(final ICobolStringBinding ce, final byte[] hostTarget,
final int offset) throws HostException {
int newOffset = 0;
try {
newOffset = toHostSingle(ce.getStringValue(), getCobolContext()
.getHostCharsetName(), getCobolContext()
.getAlphanumPaddingChar(), getCobolContext()
.failOnAlphanumOverflow(), ce.getByteLength(),
ce.isJustifiedRight(), hostTarget, offset);
} catch (CobolConversionException e) {
throwHostException(ce, e);
}
return newOffset;
}
/** {@inheritDoc} */
public int toHost(final ICobolArrayStringBinding ce,
final byte[] hostTarget, final int offset, final int currentOccurs)
throws HostException {
int newOffset = offset;
try {
for (String javaSource : ce.getStringList()) {
newOffset = toHostSingle(javaSource, getCobolContext()
.getHostCharsetName(), getCobolContext()
.getAlphanumPaddingChar(), getCobolContext()
.failOnAlphanumOverflow(), ce.getItemByteLength(),
ce.isJustifiedRight(), hostTarget, newOffset);
}
/* If necessary, fill in the array with missing items */
for (int i = ce.getStringList().size(); i < currentOccurs; i++) {
newOffset = toHostSingle("", getCobolContext()
.getHostCharsetName(), getCobolContext()
.getAlphanumPaddingChar(), getCobolContext()
.failOnAlphanumOverflow(), ce.getItemByteLength(),
ce.isJustifiedRight(), hostTarget, newOffset);
}
} catch (CobolConversionException e) {
throwHostException(ce, e);
}
return newOffset;
}
/** {@inheritDoc} */
public int fromHost(final ICobolStringBinding ce, final byte[] hostSource,
final int offset) throws HostException {
int newOffset = offset;
try {
String javaString = fromHostSingle(getCobolContext()
.getHostCharsetName(), ce.getByteLength(), hostSource,
newOffset);
ce.setStringValue(javaString);
newOffset += ce.getByteLength();
} catch (CobolConversionException e) {
throwHostException(ce, e);
}
return newOffset;
}
/** {@inheritDoc} */
public int fromHost(final ICobolArrayStringBinding ce,
final byte[] hostSource, final int offset, final int currentOccurs)
throws HostException {
List < String > lArray = new ArrayList < String >();
int newOffset = offset;
try {
for (int i = 0; i < currentOccurs; i++) {
String javaString = fromHostSingle(getCobolContext()
.getHostCharsetName(), ce.getItemByteLength(),
hostSource, newOffset);
lArray.add(javaString);
newOffset += ce.getItemByteLength();
}
ce.setStringList(lArray);
} catch (CobolConversionException e) {
throwHostException(ce, e);
}
return newOffset;
}
/**
* Converts a Java String to a host character stream using the host
* character set unless content represents binary data.
*
* Any character string following this pattern: '0x[\\da-fA-F]+' is
* interpreted as binary content.
*
* @param javaString java string to convert
* @param hostCharsetName host character set
* @param paddingChar padding character
* @param cobolByteLength host byte length
* @param isJustifiedRight is Cobol data right justified
* @param hostTarget target host buffer
* @param offset offset in target host buffer
* @return offset after host buffer is updated
* @throws CobolConversionException if conversion fails
*/
public static final int toHostSingle(final String javaString,
final String hostCharsetName, final Byte paddingChar,
final int cobolByteLength, final boolean isJustifiedRight,
final byte[] hostTarget, final int offset)
throws CobolConversionException {
return toHostSingle(javaString, hostCharsetName, paddingChar, false,
cobolByteLength, isJustifiedRight, hostTarget, offset);
}
/**
* Converts a Java String to a host character stream using the host
* character set unless content represents binary data.
*
* Any character string following this pattern: '0x[\\da-fA-F]+' is
* interpreted as binary content.
*
* @param javaString java string to convert
* @param hostCharsetName host character set
* @param paddingChar padding character
* @param failOnOverflow true if an exception should be raised if string
* content does not fit in target alphanumeric data item
* @param cobolByteLength host byte length
* @param isJustifiedRight is Cobol data right justified
* @param hostTarget target host buffer
* @param offset offset in target host buffer
* @return offset after host buffer is updated
* @throws CobolConversionException if conversion fails
*/
public static final int toHostSingle(final String javaString,
final String hostCharsetName, final Byte paddingChar,
final boolean failOnOverflow, final int cobolByteLength,
final boolean isJustifiedRight, final byte[] hostTarget,
final int offset) throws CobolConversionException {
/* Check that we are still within the host target range */
int lastOffset = offset + cobolByteLength;
if (lastOffset > hostTarget.length) {
throw (new CobolConversionException(
"Attempt to write past end of host source buffer",
new HostData(hostTarget), offset, cobolByteLength));
}
/* HostData before it is positioned in the hostTarget buffer. */
byte[] hostSource = new byte[0];
byte padChar;
/*
* If data being passed represent binary content convert from hex string
* otherwise use the host charset for conversion.
*/
if (isBinaryContent(javaString)) {
padChar = (paddingChar == null) ? 0x0 : paddingChar;
hostSource = HostData.toByteArray(javaString.substring(2));
} else {
try {
padChar = (paddingChar == null) ? " ".getBytes(hostCharsetName)[0]
: paddingChar;
if (javaString != null) {
hostSource = javaString.getBytes(hostCharsetName);
}
} catch (UnsupportedEncodingException e) {
throw new CobolConversionException(
"UnsupportedEncodingException:" + e.getMessage());
}
}
/*
* If required, fail if target alphanumeric data item is too short,
* otherwise just truncate.
*/
if (failOnOverflow && hostSource.length > cobolByteLength) {
throw new CobolConversionException(
"Java string content too long for target COBOL alphanumeric data item");
}
/*
* The target host element might be larger than the converted java
* String and might have to be right or left justified.
*/
int leftPadIndex = offset;
int rightPadIndex = lastOffset;
if (hostSource.length < cobolByteLength) {
if (isJustifiedRight) {
leftPadIndex = offset + cobolByteLength - hostSource.length;
} else {
rightPadIndex = lastOffset - 1 - cobolByteLength
+ hostSource.length;
}
}
int iSource = 0;
for (int iTarget = offset; iTarget < lastOffset; iTarget++) {
if (iTarget < leftPadIndex || iTarget > rightPadIndex) {
hostTarget[iTarget] = padChar;
} else {
hostTarget[iTarget] = hostSource[iSource];
iSource++;
}
}
return lastOffset;
}
/**
* Check that content represents binary data.
*
* @param javaString the java string which content must be tested
* @return true if content represents a valid hexadecimal string
*/
private static boolean isBinaryContent(final String javaString) {
if (javaString != null && javaString.length() > 2
&& javaString.charAt(0) == '0') {
Matcher matcher = BINARY_CONTENT_PATTERN.matcher(javaString);
if (matcher.matches()) {
return true;
}
}
return false;
}
/**
* Converts a host character string into a Java string.
*
* @param hostCharsetName host character set
* @param cobolByteLength host byte length
* @param hostSource source host buffer
* @param offset offset in source host buffer
* @return offset after host buffer is read
* @throws CobolConversionException if conversion fails
*/
public static final String fromHostSingle(final String hostCharsetName,
final int cobolByteLength, final byte[] hostSource, final int offset)
throws CobolConversionException {
String javaString = null;
int javaStringLength = cobolByteLength;
/*
* Check that we are still within the host source range. If not,
* consider the host optimized its payload by truncating trailing nulls
* in which case, we just need to process the characters returned if
* any.
*/
int lastOffset = offset + cobolByteLength;
if (lastOffset > hostSource.length) {
if (offset >= hostSource.length) {
return javaString;
} else {
javaStringLength = hostSource.length - offset;
}
}
/*
* The Java String is obtained by translating from the host code page to
* the local code page.
*/
try {
/* Trim low-values unless there is only one */
int i = javaStringLength;
while (i > 0 && (hostSource[offset + i - 1] == 0)) {
i--;
}
javaStringLength = i;
javaString = new String(hostSource, offset, javaStringLength,
hostCharsetName);
/*
* Some low-value characters may have slipped into the resulting
* string.
*/
if (javaString.indexOf("\0") != -1) {
javaString = javaString.replace('\0', ' ');
}
// Trim trailing spaces
int end = javaString.length();
while ((end != 0)
&& Character.isWhitespace(javaString.charAt(end - 1))) {
end--;
}
return javaString.substring(0, end);
} catch (UnsupportedEncodingException uee) {
throw new CobolConversionException("UnsupportedEncodingException:"
+ uee.getMessage());
}
}
}