diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 00000000..0300e140 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,25 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: JavaDBF CI +on: + push: + branches: [ main, 0.x ] + pull_request: + branches: [ main, 0.x ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + java: [ 8, 11 ] + name: Java ${{matrix.java}} + steps: + - uses: actions/checkout@v2 + - name: Setup java + uses: actions/setup-java@v1 + with: + java-version: ${{matrix.java}} + - name: Build with Maven + run: mvn -B -Dgpg.skip=true -Dmaven.javadoc.skip=true clean package verify diff --git a/.gitignore b/.gitignore index 8bd3a058..ea6ab823 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /.settings/ /.classpath /.project +/bin/ diff --git a/.travis.yml b/.travis.yml index 69040a75..8aba7ea0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,11 @@ language: java install: mvn install -DskipTests=true -Dgpg.skip=true -Dmaven.javadoc.skip=true jdk: - - openjdk7 - - oraclejdk8 + - openjdk8 + - openjdk9 + - openjdk10 + - openjdk11 + - openjdk12 + - \ No newline at end of file + diff --git a/README.md b/README.md index fa402d1c..91d7d328 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ If you are using Maven, you can add JavaDBF to your project using this dependenc com.github.albfernandez javadbf - 0.8.0 + 0.11.1 ``` @@ -333,9 +333,10 @@ Clone the repository or download de tar file from releases page on github, run t git clone https://github.com/albfernandez/javadbf.git cd javadbf + git checkout tags/v.0.10.0 mvn clean package -The result file is ``target/javadbf-0.8.0.jar`` +The result file is ``target/javadbf-0.10.0.jar`` diff --git a/doc/old_javadbf_0.4.0_tuturial.md b/doc/old_javadbf_0.4.0_tuturial.md new file mode 100644 index 00000000..abad6bec --- /dev/null +++ b/doc/old_javadbf_0.4.0_tuturial.md @@ -0,0 +1,298 @@ +# JavaDBF Library Tutorial + + +(for JavaDBF ver. 0.4.0 and above)\ + Anil Kumar K.\ + anil at linuxense dot com\ + Linuxense Information Systems Pvt. Ltd., +Trivandrum, India + +## 1. Introduction + + +JavaDBF is a Java library for reading and writing XBase files. There are +plenty of legacy applications around with `.dbf` as their primary +storage format. JavaDBF was initially written for data transfer with +such applications. + +Other than that, there are requirements to export data from a Java +application to a spreadshet program like GNumeric, Excel or Lotus 123. A +DBF file would be more appropriate in such situations rather than a CSV +or an HTML file because a DBF file can carry field type information. +More over, XBase format is like an Open-standard; it is understood by +almost all spreadsheet programms. + +## 2. Getting and Installing + +Obtain the latest version of JavaDBF from +http://sarovar.org/projects/javadbf/. +Create a folder in a convenient location and run: + +```bash + tar xvfz javadbf-x.x.x-tar.gz + cd javadbf-x.x.x +``` + +In this folder you will find `javadbf.jar` which contains the library. +Include this jar file in your `$CLASSPATH` variable. You are ready to +go. + +# 3. Overview of the Library + +JavaDBF has a simple API of its own and it does not implement the JDBC +API. It is designed this way because JavaDBF is not indedned to support +full-blown RDBMS-style database interaction. And you are not supposed to +use it like a back-end; it just doesn't work that way. Also, JavaDBF is +not designed to be thread-safe; keep that in mind when you design +threaded applications. + +JavaDBF comes in the package `com.linuxense.javadbf`. Import that +package in your Java code. Following examples will familiarise you with +its APIs. + +### 3.1. Data Type Mapping + +In version 0.3.2, JavaDBF supports almost all XBase data types except +Memo field. While reading, those types are interpretted as appropriate +Java types. Following table shows the mapping scheme. + +| XBase Type | XBase Symbol | Java Type used in JavaDBF | +|---------- | ------------ | --------------------------- +|Character | C | java.lang.String | +|Numeric | N | java.math.BigDecimal | +|Double | F | java.math.BigDecimal | +|Logical | L | java.lang.Boolean | +|Date | D | java.util.Date | + +## 4. Reading a DBF File + +To read a DBF file, JavaDBF provides a DBFReader class. Following is a +ready-to-compile, self-explanatory program describing almost all feature +of the `DBFReader` class. Copy/paste this listing and compile it. Keep a +`.dbf` file handy to pass to this program as its argument. + +```java + import java.io.*; + import com.linuxense.javadbf.*; + + public class JavaDBFReaderTest { + + public static void main( String args[]) { + + try { + + // create a DBFReader object + // + InputStream inputStream = new FileInputStream( args[ 0]); // take dbf file as program argument + DBFReader reader = new DBFReader( inputStream); + + // get the field count if you want for some reasons like the following + // + int numberOfFields = reader.getFieldCount(); + + // use this count to fetch all field information + // if required + // + for( int i=0; i4.0.0 com.github.albfernandez javadbf - 0.9.0 + 0.12.0-SNAPSHOT https://github.com/albfernandez/javadbf jar javadbf @@ -32,7 +32,10 @@ https://github.com/albfernandez/javadbf/issues - + + UTF-8 + UTF-8 + @@ -49,7 +52,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.7.0 1.7 1.7 @@ -58,7 +61,7 @@ org.codehaus.mojo findbugs-maven-plugin - 3.0.3 + 3.0.5 findbugs-check @@ -75,7 +78,7 @@ org.apache.maven.plugins maven-pmd-plugin - 3.6 + 3.8 true @@ -91,9 +94,12 @@ org.apache.maven.plugins maven-jar-plugin - 2.6 + 3.0.2 + + com.github.albfernandez.javadbf + true true @@ -104,7 +110,7 @@ org.apache.maven.plugins maven-source-plugin - 2.4 + 3.0.1 attach-sources @@ -117,7 +123,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.0.0 attach-javadocs @@ -126,53 +132,27 @@ - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - ${gpg.keyname} - ${gpg.keyname} - - - - sign-artifacts - verify - - sign - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.6 - true - - ossrh - https://oss.sonatype.org/ - true - - - + - + + org.apache.maven.plugins + maven-jxr-plugin + 2.5 + org.apache.maven.plugins maven-pmd-plugin - 3.6 + 3.7 org.codehaus.mojo findbugs-maven-plugin - 3.0.3 + 3.0.4 org.apache.maven.plugins @@ -189,9 +169,46 @@ + + + + deploy + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + ${gpg.keyname} + ${gpg.keyname} + + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + ossrh + https://oss.sonatype.org/ + true + + + + + + + + - - UTF-8 - UTF-8 - \ No newline at end of file diff --git a/src/main/java/com/linuxense/javadbf/DBFBase.java b/src/main/java/com/linuxense/javadbf/DBFBase.java index f73a33b8..0de99c3d 100644 --- a/src/main/java/com/linuxense/javadbf/DBFBase.java +++ b/src/main/java/com/linuxense/javadbf/DBFBase.java @@ -64,7 +64,10 @@ public void setCharset(Charset charset) { */ @Deprecated public String getCharactersetName() { - return this.charset.displayName(); + if (this.charset != null) { + return this.charset.displayName(); + } + return null; } /** @@ -80,7 +83,7 @@ public String getCharactersetName() { */ @Deprecated public void setCharactersetName(String characterSetName) { - this.charset = Charset.forName(characterSetName); + setCharset(Charset.forName(characterSetName)); } } diff --git a/src/main/java/com/linuxense/javadbf/DBFCharsetHelper.java b/src/main/java/com/linuxense/javadbf/DBFCharsetHelper.java index d574f71b..6f7a6cfb 100644 --- a/src/main/java/com/linuxense/javadbf/DBFCharsetHelper.java +++ b/src/main/java/com/linuxense/javadbf/DBFCharsetHelper.java @@ -15,8 +15,8 @@ private DBFCharsetHelper() { * (0x1D) is code page mark See * https://msdn.microsoft.com/en-us/library/aa975345(v=vs.71).aspx * - * @param b - * @return + * @param b the codepage to check + * @return Charset for the code page */ public static Charset getCharsetByByte(int b) { switch (b) { @@ -45,10 +45,10 @@ public static Charset getCharsetByByte(int b) { return forName("IBM852"); case 0x65: // Russian MS-DOS - return forName("IBM865"); + return forName("IBM866"); case 0x66: // Nordic MS-DOS - return forName("IBM866"); + return forName("IBM865"); case 0x67: // Icelandic MS-DOS return forName("IBM861"); @@ -123,86 +123,86 @@ public static int getDBFCodeForCharset(Charset charset) { if (charset == null) { return 0; } - String charsetName = charset.toString().toLowerCase(); + String charsetName = charset.toString(); - if ("ibm437".equals(charsetName)) { + if ("ibm437".equalsIgnoreCase(charsetName)) { return 0x01; } - if ("ibm850".equals(charsetName)) { + if ("ibm850".equalsIgnoreCase(charsetName)) { return 0x02; } - if ("windows-1252".equals(charsetName)) { + if ("windows-1252".equalsIgnoreCase(charsetName)) { return 0x03; } - if ("iso-8859-1".equals(charsetName)) { + if ("iso-8859-1".equalsIgnoreCase(charsetName)) { return 0x03; } - if ("MacRoman".equals(charsetName)) { + if ("MacRoman".equalsIgnoreCase(charsetName)) { return 0x04; } - if ("IBM852".equals(charsetName)) { + if ("IBM852".equalsIgnoreCase(charsetName)) { return 0x64; } - if ("IBM865".equals(charsetName)) { - return 0x65; - } - if ("IBM866".equals(charsetName)) { + if ("IBM865".equalsIgnoreCase(charsetName)) { return 0x66; } - if ("IBM861".equals(charsetName)) { + if ("IBM866".equalsIgnoreCase(charsetName)) { + return 0x65; + } + if ("IBM861".equalsIgnoreCase(charsetName)) { return 0x67; } // 0x68 // 0x69 - if ("IBM737".equals(charsetName)) { + if ("IBM737".equalsIgnoreCase(charsetName)) { return 0x6a; } - if ("IBM857".equals(charsetName)) { + if ("IBM857".equalsIgnoreCase(charsetName)) { return 0x6b; } - if ("windows-950".equals(charsetName)) { + if ("windows-950".equalsIgnoreCase(charsetName)) { return 0x78; } - if ("windows-949".equals(charsetName)) { + if ("windows-949".equalsIgnoreCase(charsetName)) { return 0x79; } - if ("gbk".equals(charsetName)) { + if ("gbk".equalsIgnoreCase(charsetName)) { return 0x7a; } - if ("windows-932".equals(charsetName)) { + if ("windows-932".equalsIgnoreCase(charsetName)) { return 0x7b; } - if ("windows-874".equals(charsetName)) { + if ("windows-874".equalsIgnoreCase(charsetName)) { return 0x7c; } - if ("windows-1255".equals(charsetName)) { + if ("windows-1255".equalsIgnoreCase(charsetName)) { return 0x7d; } - if ("windows-1256".equals(charsetName)) { + if ("windows-1256".equalsIgnoreCase(charsetName)) { return 0x7e; } - if ("x-MacCyrillic".equals(charsetName)) { + if ("x-MacCyrillic".equalsIgnoreCase(charsetName)) { return 0x96; } - if ("x-MacCentralEurope".equals(charsetName)) { + if ("x-MacCentralEurope".equalsIgnoreCase(charsetName)) { return 0x97; } - if ("x-MacGreek".equals(charsetName)) { + if ("x-MacGreek".equalsIgnoreCase(charsetName)) { return 0x98; } - if ("windows-1250".equals(charsetName)) { + if ("windows-1250".equalsIgnoreCase(charsetName)) { return 0xc8; } - if ("windows-1251".equals(charsetName)) { + if ("windows-1251".equalsIgnoreCase(charsetName)) { return 0xc9; } - if ("windows-1254".equals(charsetName)) { + if ("windows-1254".equalsIgnoreCase(charsetName)) { return 0xca; } - if ("windows-1253".equals(charsetName)) { + if ("windows-1253".equalsIgnoreCase(charsetName)) { return 0xcb; } // Unsupported charsets returns 0 diff --git a/src/main/java/com/linuxense/javadbf/DBFDataType.java b/src/main/java/com/linuxense/javadbf/DBFDataType.java index efadc027..b8d08e95 100644 --- a/src/main/java/com/linuxense/javadbf/DBFDataType.java +++ b/src/main/java/com/linuxense/javadbf/DBFDataType.java @@ -50,7 +50,7 @@ public enum DBFDataType { /** * Numeric data */ - NUMERIC ((byte) 'N', 1, 18, 0, true), + NUMERIC ((byte) 'N', 1, 32, 0, true), /** * Numeric long (FoxPro) */ @@ -90,6 +90,13 @@ private DBFDataType(byte code, int minSize, int maxSize, int defaultSize, boolea public byte getCode() { return this.code; } + /** + * Gets the code as stored in the dbf file as character for display purposes. + * @return the code for this type + */ + public char getCharCode() { + return (char) this.code; + } /** * Gets the minimum size for this type @@ -133,5 +140,14 @@ public static DBFDataType fromCode(byte cod) { throw new IllegalArgumentException("Unknown data type:" + cod); } + /** + * Gets the DBFDataType from the code used in the file + * @param code the code used by dbase + * @return The DBFDataType from the code used in the file + */ + public static DBFDataType fromCode(char code) { + return fromCode((byte) code); + } + } diff --git a/src/main/java/com/linuxense/javadbf/DBFField.java b/src/main/java/com/linuxense/javadbf/DBFField.java index db4ed0a7..c7ebca82 100644 --- a/src/main/java/com/linuxense/javadbf/DBFField.java +++ b/src/main/java/com/linuxense/javadbf/DBFField.java @@ -142,10 +142,19 @@ protected static DBFField createField(DataInput in, Charset charset) throws IOEx field.setFieldsFlag = in.readByte(); /* 23 */ in.readFully(field.reserv4); /* 24-30 */ field.indexFieldFlag = in.readByte(); /* 31 */ - + adjustLengthForBigCharSupport(field); return field; } - + private static void adjustLengthForBigCharSupport(DBFField field) { + // if field type is char, then read length and decimalCount as one number to allow char fields to be + // longer than 256 bytes. + // This is the way Clipper and FoxPro do it, and there is really no downside + // since for char fields decimal count should be zero for other versions that do not support this extended functionality. + if (field.type == DBFDataType.CHARACTER) { + field.fieldLength |= field.decimalCount << 8; + field.decimalCount = 0; + } + } /** * Writes the content of DBFField object into the stream as per DBF format * specifications. @@ -322,6 +331,15 @@ public void setDecimalCount(int size) { } this.decimalCount = (byte) size; } + + public String toString() { + return + this.name+"|" + this.type + " (" + this.type.getCharCode() + ")" + + "\nLength: " + this.fieldLength + + "\nDecimalCount:" + this.decimalCount + + "\nIndex:" + this.indexFieldFlag; + } + /** * Sets the data type of the field. diff --git a/src/main/java/com/linuxense/javadbf/DBFHeader.java b/src/main/java/com/linuxense/javadbf/DBFHeader.java index 2e7efaa5..54d565cd 100644 --- a/src/main/java/com/linuxense/javadbf/DBFHeader.java +++ b/src/main/java/com/linuxense/javadbf/DBFHeader.java @@ -128,9 +128,17 @@ void write(DataOutput dataOutput) throws IOException { this.numberOfRecords = DBFUtils.littleEndian(this.numberOfRecords); dataOutput.writeInt(this.numberOfRecords); /* 4-7 */ - this.headerLength = findHeaderLength(); + short oldHeaderLength = this.headerLength; + short newHeaderLength = findHeaderLength(); + if (oldHeaderLength == 0) { + this.headerLength = newHeaderLength; + } + else if (newHeaderLength > oldHeaderLength) { + throw new IOException("Invalid header length"); + } dataOutput.writeShort(DBFUtils.littleEndian(this.headerLength)); /* 8-9 */ + this.recordLength = sumUpLenghtOfFields(); dataOutput.writeShort(DBFUtils.littleEndian(this.recordLength)); /* 10-11 */ @@ -142,7 +150,15 @@ void write(DataOutput dataOutput) throws IOException { dataOutput.writeInt(DBFUtils.littleEndian(this.reserv3)); /* 24-27 */ dataOutput.writeByte(this.mdxFlag); /* 28 */ - dataOutput.writeByte(this.languageDriver); /* 29 */ + if (this.languageDriver != 0) { + dataOutput.writeByte(this.languageDriver); /* 29 */ + } + else if (getUsedCharset() != null) { + dataOutput.writeByte(DBFCharsetHelper.getDBFCodeForCharset(getUsedCharset())); /* 29 */ + } + else { + dataOutput.writeByte(0); /* 29 */ + } dataOutput.writeShort(DBFUtils.littleEndian(this.reserv4)); /* 30-31 */ for (DBFField field : this.fieldArray) { field.write(dataOutput,getUsedCharset()); diff --git a/src/main/java/com/linuxense/javadbf/DBFReader.java b/src/main/java/com/linuxense/javadbf/DBFReader.java index 8f9ab8d5..810db899 100644 --- a/src/main/java/com/linuxense/javadbf/DBFReader.java +++ b/src/main/java/com/linuxense/javadbf/DBFReader.java @@ -80,11 +80,12 @@ */ public class DBFReader extends DBFBase { - private DataInputStream dataInputStream; - private DBFHeader header; - private static final long MILLISECS_PER_DAY = 24*60*60*1000; private static final long MILLIS_SINCE_4713 = -210866803200000L; + + private DataInputStream dataInputStream; + private DBFHeader header; + private boolean trimRightSpaces = false; /** * Initializes a DBFReader object. @@ -190,34 +191,56 @@ public Object[] nextRecord() throws DBFException { try { boolean isDeleted = false; do { - if (isDeleted) { - skip(this.header.recordLength - 1); + try { + if (isDeleted) { + skip(this.header.recordLength - 1); + } + int t_byte = this.dataInputStream.readByte(); + if (t_byte == END_OF_DATA || t_byte == -1) { + return null; + } + isDeleted = t_byte == '*'; } - int t_byte = this.dataInputStream.readByte(); - if (t_byte == END_OF_DATA) { + catch (EOFException e) { return null; } - isDeleted = t_byte == '*'; } while (isDeleted); - + int bytesReaded = 0; for (int i = 0; i < this.header.fieldArray.length; i++) { switch (this.header.fieldArray[i].getType()) { case CHARACTER: byte b_array[] = new byte[this.header.fieldArray[i].getFieldLength()]; - this.dataInputStream.read(b_array); - recordObjects[i] = new String(b_array, getCharset()); + bytesReaded = this.dataInputStream.read(b_array); + if (bytesReaded != b_array.length) { + throw new EOFException("Unexpected end of file"); + } + if (this.trimRightSpaces) { + recordObjects[i] = new String(DBFUtils.trimRightSpaces(b_array), getCharset()); + } + else { + recordObjects[i] = new String(b_array, getCharset()); + } break; case DATE: byte t_byte_year[] = new byte[4]; - this.dataInputStream.read(t_byte_year); + bytesReaded = this.dataInputStream.read(t_byte_year); + if (bytesReaded != 4) { + throw new EOFException("Unexpected end of file"); + } byte t_byte_month[] = new byte[2]; - this.dataInputStream.read(t_byte_month); + bytesReaded = this.dataInputStream.read(t_byte_month); + if (bytesReaded != 2) { + throw new EOFException("Unexpected end of file"); + } byte t_byte_day[] = new byte[2]; - this.dataInputStream.read(t_byte_day); + bytesReaded = this.dataInputStream.read(t_byte_day); + if (bytesReaded != 2) { + throw new EOFException("Unexpected end of file"); + } try { GregorianCalendar calendar = new GregorianCalendar(Integer.parseInt(new String(t_byte_year, StandardCharsets.US_ASCII)), @@ -238,10 +261,19 @@ public Object[] nextRecord() throws DBFException { case NUMERIC: try { byte t_float[] = new byte[this.header.fieldArray[i].getFieldLength()]; - this.dataInputStream.read(t_float); + bytesReaded = this.dataInputStream.read(t_float); + if (bytesReaded != t_float.length) { + throw new EOFException("Unexpected end of file"); + } t_float = DBFUtils.removeSpaces(t_float); if (t_float.length > 0 && !DBFUtils.contains(t_float, (byte) '?') && !DBFUtils.contains(t_float, (byte) '*')) { - recordObjects[i] = new Double(new String(t_float, StandardCharsets.US_ASCII)); + String aux = new String(t_float, StandardCharsets.US_ASCII).replace(',', '.'); + if (".".equals(aux)) { + recordObjects[i] = Double.valueOf("0.0"); + } + else { + recordObjects[i] = Double.valueOf(aux); + } } else { recordObjects[i] = null; } @@ -270,13 +302,19 @@ public Object[] nextRecord() throws DBFException { case TIMESTAMP: byte t_byte_date[] = new byte[4]; - this.dataInputStream.read(t_byte_date); + bytesReaded = this.dataInputStream.read(t_byte_date); + if (bytesReaded != t_byte_date.length) { + throw new EOFException("Unexpected end of file"); + } byte t_byte_date_reversed[] = {t_byte_date[3],t_byte_date[2],t_byte_date[1],t_byte_date[0]}; int days = ByteBuffer.wrap(t_byte_date_reversed).getInt(); byte t_byte_time[] = new byte[4]; - this.dataInputStream.read(t_byte_time); + bytesReaded = this.dataInputStream.read(t_byte_time); + if (bytesReaded != t_byte_time.length) { + throw new EOFException("Unexpected end of file"); + } byte t_byte_time_reversed[] = {t_byte_time[3],t_byte_time[2],t_byte_time[1],t_byte_time[0]}; int time = ByteBuffer.wrap(t_byte_time_reversed).getInt(); @@ -295,9 +333,8 @@ public Object[] nextRecord() throws DBFException { recordObjects[i] = "null"; } } - } catch (EOFException e) { - return null; - } catch (IOException e) { + } + catch (IOException e) { throw new DBFException(e.getMessage(), e); } @@ -320,4 +357,12 @@ protected DBFHeader getHeader() { return this.header; } + public boolean isTrimRightSpaces() { + return this.trimRightSpaces; + } + + public void setTrimRightSpaces(boolean trimRightSpaces) { + this.trimRightSpaces = trimRightSpaces; + } + } diff --git a/src/main/java/com/linuxense/javadbf/DBFUtils.java b/src/main/java/com/linuxense/javadbf/DBFUtils.java index ddf47d7b..f855fe1f 100644 --- a/src/main/java/com/linuxense/javadbf/DBFUtils.java +++ b/src/main/java/com/linuxense/javadbf/DBFUtils.java @@ -22,6 +22,7 @@ package com.linuxense.javadbf; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.DataInput; import java.io.IOException; import java.nio.charset.Charset; @@ -173,33 +174,36 @@ public static byte[] textPadding(String text, Charset charset, int length, DBFAl /** * Format a number to write to a dbf file - * @param num number to write + * @param doubleNumber number to write * @param charset charset to use * @param fieldLength * @param sizeDecimalPart * @return bytes to write to the dbf file */ - public static byte[] doubleFormating(Number num, Charset charset, int fieldLength, int sizeDecimalPart) { - return doubleFormating(num.doubleValue(), charset, fieldLength, sizeDecimalPart); + public static byte[] doubleFormating(Double doubleNumber, Charset charset, int fieldLength, int sizeDecimalPart) { + return doubleFormating((Number) doubleNumber, charset, fieldLength, sizeDecimalPart); } /** * Format a double number to write to a dbf file - * @param doubleNum - * @param charset - * @param fieldLength + * @param num Number to write + * @param charset charset to use + * @param fieldLength * @param sizeDecimalPart * @return bytes to write to the dbf file */ - public static byte[] doubleFormating(Double doubleNum, Charset charset, int fieldLength, int sizeDecimalPart) { + public static byte[] doubleFormating(Number num, Charset charset, int fieldLength, int sizeDecimalPart) { int sizeWholePart = fieldLength - (sizeDecimalPart > 0 ? (sizeDecimalPart + 1) : 0); StringBuilder format = new StringBuilder(fieldLength); - for (int i = 0; i < sizeWholePart; i++) { + for (int i = 0; i < sizeWholePart-1; i++) { format.append("#"); } + if (format.length() < sizeWholePart) { + format.append("0"); + } if (sizeDecimalPart > 0) { format.append("."); for (int i = 0; i < sizeDecimalPart; i++) { @@ -209,7 +213,7 @@ public static byte[] doubleFormating(Double doubleNum, Charset charset, int fiel DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH); df.applyPattern(format.toString()); - return textPadding(df.format(doubleNum.doubleValue()).toString(), charset, fieldLength, DBFAlignment.RIGHT, (byte) ' '); + return textPadding(df.format(num).toString(), charset, fieldLength, DBFAlignment.RIGHT, (byte) ' '); } /** @@ -236,10 +240,12 @@ public static boolean contains(byte[] array, byte value) { * @return true if is ascci */ public static boolean isPureAscii(String stringToCheck) { - if (stringToCheck == null) { + if (stringToCheck == null || stringToCheck.length() == 0) { return true; } - return ASCII_ENCODER.canEncode(stringToCheck); + synchronized (ASCII_ENCODER) { + return ASCII_ENCODER.canEncode(stringToCheck); + } } /** @@ -255,5 +261,39 @@ public static Object toBoolean(byte t_logical) { } return null; } + + public static byte[] trimRightSpaces(byte[] b_array) { + if (b_array == null || b_array.length == 0) { + return new byte[0]; + } + int pos = getRightPos(b_array); + int length = pos+1; + byte[] newBytes = new byte[length]; + System.arraycopy(b_array, 0, newBytes, 0, length); + return newBytes; + } + + private static int getRightPos(byte[] b_array) { + int pos = b_array.length - 1; + while (pos >= 0 && b_array[pos] == (byte)' ') { + pos--; + } + return pos; + } + + /** + * Closes silently a #{@link java.io.Closeable}. + * it can be null or throws an exception, will be ignored. + * @param closeable The item to close + */ + public static void close(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (Exception e) { //NOPMD + // nop + } + } + } } diff --git a/src/main/java/com/linuxense/javadbf/DBFWriter.java b/src/main/java/com/linuxense/javadbf/DBFWriter.java index 366ed3d9..4ea6b252 100644 --- a/src/main/java/com/linuxense/javadbf/DBFWriter.java +++ b/src/main/java/com/linuxense/javadbf/DBFWriter.java @@ -110,6 +110,9 @@ public DBFWriter(File dbfFile, Charset charset) throws DBFException { */ if (dbfFile.length() == 0) { if (charset != null) { + if (DBFCharsetHelper.getDBFCodeForCharset(charset) == 0) { + throw new DBFException("Unssuported charset " + charset); + } setCharset(charset); this.header.setUsedCharset(charset); } @@ -123,9 +126,15 @@ public DBFWriter(File dbfFile, Charset charset) throws DBFException { this.header.read(this.raf, charset); setCharset(this.header.getUsedCharset()); - /* position file pointer at the end of the raf */ + // position file pointer at the end of the raf // to ignore the END_OF_DATA byte at EoF - this.raf.seek(this.raf.length() - 1); + // Only if there are records (ignore if the file is only the header) + if (this.raf.length() > header.headerLength) { + this.raf.seek(this.raf.length() - 1); + } + else { + this.raf.seek(this.raf.length()); + } } catch (FileNotFoundException e) { throw new DBFException("Specified file is not found. " + e.getMessage(), e); } catch (IOException e) { @@ -310,7 +319,8 @@ private void writeRecord(DataOutput dataOutput, Object[] objectArray) throws IOE if (objectArray[j] != null) { GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime((Date) objectArray[j]); - dataOutput.write(String.valueOf(calendar.get(Calendar.YEAR)).getBytes(StandardCharsets.US_ASCII)); + dataOutput.write(DBFUtils.textPadding(String.valueOf(calendar.get(Calendar.YEAR)), + StandardCharsets.US_ASCII, 4, DBFAlignment.RIGHT, (byte) '0')); dataOutput.write(DBFUtils.textPadding(String.valueOf(calendar.get(Calendar.MONTH) + 1), StandardCharsets.US_ASCII, 2, DBFAlignment.RIGHT, (byte) '0')); dataOutput.write(DBFUtils.textPadding(String.valueOf(calendar.get(Calendar.DAY_OF_MONTH)), @@ -351,4 +361,11 @@ private void writeRecord(DataOutput dataOutput, Object[] objectArray) throws IOE } } } + @Override + public void setCharset(Charset charset) { + super.setCharset(charset); + if (this.header != null) { + this.header.setUsedCharset(charset); + } + } } diff --git a/src/test/java/com/linuxense/javadbf/DBFCharsetHelperTest.java b/src/test/java/com/linuxense/javadbf/DBFCharsetHelperTest.java index 560b6f08..4e123c1e 100644 --- a/src/test/java/com/linuxense/javadbf/DBFCharsetHelperTest.java +++ b/src/test/java/com/linuxense/javadbf/DBFCharsetHelperTest.java @@ -87,6 +87,27 @@ public void listEncodings() { } } + + @Test + public void testRussianAndNordicEncodingsBug35() { + /* Russian IBM866 and Nordic ISO865 has changed values. + * + * Correct values: https://msdn.microsoft.com/en-us/library/8t45x02s(v=vs.80).aspx + * + */ + + // Russian IBM866 0x65 + Charset russian = Charset.forName("IBM866"); + + Assert.assertEquals(0x65, DBFCharsetHelper.getDBFCodeForCharset(russian)); + Assert.assertEquals(russian, DBFCharsetHelper.getCharsetByByte(0x65)); + + // Nordic IBM865 0x66 + + Charset nordic = Charset.forName("IBM865"); + Assert.assertEquals(0x66, DBFCharsetHelper.getDBFCodeForCharset(nordic)); + Assert.assertEquals(nordic, DBFCharsetHelper.getCharsetByByte(0x66)); + } } diff --git a/src/test/java/com/linuxense/javadbf/DBFReaderTest.java b/src/test/java/com/linuxense/javadbf/DBFReaderTest.java index bbe8253c..277f7333 100644 --- a/src/test/java/com/linuxense/javadbf/DBFReaderTest.java +++ b/src/test/java/com/linuxense/javadbf/DBFReaderTest.java @@ -10,7 +10,7 @@ import org.junit.Assert; import org.junit.Test; -import com.linuxsense.javadbf.mocks.FailInputStream; +import com.linuxense.javadbf.mocks.FailInputStream; public class DBFReaderTest { diff --git a/src/test/java/com/linuxense/javadbf/DBFWriterStreamTest.java b/src/test/java/com/linuxense/javadbf/DBFWriterStreamTest.java index 5bdc88f4..0fb57704 100644 --- a/src/test/java/com/linuxense/javadbf/DBFWriterStreamTest.java +++ b/src/test/java/com/linuxense/javadbf/DBFWriterStreamTest.java @@ -6,7 +6,7 @@ import org.junit.Assert; import org.junit.Test; -import com.linuxsense.javadbf.mocks.NullOutputStream; +import com.linuxense.javadbf.mocks.NullOutputStream; public class DBFWriterStreamTest { diff --git a/src/test/java/com/linuxense/javadbf/EncodingTest.java b/src/test/java/com/linuxense/javadbf/EncodingTest.java index e09684cc..f3f5e374 100644 --- a/src/test/java/com/linuxense/javadbf/EncodingTest.java +++ b/src/test/java/com/linuxense/javadbf/EncodingTest.java @@ -1,12 +1,14 @@ package com.linuxense.javadbf; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -152,4 +154,37 @@ public void testSetEncoding() throws DBFException { Assert.assertEquals(StandardCharsets.ISO_8859_1, writer.getCharset()); } } + + @Test + public void testSetEncodingCP866() throws DBFException { + DBFWriter writer = null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + writer = new DBFWriter(); + writer.setCharactersetName("CP866"); + DBFField fields[] = new DBFField[1]; + + fields[0] = new DBFField(); + fields[0].setName("emp_name"); + fields[0].setType(DBFDataType.CHARACTER); + fields[0].setFieldLength(10); + writer.setFields(fields); + writer.addRecord(new Object[] { "Simon" }); + writer.addRecord(new Object[] { "Julian"}); + writer.write(baos); + } + finally { + DBFUtils.close(writer); + } + byte[] data = baos.toByteArray(); + Assert.assertEquals(0x65, data[29]); + } + + @Test + public void testSetEncodingCP866StringConversion() throws DBFException { + Charset charset = Charset.forName("CP866"); + String charsetString = charset.toString().toLowerCase(); + + Assert.assertEquals("ibm866", charsetString); + } } diff --git a/src/test/java/com/linuxense/javadbf/FixtureCp1251Test.java b/src/test/java/com/linuxense/javadbf/FixtureCp1251Test.java new file mode 100644 index 00000000..b3e85966 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureCp1251Test.java @@ -0,0 +1,102 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; + +public class FixtureCp1251Test { + @Test + public void test8b() throws Exception { + File file = new File("src/test/resources/fixtures/cp1251.dbf"); + DBFReader reader = null; + InputStream is = null; + try { + is = new FileInputStream(file); + reader = new DBFReader(is); + + DBFHeader header = reader.getHeader(); + + Assert.assertNotNull(header); + Assert.assertEquals(2, header.fieldArray.length); + + Assert.assertEquals("RN", header.fieldArray[0].getName()); + Assert.assertEquals(DBFDataType.NUMERIC, header.fieldArray[0].getType()); + Assert.assertEquals(0, header.fieldArray[0].getDecimalCount()); + Assert.assertEquals(4, header.fieldArray[0].getFieldLength()); + + Assert.assertEquals("NAME", header.fieldArray[1].getName()); + Assert.assertEquals(DBFDataType.CHARACTER, header.fieldArray[1].getType()); + Assert.assertEquals(0, header.fieldArray[1].getDecimalCount()); + Assert.assertEquals(100, header.fieldArray[1].getFieldLength()); + + + + Assert.assertEquals(4, header.numberOfRecords); + + + Object[] row = null; + + row = reader.nextRecord(); + Assert.assertEquals(1, ((Number) row[0]).intValue()); + Assert.assertEquals("àìáóëàòîðíî-ïîëèêëèíè÷åñêîå", ((String)row[1]).trim()); + + row = reader.nextRecord(); + Assert.assertEquals(2, ((Number) row[0]).intValue()); + Assert.assertEquals("áîëüíè÷íîå", ((String)row[1]).trim()); + + row = reader.nextRecord(); + Assert.assertEquals(3, ((Number) row[0]).intValue()); + Assert.assertEquals("ÍÈÈ", ((String)row[1]).trim()); + + row = reader.nextRecord(); + Assert.assertEquals(4, ((Number) row[0]).intValue()); + Assert.assertEquals("îáðàçîâàòåëüíîå ìåäèöèíñêîå ó÷ðåæäåíèå", ((String)row[1]).trim()); + + row = reader.nextRecord(); + Assert.assertNull(row); + + + + } finally { + DBFUtils.close(is); + } + + } +} + + +/* + +Database: cp1251.dbf +Type: (30) Visual FoxPro +Memo File: false +Records: 4 + +Fields: +Name Type Length Decimal +------------------------------------------------------------------------------ +RN N 4 0 +NAME C 100 0 + +*/ \ No newline at end of file diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBase03Test.java b/src/test/java/com/linuxense/javadbf/FixtureDBase03Test.java new file mode 100644 index 00000000..01ce0b60 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBase03Test.java @@ -0,0 +1,135 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.testutils.AssertUtils; +import com.linuxense.javadbf.testutils.DbfToTxtTest; + +public class FixtureDBase03Test { + @Test + public void test8b() throws Exception { + File file = new File("src/test/resources/fixtures/dbase_03.dbf"); + DBFReader reader = null; + InputStream is = null; + try { + is = new FileInputStream(file); + reader = new DBFReader(is); + + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(31, header.fieldArray.length); + Assert.assertEquals(14, header.numberOfRecords); + DBFField []fieldArray = header.fieldArray; + + int i = 0; + + AssertUtils.assertColumnDefinition(fieldArray[i++], "Point_ID" , DBFDataType.fromCode((byte) 'C'), 12, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Type" , DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Shape" , DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Circular_D", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Non_circul", DBFDataType.fromCode((byte) 'C'), 60, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Flow_prese", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Condition" , DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Comments" , DBFDataType.fromCode((byte) 'C'), 60, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Date_Visit", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Time" , DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Max_PDOP" , DBFDataType.fromCode((byte) 'N'), 5 , 1); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Max_HDOP" , DBFDataType.fromCode((byte) 'N'), 5 , 1); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Corr_Type" , DBFDataType.fromCode((byte) 'C'), 36, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Rcvr_Type" , DBFDataType.fromCode((byte) 'C'), 36, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GPS_Date" , DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GPS_Time" , DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Update_Sta", DBFDataType.fromCode((byte) 'C'), 36, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Feat_Name" , DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Datafile" , DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Unfilt_Pos", DBFDataType.fromCode((byte) 'N'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Filt_Pos" , DBFDataType.fromCode((byte) 'N'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Data_Dicti", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GPS_Week" , DBFDataType.fromCode((byte) 'N'), 6 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GPS_Second", DBFDataType.fromCode((byte) 'N'), 12, 3); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GPS_Height", DBFDataType.fromCode((byte) 'N'), 16, 3); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Vert_Prec" , DBFDataType.fromCode((byte) 'N'), 16, 1); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Horz_Prec" , DBFDataType.fromCode((byte) 'N'), 16, 1); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Std_Dev" , DBFDataType.fromCode((byte) 'N'), 16, 6); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Northing" , DBFDataType.fromCode((byte) 'N'), 16, 3); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Easting" , DBFDataType.fromCode((byte) 'N'), 16, 3); + AssertUtils.assertColumnDefinition(fieldArray[i++], "Point_ID" , DBFDataType.fromCode((byte) 'N'), 9 , 0); + + DbfToTxtTest.export(reader, File.createTempFile("javadbf-test", ".txt")); + + } finally { + DBFUtils.close(is); + } + + } +} + + + + +/* + +Database: dbase_03.dbf +Type: (03) dBase III without memo file +Memo File: false +Records: 14 + +Fields: +Name Type Length Decimal +------------------------------------------------------------------------------ +Point_ID C 12 0 +Type C 20 0 +Shape C 20 0 +Circular_D C 20 0 +Non_circul C 60 0 +Flow_prese C 20 0 +Condition C 20 0 +Comments C 60 0 +Date_Visit D 8 0 +Time C 10 0 +Max_PDOP N 5 1 +Max_HDOP N 5 1 +Corr_Type C 36 0 +Rcvr_Type C 36 0 +GPS_Date D 8 0 +GPS_Time C 10 0 +Update_Sta C 36 0 +Feat_Name C 20 0 +Datafile C 20 0 +Unfilt_Pos N 10 0 +Filt_Pos N 10 0 +Data_Dicti C 20 0 +GPS_Week N 6 0 +GPS_Second N 12 3 +GPS_Height N 16 3 +Vert_Prec N 16 1 +Horz_Prec N 16 1 +Std_Dev N 16 6 +Northing N 16 3 +Easting N 16 3 +Point_ID N 9 0 + +*/ \ No newline at end of file diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBase30Test.java b/src/test/java/com/linuxense/javadbf/FixtureDBase30Test.java new file mode 100644 index 00000000..17d9200c --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBase30Test.java @@ -0,0 +1,206 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.testutils.AssertUtils; +import com.linuxense.javadbf.testutils.DbfToTxtTest; + +public class FixtureDBase30Test { + + @Test + public void test30 () throws Exception { + File file = new File("src/test/resources/fixtures/dbase_30.dbf"); + DBFReader reader = null; + InputStream is = null; + try { + is = new FileInputStream(file); + reader = new DBFReader(is); + + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(145, header.fieldArray.length); + Assert.assertEquals(34, header.numberOfRecords); + DBFField []fieldArray = header.fieldArray; + + int i = 0; + + + AssertUtils.assertColumnDefinition(fieldArray[i++], "ACCESSNO", DBFDataType.fromCode((byte) 'C'), 15 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ACQVALUE", DBFDataType.fromCode((byte) 'N'), 12 , 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "APPNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "APPRAISOR", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CABINET", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CAPTION", DBFDataType.fromCode((byte) 'C'), 30 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CAT", DBFDataType.fromCode((byte) 'C'), 1 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CATBY", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CATDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CATTYPE", DBFDataType.fromCode((byte) 'C'), 15 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CLASSES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COLLECTION", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CONDDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CONDEXAM", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CONDITION", DBFDataType.fromCode((byte) 'C'), 35 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CONDNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CONTAINER", DBFDataType.fromCode((byte) 'C'), 40 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COPYRIGHT", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CREATOR", DBFDataType.fromCode((byte) 'C'), 80 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CREDIT", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CURVALMAX", DBFDataType.fromCode((byte) 'N'), 12 , 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CURVALUE", DBFDataType.fromCode((byte) 'N'), 12 , 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DATASET", DBFDataType.fromCode((byte) 'C'), 15 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DATE", DBFDataType.fromCode((byte) 'C'), 50 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DESCRIP", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DIMNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DISPVALUE", DBFDataType.fromCode((byte) 'C'), 10 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DRAWER", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EARLYDATE", DBFDataType.fromCode((byte) 'N'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EVENT", DBFDataType.fromCode((byte) 'C'), 80 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHIBITID", DBFDataType.fromCode((byte) 'C'), 36 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHIBITNO", DBFDataType.fromCode((byte) 'N'), 7 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHLABEL1", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHLABEL2", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHLABEL3", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHLABEL4", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "EXHSTART", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "FILMSIZE", DBFDataType.fromCode((byte) 'C'), 35 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "FLAGDATE", DBFDataType.fromCode((byte) 'T'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "FLAGNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "FLAGREASON", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "FRAME", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "FRAMENO", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GPARENT", DBFDataType.fromCode((byte) 'C'), 45 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "HOMELOC", DBFDataType.fromCode((byte) 'C'), 60 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "IMAGEFILE", DBFDataType.fromCode((byte) 'C'), 60 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "IMAGENO", DBFDataType.fromCode((byte) 'N'), 3 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INSCOMP", DBFDataType.fromCode((byte) 'C'), 30 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INSDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INSPHONE", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INSPREMIUM", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INSREP", DBFDataType.fromCode((byte) 'C'), 30 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INSVALUE", DBFDataType.fromCode((byte) 'N'), 10 , 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INVNBY", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INVNDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LATEDATE", DBFDataType.fromCode((byte) 'N'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LEGAL", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LOANCOND", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LOANDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LOANDUE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LOANID", DBFDataType.fromCode((byte) 'C'), 36 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LOANINNO", DBFDataType.fromCode((byte) 'C'), 15 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "MAINTCYCLE", DBFDataType.fromCode((byte) 'C'), 10 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "MAINTDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "MAINTNOTE", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "MEDIUM", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NEGLOC", DBFDataType.fromCode((byte) 'C'), 60 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NEGNO", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBJECTID", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBJNAME", DBFDataType.fromCode((byte) 'C'), 40 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OLDNO", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ORIGCOPY", DBFDataType.fromCode((byte) 'C'), 15 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OTHERNO", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OUTDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PARENT", DBFDataType.fromCode((byte) 'C'), 40 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PEOPLE", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PLACE", DBFDataType.fromCode((byte) 'C'), 100 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "POLICYNO", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PRINTSIZE", DBFDataType.fromCode((byte) 'C'), 35 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PROCESS", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PROVENANCE", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PUBNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "RECAS", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "RECDATE", DBFDataType.fromCode((byte) 'C'), 10 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "RECFROM", DBFDataType.fromCode((byte) 'C'), 120 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "RELATION", DBFDataType.fromCode((byte) 'C'), 36 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "RELNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ROOM", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SGFLAG", DBFDataType.fromCode((byte) 'C'), 1 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SHELF", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SITE", DBFDataType.fromCode((byte) 'C'), 40 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SITENO", DBFDataType.fromCode((byte) 'C'), 12 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SLIDENO", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "STATUS", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "STATUSBY", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "STATUSDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "STERMS", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "STUDIO", DBFDataType.fromCode((byte) 'C'), 60 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SUBJECTS", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TCABINET", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TCONTAINER", DBFDataType.fromCode((byte) 'C'), 40 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TDRAWER", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPAUTHOR", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPBY", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPLOC", DBFDataType.fromCode((byte) 'C'), 60 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPNOTES", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPREASON", DBFDataType.fromCode((byte) 'C'), 50 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TEMPUNTIL", DBFDataType.fromCode((byte) 'C'), 10 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TITLE", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TITLESORT", DBFDataType.fromCode((byte) 'C'), 100 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TROOM", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TSHELF", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TWALL", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF1", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF10", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF11", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF12", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF13", DBFDataType.fromCode((byte) 'N'), 12 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF14", DBFDataType.fromCode((byte) 'N'), 12 , 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF15", DBFDataType.fromCode((byte) 'N'), 12 , 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF16", DBFDataType.fromCode((byte) 'N'), 12 , 3); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF17", DBFDataType.fromCode((byte) 'N'), 12 , 3); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF18", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF19", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF20", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF21", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF22", DBFDataType.fromCode((byte) 'M'), 4 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF2", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF3", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF4", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF5", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF6", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF7", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF8", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UDF9", DBFDataType.fromCode((byte) 'C'), 75 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UPDATED", DBFDataType.fromCode((byte) 'T'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UPDATEDBY", DBFDataType.fromCode((byte) 'C'), 25 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "VALUEDATE", DBFDataType.fromCode((byte) 'D'), 8 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "WALL", DBFDataType.fromCode((byte) 'C'), 20 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "WEBINCLUDE", DBFDataType.fromCode((byte) 'L'), 1 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ZSORTER", DBFDataType.fromCode((byte) 'C'), 69 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ZSORTERX", DBFDataType.fromCode((byte) 'C'), 44 , 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PPID", DBFDataType.fromCode((byte) 'C'), 36 , 0); + + DbfToTxtTest.export(reader, File.createTempFile("javadbf-test", ".txt")); + + + } finally { + DBFUtils.close(is); + } + + } + +} diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBase31Test.java b/src/test/java/com/linuxense/javadbf/FixtureDBase31Test.java new file mode 100644 index 00000000..297f0f6d --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBase31Test.java @@ -0,0 +1,95 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.testutils.AssertUtils; +import com.linuxense.javadbf.testutils.DbfToTxtTest; + +public class FixtureDBase31Test { + + @Test + public void test31 () throws Exception { + File file = new File("src/test/resources/fixtures/dbase_31.dbf"); + DBFReader reader = null; + java.io.InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + reader = new DBFReader(is); + + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(11, header.fieldArray.length); + Assert.assertEquals(77, header.numberOfRecords); + DBFField []fieldArray = header.fieldArray; + + int i = 0; + + AssertUtils.assertColumnDefinition(fieldArray[i++], "PRODUCTID", DBFDataType.fromCode((byte) 'I'), 4 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PRODUCTNAM", DBFDataType.fromCode((byte) 'C'), 40 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SUPPLIERID", DBFDataType.fromCode((byte) 'I'), 4 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CATEGORYID", DBFDataType.fromCode((byte) 'I'), 4 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "QUANTITYPE", DBFDataType.fromCode((byte) 'C'), 20 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UNITPRICE", DBFDataType.fromCode((byte) 'Y'), 8 ,4); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UNITSINSTO", DBFDataType.fromCode((byte) 'I'), 4 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "UNITSONORD", DBFDataType.fromCode((byte) 'I'), 4 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "REORDERLEV", DBFDataType.fromCode((byte) 'I'), 4 ,0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DISCONTINU", DBFDataType.fromCode((byte) 'L'), 1 ,0); +// AssertUtils.assertColumnDefinition(fieldArray[i++], "_NullFlags", DBFDataType.NULL_FLAGS, 1 ,0); + + + DbfToTxtTest.export(reader, File.createTempFile("javadbf-test", ".txt")); + + } finally { + DBFUtils.close(is); + } + + } + +} + + + +/* + Database: dbase_31.dbf +Type: (31) Visual FoxPro with AutoIncrement field +Memo File: false +Records: 77 + +Fields: +Name Type Length Decimal +------------------------------------------------------------------------------ +PRODUCTID I 4 0 +PRODUCTNAM C 40 0 +SUPPLIERID I 4 0 +CATEGORYID I 4 0 +QUANTITYPE C 20 0 +UNITPRICE Y 8 4 +UNITSINSTO I 4 0 +UNITSONORD I 4 0 +REORDERLEV I 4 0 +DISCONTINU L 1 0 +_NullFlags 0 1 0 +*/ diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBase7Test.java b/src/test/java/com/linuxense/javadbf/FixtureDBase7Test.java new file mode 100644 index 00000000..909b080b --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBase7Test.java @@ -0,0 +1,78 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import static com.linuxense.javadbf.testutils.DateUtils.createDate; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.linuxense.javadbf.testutils.AssertUtils; + +public class FixtureDBase7Test { + + @Test + @Ignore("dbase 7 not supported in 0.x") + public void test7 () throws Exception { + File file = new File("src/test/resources/fixtures/dbase_7.dbf"); + InputStream is = null; + DBFReader reader = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + reader = new DBFReader(is); + + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(4, header.fieldArray.length); + Assert.assertEquals(3, header.numberOfRecords); + DBFField []fieldArray = header.fieldArray; + AssertUtils.assertColumnDefinition(fieldArray[0], "ACTION", DBFDataType.MEMO, 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[1], "DATE", DBFDataType.DATE, 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[2], "USER", DBFDataType.CHARACTER, 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[3], "ID", DBFDataType.CHARACTER, 12, 0); + + Object[] row = null; + + row = reader.nextRecord(); + Assert.assertEquals(createDate(2015,2,23), row[1]); + Assert.assertEquals("DFG", row[2]); + Assert.assertEquals("1", row[3]); + + row = reader.nextRecord(); + Assert.assertEquals(createDate(2013,1,31), row[1]); + Assert.assertEquals("GFS", row[2]); + Assert.assertEquals("2", row[3]); + + row = reader.nextRecord(); + Assert.assertEquals(createDate(2014,10,28), row[1]); + Assert.assertEquals("HSJ", row[2]); + Assert.assertEquals("3", row[3]); + + } + finally { + DBFUtils.close(is); + } + } +} diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBase83Test.java b/src/test/java/com/linuxense/javadbf/FixtureDBase83Test.java new file mode 100644 index 00000000..3efdd017 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBase83Test.java @@ -0,0 +1,101 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.testutils.AssertUtils; +import com.linuxense.javadbf.testutils.DbfToTxtTest; + +public class FixtureDBase83Test { + + @Test + public void test8b() throws Exception { + File file = new File("src/test/resources/fixtures/dbase_83.dbf"); + InputStream inputStream = null; + try { + inputStream = new BufferedInputStream(new FileInputStream(file)); + DBFReader reader = new DBFReader(inputStream); +// reader.setMemoFile(new File("src/test/resources/fixtures/dbase_83.dbt")); + + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(15, header.fieldArray.length); + Assert.assertEquals(67, header.numberOfRecords); + + DBFField[] fieldArray = header.fieldArray; + + int i = 0; + + AssertUtils.assertColumnDefinition(fieldArray[i++], "ID", DBFDataType.fromCode('N'), 19, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CATCOUNT", DBFDataType.fromCode('N'), 19, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "AGRPCOUNT", DBFDataType.fromCode('N'), 19, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PGRPCOUNT", DBFDataType.fromCode('N'), 19, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ORDER", DBFDataType.fromCode('N'), 19, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "CODE", DBFDataType.fromCode('C'), 50, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NAME", DBFDataType.fromCode('C'), 100, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "THUMBNAIL", DBFDataType.fromCode('C'), 254, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "IMAGE", DBFDataType.fromCode('C'), 254, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PRICE", DBFDataType.fromCode('N'), 13, 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COST", DBFDataType.fromCode('N'), 13, 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DESC", DBFDataType.fromCode('M'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "WEIGHT", DBFDataType.fromCode('N'), 13, 2); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TAXABLE", DBFDataType.fromCode('L'), 1, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ACTIVE", DBFDataType.fromCode('L'), 1, 0); + + DbfToTxtTest.export(reader, File.createTempFile("javadbf-test", ".txt")); + + } finally { + DBFUtils.close(inputStream); + } + } +} + +/* +Database: dbase_83.dbf +Type: (83) dBase III with memo file +Memo File: true +Records: 67 + +Fields: +Name Type Length Decimal +------------------------------------------------------------------------------ +ID N 19 0 +CATCOUNT N 19 0 +AGRPCOUNT N 19 0 +PGRPCOUNT N 19 0 +ORDER N 19 0 +CODE C 50 0 +NAME C 100 0 +THUMBNAIL C 254 0 +IMAGE C 254 0 +PRICE N 13 2 +COST N 13 2 +DESC M 10 0 +WEIGHT N 13 2 +TAXABLE L 1 0 +ACTIVE L 1 0 + +*/ \ No newline at end of file diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBase8bTest.java b/src/test/java/com/linuxense/javadbf/FixtureDBase8bTest.java new file mode 100644 index 00000000..4d0e9724 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBase8bTest.java @@ -0,0 +1,239 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import static com.linuxense.javadbf.testutils.DateUtils.createDate; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Date; + +import org.junit.Assert; +import org.junit.Test; + +public class FixtureDBase8bTest { + + @Test + public void test8b() throws Exception { + File file = new File("src/test/resources/fixtures/dbase_8b.dbf"); + DBFReader reader = null; + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + reader = new DBFReader(is); + reader.setTrimRightSpaces(true); + + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(6, header.fieldArray.length); + + Assert.assertEquals("CHARACTER", header.fieldArray[0].getName()); + Assert.assertEquals(DBFDataType.CHARACTER, header.fieldArray[0].getType()); + Assert.assertEquals(0, header.fieldArray[0].getDecimalCount()); + Assert.assertEquals(100, header.fieldArray[0].getFieldLength()); + + Assert.assertEquals("NUMERICAL", header.fieldArray[1].getName()); + Assert.assertEquals(DBFDataType.NUMERIC, header.fieldArray[1].getType()); + Assert.assertEquals(2, header.fieldArray[1].getDecimalCount()); + Assert.assertEquals(20, header.fieldArray[1].getFieldLength()); + + Assert.assertEquals("DATE", header.fieldArray[2].getName()); + Assert.assertEquals(DBFDataType.DATE, header.fieldArray[2].getType()); + Assert.assertEquals(0, header.fieldArray[2].getDecimalCount()); + Assert.assertEquals(8, header.fieldArray[2].getFieldLength()); + + Assert.assertEquals("LOGICAL", header.fieldArray[3].getName()); + Assert.assertEquals(DBFDataType.LOGICAL, header.fieldArray[3].getType()); + Assert.assertEquals(0, header.fieldArray[3].getDecimalCount()); + Assert.assertEquals(1, header.fieldArray[3].getFieldLength()); + + Assert.assertEquals("FLOAT", header.fieldArray[4].getName()); + Assert.assertEquals(DBFDataType.FLOATING_POINT, header.fieldArray[4].getType()); + Assert.assertEquals(18, header.fieldArray[4].getDecimalCount()); + Assert.assertEquals(20, header.fieldArray[4].getFieldLength()); + + Assert.assertEquals("MEMO", header.fieldArray[5].getName()); + Assert.assertEquals(DBFDataType.MEMO, header.fieldArray[5].getType()); + Assert.assertEquals(0, header.fieldArray[5].getDecimalCount()); + Assert.assertEquals(10, header.fieldArray[5].getFieldLength()); + + Assert.assertEquals(10, header.numberOfRecords); + + + Object[] row = null; + + + row = reader.nextRecord(); + Assert.assertEquals("One", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(1, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1970,1,1), row[2]); + Assert.assertTrue(row[3] instanceof Boolean); + Assert.assertTrue((Boolean) row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(1.23456789012346, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("First memo\r\n", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Two", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(2, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1970,12,31), row[2]); + Assert.assertTrue(row[3] instanceof Boolean); + Assert.assertTrue((Boolean) row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(2.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Second memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Three", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(3, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1980,1,1), row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(3.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Thierd memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Four", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(4, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1900,1,1), row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(4.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Fourth memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Five", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(5, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1900,12,31), row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(5.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Fifth memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Six", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(6, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1901,1,1), row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(6.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Sixth memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Seven", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(7, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1999,12,31), row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(7.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Seventh memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Eight", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(8, ((Number)row[1]).intValue()); + Assert.assertTrue(row[2] instanceof Date); + Assert.assertEquals(createDate(1919,12,31), row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(8.0, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertEquals("Eigth memo", row[5]); + + row = reader.nextRecord(); + Assert.assertEquals("Nine", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(9, ((Number)row[1]).intValue()); + Assert.assertNull(row[2]); + Assert.assertNull(row[3]); + Assert.assertNull(row[4]); +// Assert.assertEquals("Nineth memo", row[5]); + + + row = reader.nextRecord(); + Assert.assertEquals("Ten records stored in this database", row[0]); + Assert.assertTrue(row[1] instanceof Number); + Assert.assertEquals(10, ((Number)row[1]).intValue()); + Assert.assertNull(row[2]); + Assert.assertNull(row[3]); + Assert.assertTrue(row[4] instanceof Number); + Assert.assertEquals(0.1, ((Number)row[4]).doubleValue(), 0.0001); +// Assert.assertNull(row[5]); + + row = reader.nextRecord(); + + Assert.assertNull(row); + + + + + } finally { + DBFUtils.close(is); + } + + } + + +} + + +/* +Database: dbase_8b.dbf +Type: (8b) dBase IV with memo file +Memo File: true +Records: 10 + +Fields: +Name Type Length Decimal +------------------------------------------------------------------------------ +CHARACTER C 100 0 +NUMERICAL N 20 2 +DATE D 8 0 +LOGICAL L 1 0 +FLOAT F 20 18 +MEMO M 10 0 +*/ + +/* +One ;1.0;Thu Jan 01 00:00:00 CET 1970;true;1.23456789012346;null; +Two ;2.0;Thu Dec 31 00:00:00 CET 1970;true;2.0;null; +Three ;3.0;Tue Jan 01 00:00:00 CET 1980;null;3.0;null; +Four ;4.0;Mon Jan 01 00:00:00 CET 1900;null;4.0;null; +Five ;5.0;Mon Dec 31 00:00:00 CET 1900;null;5.0;null; +Six ;6.0;Tue Jan 01 00:14:44 CET 1901;null;6.0;null; +Seven ;7.0;Fri Dec 31 00:00:00 CET 1999;null;7.0;null; +Eight ;8.0;Wed Dec 31 00:00:00 CET 1919;null;8.0;null; +Nine ;9.0;null;null;null;null; +Ten records stored in this database ;10.0;null;null;0.1;null; +*/ \ No newline at end of file diff --git a/src/test/java/com/linuxense/javadbf/FixtureDBaseF5Test.java b/src/test/java/com/linuxense/javadbf/FixtureDBaseF5Test.java new file mode 100644 index 00000000..a8a6c84e --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/FixtureDBaseF5Test.java @@ -0,0 +1,194 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.testutils.AssertUtils; +import com.linuxense.javadbf.testutils.DbfToTxtTest; + +public class FixtureDBaseF5Test { + + @Test + public void test31() throws Exception { + File file = new File("src/test/resources/fixtures/dbase_f5.dbf"); + InputStream inputStream = null; + try { + inputStream = new BufferedInputStream(new FileInputStream(file)); + DBFReader reader = new DBFReader(inputStream); +// reader.setMemoFile(new File("src/test/resources/fixtures/dbase_f5.fpt")); + DBFHeader header = reader.getHeader(); + Assert.assertNotNull(header); + Assert.assertEquals(59, header.fieldArray.length); + Assert.assertEquals(975, header.numberOfRecords); + DBFField[] fieldArray = header.fieldArray; + + int i = 0; + + AssertUtils.assertColumnDefinition(fieldArray[i++], "NF", DBFDataType.fromCode((byte) 'N'), 5, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "SEXE", DBFDataType.fromCode((byte) 'C'), 1, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NOM", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COG1", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COG2", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TELEFON", DBFDataType.fromCode((byte) 'C'), 9, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "RENOM", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NFP", DBFDataType.fromCode((byte) 'N'), 5, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NFM", DBFDataType.fromCode((byte) 'N'), 5, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ARXN", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DATN", DBFDataType.fromCode((byte) 'D'), 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LLON", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "MUNN", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COMN", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PROV", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PAIN", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OFIC", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ARXB", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DATB", DBFDataType.fromCode((byte) 'D'), 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LLOB", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "MUNB", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "COMB", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "PAIB", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DRIB", DBFDataType.fromCode((byte) 'C'), 30, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "INAB", DBFDataType.fromCode((byte) 'C'), 30, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OFTB", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OFNB", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "AXC1", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DTC1", DBFDataType.fromCode((byte) 'D'), 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LLC1", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NFC1", DBFDataType.fromCode((byte) 'N'), 5, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TCA1", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OTC1", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ONC1", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "AXC2", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DTC2", DBFDataType.fromCode((byte) 'D'), 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LLC2", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NFC2", DBFDataType.fromCode((byte) 'N'), 5, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TCA2", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OTC2", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ONC2", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "AXC3", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DTC3", DBFDataType.fromCode((byte) 'D'), 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LLC3", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "NFC3", DBFDataType.fromCode((byte) 'N'), 5, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "TCA3", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OTC3", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ONC3", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "ARXD", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "DATD", DBFDataType.fromCode((byte) 'D'), 8, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "LLOD", DBFDataType.fromCode((byte) 'C'), 15, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OFTD", DBFDataType.fromCode((byte) 'C'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OFND", DBFDataType.fromCode((byte) 'C'), 20, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBS1", DBFDataType.fromCode((byte) 'C'), 70, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBS2", DBFDataType.fromCode((byte) 'C'), 70, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBS3", DBFDataType.fromCode((byte) 'C'), 70, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBS4", DBFDataType.fromCode((byte) 'C'), 70, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "OBSE", DBFDataType.fromCode((byte) 'M'), 10, 0); + AssertUtils.assertColumnDefinition(fieldArray[i++], "GHD", DBFDataType.fromCode((byte) 'C'), 15, 0); + + + DbfToTxtTest.export(reader, File.createTempFile("javadbf-test", ".txt")); + + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + + } + +} + +/* + + + +Database: dbase_f5.dbf +Type: (f5) FoxPro with memo file +Memo File: true +Records: 975 + +Fields: +Name Type Length Decimal +------------------------------------------------------------------------------ +NF N 5 0 +SEXE C 1 0 +NOM C 20 0 +COG1 C 15 0 +COG2 C 15 0 +TELEFON C 9 0 +RENOM C 15 0 +NFP N 5 0 +NFM N 5 0 +ARXN C 10 0 +DATN D 8 0 +LLON C 15 0 +MUNN C 15 0 +COMN C 15 0 +PROV C 15 0 +PAIN C 15 0 +OFIC C 15 0 +ARXB C 10 0 +DATB D 8 0 +LLOB C 15 0 +MUNB C 15 0 +COMB C 15 0 +PAIB C 15 0 +DRIB C 30 0 +INAB C 30 0 +OFTB C 10 0 +OFNB C 20 0 +AXC1 C 10 0 +DTC1 D 8 0 +LLC1 C 15 0 +NFC1 N 5 0 +TCA1 C 10 0 +OTC1 C 10 0 +ONC1 C 20 0 +AXC2 C 10 0 +DTC2 D 8 0 +LLC2 C 15 0 +NFC2 N 5 0 +TCA2 C 10 0 +OTC2 C 10 0 +ONC2 C 20 0 +AXC3 C 10 0 +DTC3 D 8 0 +LLC3 C 15 0 +NFC3 N 5 0 +TCA3 C 10 0 +OTC3 C 10 0 +ONC3 C 20 0 +ARXD C 10 0 +DATD D 8 0 +LLOD C 15 0 +OFTD C 10 0 +OFND C 20 0 +OBS1 C 70 0 +OBS2 C 70 0 +OBS3 C 70 0 +OBS4 C 70 0 +OBSE M 10 0 +GHD C 15 0 +*/ diff --git a/src/test/java/com/linuxense/javadbf/UTF8Test.java b/src/test/java/com/linuxense/javadbf/UTF8Test.java new file mode 100644 index 00000000..b3e0ee41 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/UTF8Test.java @@ -0,0 +1,79 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.charset.Charset; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class UTF8Test { + + public UTF8Test () { + super(); + } + + @Test + @Ignore + public void testUTF8() throws Exception { + String testString = "Cộng hòa xã hội"; + DBFField fields[] = new DBFField[1]; + fields[0] = new DBFField(); + fields[0].setName("abc"); + fields[0].setType(DBFDataType.CHARACTER); + fields[0].setFieldLength(10); + + DBFWriter writer = null; + ByteArrayOutputStream fos = null; + try { + fos = new ByteArrayOutputStream(); + writer = new DBFWriter(Charset.forName("UTF-8")); + writer.setFields(fields); + Object rowData[] = new Object[1]; + + rowData[0] = testString; + + writer.addRecord(rowData); + + writer.write(fos); + + } + finally { + DBFUtils.close(fos); + } + byte[] data = fos.toByteArray(); + + + DBFReader reader = null; + InputStream is = null; + try { + is = new ByteArrayInputStream(data); + reader = new DBFReader(is); + Object[] rowObjects = reader.nextRecord(); + Assert.assertEquals(testString, rowObjects[0]); + } + finally { + DBFUtils.close(is); + } + } +} diff --git a/src/test/java/com/linuxense/javadbf/UtilsTest.java b/src/test/java/com/linuxense/javadbf/UtilsTest.java index 7895a3d6..701d9a02 100644 --- a/src/test/java/com/linuxense/javadbf/UtilsTest.java +++ b/src/test/java/com/linuxense/javadbf/UtilsTest.java @@ -8,6 +8,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import org.junit.Assert; import org.junit.Test; @@ -51,7 +52,19 @@ public void testContains () { } @Test public void doubleFormating() { - // TODO + Assert.assertEquals( + " 0.00", + new String(DBFUtils.doubleFormating(new Double(0.0), Charset.defaultCharset(), 5, 2)) + ); + + Assert.assertEquals( + "10.00", + new String(DBFUtils.doubleFormating(new Double(10.0), Charset.defaultCharset(), 5, 2)) + ); + Assert.assertEquals( + " 5.05", + new String(DBFUtils.doubleFormating(new Double(5.05), Charset.defaultCharset(), 5, 2)) + ); } @Test public void testLittleEndian() { diff --git a/src/test/java/com/linuxense/javadbf/bug33_corrupted_sync/Bug33CorruptedSyncModeTest.java b/src/test/java/com/linuxense/javadbf/bug33_corrupted_sync/Bug33CorruptedSyncModeTest.java new file mode 100644 index 00000000..ede813a2 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/bug33_corrupted_sync/Bug33CorruptedSyncModeTest.java @@ -0,0 +1,68 @@ +package com.linuxense.javadbf.bug33_corrupted_sync; + +import java.io.File; +import java.util.Date; + +import org.junit.Test; + +import com.linuxense.javadbf.DBFException; +import com.linuxense.javadbf.DBFWriter; +import com.linuxense.javadbf.testutils.DbfToTxtTest; +import com.linuxense.javadbf.testutils.FileUtils; + +public class Bug33CorruptedSyncModeTest { + + public Bug33CorruptedSyncModeTest() { + super(); + } + + @Test(expected=DBFException.class) + public void testCorruptedFile() throws Exception { + String fileName = "src/test/resources/bug-33-corrupted-file-sync-mode/myfileafter-corrupted.dbf"; + DbfToTxtTest.writeToConsole(new File(fileName)); + } + + + + @Test + public void testBug() throws Exception { + File tmp = File.createTempFile("example", ".dbf"); + File orig = new File("src/test/resources/bug-33-corrupted-file-sync-mode/myfilebefore.dbf"); + + FileUtils.copyFile(orig, tmp); + + DBFWriter writer = new DBFWriter(tmp); + + Object rowData[] = new Object[21]; + rowData[0] = 702; + rowData[1] = "114"; + rowData[2] = "57272"; + rowData[3] = new Date(1493676000000L);// "Tue May 02 00:00:00 CEST 2017" + rowData[4] = "11044"; + rowData[5] = "140-01"; + rowData[6] = "AD"; + rowData[7] = ""; + rowData[8] = ""; + rowData[9] = 80; + rowData[10] = "09"; + rowData[11] = "LPG"; + rowData[12] = new Double(0); + rowData[13] = new Double(0); + rowData[14] = new Double(3); + rowData[15] = new Double(0); + rowData[16] = new Double(0); + rowData[17] = new Double(0); + rowData[18] = new Double(0); + rowData[19] = new Double(0); + rowData[20] = ""; + + writer.addRecord(rowData); + + writer.close(); + + DbfToTxtTest.writeToConsole(tmp); + } + + + +} diff --git a/src/test/java/com/linuxense/javadbf/bug46_zero_field_count/ZeroFieldCountTest.java b/src/test/java/com/linuxense/javadbf/bug46_zero_field_count/ZeroFieldCountTest.java new file mode 100644 index 00000000..96ccb4cf --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/bug46_zero_field_count/ZeroFieldCountTest.java @@ -0,0 +1,37 @@ +package com.linuxense.javadbf.bug46_zero_field_count; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.DBFReader; +import com.linuxense.javadbf.DBFUtils; + +public class ZeroFieldCountTest { + + public ZeroFieldCountTest() { + super(); + } + + @Test + public void test () throws Exception { + DBFReader dbfReader = null; + InputStream in = null; + File input = new File ("src/test/resources/bug-46-zero_field_count/a3.dbf"); + try { + in = new BufferedInputStream(new FileInputStream(input)); + dbfReader = new DBFReader(in); + int count = dbfReader.getFieldCount(); + System.out.println("" + dbfReader.toString()); + Assert.assertEquals(17, count); + } + finally { + DBFUtils.close(in); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/linuxense/javadbf/bug_dates/BugDatesTest.java b/src/test/java/com/linuxense/javadbf/bug_dates/BugDatesTest.java new file mode 100644 index 00000000..b2fdfb63 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/bug_dates/BugDatesTest.java @@ -0,0 +1,57 @@ +package com.linuxense.javadbf.bug_dates; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.Timestamp; +import java.util.GregorianCalendar; + +import org.junit.Assert; +import org.junit.Test; + +import com.linuxense.javadbf.DBFDataType; +import com.linuxense.javadbf.DBFField; +import com.linuxense.javadbf.DBFReader; +import com.linuxense.javadbf.DBFWriter; + +public class BugDatesTest { + + public BugDatesTest() { + super(); + } + + @Test + public void test1() throws Exception { + File dbfFile = File.createTempFile("dates", ".dbf"); + try { + DBFWriter dbfWriter = new DBFWriter(); + DBFField field = new DBFField(); + field.setName("date"); // give a name to the field + field.setType(DBFDataType.DATE); // and set its type + dbfWriter.setFields(new DBFField[] {field}); + GregorianCalendar calendar = new GregorianCalendar(2,1,1); + Timestamp date = new Timestamp(calendar.getTime().getTime()); + dbfWriter.addRecord(new Object[] {date}); + + OutputStream os = new FileOutputStream(dbfFile); + dbfWriter.write(os); + dbfWriter.close(); + os.close(); + + + InputStream is = new FileInputStream(dbfFile); + DBFReader reader = new DBFReader(is); + Object[] o = reader.nextRecord(); + is.close(); + Object value = o[0]; + System.out.println(value); + Assert.assertEquals(calendar.getTime(), value); + } + finally { + dbfFile.delete(); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/linuxsense/javadbf/mocks/FailInputStream.java b/src/test/java/com/linuxense/javadbf/mocks/FailInputStream.java similarity index 84% rename from src/test/java/com/linuxsense/javadbf/mocks/FailInputStream.java rename to src/test/java/com/linuxense/javadbf/mocks/FailInputStream.java index 14a34393..b0cc8998 100644 --- a/src/test/java/com/linuxsense/javadbf/mocks/FailInputStream.java +++ b/src/test/java/com/linuxense/javadbf/mocks/FailInputStream.java @@ -1,4 +1,4 @@ -package com.linuxsense.javadbf.mocks; +package com.linuxense.javadbf.mocks; import java.io.IOException; import java.io.InputStream; diff --git a/src/test/java/com/linuxsense/javadbf/mocks/FailOutputStream.java b/src/test/java/com/linuxense/javadbf/mocks/FailOutputStream.java similarity index 85% rename from src/test/java/com/linuxsense/javadbf/mocks/FailOutputStream.java rename to src/test/java/com/linuxense/javadbf/mocks/FailOutputStream.java index 85195c91..da0c01e3 100644 --- a/src/test/java/com/linuxsense/javadbf/mocks/FailOutputStream.java +++ b/src/test/java/com/linuxense/javadbf/mocks/FailOutputStream.java @@ -1,4 +1,4 @@ -package com.linuxsense.javadbf.mocks; +package com.linuxense.javadbf.mocks; import java.io.IOException; import java.io.OutputStream; diff --git a/src/test/java/com/linuxsense/javadbf/mocks/NullOutputStream.java b/src/test/java/com/linuxense/javadbf/mocks/NullOutputStream.java similarity index 96% rename from src/test/java/com/linuxsense/javadbf/mocks/NullOutputStream.java rename to src/test/java/com/linuxense/javadbf/mocks/NullOutputStream.java index 158b107f..ea1d1cca 100644 --- a/src/test/java/com/linuxsense/javadbf/mocks/NullOutputStream.java +++ b/src/test/java/com/linuxense/javadbf/mocks/NullOutputStream.java @@ -1,4 +1,4 @@ -package com.linuxsense.javadbf.mocks; +package com.linuxense.javadbf.mocks; import java.io.IOException; import java.io.OutputStream; diff --git a/src/test/java/com/linuxense/javadbf/testutils/AssertUtils.java b/src/test/java/com/linuxense/javadbf/testutils/AssertUtils.java new file mode 100644 index 00000000..8aa8c1e8 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/testutils/AssertUtils.java @@ -0,0 +1,38 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ + +package com.linuxense.javadbf.testutils; + + + +import org.junit.Assert; + +import com.linuxense.javadbf.DBFDataType; +import com.linuxense.javadbf.DBFField; + +public class AssertUtils { + + public static void assertColumnDefinition(DBFField field, String columnName, DBFDataType type, int length, int decimal) { + Assert.assertEquals(columnName, field.getName()); + Assert.assertEquals(type, field.getType()); +// Assert.assertEquals(length, field.getLength()); + Assert.assertEquals(decimal, field.getDecimalCount()); + } + +} diff --git a/src/test/java/com/linuxense/javadbf/testutils/DateUtils.java b/src/test/java/com/linuxense/javadbf/testutils/DateUtils.java new file mode 100644 index 00000000..fb631a13 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/testutils/DateUtils.java @@ -0,0 +1,37 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf.testutils; + +import java.util.Calendar; +import java.util.Date; + +public class DateUtils { + + public static Date createDate(int year, int month, int day) { + Calendar c = Calendar.getInstance(); + c.set(Calendar.YEAR, year); + c.set(Calendar.MONTH, month - 1); + c.set(Calendar.DAY_OF_MONTH, day); + c.set(Calendar.HOUR_OF_DAY, 0); + c.set(Calendar.MINUTE, 0); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + return c.getTime(); + } +} diff --git a/src/test/java/com/linuxense/javadbf/testutils/DbfToTxtTest.java b/src/test/java/com/linuxense/javadbf/testutils/DbfToTxtTest.java new file mode 100644 index 00000000..11b6aeb6 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/testutils/DbfToTxtTest.java @@ -0,0 +1,109 @@ +/* + +(C) Copyright 2017 Alberto Fernández + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . + +*/ +package com.linuxense.javadbf.testutils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; + +import com.linuxense.javadbf.DBFField; +import com.linuxense.javadbf.DBFReader; + +public final class DbfToTxtTest { + + private DbfToTxtTest() { + throw new AssertionError("no instances"); + } + + public static void export(DBFReader reader, File file) { + + PrintWriter writer = null; + try { + writer = new PrintWriter(file, "UTF-8"); + Object[] row = null; + + while ((row = reader.nextRecord()) != null) { + for (Object o : row) { + writer.print(o + ";"); + } + writer.println(""); + } + } + catch (IOException e) { + // nop + } + finally { + if (writer != null) { + writer.close(); + } + } + } + + public static void writeToConsole(File file) throws Exception { + DBFReader reader = null; + InputStream is = null; + try { + + is = new FileInputStream(file); + // create a DBFReader object + reader = new DBFReader(is); + + // get the field count if you want for some reasons like the following + + int numberOfFields = reader.getFieldCount(); + + // use this count to fetch all field information + // if required + + for (int i = 0; i < numberOfFields; i++) { + + DBFField field = reader.getField(i); + + // do something with it if you want + // refer the JavaDoc API reference for more details + // + System.out.println(field.getType() + " " + field.getName()); + } + + // Now, lets us start reading the rows + + Object[] rowObjects; + + System.out.println("-------------------"); + while ((rowObjects = reader.nextRecord()) != null) { + for (int i = 0; i < rowObjects.length; i++) { + System.out.println(rowObjects[i]); + } + System.out.println("-------------------"); + } + + // By now, we have iterated through all of the rows + + + } + finally { + if(is!=null){ + is.close(); + } + } + } +} diff --git a/src/test/java/com/linuxense/javadbf/testutils/FileUtils.java b/src/test/java/com/linuxense/javadbf/testutils/FileUtils.java new file mode 100644 index 00000000..edfefc37 --- /dev/null +++ b/src/test/java/com/linuxense/javadbf/testutils/FileUtils.java @@ -0,0 +1,31 @@ +package com.linuxense.javadbf.testutils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public final class FileUtils { + + private FileUtils() { + throw new AssertionError("No instances allowed"); + } + public static void copyFile(File source, File dest) throws IOException { + InputStream is = null; + OutputStream os = null; + try { + is = new FileInputStream(source); + os = new FileOutputStream(dest); + byte[] buffer = new byte[1024]; + int length; + while ((length = is.read(buffer)) > 0) { + os.write(buffer, 0, length); + } + } finally { + is.close(); + os.close(); + } + } +} diff --git a/src/test/resources/bug-33-corrupted-file-sync-mode/myfileafter-corrupted.dbf b/src/test/resources/bug-33-corrupted-file-sync-mode/myfileafter-corrupted.dbf new file mode 100644 index 00000000..4227cbf4 Binary files /dev/null and b/src/test/resources/bug-33-corrupted-file-sync-mode/myfileafter-corrupted.dbf differ diff --git a/src/test/resources/bug-33-corrupted-file-sync-mode/myfilebefore.dbf b/src/test/resources/bug-33-corrupted-file-sync-mode/myfilebefore.dbf new file mode 100644 index 00000000..f8fae15b Binary files /dev/null and b/src/test/resources/bug-33-corrupted-file-sync-mode/myfilebefore.dbf differ diff --git a/src/test/resources/bug-46-zero_field_count/a3.dbf b/src/test/resources/bug-46-zero_field_count/a3.dbf new file mode 100644 index 00000000..2cb98cd9 Binary files /dev/null and b/src/test/resources/bug-46-zero_field_count/a3.dbf differ diff --git a/src/test/resources/fixtures/dbase_7.dbf b/src/test/resources/fixtures/dbase_7.dbf new file mode 100644 index 00000000..1c05183f Binary files /dev/null and b/src/test/resources/fixtures/dbase_7.dbf differ