Index: tmp/org.txm.libs.office/src/org/txm/libs/office/ReadODS.java
===================================================================
--- tmp/org.txm.libs.office/src/org/txm/libs/office/ReadODS.java	(revision 2257)
+++ tmp/org.txm.libs.office/src/org/txm/libs/office/ReadODS.java	(revision 2258)
@@ -13,6 +13,60 @@
 
 public class ReadODS {
 	
+	SpreadsheetDocument spreadsheet = null;
+	Table table = null;
+	String[] headers;
+	
+	public ReadODS(File tableFile, String sheetname) throws Exception {
+		spreadsheet = SpreadsheetDocument.loadDocument(tableFile);
+
+		// the first access to the document causes a very long process
+		int sheetCount = spreadsheet.getSheetCount();
+		if (sheetCount < 1) {
+			System.out.println("** ReadODS: no sheet found in file. Aborting.");
+			return;
+		}
+		
+		Table table = null;
+		if (sheetname != null) {
+			table = spreadsheet.getSheetByName(sheetname);
+		}
+		if (table == null) {
+			table = spreadsheet.getSheetByIndex(0);
+		}
+		
+		//table.getRowByIndex(0);
+	}
+	
+	public boolean readHeaders() {
+		Row row = table.getRowByIndex(0);
+		int ncolumns = row.getCellCount();
+		
+		headers = new String[ncolumns];
+		for (int j = 0 ; j < ncolumns ; j++) {
+			String cell = row.getCellByIndex(j).getDisplayText();
+			if (cell == null) {
+				headers[j] = "";
+			} else {
+				headers[j] = cell;
+			}
+		}
+		
+		return headers.length > 0;
+	}
+	
+	public String[] getHeaders() {
+		return headers;
+	}
+	
+	public boolean readRecord() {
+		return false;
+	}
+	
+	public HashMap<String, String> getRecord() {
+		return null;
+	}
+
 	public static ArrayList<HashMap<String, String>> toHashMap(File inputFile, String sheetname) throws Exception {
 		SpreadsheetDocument spreadsheet = SpreadsheetDocument.loadDocument(inputFile);
 
Index: tmp/org.txm.utils/META-INF/MANIFEST.MF
===================================================================
--- tmp/org.txm.utils/META-INF/MANIFEST.MF	(revision 2257)
+++ tmp/org.txm.utils/META-INF/MANIFEST.MF	(revision 2258)
@@ -8,7 +8,9 @@
  org.eclipse.core.runtime;visibility:=reexport,
  org.eclipse.core.net;bundle-version="1.2.200";visibility:=reexport,
  org.txm.libs.colt;bundle-version="1.2.0";visibility:=reexport,
- org.txm.libs.itext;bundle-version="2.1.5";visibility:=reexport
+ org.txm.libs.itext;bundle-version="2.1.5";visibility:=reexport,
+ org.txm.libs.msoffice;bundle-version="1.0.0";visibility:=reexport,
+ org.txm.libs.office;bundle-version="0.8.2";visibility:=reexport
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
 Export-Package: org.apache.commons.cli,
  org.apache.commons.io;uses:="org.apache.commons.io.filefilter",
Index: tmp/org.txm.utils/src/org/txm/utils/TableReader.java
===================================================================
--- tmp/org.txm.utils/src/org/txm/utils/TableReader.java	(revision 0)
+++ tmp/org.txm.utils/src/org/txm/utils/TableReader.java	(revision 2258)
@@ -0,0 +1,134 @@
+package org.txm.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.txm.libs.msoffice.ReadExcel;
+import org.txm.libs.office.ReadODS;
+
+/**
+ * Read a table from a TSV, XLSX or ODS file
+ * 
+ * @author mdecorde
+ *
+ */
+public class TableReader {
+	
+	File tableFile;
+	String mode = "tsv";
+	
+	HashMap<String, String> record;
+	CsvReader tsvReader = null;
+	ReadExcel excelReader = null;
+	ReadODS odsReader;
+	
+	public TableReader(File tableFile) throws Exception {
+		this.tableFile = tableFile;
+		
+		if (tableFile.getName().toLowerCase().endsWith(".xlsx")) {
+			mode = "excel";
+			excelReader = new ReadExcel(tableFile, null);
+		} else if (tableFile.getName().toLowerCase().endsWith(".ods")) {
+			mode = "ods";
+			odsReader = new ReadODS(tableFile, null);
+		} else if (tableFile.getName().toLowerCase().endsWith(".tsv")) {
+			tsvReader = new CsvReader(tableFile.getAbsolutePath(), "\t".charAt(0), Charset.forName("UTF-8"));
+			mode = "tsv";
+		}
+	}
+	
+	public String getMode() {
+		return mode;
+	}
+	
+	public boolean readHeaders() throws IOException {
+		if (tsvReader != null) {
+			return tsvReader.readHeaders();
+		} else if (excelReader != null) {
+			return excelReader.readHeaders();
+		}
+		
+		return false;
+	}
+	
+	/**
+	 * read the next record
+	 * @return true if there is another record
+	 * @throws IOException
+	 */
+	public boolean readRecord() throws IOException {
+		if (tsvReader != null) {
+			if (tsvReader.readRecord()) {
+				record = tsvReader.getRecord();
+				return true;
+			} else {
+				return false;
+			}
+		} else if (excelReader != null) {
+			if (excelReader.readRecord()) {
+				record = excelReader.getRecord();
+				return true;
+			} else {
+				return false;
+			}
+		}
+		
+		return false;
+	}
+	
+	public HashMap<String, String> getRecord() {
+		return record;
+	}
+
+	public String[] getHeaders() throws IOException {
+		if (tsvReader != null) {
+			return tsvReader.getHeaders();
+		} else if (excelReader != null) {
+			return excelReader.getHeaders();
+		}
+		
+		return null;
+	}
+	
+	String EMPTY = "";
+	public String get(String h) throws IOException {
+		String s = getRecord().get(h);
+		if (s == null) return EMPTY;
+		
+		return s;
+	}
+	
+	public void close() throws IOException {
+		if (tsvReader != null) {
+			tsvReader.close();
+		} else if (excelReader != null) {
+			excelReader.close();
+		}
+	}
+	
+	public static void main(String[] args) {
+		try {
+			System.out.println("Loading...");
+			TableReader reader = new TableReader(new File("/home/mdecorde/TEMP/ANTRACT/AF/ANTRACT_AF_Notices_3oct19.xlsx"));
+			System.out.println("Table loaded");
+			
+			System.out.println("Reading headers...");
+			reader.readHeaders();
+			System.out.println(Arrays.toString(reader.getHeaders()));
+			
+			System.out.println("Reading record...");
+			reader.readRecord();
+			System.out.println(reader.getRecord());
+			
+			System.out.println("Reading record...");
+			reader.readRecord();
+			System.out.println(reader.getRecord());
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+}

Property changes on: tmp/org.txm.utils/src/org/txm/utils/TableReader.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.utils/src/org/txm/utils/CsvReader.java
===================================================================
--- tmp/org.txm.utils/src/org/txm/utils/CsvReader.java	(revision 2257)
+++ tmp/org.txm.utils/src/org/txm/utils/CsvReader.java	(revision 2258)
@@ -66,7 +66,7 @@
  * stream.
  */
 public class CsvReader {
-	
+
 	/** The input stream. */
 	private Reader inputStream = null;
 
@@ -905,24 +905,24 @@
 
 									if (userSettings.SafetySwitch
 											&& dataBuffer.Position
-													- dataBuffer.ColumnStart
-													+ columnBuffer.Position > 100000) {
+											- dataBuffer.ColumnStart
+											+ columnBuffer.Position > 100000) {
 										close();
 
 										throw new IOException(
 												"Maximum column length of 100,000 exceeded in column " //$NON-NLS-1$
-														+ NumberFormat
-																.getIntegerInstance()
-																.format(
-																		columnsCount)
-														+ " in record " //$NON-NLS-1$
-														+ NumberFormat
-																.getIntegerInstance()
-																.format(
-																		currentRecord)
-														+ ". Set the SafetySwitch property to false" //$NON-NLS-1$
-														+ " if you're expecting column lengths greater than 100,000 characters to" //$NON-NLS-1$
-														+ " avoid this error."); //$NON-NLS-1$
+												+ NumberFormat
+												.getIntegerInstance()
+												.format(
+														columnsCount)
+												+ " in record " //$NON-NLS-1$
+												+ NumberFormat
+												.getIntegerInstance()
+												.format(
+														currentRecord)
+												+ ". Set the SafetySwitch property to false" //$NON-NLS-1$
+												+ " if you're expecting column lengths greater than 100,000 characters to" //$NON-NLS-1$
+												+ " avoid this error."); //$NON-NLS-1$
 									}
 								}
 							} // end else
@@ -1158,24 +1158,24 @@
 
 									if (userSettings.SafetySwitch
 											&& dataBuffer.Position
-													- dataBuffer.ColumnStart
-													+ columnBuffer.Position > 100000) {
+											- dataBuffer.ColumnStart
+											+ columnBuffer.Position > 100000) {
 										close();
 
 										throw new IOException(
 												"Maximum column length of 100,000 exceeded in column " //$NON-NLS-1$
-														+ NumberFormat
-																.getIntegerInstance()
-																.format(
-																		columnsCount)
-														+ " in record " //$NON-NLS-1$
-														+ NumberFormat
-																.getIntegerInstance()
-																.format(
-																		currentRecord)
-														+ ". Set the SafetySwitch property to false" //$NON-NLS-1$
-														+ " if you're expecting column lengths greater than 100,000 characters to" //$NON-NLS-1$
-														+ " avoid this error."); //$NON-NLS-1$
+												+ NumberFormat
+												.getIntegerInstance()
+												.format(
+														columnsCount)
+												+ " in record " //$NON-NLS-1$
+												+ NumberFormat
+												.getIntegerInstance()
+												.format(
+														currentRecord)
+												+ ". Set the SafetySwitch property to false" //$NON-NLS-1$
+												+ " if you're expecting column lengths greater than 100,000 characters to" //$NON-NLS-1$
+												+ " avoid this error."); //$NON-NLS-1$
 									}
 								}
 							} // end else
@@ -1203,13 +1203,13 @@
 				if (rawBuffer.Position == 0) {
 					rawRecord = new String(dataBuffer.Buffer,
 							dataBuffer.LineStart, dataBuffer.Position
-									- dataBuffer.LineStart - 1);
+							- dataBuffer.LineStart - 1);
 				} else {
 					rawRecord = new String(rawBuffer.Buffer, 0,
 							rawBuffer.Position)
 							+ new String(dataBuffer.Buffer,
 									dataBuffer.LineStart, dataBuffer.Position
-											- dataBuffer.LineStart - 1);
+									- dataBuffer.LineStart - 1);
 				}
 			} else {
 				// for hasMoreData to ever be false, all data would have had to
@@ -1261,7 +1261,7 @@
 
 			System.arraycopy(dataBuffer.Buffer, dataBuffer.LineStart,
 					rawBuffer.Buffer, rawBuffer.Position, dataBuffer.Count
-							- dataBuffer.LineStart);
+					- dataBuffer.LineStart);
 
 			rawBuffer.Position += dataBuffer.Count - dataBuffer.LineStart;
 		}
@@ -1387,7 +1387,7 @@
 
 					currentValue = new String(dataBuffer.Buffer,
 							dataBuffer.ColumnStart, lastLetter
-									- dataBuffer.ColumnStart + 1);
+							- dataBuffer.ColumnStart + 1);
 				}
 			} else {
 				updateCurrentValue();
@@ -1415,11 +1415,11 @@
 
 			throw new IOException(
 					"Maximum column count of 100,000 exceeded in record " //$NON-NLS-1$
-							+ NumberFormat.getIntegerInstance().format(
-									currentRecord)
-							+ ". Set the SafetySwitch property to false" //$NON-NLS-1$
-							+ " if you're expecting more than 100,000 columns per record to" //$NON-NLS-1$
-							+ " avoid this error."); //$NON-NLS-1$
+					+ NumberFormat.getIntegerInstance().format(
+							currentRecord)
+					+ ". Set the SafetySwitch property to false" //$NON-NLS-1$
+					+ " if you're expecting more than 100,000 columns per record to" //$NON-NLS-1$
+					+ " avoid this error."); //$NON-NLS-1$
 		}
 
 		// check to see if our current holder array for
@@ -1687,7 +1687,7 @@
 	 * The Class ComplexEscape.
 	 */
 	private class ComplexEscape {
-		
+
 		/** The Constant UNICODE. */
 		private static final int UNICODE = 1;
 
@@ -1725,7 +1725,7 @@
 	 * The Class DataBuffer.
 	 */
 	private class DataBuffer {
-		
+
 		/** The Buffer. */
 		public char[] Buffer;
 
@@ -1766,7 +1766,7 @@
 	 * The Class ColumnBuffer.
 	 */
 	private class ColumnBuffer {
-		
+
 		/** The Buffer. */
 		public char[] Buffer;
 
@@ -1786,7 +1786,7 @@
 	 * The Class RawRecordBuffer.
 	 */
 	private class RawRecordBuffer {
-		
+
 		/** The Buffer. */
 		public char[] Buffer;
 
@@ -1798,7 +1798,7 @@
 		 */
 		public RawRecordBuffer() {
 			Buffer = new char[StaticSettings.INITIAL_COLUMN_BUFFER_SIZE
-					* StaticSettings.INITIAL_COLUMN_COUNT];
+			                  * StaticSettings.INITIAL_COLUMN_COUNT];
 			Position = 0;
 		}
 	}
@@ -1807,7 +1807,7 @@
 	 * The Class Letters.
 	 */
 	private class Letters {
-		
+
 		/** The Constant LF. */
 		public static final char LF = '\n';
 
@@ -1916,7 +1916,7 @@
 	 * The Class HeadersHolder.
 	 */
 	private class HeadersHolder {
-		
+
 		/** The Headers. */
 		public String[] Headers;
 
@@ -1955,4 +1955,13 @@
 		/** The Constant INITIAL_COLUMN_BUFFER_SIZE. */
 		public static final int INITIAL_COLUMN_BUFFER_SIZE = 50;
 	}
+
+	protected HashMap<String, String> getRecord() throws IOException {
+		HashMap<String, String> record = new HashMap<String, String>();
+		for (String h : getHeaders()) {
+			record.put(h, get(h));
+		}
+
+		return record;
+	}
 }
\ No newline at end of file
Index: tmp/org.txm.libs.msoffice/src/org/txm/libs/msoffice/ReadExcel.java
===================================================================
--- tmp/org.txm.libs.msoffice/src/org/txm/libs/msoffice/ReadExcel.java	(revision 2257)
+++ tmp/org.txm.libs.msoffice/src/org/txm/libs/msoffice/ReadExcel.java	(revision 2258)
@@ -1,9 +1,15 @@
 package org.txm.libs.msoffice;
 
 import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.HashMap;
 
+import org.apache.poi.EncryptedDocumentException;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DateUtil;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
@@ -11,11 +17,103 @@
 
 public class ReadExcel {
 
+	Workbook wb = null;
+	Sheet ws = null;
+	String[] header = null;
+	HashMap<String, String> record = null;
+	int iRow = 0;
+	int nRows;
+	
+	public ReadExcel(File tableFile, String sheetName) throws EncryptedDocumentException, InvalidFormatException, IOException {
+		wb = WorkbookFactory.create(tableFile);
+		
+		if (sheetName == null || sheetName.length() == 0) {
+			ws = wb.getSheetAt(0);
+		} else {
+			ws = wb.getSheet(sheetName);
+			if (ws == null) {
+				ws = wb.getSheetAt(0);
+			}
+		}
+		
+		nRows = ws.getPhysicalNumberOfRows();
+	}
+	
+	public boolean readHeaders() {
+		
+		if (nRows == 0) {
+			header = new String[0];
+			return header != null;
+		}
+
+		Row firstRow = ws.getRow(0);
+		int colMax = firstRow.getLastCellNum();
+
+		header = new String[colMax];
+		for (int it = 0 ; it < colMax; it++) {
+			header[it] = firstRow.getCell(it).getStringCellValue();
+		}
+		
+		if (iRow == 0) iRow = 1; // skip first line
+		return true;
+	}
+	
+	public boolean readRecord() {
+		if (iRow < nRows) {
+			_getRecord();
+			iRow++; // for next 
+			return true;
+		} else { // end of file
+			record = null;
+			return false;
+		}
+	}
+	
+	public String[] getHeaders() {
+		return header;
+	}
+	
+	public HashMap<String, String> getRecord() {
+		return record;
+	}
+	
+	public String get(String h) {
+		if (record == null) return null;
+		
+		return record.get(h);
+	}
+	
+	protected void _getRecord() {
+		record = new HashMap<String, String>();
+		Row row = ws.getRow(iRow);
+		
+		for (int colIndex = 0 ; colIndex < header.length ; colIndex++) {
+			String col = header[colIndex];
+			Cell cell = row.getCell(colIndex);
+			if (cell != null) {
+				String value = cellToString(cell).trim();
+				if (value == null) {
+					record.put(header[colIndex], "");
+				} else {
+					record.put(header[colIndex], value);
+				}
+			} else {
+				record.put(header[colIndex], "");
+			}
+		}
+		
+		for (String k : record.keySet()) if (record.get(k) == null) System.out.println("ERROR null value with "+k);
+	}
+	
+	public void close() throws IOException {
+		if (wb != null) wb.close();
+	}
+
 	/**
 	 * 
 	 * @param inputFile
 	 * @param sheetName
-	 * @return list of lines (line = list of cells) with values converted to String
+	 * @return list of lines (line = list of cells) with values converted to String - the file is completely read
 	 */
 	public static ArrayList<ArrayList<String>> toTable(File inputFile, String sheetName) {
 
@@ -88,7 +186,13 @@
 		case FORMULA:
 			return "#formulla";
 		case NUMERIC:
-			return ""+cell.getNumericCellValue();
+			if (DateUtil.isCellDateFormatted(cell)) {
+                SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
+                return dateFormat.format(cell.getDateCellValue());
+            } else {
+                Double value = cell.getNumericCellValue();
+                return value.toString();
+            }
 		case STRING:
 			return cell.getStringCellValue();
 		case BLANK:
@@ -100,7 +204,6 @@
 		default:
 			return "#typeerror";
 		}
-
 	}
 
 	public static void main(String[] args) {
