org.bimserver.ifc.step.deserializer.IfcStepDeserializer.java Source code

Java tutorial

Introduction

Here is the source code for org.bimserver.ifc.step.deserializer.IfcStepDeserializer.java

Source

package org.bimserver.ifc.step.deserializer;

/******************************************************************************
 * Copyright (C) 2009-2013  BIMserver.org
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************************/

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bimserver.emf.IdEObject;
import org.bimserver.emf.IdEObjectImpl;
import org.bimserver.emf.IfcModelInterface;
import org.bimserver.emf.IfcModelInterfaceException;
import org.bimserver.ifc.IfcModel;
import org.bimserver.interfaces.objects.SIfcHeader;
import org.bimserver.models.ifc2x3tc1.Ifc2x3tc1Factory;
import org.bimserver.models.ifc2x3tc1.Ifc2x3tc1Package;
import org.bimserver.models.ifc2x3tc1.IfcBoolean;
import org.bimserver.models.ifc2x3tc1.IfcLogical;
import org.bimserver.models.ifc2x3tc1.Tristate;
import org.bimserver.plugins.deserializers.DeserializeException;
import org.bimserver.plugins.deserializers.EmfDeserializer;
import org.bimserver.plugins.schema.Attribute;
import org.bimserver.plugins.schema.BooleanType;
import org.bimserver.plugins.schema.DefinedType;
import org.bimserver.plugins.schema.EntityDefinition;
import org.bimserver.plugins.schema.ExplicitAttribute;
import org.bimserver.plugins.schema.IntegerType;
import org.bimserver.plugins.schema.RealType;
import org.bimserver.plugins.schema.SchemaDefinition;
import org.bimserver.plugins.schema.StringType;
import org.bimserver.plugins.schema.UnderlyingType;
import org.bimserver.shared.ListWaitingObject;
import org.bimserver.shared.SingleWaitingObject;
import org.bimserver.shared.WaitingList;
import org.bimserver.utils.FakeClosingInputStream;
import org.bimserver.utils.StringUtils;
import org.bimserver.utils.TokenizeException;
import org.bimserver.utils.Tokenizer;
import org.eclipse.emf.common.util.AbstractEList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EClassImpl;
import org.eclipse.emf.ecore.impl.EEnumImpl;

import com.google.common.base.Charsets;

public class IfcStepDeserializer extends EmfDeserializer {

    private static final int AVERAGE_LINE_LENGTH = 58;
    private static final EPackage ePackage = Ifc2x3tc1Package.eINSTANCE;
    private static final String WRAPPED_VALUE = "wrappedValue";
    private static final Map<String, EClassifier> classes = initClasses();

    /*
     * The following hacks are present
     * 
     * - For every feature of type double there is an extra feature (name
     * appended with "AsString") of type String to keep the original String
     * version this is also done for aggregate features - WrappedValues for all
     * for derived primitive types and enums that are used in a "select"
     */

    private final WaitingList<Integer> waitingList = new WaitingList<Integer>();
    private SchemaDefinition schema;
    private Mode mode = Mode.HEADER;
    private IfcModelInterface model;

    public enum Mode {
        HEADER, DATA, FOOTER, DONE
    }

    public void init(SchemaDefinition schema) {
        this.schema = schema;
    }

    public IfcModelInterface read(InputStream in, String filename, long fileSize) throws DeserializeException {
        mode = Mode.HEADER;
        if (filename != null
                && (filename.toUpperCase().endsWith(".ZIP") || filename.toUpperCase().endsWith(".IFCZIP"))) {
            ZipInputStream zipInputStream = new ZipInputStream(in);
            ZipEntry nextEntry;
            try {
                nextEntry = zipInputStream.getNextEntry();
                if (nextEntry == null) {
                    throw new DeserializeException(
                            "Zip files must contain exactly one IFC-file, this zip-file looks empty");
                }
                if (nextEntry.getName().toUpperCase().endsWith(".IFC")) {
                    IfcModelInterface model = null;
                    FakeClosingInputStream fakeClosingInputStream = new FakeClosingInputStream(zipInputStream);
                    model = read(fakeClosingInputStream, fileSize);
                    if (model.size() == 0) {
                        throw new DeserializeException("Uploaded file does not seem to be a correct IFC file");
                    }
                    if (zipInputStream.getNextEntry() != null) {
                        zipInputStream.close();
                        throw new DeserializeException(
                                "Zip files may only contain one IFC-file, this zip-file contains more files");
                    } else {
                        zipInputStream.close();
                        return model;
                    }
                } else {
                    throw new DeserializeException(
                            "Zip files must contain exactly one IFC-file, this zip-file seems to have one or more non-IFC files");
                }
            } catch (IOException e) {
                throw new DeserializeException(e);
            }
        } else {
            return read(in, fileSize);
        }
    }

    private void filterComments(Tokenizer tokenizer) throws TokenizeException {
        if (tokenizer.startsWith("/*")) {
            tokenizer.zoomIn("/*", "*/");
            tokenizer.readAll();
            tokenizer.zoomOut();
        }
    }

    private IfcModelInterface read(InputStream inputStream, long fileSize) throws DeserializeException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charsets.UTF_8));
        int initialCapacity = (int) (fileSize / AVERAGE_LINE_LENGTH);
        model = new IfcModel(initialCapacity);
        int lineNumber = 0;
        try {
            String line = reader.readLine();
            MessageDigest md = MessageDigest.getInstance("MD5");
            while (line != null) {
                byte[] bytes = line.getBytes(Charsets.UTF_8);
                md.update(bytes, 0, bytes.length);
                try {
                    while (!processLine(line.trim())) {
                        String readLine = reader.readLine();
                        if (readLine == null) {
                            break;
                        }
                        line += readLine;
                        lineNumber++;
                    }
                } catch (Exception e) {
                    throw new DeserializeException(
                            "Error on line " + lineNumber + " (" + e.getMessage() + ") " + line, e);
                }
                line = reader.readLine();
                lineNumber++;
            }
            model.getModelMetaData().setChecksum(md.digest());
            if (mode == Mode.HEADER) {
                throw new DeserializeException("No valid IFC header found");
            }
        } catch (FileNotFoundException e) {
            throw new DeserializeException(e);
        } catch (IOException e) {
            throw new DeserializeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new DeserializeException(e);
        }
        return model;
    }

    public IfcModelInterface read(File sourceFile) throws DeserializeException {
        if (schema == null) {
            throw new DeserializeException("No schema");
        }
        try {
            FileInputStream in = new FileInputStream(sourceFile);
            read(in, sourceFile.length());
            in.close();
            model.getModelMetaData().setDate(new Date());
            model.getModelMetaData().setName(sourceFile.getName());
            return model;
        } catch (FileNotFoundException e) {
            throw new DeserializeException(e);
        } catch (IOException e) {
            throw new DeserializeException(e);
        }
    }

    public IfcModelInterface getModel() {
        return model;
    }

    private static Map<String, EClassifier> initClasses() {
        HashMap<String, EClassifier> classes = new HashMap<String, EClassifier>(
                Ifc2x3tc1Package.eINSTANCE.getEClassifiers().size());
        for (EClassifier classifier : Ifc2x3tc1Package.eINSTANCE.getEClassifiers()) {
            classes.put(classifier.getName().toUpperCase(), classifier);
        }
        return classes;
    }

    private boolean processLine(String line) throws DeserializeException {
        switch (mode) {
        case HEADER:
            if (line.length() > 0) {
                if (line.endsWith(";")) {
                    processHeader(line);
                } else {
                    return false;
                }
            }
            if (line.equals("DATA;")) {
                mode = Mode.DATA;
            }
            break;
        case DATA:
            if (line.equals("ENDSEC;")) {
                mode = Mode.FOOTER;
            } else {
                if (line.length() > 0 && line.charAt(0) == '#') {
                    while (line.endsWith("*/")) {
                        line = line.substring(0, line.lastIndexOf("/*")).trim();
                    }
                    if (line.endsWith(";")) {
                        processRecord(line);
                    } else {
                        return false;
                    }
                }
            }
            break;
        case FOOTER:
            if (line.equals("ENDSEC;")) {
                mode = Mode.DONE;
            }
            break;
        case DONE:
        }
        return true;
    }

    private void processHeader(String line) throws DeserializeException {
        try {
            SIfcHeader ifcHeader = model.getModelMetaData().getIfcHeader();
            if (ifcHeader == null) {
                model.getModelMetaData().setIfcHeader(new SIfcHeader());
            }
            if (line.startsWith("FILE_DESCRIPTION")) {
                Tokenizer tokenizer = new Tokenizer(line.substring(line.indexOf("(")));
                tokenizer.zoomIn("(", ")");
                tokenizer.zoomIn("(", ")");
                filterComments(tokenizer);
                while (!tokenizer.isEmpty()) {
                    ifcHeader.getDescription().add(tokenizer.readSingleQuoted());
                    if (tokenizer.nextIsAComma()) {
                        tokenizer.readComma();
                    }
                }
                tokenizer.zoomOut();
                tokenizer.readComma();
                filterComments(tokenizer);
                ifcHeader.setImplementationLevel(tokenizer.readSingleQuoted());
                tokenizer.zoomOut();
                tokenizer.shouldBeFinished();
            } else if (line.startsWith("FILE_NAME")) {
                Tokenizer tokenizer = new Tokenizer(line.substring(line.indexOf("(")));
                tokenizer.zoomIn("(", ")");
                filterComments(tokenizer);
                ifcHeader.setFilename(tokenizer.readSingleQuoted());
                SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'kk:mm:ss");
                tokenizer.readComma();
                filterComments(tokenizer);
                ifcHeader.setTimeStamp(dateFormatter.parse(tokenizer.readSingleQuoted()));
                tokenizer.readComma();
                filterComments(tokenizer);
                tokenizer.zoomIn("(", ")");
                while (!tokenizer.isEmpty()) {
                    ifcHeader.getAuthor().add(tokenizer.readSingleQuoted());
                    if (tokenizer.nextIsAComma()) {
                        tokenizer.readComma();
                    }
                }
                tokenizer.zoomOut();
                tokenizer.readComma();
                filterComments(tokenizer);
                tokenizer.zoomIn("(", ")");
                while (!tokenizer.isEmpty()) {
                    ifcHeader.getOrganization().add(tokenizer.readSingleQuoted());
                    if (tokenizer.nextIsAComma()) {
                        tokenizer.readComma();
                    }
                }
                tokenizer.zoomOut();
                tokenizer.readComma();
                filterComments(tokenizer);
                ifcHeader.setPreProcessorVersion(tokenizer.readSingleQuoted());
                tokenizer.readComma();
                filterComments(tokenizer);
                ifcHeader.setOriginatingSystem(tokenizer.readSingleQuoted());
                tokenizer.readComma();
                filterComments(tokenizer);
                if (tokenizer.nextIsDollar()) {
                    tokenizer.readDollar();
                } else {
                    ifcHeader.setAuthorization(tokenizer.readSingleQuoted());
                }
                tokenizer.zoomOut();
                tokenizer.shouldBeFinished();
            } else if (line.startsWith("FILE_SCHEMA")) {
                Tokenizer tokenizer = new Tokenizer(line.substring(line.indexOf("(")));
                ifcHeader.setIfcSchemaVersion(tokenizer.zoomIn("(", ")").zoomIn("(", ")").readSingleQuoted());
            } else if (line.startsWith("ENDSEC;")) {
                // Do nothing
            }
        } catch (TokenizeException e) {
            throw new DeserializeException(e);
        } catch (ParseException e) {
            throw new DeserializeException(e);
        }
    }

    public void processRecord(String line) throws DeserializeException {
        int equalSignLocation = line.indexOf("=");
        int lastIndexOfSemiColon = line.lastIndexOf(";");
        if (lastIndexOfSemiColon == -1) {
            throw new DeserializeException("No semicolon found in line");
        }
        int indexOfFirstParen = line.indexOf("(", equalSignLocation);
        if (indexOfFirstParen == -1) {
            throw new DeserializeException("No left parenthesis found in line");
        }
        int indexOfLastParen = line.lastIndexOf(")", lastIndexOfSemiColon);
        if (indexOfLastParen == -1) {
            throw new DeserializeException("No right parenthesis found in line");
        }
        int recordNumber = Integer.parseInt(line.substring(1, equalSignLocation).trim());
        String name = line.substring(equalSignLocation + 1, indexOfFirstParen).trim();
        EClass classifier = (EClass) classes.get(name);
        if (classifier != null) {
            IdEObject object = (IdEObject) Ifc2x3tc1Factory.eINSTANCE.create(classifier);
            try {
                model.add(recordNumber, object);
            } catch (IfcModelInterfaceException e) {
                throw new DeserializeException(e);
            }
            ((IdEObjectImpl) object).setExpressId(recordNumber);
            String realData = line.substring(indexOfFirstParen + 1, indexOfLastParen);
            int lastIndex = 0;
            EntityDefinition entityBN = schema.getEntityBN(name);
            if (entityBN == null) {
                throw new DeserializeException("Unknown entity " + name);
            }
            for (Attribute attribute : entityBN.getAttributesCached(true)) {
                if (attribute instanceof ExplicitAttribute) {
                    if (!entityBN.isDerived(attribute.getName())) {
                        EStructuralFeature structuralFeature = classifier
                                .getEStructuralFeature(attribute.getName());
                        if (structuralFeature == null) {
                            throw new DeserializeException(
                                    "Unknown feature " + classifier.getName() + "." + attribute.getName());
                        }
                        int nextIndex = StringUtils.nextString(realData, lastIndex);
                        String val = null;
                        try {
                            val = realData.substring(lastIndex, nextIndex - 1).trim();
                        } catch (Exception e) {
                            int expected = 0;
                            for (Attribute attribute2 : entityBN.getAttributesCached(true)) {
                                if (attribute2 instanceof ExplicitAttribute) {
                                    expected++;
                                }
                            }
                            throw new DeserializeException(
                                    classifier.getName() + " expects " + expected + " fields, but less found");
                        }
                        lastIndex = nextIndex;
                        char firstChar = val.charAt(0);
                        if (firstChar == '$') {
                            object.eUnset(structuralFeature);
                            if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
                                EStructuralFeature doubleStringFeature = classifier
                                        .getEStructuralFeature(attribute.getName() + "AsString");
                                object.eSet(doubleStringFeature, val);
                            }
                        } else if (firstChar == '#') {
                            readReference(val, object, structuralFeature);
                        } else if (firstChar == '.') {
                            readEnum(val, object, structuralFeature);
                        } else if (firstChar == '(') {
                            readList(val, object, structuralFeature);
                        } else if (firstChar == '*') {
                        } else {
                            if (!structuralFeature.isMany()) {
                                object.eSet(structuralFeature, convert(structuralFeature.getEType(), val));
                                if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
                                    EStructuralFeature doubleStringFeature = classifier
                                            .getEStructuralFeature(attribute.getName() + "AsString");
                                    object.eSet(doubleStringFeature, val);
                                }
                            } else {
                                // It's not a list in the file, but it is in the
                                // schema??
                            }
                        }
                    } else {
                        int nextIndex = StringUtils.nextString(realData, lastIndex);
                        lastIndex = nextIndex;
                    }
                }
            }
            if (waitingList.containsKey(recordNumber)) {
                waitingList.updateNode(recordNumber, classifier, object);
            }
        } else {
            throw new DeserializeException(name + " is not a known entity");
        }
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void readList(String val, EObject object, EStructuralFeature structuralFeature)
            throws DeserializeException {
        int index = 0;
        if (!structuralFeature.isMany()) {
            throw new DeserializeException("Field " + structuralFeature.getName() + " of "
                    + structuralFeature.getEContainingClass().getName() + " is no aggregation");
        }
        AbstractEList list = (AbstractEList) object.eGet(structuralFeature);
        AbstractEList doubleStringList = null;
        if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
            EStructuralFeature doubleStringFeature = structuralFeature.getEContainingClass()
                    .getEStructuralFeature(structuralFeature.getName() + "AsString");
            if (doubleStringFeature == null) {
                throw new DeserializeException("Field not found: " + structuralFeature.getName() + "AsString");
            }
            doubleStringList = (AbstractEList) object.eGet(doubleStringFeature);
        }
        String realData = val.substring(1, val.length() - 1);
        int lastIndex = 0;
        while (lastIndex != realData.length() + 1) {
            int nextIndex = StringUtils.nextString(realData, lastIndex);
            String stringValue = realData.substring(lastIndex, nextIndex - 1).trim();
            lastIndex = nextIndex;
            if (stringValue.length() > 0) {
                if (stringValue.charAt(0) == '#') {
                    Integer referenceId = Integer.parseInt(stringValue.substring(1));
                    if (model.contains(referenceId)) {
                        EObject referencedObject = model.get(referenceId);
                        if (referencedObject != null) {
                            EClass referenceEClass = referencedObject.eClass();
                            if (((EClass) structuralFeature.getEType()).isSuperTypeOf(referenceEClass)) {
                                while (list.size() <= index) {
                                    list.addUnique(ePackage.getEFactoryInstance().create(referenceEClass));
                                }
                                list.setUnique(index, referencedObject);
                            } else {
                                throw new DeserializeException(referenceEClass.getName() + " cannot be stored in "
                                        + structuralFeature.getName());
                            }
                        }
                    } else {
                        waitingList.add(referenceId, new ListWaitingObject(object, structuralFeature, index));
                    }
                } else {
                    Object convert = convert(structuralFeature.getEType(), stringValue);
                    if (convert != null) {
                        while (list.size() <= index) {
                            if (doubleStringList != null) {
                                doubleStringList.addUnique(stringValue);
                            }
                            list.addUnique(convert);
                        }
                        if (doubleStringList != null) {
                            doubleStringList.setUnique(index, stringValue);
                        }
                        list.setUnique(index, convert);
                    }
                }
            }
            index++;
        }
    }

    private Object convertSimpleValue(Class<?> instanceClass, String value) throws DeserializeException {
        if (!value.equals("")) {
            if (instanceClass == Integer.class || instanceClass == int.class) {
                return Integer.parseInt(value);
            } else if (instanceClass == Long.class || instanceClass == long.class) {
                return Long.parseLong(value);
            } else if (instanceClass == Boolean.class || instanceClass == boolean.class) {
                return Boolean.parseBoolean(value);
            } else if (instanceClass == Double.class || instanceClass == double.class) {
                try {
                    return Double.parseDouble(value);
                } catch (NumberFormatException e) {
                    throw new DeserializeException("Incorrect double floating point value", e);
                }
            } else if (instanceClass == String.class) {
                if (value.startsWith("'") && value.endsWith("'")) {
                    return readString(value);
                } else {
                    return value;
                }
            }
        }
        return null;
    }

    private String readString(String value) throws DeserializeException {
        String result = value.substring(1, value.length() - 1);
        // Replace all '' with '
        while (result.contains("''")) {
            int index = result.indexOf("''");
            result = result.substring(0, index) + "'" + result.substring(index + 2);
        }
        while (result.contains("\\S\\")) {
            int index = result.indexOf("\\S\\");
            char x = result.charAt(index + 3);
            ByteBuffer b = ByteBuffer.wrap(new byte[] { (byte) (x + 128) });
            CharBuffer decode = Charsets.ISO_8859_1.decode(b);
            result = result.substring(0, index) + decode.get() + result.substring(index + 4);
        }
        while (result.contains("\\X\\")) {
            int index = result.indexOf("\\X\\");
            int code = Integer.parseInt(result.substring(index + 3, index + 5), 16);
            ByteBuffer b = ByteBuffer.wrap(new byte[] { (byte) (code) });
            CharBuffer decode = Charsets.ISO_8859_1.decode(b);
            result = result.substring(0, index) + decode.get() + result.substring(index + 5);
        }
        while (result.contains("\\X2\\")) {
            int index = result.indexOf("\\X2\\");
            int indexOfEnd = result.indexOf("\\X0\\");
            if (indexOfEnd == -1) {
                throw new DeserializeException("\\X2\\ not closed with \\X0\\");
            }
            if ((indexOfEnd - index) % 4 != 0) {
                throw new DeserializeException("Number of hex chars in \\X2\\ definition not divisible by 4");
            }
            try {
                ByteBuffer buffer = ByteBuffer
                        .wrap(Hex.decodeHex(result.substring(index + 4, indexOfEnd).toCharArray()));
                CharBuffer decode = Charsets.UTF_16BE.decode(buffer);
                result = result.substring(0, index) + decode.toString() + result.substring(indexOfEnd + 4);
            } catch (DecoderException e) {
                throw new DeserializeException(e);
            }
        }
        while (result.contains("\\X4\\")) {
            int index = result.indexOf("\\X4\\");
            int indexOfEnd = result.indexOf("\\X0\\");
            if (indexOfEnd == -1) {
                throw new DeserializeException("\\X4\\ not closed with \\X0\\");
            }
            if ((indexOfEnd - index) % 8 != 0) {
                throw new DeserializeException("Number of hex chars in \\X4\\ definition not divisible by 8");
            }
            try {
                ByteBuffer buffer = ByteBuffer
                        .wrap(Hex.decodeHex(result.substring(index + 4, indexOfEnd).toCharArray()));
                CharBuffer decode = Charset.forName("UTF-32").decode(buffer);
                result = result.substring(0, index) + decode.toString() + result.substring(indexOfEnd + 4);
            } catch (DecoderException e) {
                throw new DeserializeException(e);
            } catch (UnsupportedCharsetException e) {
                throw new DeserializeException("UTF-32 is not supported on your system", e);
            }
        }
        // Replace all \\ with \
        while (result.contains("\\\\")) {
            int index = result.indexOf("\\\\");
            result = result.substring(0, index) + "\\" + result.substring(index + 2);
        }
        return result;
    }

    private Object convert(EClassifier classifier, String value) throws DeserializeException {
        if (classifier != null) {
            if (classifier instanceof EClassImpl) {
                if (null != ((EClassImpl) classifier).getEStructuralFeature(WRAPPED_VALUE)) {
                    IdEObject create = (IdEObject) ePackage.getEFactoryInstance().create((EClass) classifier);
                    Class<?> instanceClass = create.eClass().getEStructuralFeature(WRAPPED_VALUE).getEType()
                            .getInstanceClass();
                    if (value.equals("")) {

                    } else {
                        if (instanceClass == Integer.class || instanceClass == int.class) {
                            try {
                                create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE),
                                        Integer.parseInt(value));
                            } catch (NumberFormatException e) {
                                throw new DeserializeException(value + " is not a valid integer value");
                            }
                        } else if (instanceClass == Long.class || instanceClass == long.class) {
                            create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE),
                                    Long.parseLong(value));
                        } else if (instanceClass == Boolean.class || instanceClass == boolean.class) {
                            create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE), value.equals(".T."));
                        } else if (instanceClass == Double.class || instanceClass == double.class) {
                            try {
                                create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE),
                                        Double.parseDouble(value));
                            } catch (NumberFormatException e) {
                                throw new DeserializeException(
                                        value + " is not a valid double floating point number");
                            }
                            create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE + "AsString"), value);
                        } else if (instanceClass == String.class) {
                            create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE), readString(value));
                        } else if (instanceClass == Tristate.class) {
                            Tristate tristate = null;
                            if (value.equals(".T.")) {
                                tristate = Tristate.TRUE;
                            } else if (value.equals(".F.")) {
                                tristate = Tristate.FALSE;
                            } else if (value.equals(".U.")) {
                                tristate = Tristate.UNDEFINED;
                            }
                            create.eSet(create.eClass().getEStructuralFeature(WRAPPED_VALUE), tristate);
                        }
                    }
                    return create;
                } else {
                    return processInline(classifier, value);
                }
            } else if (classifier instanceof EDataType) {
                return convertSimpleValue(classifier.getInstanceClass(), value);
            }
        }
        return null;
    }

    private Object processInline(EClassifier classifier, String value) throws DeserializeException {
        if (value.indexOf("(") != -1) {
            String typeName = value.substring(0, value.indexOf("(")).trim();
            String v = value.substring(value.indexOf("(") + 1, value.length() - 1);
            EClassifier eClassifier = classes.get(typeName);
            if (eClassifier instanceof EClass) {
                EClass cl = (EClass) classes.get(typeName);
                if (cl == null) {
                    DefinedType typeBN = schema.getTypeBN(typeName);
                    if (typeBN == null) {
                        throw new DeserializeException(typeName + " is not an existing IFC entity");
                    }
                    return convertSimpleValue(typeBN.getDomain(), v);
                } else {
                    Object convert = convert(cl, v);
                    try {
                        model.add(-1, (IdEObject) convert);
                    } catch (IfcModelInterfaceException e) {
                        throw new DeserializeException(e);
                    }
                    return convert;
                }
            } else {
                throw new DeserializeException(typeName + " is not an existing IFC entity");
            }
        } else {
            return convertSimpleValue(classifier.getInstanceClass(), value);
        }
    }

    private Object convertSimpleValue(UnderlyingType domain, String value) {
        if (!value.equals("")) {
            if (domain instanceof RealType) {
                return Double.parseDouble(value);
            } else if (domain instanceof IntegerType) {
                return Integer.parseInt(value);
            } else if (domain instanceof BooleanType) {
                return Boolean.parseBoolean(value);
            } else if (domain instanceof StringType) {
                return value;
            }
        }
        return null;
    }

    private void readEnum(String val, EObject object, EStructuralFeature structuralFeature)
            throws DeserializeException {
        if (val.equals(".T.")) {
            if (structuralFeature.getEType() == Ifc2x3tc1Package.eINSTANCE.getTristate()) {
                object.eSet(structuralFeature, Tristate.TRUE);
            } else if (structuralFeature.getEType().getName().equals("IfcBoolean")) {
                IfcBoolean createIfcBoolean = Ifc2x3tc1Factory.eINSTANCE.createIfcBoolean();
                createIfcBoolean.setWrappedValue(Tristate.TRUE);
                object.eSet(structuralFeature, createIfcBoolean);
            } else if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean()) {
                object.eSet(structuralFeature, true);
            } else {
                IfcLogical createIfcBoolean = Ifc2x3tc1Factory.eINSTANCE.createIfcLogical();
                createIfcBoolean.setWrappedValue(Tristate.TRUE);
                object.eSet(structuralFeature, createIfcBoolean);
            }
        } else if (val.equals(".F.")) {
            if (structuralFeature.getEType() == Ifc2x3tc1Package.eINSTANCE.getTristate()) {
                object.eSet(structuralFeature, Tristate.FALSE);
            } else if (structuralFeature.getEType().getName().equals("IfcBoolean")) {
                IfcBoolean createIfcBoolean = Ifc2x3tc1Factory.eINSTANCE.createIfcBoolean();
                createIfcBoolean.setWrappedValue(Tristate.FALSE);
                object.eSet(structuralFeature, createIfcBoolean);
            } else if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean()) {
                object.eSet(structuralFeature, false);
            } else {
                IfcLogical createIfcBoolean = Ifc2x3tc1Factory.eINSTANCE.createIfcLogical();
                createIfcBoolean.setWrappedValue(Tristate.FALSE);
                object.eSet(structuralFeature, createIfcBoolean);
            }
        } else if (val.equals(".U.")) {
            if (structuralFeature.getEType() == Ifc2x3tc1Package.eINSTANCE.getTristate()) {
                object.eSet(structuralFeature, Tristate.UNDEFINED);
            } else if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean()) {
                object.eUnset(structuralFeature);
            } else {
                IfcLogical createIfcBoolean = Ifc2x3tc1Factory.eINSTANCE.createIfcLogical();
                createIfcBoolean.setWrappedValue(Tristate.UNDEFINED);
                object.eSet(structuralFeature, createIfcBoolean);
            }
        } else {
            if (structuralFeature.getEType() instanceof EEnumImpl) {
                String realEnumValue = val.substring(1, val.length() - 1);
                EEnumLiteral enumValue = (((EEnumImpl) structuralFeature.getEType())
                        .getEEnumLiteral(realEnumValue));
                if (enumValue == null) {
                    throw new DeserializeException("Enum type " + structuralFeature.getEType().getName()
                            + " has no literal value '" + realEnumValue + "'");
                }
                object.eSet(structuralFeature, enumValue.getInstance());
            } else {
                throw new DeserializeException("Value " + val + " indicates enum type but "
                        + structuralFeature.getEType().getName() + " expected");
            }
        }
    }

    private void readReference(String val, EObject object, EStructuralFeature structuralFeature)
            throws DeserializeException {
        int referenceId;
        try {
            referenceId = Integer.parseInt(val.substring(1));
        } catch (NumberFormatException e) {
            throw new DeserializeException("'" + val + "' is not a valid reference");
        }
        if (model.contains(referenceId)) {
            object.eSet(structuralFeature, model.get(referenceId));
        } else {
            waitingList.add(referenceId, new SingleWaitingObject(object, structuralFeature));
        }
    }
}