/* Copyright 2013 Nationale-Nederlanden Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package nl.nn.adapterframework.batch; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import nl.nn.adapterframework.util.LogUtil; import nl.nn.adapterframework.util.Misc; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; /** * * @author Gerrit van Brakel * @since 4.10 */ public class DelphiStringRecordReader extends Reader { protected Logger log = LogUtil.getLogger(this); private InputStream in; private String charsetName; private int stringLength; private int stringsPerRecord; // 0 means read till end of file private String separator; private String separatorReplacement; private StringBuffer buffer; private int bufferLen=0; private int bufferPos=0; boolean eof=false; private final boolean trace=false; public DelphiStringRecordReader(InputStream in, String charsetName, int stringLength, int stringsPerRecord, String separator, String separatorReplacement) { super(); this.in=in; this.charsetName=charsetName; this.stringLength=stringLength; this.stringsPerRecord=stringsPerRecord; this.separator=separator; this.separatorReplacement=separatorReplacement; } /* * Fill buffer if empty, then copy characters as required. */ public int read(char[] cbuf, int off, int len) throws IOException { if (buffer==null || bufferPos>=bufferLen) { fillBuffer(); } if (buffer==null) { return -1; } int bytesRead=0; while (bufferPos<bufferLen && bytesRead++<len) { cbuf[off++]=buffer.charAt(bufferPos++); } return bytesRead; } public void close() throws IOException { in.close(); } /* * read a single string from the input, then skip to stringLength. */ private String readString() throws IOException { int len; len=in.read(); // first read the byte that holds the length of the string if (len<0) { return null; } if (trace && log.isDebugEnabled()) log.debug("read byte for string length ["+len+"]"); byte[] buf=new byte[len]; // allocate space for the bytes of the string int bytesToRead=len; int pos=0; while (bytesToRead>0) { int bytesRead = in.read(buf,pos,bytesToRead); if (bytesRead>0) { pos+=bytesRead; bytesToRead-=bytesRead; } else { String currentResult=null; try { currentResult=new String(buf,charsetName); } catch (Exception e) { currentResult=e.getClass().getName()+": "+e.getMessage(); } throw new EOFException("unexpected EOF after reading ["+pos+"] bytes of a string of length ["+len+"], current result ["+currentResult+"]"); } } if (pos<stringLength) { if (trace && log.isDebugEnabled()) log.debug("skipping ["+(stringLength-pos)+"] bytes"); in.skip(stringLength-pos); } String result=new String(buf,charsetName); if (StringUtils.isNotEmpty(separatorReplacement)) { result=Misc.replace(result,separator,separatorReplacement); } if (trace && log.isDebugEnabled()) log.debug("read string ["+result+"]"); return result; } /* * accumulate strings in buffer. */ private void fillBuffer() throws IOException { int stringsRead=0; buffer=new StringBuffer(); while (!eof && (stringsPerRecord==0 || stringsRead<stringsPerRecord)) { String part=readString(); if (part==null) { eof=true; } else { buffer.append(part).append(separator); stringsRead++; } } if (trace && log.isDebugEnabled()) log.debug("read ["+stringsRead+"] strings"); if (stringsRead==0) { buffer=null; } else { buffer.append("\n"); bufferLen=buffer.length(); bufferPos=0; } } }