Commit a132eb12 authored by Matthew Dawson's avatar Matthew Dawson
Browse files

Add a system to deal with reduced header MAT files.

Files produced by Simulink, along with embedded MAT files inside of MAT files
don't have the full header.  Thus enable parsing them as necessary.
parent a1ab3221
Loading
Loading
Loading
Loading
+40 −25
Original line number Diff line number Diff line
@@ -73,6 +73,10 @@ public class MatFileReader
    public static final int DIRECT_BYTE_BUFFER = 2;
    public static final int HEAP_BYTE_BUFFER   = 4;

    /**
     * Type of matlab mat file.
     */
    private final MatFileType matType;
    /**
     * MAT-file header
     */
@@ -100,7 +104,7 @@ public class MatFileReader
     */
    public MatFileReader(String fileName) throws FileNotFoundException, IOException
    {
        this ( new File(fileName), new MatFileFilter() );
        this ( new File(fileName), new MatFileFilter(), MatFileType.Regular);
    }
    /**
     * Creates instance of <code>MatFileReader</code> and reads MAT-file 
@@ -115,8 +119,9 @@ public class MatFileReader
     */
    public MatFileReader(String fileName, MatFileFilter filter ) throws IOException
    {
        this( new File(fileName), filter );
        this( new File(fileName), filter, MatFileType.Regular);
    }

    /**
     * Creates instance of <code>MatFileReader</code> and reads MAT-file
     * from <code>file</code>. 
@@ -128,9 +133,10 @@ public class MatFileReader
     */
    public MatFileReader(File file) throws IOException
    {
        this ( file, new MatFileFilter() );
        this ( file, new MatFileFilter(), MatFileType.Regular);
        
    }

    /**
     * Creates instance of <code>MatFileReader</code> and reads MAT-file from
     * <code>file</code>.
@@ -148,15 +154,16 @@ public class MatFileReader
     * @throws IOException
     *             when error occurred while processing the file.
     */
    public MatFileReader(File file, MatFileFilter filter) throws IOException
    public MatFileReader(File file, MatFileFilter filter, MatFileType matType) throws IOException
    {
        this();
        this(matType);
        
        read(file, filter, MEMORY_MAPPED_FILE);
    }
    
    public MatFileReader()
    public MatFileReader(MatFileType matType)
    {
        this.matType = matType;
        filter  = new MatFileFilter();
        data    = new LinkedHashMap<String, MLArray>();
    }
@@ -172,9 +179,9 @@ public class MatFileReader
     * @throws IOException
     *             when error occurred while processing the file.
     */
    public MatFileReader(InputStream stream) throws IOException
    public MatFileReader(InputStream stream, MatFileType type) throws IOException
    {
        this(stream, new MatFileFilter());
        this(stream, new MatFileFilter(), type);
    }

    /**
@@ -196,9 +203,9 @@ public class MatFileReader
     * @throws IOException
     *             when error occurred while processing the file.
     */
    public MatFileReader(InputStream stream, MatFileFilter filter) throws IOException
    public MatFileReader(InputStream stream, MatFileFilter filter, MatFileType type) throws IOException
    {
        this();
        this(type);

        read(stream, filter);
    }
@@ -1127,19 +1134,23 @@ public class MatFileReader
        int version;
        byte[] endianIndicator = new byte[2];

        // This part of the header is missing if the file isn't a regular mat file.  So ignore.
        if (matType == MatFileType.Regular) {
            //descriptive text 116 bytes
            byte[] descriptionBuffer = new byte[116];
            buf.get(descriptionBuffer);

            description = zeroEndByteArrayToString(descriptionBuffer);

        if ( !description.matches("MATLAB 5.0 MAT-file.*") )
        {
            if (!description.matches("MATLAB 5.0 MAT-file.*")) {
                throw new MatlabIOException("This is not a valid MATLAB 5.0 MAT-file.");
            }

            //subsyst data offset 8 bytes
            buf.position(buf.position() + 8);
        } else {
            description = "Simulink generated MATLAB 5.0 MAT-file"; // Default simulink description.
        }
        
        byte[] bversion = new byte[2];
        //version 2 bytes
@@ -1164,6 +1175,10 @@ public class MatFileReader
        buf.order( byteOrder );
        
        matFileHeader = new MatFileHeader(description, version, endianIndicator);

        // After the header, the next read must be aligned.  Thus force the alignment.  Only matters with reduced header data,
        // but apply it regardless for safety.
        buf.position((buf.position() + 7) & 0xfffffff8);
    }
    /**
     * TAG operator. Facilitates reading operations.
+9 −0
Original line number Diff line number Diff line
package com.jmatio.io;

/** Describes the type of Mat file.
 * @author Matthew Dawson <matthew@mjdsystems.ca>
 */
public enum MatFileType {
    Regular,
    ReducedHeader
}
+5 −8
Original line number Diff line number Diff line
@@ -18,14 +18,11 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;

import com.jmatio.io.*;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.jmatio.io.MatFileFilter;
import com.jmatio.io.MatFileIncrementalWriter;
import com.jmatio.io.MatFileReader;
import com.jmatio.io.MatFileWriter;
import com.jmatio.types.MLArray;
import com.jmatio.types.MLCell;
import com.jmatio.types.MLChar;
@@ -964,7 +961,7 @@ public class MatIOTest
        MLArray array = null;
        
        //try to read it
        MatFileReader reader = new MatFileReader();
        MatFileReader reader = new MatFileReader(MatFileType.Regular);
        reader.read(f, MatFileReader.MEMORY_MAPPED_FILE );
        array = reader.getMLArray("m1");
        assertEquals("Test if is correct file", array, m1);
@@ -1022,7 +1019,7 @@ public class MatIOTest
    public void testBigSparseFile() throws IOException
    {
        //read array form file
        MatFileReader mfr = new MatFileReader();
        MatFileReader mfr = new MatFileReader(MatFileType.Regular);
        //reader crashes on reading this file
        //bug caused by sparse array allocation
        mfr.read( fileFromStream("/bigsparse.mat"), MatFileReader.DIRECT_BYTE_BUFFER );
@@ -1051,12 +1048,12 @@ public class MatIOTest
        writer.write( filename, Arrays.asList( (MLArray)single) );
        
        //Test reading the MLSingle
        MatFileReader reader = new MatFileReader();
        MatFileReader reader = new MatFileReader(MatFileType.Regular);
        MLSingle readSingle = (MLSingle) reader.read( new File(filename) ).get( "arr" );
        
        assertEquals( single, readSingle );
        
        //Test reading the MLSingle generated natively by Matlab
        //Test reading the MLSingle generated natively by Regular
        MLSingle readSingleMatlabGenerated = (MLSingle) reader.read( fileFromStream("/single.mat") ).get( "arr" );
        
        assertEquals( single, readSingleMatlabGenerated );