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

Add in the beginnings of an MCOS parser.

MCOS is handled completely separately through a weird format.  Thus, start
supporting it by reading in the necessary data.  Currently it isn't fully
parsed, as the first unit test doesn't require extra data.  Also include the
MATLAB class file used to generate the test.
parent a132eb12
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
classdef SimpleEmpty
    %SIMPLEEMPTY A simple empty class definition.
    
    properties
    end
    
    methods
    end
    
end
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright 2014 Matthew Dawson <matthew@mjdsystems.ca>
 */
package com.jmatio.io;

import com.jmatio.types.MLArray;

/**
 *
 * @author Matthew Dawson <matthew@mjdsystems.ca>
 */
class MLObjectPlaceholder extends MLArray {
    MLObjectPlaceholder( String name, String className, int[][] information )
    {
        super( name, new int[] {1, 1}, -1, 0 );
        this.className = className;
        this.information = information;
    }

    final String className;
    final int[][] information;
}
+80 −26
Original line number Diff line number Diff line
@@ -93,6 +93,15 @@ public class MatFileReader
     * Array name filter
     */
    private MatFileFilter filter;
    /**
     * Whether or not we have found an MCOS type variable.  Needed to know if further processing is needed.
     */
    private boolean haveMCOS = false;
    /**
     * Holds the likely candidate for the MCOS extra data at the end of a MAT file.
     */
    private MLUInt8 mcosData;

    /**
     * Creates instance of <code>MatFileReader</code> and reads MAT-file 
     * from location given as <code>fileName</code>.
@@ -360,10 +369,22 @@ public class MatFileReader
            //read in file header
            readHeader(buf);
            
            while ( buf.remaining() > 0 )
            {
            while ( buf.remaining() > 0 ) {
                readData( buf );
            }
            if ( haveMCOS ) {
                parseMCOS(mcosData);
                if ( data.get("@") == mcosData ) {
                    data.remove("@");
                }
                for ( Map.Entry<String, MLArray> it : data.entrySet() ) {
                    if ( it.getValue() == mcosData ) {
                        data.remove(it.getKey());
                        break;
                    }
                }
            }
            mcosData = null;
            
            return getContent();
        }
@@ -408,6 +429,25 @@ public class MatFileReader
        
    }

    private void parseMCOS(MLUInt8 mcosData) throws IOException
    {
        // First, parse back out the mcosData.
        ByteBuffer buffer = mcosData.getRealByteBuffer();
        ByteBufferInputStream dataStream = new ByteBufferInputStream(buffer, buffer.limit());

        Map<String, MLArray> mcosContent;

        mcosContent = (new MatFileReader(dataStream, MatFileType.ReducedHeader)).getContent();
        MLCell mcosInfo = (MLCell) ((MLStructure) mcosContent.get("@0")).getField("MCOS");

        for (Map.Entry<String, MLArray> it : data.entrySet()) {
            if ( it.getValue() instanceof MLObjectPlaceholder ) {
                MLObjectPlaceholder obj = (MLObjectPlaceholder) it.getValue();
                it.setValue(new MLObject(obj.name, obj.className, new MLStructure("", new int[]{1, 1})));
            }
        }
    }

    /**
     * Read a mat file from a stream. Internally this will read the stream fully
     * into memory before parsing it.
@@ -804,6 +844,11 @@ public class MatFileReader
                            (MLNumericArray<?>) mlArray );
                }

                // This might be the MCOS extra data.  If there is no name, set it as the current set of data.
                if ( name.equals("") ) {
                    mcosData = (MLUInt8) mlArray;
                }

                break;
            case MLArray.mxINT8_CLASS:
                mlArray = new MLInt8(name, dims, type, attributes);
@@ -964,32 +1009,41 @@ public class MatFileReader
                // next tag should be miMatrix
                ISMatTag contentTag = new ISMatTag(buf);
                
                if ( contentTag.type == MatDataTypes.miMATRIX )
                {
                if ( contentTag.type == MatDataTypes.miMATRIX ) {
                    if ( name.equals("java") ) {
                        // should return UInt8
                        MLUInt8 content = (MLUInt8) readMatrix(buf, false);

                        // de-serialize object
                        ObjectInputStream ois = new ObjectInputStream(
                                new ByteBufferInputStream(content.getRealByteBuffer(),
                                                       content.getRealByteBuffer().limit()  ) );
                    try
                    {
                                        content.getRealByteBuffer().limit())
                        );
                        try {
                            Object o = ois.readObject();
                            mlArray = new MLJavaObject(arrName, className, o);
                    }
                    catch (Exception e) 
                    {
                        } catch (Exception e) {
                            throw new IOException(e);
                    }
                    finally
                    {
                        } finally {
                            ois.close();
                        }
                    } else if ( name.equals("MCOS") ) {
                        // FileWrapper__ is a special MATLAB internal name.  Should never appear from users.
                        if ( !className.equals("FileWrapper__") ) {
                            MLUInt32 content = (MLUInt32) readMatrix(buf, false);
                            int[][] t = content.getArray();
                            mlArray = new MLObjectPlaceholder(arrName, className, t);
                            haveMCOS = true;
                        } else { // This is where we get the useful MCOS data.  Only used on FileWrapper__ classes.
                            mlArray = readMatrix(buf, false);
                        }
                    } else {
                        throw new IOException("Unknown object type (" + name + ") found.");
                    }
                }
               else
                {
                    throw new IOException("Unexpected java object content");
                    throw new IOException("Unexpected object content");
                }
                break;
            case MLArray.mxOBJECT_CLASS:
+64 −0
Original line number Diff line number Diff line
/*
 * Copyright 2014 Matthew Dawson <matthew@mjdsystems.ca>
 */
package com.jmatio.test;

import com.jmatio.io.MatFileReader;
import com.jmatio.types.MLArray;
import com.jmatio.types.MLObject;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.io.*;
import java.util.Map;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;

/**
 * This test verifies that ReducedHeader generated mat files work correctly.
 *
 * @author Matthew Dawson <matthew@mjdsystems.ca>
 */
@RunWith(JUnit4.class)
public class MatlabMCOSTest {
    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

    @Test
    public void testParsingSimpleEmptyMCOS() throws IOException
    {
        File file = fileFromStream("/mcos/simpleempty.mat");
        MatFileReader reader = new MatFileReader(file);
        Map<String, MLArray> content = reader.getContent();

        assertThat(content.size(), is(1));

        MLObject obj = (MLObject) content.get("obj");
        assertThat(obj, is(notNullValue()));

        assertThat(obj.getName(), is("obj"));
        assertThat(obj.getClassName(), is("SimpleEmpty"));
        assertThat(obj.getObject().getAllFields().size(), is(0));
    }

    private File fileFromStream(String location) throws IOException
    {
        String outname = location.replace("/", "_");
        File f = folder.newFile(outname);
        InputStream stream = MatlabMCOSTest.class.getResourceAsStream(location);
        OutputStream fos = new BufferedOutputStream(new FileOutputStream(f));
        byte[] buffer = new byte[1024];
        int read = 0;
        while ((read = stream.read(buffer)) != -1) {
            fos.write(buffer, 0, read);
        }
        fos.flush();
        fos.close();
        return f;
    }
}
+1.05 KiB

File added.

No diff preview for this file type.