diff --git a/src/main/java/com/linuxense/javadbf/DBFMemoFile.java b/src/main/java/com/linuxense/javadbf/DBFMemoFile.java index 53e3bcd..8fcdd3f 100644 --- a/src/main/java/com/linuxense/javadbf/DBFMemoFile.java +++ b/src/main/java/com/linuxense/javadbf/DBFMemoFile.java @@ -144,7 +144,7 @@ protected byte[] readBinary(int block) { protected Object readData(int block, DBFDataType type) { long blockStart = this.blockSize * (long) block; - DBFDataType usedType = type; + DBFDataType usedType = null; try { seek(blockStart); byte[] blockData = new byte[this.blockSize]; @@ -196,10 +196,14 @@ else if (intType == 0) { } } byte[] data = baos.toByteArray(); - if (usedType != DBFDataType.MEMO) { - return data; + + if (usedType == null) { + usedType = type; } - return new String(data, charset); + if (usedType == DBFDataType.MEMO && type == DBFDataType.MEMO){ + return new String(data, charset); + } + return data; } catch (IOException ex) { diff --git a/src/main/java/com/linuxense/javadbf/DBFReader.java b/src/main/java/com/linuxense/javadbf/DBFReader.java index f4f80a7..3271c52 100644 --- a/src/main/java/com/linuxense/javadbf/DBFReader.java +++ b/src/main/java/com/linuxense/javadbf/DBFReader.java @@ -37,8 +37,10 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TimeZone; /** @@ -155,6 +157,8 @@ public class DBFReader extends DBFBase implements Closeable { private Map mapFieldNames = new HashMap(); private boolean showDeletedRows = false; + + private Set fieldsAsBinary = new HashSet<>(); /** * Intializes a DBFReader object. @@ -268,7 +272,26 @@ private Map createMapFieldNames(DBFField[] fieldArray) { } return Collections.unmodifiableMap(fieldNames); } + + /** + * Set the list of memo fields to be readed as binary. + * By default memo fields are retrieved as Strings, but if you know they store binary data + * you can set the names of the memo fields to be recovered unproceesded as byte[] + * @param names name of the memol fields to be treated as binary data. + */ + public void setReadMemoFieldsAsBinary(String... names) { + Set newSet = new HashSet<>(); + for (String name: names) { + if (name != null) { + String name1 = name.toUpperCase().trim(); + if (name1.length() > 0) { + newSet.add(name1); + } + } + } + this.fieldsAsBinary = newSet; + } /** Returns the number of records in the DBF. This number includes deleted (hidden) records @@ -534,7 +557,11 @@ private Object readMemoField(DBFField field) throws IOException { nBlock = DBFUtils.readLittleEndianInt(this.dataInputStream); } if (this.memoFile != null && nBlock != null) { - return memoFile.readData(nBlock.intValue(), field.getType()); + DBFDataType type = field.getType(); + if (type == DBFDataType.MEMO && fieldsAsBinary.contains(field.getName().toUpperCase())) { + type = DBFDataType.BINARY; + } + return memoFile.readData(nBlock.intValue(), type); } return null; } diff --git a/src/test/java/com/linuxense/javadbf/bug98/ReadMemoAsBinaryTest.java b/src/test/java/com/linuxense/javadbf/bug98/ReadMemoAsBinaryTest.java new file mode 100644 index 0000000..f7e63ee --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/bug98/ReadMemoAsBinaryTest.java @@ -0,0 +1,40 @@ +package com.linuxense.javadbf.bug98; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.linuxense.javadbf.DBFReader; +import com.linuxense.javadbf.DBFRow; +import com.linuxense.javadbf.DBFUtils; + +public class ReadMemoAsBinaryTest { + + public ReadMemoAsBinaryTest() { + super(); + } + + @Test + public void testReadMemoAsBinary() throws Exception { + File file = new File("src/test/resources/fixtures/dbase_8b.dbf"); + DBFReader reader = null; + try { + reader = new DBFReader( new BufferedInputStream(new FileInputStream(file))); + reader.setMemoFile(new File("src/test/resources/fixtures/dbase_8b.dbt")); + reader.setReadMemoFieldsAsBinary("MEMO"); + DBFRow row = null; + while ((row = reader.nextRow()) != null) { + byte[] data = row.getBytes("MEMO"); + Assertions.assertTrue(data == null || data instanceof byte[]); + } + + } + finally { + DBFUtils.close(reader); + } + } + +}