package jmathlib.toolbox.io; import jmathlib.core.tokens.Token; import jmathlib.core.tokens.OperandToken; import jmathlib.core.tokens.numbertokens.DoubleNumberToken; import jmathlib.core.functions.ExternalFunction; import jmathlib.core.interpreter.ErrorLogger; import jmathlib.core.interpreter.GlobalValues; import java.io.*; /**An external function for loading a matrix from a csv file*/ public class load extends ExternalFunction { //!!!! make a functions for dataSTream.read(xxx) and swap endian // if ( dataStream.read(b,0,4) != 4) // throwMathLibException("load: could not read next tag"); // swap(b, 4, swapEndian); // MAT-file data types static final byte miINT8 = 1; static final byte miUINT8 = 2; static final byte miINT16 = 3; static final byte miUINT16 = 4; static final byte miINT32 = 5; static final byte miUINT32 = 6; static final byte miSINGLE = 7; // reserved static final byte miDOUBLE = 9; // reserved // reserved static final byte miINI64 = 12; static final byte miUINT64 = 13; static final byte miMATRIX = 14; static final byte miCOMPRESSED = 15; static final byte miUTF8 = 16; static final byte miUTF16 = 17; static final byte miUTF32 = 18; // length of each data type from above static final byte[] miLength = { 1, 1, 2, 2, 4, 4 }; // one entry of each data type // array types static final byte mxCELL = 1; static final byte mxSTRUCT = 2; static final byte mxOBJECT = 3; static final byte mxCHAR = 4; static final byte mxSPARSE = 5; static final byte mxDOUBLE = 6; static final byte mxSINGLE = 7; static final byte mxINT8 = 8; static final byte mxUINT8 = 9; static final byte mxINT16 = 10; static final byte mxUINT16 = 11; static final byte mxINT32 = 12; static final byte mxUINT32 = 13; // array to read stream of data from MAT-files byte[] b = new byte[1024]; /** Check that the operand is a string then open the file referenced. @param operands[0] = string which specifies the csv file to load @param operands[1] = the start row (optional) @param operands[2] = the start column (optional) @param operands[3] = range(optional, not implemented) @return the matrix as an OperandToken*/ public OperandToken evaluate(Token[] operands, GlobalValues globals) { OperandToken result = null; String fileName = "testvalues.mat"; // at least one operand //if (getNArgIn(operands) > 0) //{ // fileName = ((StringToken)operands[0]).toString(); //} System.out.println("load dir "+globals.getWorkingDirectory() ); File fileHandle = new File(globals.getWorkingDirectory(), fileName); if(!fileHandle.exists()) throwMathLibException("load file does not exist"); ErrorLogger.debugLine("loading CSV>"+fileName+"<"); try { // load file //FileReader fileReader = new FileReader(fileHandle); FileInputStream fileStream = new FileInputStream(fileHandle); //BufferedReader inReader = new BufferedReader( ); DataInputStream dataStream = new DataInputStream( fileStream ); try { //// load MAT-file header (128 bytes) // load descriptive header (116 bytes) if ( dataStream.read(b,0,116) != 116) throwMathLibException("load: length descriptive header != 116"); String descriptiveHeader = new String(b); System.out.println("load :"+ descriptiveHeader ); // load subsys data offset if ( dataStream.read(b,0,8) != 8) throwMathLibException("load: length subsys data offset != 8"); // version if ( dataStream.read(b,0,2) != 2) throwMathLibException("load: length version != 2"); int version = ((int)b[1])<< 8 + ((int)b[0]); if (version != 0x0100) throwMathLibException("load: version != 0x0100"); // endian indicator if ( dataStream.read(b,0,2) != 2) throwMathLibException("load: length endian indicator != 2"); // if endian indicator is "MI" now byte swapping // if endian indicator is "IM" must swap bytes boolean swapEndian = false; if ((char)b[0] == 'M' && (char)b[1]== 'I') System.out.println("load: endian ok"); else if ((char)b[0] == 'I' && (char)b[1]== 'M') { swapEndian = true; System.out.println("load: endian: must swap bytes"); } else throwMathLibException("load: endian: error"); ////// read data /////// // read next Tag if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read next tag"); // check about small an big endian swap(b, 4, swapEndian); // check if normal or small data element format byte dataType = 0; if (b[0]==0 && b[1]==0) { // normal data element format System.out.println("load: normal data element format"); dataType = b[3]; } else { // small data element format System.out.println("load: small data element format"); dataType = b[0]; } System.out.println("load: data type "+ dataType); System.out.println("load: data type "+ b[2]); System.out.println("load: data type "+ b[3]); // number of bytes byte[] number = new byte[16]; if ( dataStream.read(number,0,4) != 4) throwMathLibException("load: could not read data tag"); swap(number, 4, swapEndian); switch (dataType) { case miMATRIX: { int numberOfBytes = number[3]; // ?!? maybe all 4 bytes need treating System.out.println("load: miMATRIX: bytes "+numberOfBytes); // check dimensions if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read next tag"); swap(b, 4, swapEndian); // check data type of dimensions if (b[0]!=0 || b[1]!=0 || b[2]!=0 || b[3]!=0x06) throwMathLibException("load: miMATRIX: data type of dimension is not UINT32"); // read dimensions length if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read next tag"); swap(b, 4, swapEndian); // check length of dimensions if (b[0]!=0 || b[1]!=0 || b[2]!=0 || b[3]!=8) throwMathLibException("load: miMATRIX: dimensions should be 8"); ////// read array flags ///// if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read array flags"); swap(b, 4, swapEndian); // check if complex bit is set boolean complexFlag = false; if ((b[3]& 0x08) != 0) complexFlag = true; System.out.println("load: miMATRIX: complex flag "+complexFlag); // check if global bit is set boolean globalFlag = false; if ((b[3]& 0x04) != 0) globalFlag = true; System.out.println("load: miMATRIX: global flag "+globalFlag); // check if logical bit is set boolean logicalFlag = false; if ((b[3]& 0x02) != 0) logicalFlag = true; System.out.println("load: miMATRIX: logical flag "+logicalFlag); // read class of data of matrix int arrayClassType = b[3]; System.out.println("load: miMATRIX: array class type "+ arrayClassType); // read unused array flags if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read array flags unused"); swap(b, 4, swapEndian); /////// dimensions array //////// if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read type of dimensions array"); swap(b, 4, swapEndian); if (b[0]!=0 || b[1]!=0 || b[2]!=0 || b[3]!=0x05) throwMathLibException("load: miMATRIX: data type of dimensions array is not INT32"); if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read value of array dimensions"); swap(b, 4, swapEndian); if (b[0]!=0 || b[1]!=0 || b[2]!=0 || b[3]!=8) throwMathLibException("load: miMATRIX: data length of dimensions array is not 8"); // read length first axis if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read length of first axis"); swap(b, 4, swapEndian); int xLength = b[3]; // !?!maybe check all four bytes System.out.println("load: miMATRIX x="+xLength); // read length second axis if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read length of second axis"); swap(b, 4, swapEndian); int yLength = b[3]; // !?!maybe check all four bytes System.out.println("load: miMATRIX y="+yLength); //////// read array name //////// if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read name of array"); swap(b, 4, swapEndian); if (b[0]!=0 || b[1]!=0 || b[2]!=0 || b[3]!=1) throwMathLibException("load: miMATRIX: data type of array name is not INT8"); // length array name if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read length of name of array"); swap(b, 4, swapEndian); int nameLength = b[3]; //?!?! maybe take all 4 bytes byte[] nameB = new byte[nameLength]; if ( dataStream.read(nameB,0,nameLength) != nameLength) throwMathLibException("load: could not read name of array"); String arrayName = new String(nameB); System.out.println("load: miMATRIX array name: "+arrayName); // read bytes up to the next 8 Byte border int stuffLength = 8* ((nameLength/8) + 1) - nameLength ; System.out.println("load: miMATRIX stufflength: "+stuffLength); if ( dataStream.read(b,0,stuffLength) != stuffLength ) throwMathLibException("load: could not read stuff bytes"); //////// read real data //////// double[][] data = new double[yLength][xLength]; // read type of data if ( dataStream.read(b,0,4) != 4) throwMathLibException("load: could not read type of data"); swap(b, 4, swapEndian); int realDataType = b[3]; //?!?! maybe take all 4 bytes int realDataLength = miLength[realDataType]; for (int xi=0; xi<xLength; xi++) { for (int yi=0; yi<yLength; yi++) { if ( dataStream.read(b,0,realDataLength) != realDataLength) throwMathLibException("load: could not read real data"); swap(b, stuffLength, swapEndian); // fill array // ???? data[yi][xi] = b[]; // ???? } } //////// read imaginary data //////// break; } //case miINT8: //case miINT16; //.... // more to come default: { throwMathLibException("load: data type not yet supported"); } } result = new DoubleNumberToken(5555); } catch(Exception e) { throwMathLibException("load" + e.getMessage()); } fileStream.close(); } catch (Exception e) { throwMathLibException("load" + e.getMessage()); } return result; } /** * swap bytes if type of endian coding is necessary * @param c * @param len */ private void swap(byte[] c, int len, boolean _swapEndian) { byte d = 0; if (_swapEndian) { for (int i=0; i<len/2; i++) { d = c[len-1-i]; c[len-1-i] = c[i]; c[i] = d; } } } } /* @GROUP IO @SYNTAX load(file) @DOC Reads in a matrix from a comma seperated value file. @EXAMPLES <programlisting> load </programlisting> @SEE csvread, csvwrite */