blob: c40c6095b57599f70afa443c5dae84dc92cd2693 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.ecl.core.util;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.ecore.util.InternalEList;
public class ECLBinaryResourceImpl extends ResourceImpl {
/**
* Specify the capacity of the buffered stream used when
* {@link #doSave(OutputStream, Map) saving} or
* {@link #doLoad(InputStream, Map) loading} the resource content. The value
* must be an integer. If not specified, {@link #DEFAULT_BUFFER_CAPACITY} is
* used. A value less than one disables the cache.
*
* @since 2.6
*/
public static final String OPTION_BUFFER_CAPACITY = "BUFFER_CAPACITY";
/**
* The default {@link #OPTION_BUFFER_CAPACITY} capacity of the buffered
* stream used when {@link #doSave(OutputStream, Map) saving} or
* {@link #doLoad(InputStream, Map) loading} the resource content.
*
* @since 2.6
*/
public static final int DEFAULT_BUFFER_CAPACITY = 1024;
/**
* Extract the {@link #OPTION_BUFFER_CAPACITY} from the options.
*
* @param options
* a map of options.
* @return the value associated with the {@link #OPTION_BUFFER_CAPACITY} key
* in the options map.
* @since 2.6
*/
protected static int getBufferCapacity(Map<?, ?> options) {
if (options != null) {
Integer capacity = (Integer) options.get(OPTION_BUFFER_CAPACITY);
if (capacity != null) {
return capacity;
}
}
return DEFAULT_BUFFER_CAPACITY;
}
public ECLBinaryResourceImpl() {
super();
}
public ECLBinaryResourceImpl(URI uri) {
super(uri);
}
@Override
protected void doSave(OutputStream outputStream, Map<?, ?> options)
throws IOException {
boolean buffer = !(outputStream instanceof BufferedOutputStream);
if (buffer) {
int bufferCapacity = getBufferCapacity(options);
if (bufferCapacity > 0) {
outputStream = new BufferedOutputStream(outputStream,
bufferCapacity);
} else {
buffer = false;
}
}
try {
EObjectOutputStream eObjectOutputStream = new EObjectOutputStream(
outputStream, options);
eObjectOutputStream.saveResource(this);
} finally {
if (buffer) {
outputStream.flush();
}
}
}
@Override
protected void doLoad(InputStream inputStream, Map<?, ?> options)
throws IOException {
if (!(inputStream instanceof BufferedInputStream)) {
int bufferCapacity = getBufferCapacity(options);
if (bufferCapacity > 0) {
inputStream = new BufferedInputStream(inputStream,
bufferCapacity);
}
}
EObjectInputStream eObjectInputStream = new EObjectInputStream(
inputStream, options);
eObjectInputStream.loadResource(this);
}
public static class BinaryIO {
public enum Version {
VERSION_1_0
}
protected Version version;
protected Resource resource;
protected URI baseURI;
protected Map<?, ?> options;
protected char[] characters;
protected InternalEObject[][] internalEObjectDataArrayBuffer = new InternalEObject[50][];
protected int internalEObjectDataArrayBufferCount = -1;
protected URI resolve(URI uri) {
return baseURI != null && uri.isRelative() && uri.hasRelativePath() ? uri
.resolve(baseURI) : uri;
}
protected URI deresolve(URI uri) {
if (baseURI != null && !uri.isRelative()) {
URI deresolvedURI = uri.deresolve(baseURI, true, true, false);
if (deresolvedURI.hasRelativePath()
&& (!uri.isPlatform() || uri.segment(0).equals(
baseURI.segment(0)))) {
uri = deresolvedURI;
}
}
return uri;
}
protected InternalEObject[] allocateInternalEObjectArray(int length) {
if (internalEObjectDataArrayBufferCount == -1) {
return new InternalEObject[length];
} else {
InternalEObject[] buffer = internalEObjectDataArrayBuffer[internalEObjectDataArrayBufferCount];
internalEObjectDataArrayBuffer[internalEObjectDataArrayBufferCount--] = null;
return buffer.length >= length ? buffer
: new InternalEObject[length];
}
}
protected void recycle(InternalEObject[] values) {
if (++internalEObjectDataArrayBufferCount >= internalEObjectDataArrayBuffer.length) {
InternalEObject[][] newInternalEObjectDataArrayBuffer = new InternalEObject[internalEObjectDataArrayBufferCount * 2][];
System.arraycopy(internalEObjectDataArrayBuffer, 0,
newInternalEObjectDataArrayBuffer, 0,
internalEObjectDataArrayBufferCount);
internalEObjectDataArrayBuffer = newInternalEObjectDataArrayBuffer;
}
internalEObjectDataArrayBuffer[internalEObjectDataArrayBufferCount] = values;
}
protected FeatureMap.Entry.Internal[][] featureMapEntryDataArrayBuffer = new FeatureMap.Entry.Internal[50][];
protected int featureMapEntryDataArrayBufferCount = -1;
protected FeatureMap.Entry.Internal[] allocateFeatureMapEntryArray(
int length) {
if (featureMapEntryDataArrayBufferCount == -1) {
return new FeatureMap.Entry.Internal[length];
} else {
FeatureMap.Entry.Internal[] buffer = featureMapEntryDataArrayBuffer[featureMapEntryDataArrayBufferCount];
featureMapEntryDataArrayBuffer[featureMapEntryDataArrayBufferCount--] = null;
return buffer.length >= length ? buffer
: new FeatureMap.Entry.Internal[length];
}
}
protected void recycle(FeatureMap.Entry.Internal[] values) {
if (++featureMapEntryDataArrayBufferCount >= featureMapEntryDataArrayBuffer.length) {
FeatureMap.Entry.Internal[][] newFeatureMapEntryDataArrayBuffer = new FeatureMap.Entry.Internal[featureMapEntryDataArrayBufferCount * 2][];
System.arraycopy(featureMapEntryDataArrayBuffer, 0,
newFeatureMapEntryDataArrayBuffer, 0,
featureMapEntryDataArrayBufferCount);
featureMapEntryDataArrayBuffer = newFeatureMapEntryDataArrayBuffer;
}
featureMapEntryDataArrayBuffer[featureMapEntryDataArrayBufferCount] = values;
}
protected enum FeatureKind {
EOBJECT_CONTAINER, EOBJECT_CONTAINER_PROXY_RESOLVING,
EOBJECT, EOBJECT_PROXY_RESOLVING,
EOBJECT_LIST, EOBJECT_LIST_PROXY_RESOLVING,
EOBJECT_CONTAINMENT, EOBJECT_CONTAINMENT_PROXY_RESOLVING,
EOBJECT_CONTAINMENT_LIST, EOBJECT_CONTAINMENT_LIST_PROXY_RESOLVING,
BOOLEAN, BYTE, CHAR, DOUBLE, FLOAT, INT, LONG, SHORT, STRING,
DATA, DATA_LIST,
FEATURE_MAP;
public static FeatureKind get(EStructuralFeature eStructuralFeature) {
if (eStructuralFeature instanceof EReference) {
EReference eReference = (EReference) eStructuralFeature;
if (eReference.isContainment()) {
if (eReference.isResolveProxies()) {
if (eReference.isMany()) {
return EOBJECT_CONTAINMENT_LIST_PROXY_RESOLVING;
} else {
return EOBJECT_CONTAINMENT_PROXY_RESOLVING;
}
} else {
if (eReference.isMany()) {
return EOBJECT_CONTAINMENT_LIST;
} else {
return EOBJECT_CONTAINMENT;
}
}
} else if (eReference.isContainer()) {
if (eReference.isResolveProxies()) {
return EOBJECT_CONTAINER_PROXY_RESOLVING;
} else {
return EOBJECT_CONTAINER;
}
} else if (eReference.isResolveProxies()) {
if (eReference.isMany()) {
return EOBJECT_LIST_PROXY_RESOLVING;
} else {
return EOBJECT_PROXY_RESOLVING;
}
} else {
if (eReference.isMany()) {
return EOBJECT_LIST;
} else {
return EOBJECT;
}
}
} else {
EAttribute eAttribute = (EAttribute) eStructuralFeature;
EDataType eDataType = eAttribute.getEAttributeType();
String instanceClassName = eDataType.getInstanceClassName();
if (instanceClassName == "org.eclipse.emf.ecore.util.FeatureMap$Entry") {
return FEATURE_MAP;
} else if (eAttribute.isMany()) {
return DATA_LIST;
} else if (instanceClassName == "java.lang.String") {
return STRING;
} else if (instanceClassName == "boolean") {
return BOOLEAN;
} else if (instanceClassName == "byte") {
return BYTE;
} else if (instanceClassName == "char") {
return CHAR;
} else if (instanceClassName == "double") {
return DOUBLE;
} else if (instanceClassName == "float") {
return FLOAT;
} else if (instanceClassName == "int") {
return INT;
} else if (instanceClassName == "long") {
return LONG;
} else if (instanceClassName == "short") {
return SHORT;
} else {
return DATA;
}
}
}
}
}
public static class EObjectOutputStream extends BinaryIO {
public enum Check {
NOTHING, DIRECT_RESOURCE, RESOURCE, CONTAINER
}
protected static class EPackageData {
public int id;
public EClassData[] eClassData;
public final int allocateEClassID() {
for (int i = 0, length = eClassData.length; i < length; ++i) {
EClassData eClassData = this.eClassData[i];
if (eClassData == null) {
return i;
}
}
return -1;
}
}
protected static class EClassData {
public int ePackageID;
public int id;
public EStructuralFeatureData[] eStructuralFeatureData;
}
protected static class EStructuralFeatureData {
public String name;
public boolean isTransient;
public FeatureKind kind;
public EFactory eFactory;
public EDataType eDataType;
}
protected OutputStream outputStream;
protected Map<EPackage, EPackageData> ePackageDataMap = new HashMap<EPackage, EPackageData>();
protected Map<EClass, EClassData> eClassDataMap = new HashMap<EClass, EClassData>();
protected Map<EObject, Integer> eObjectIDMap = new HashMap<EObject, Integer>();
protected Map<URI, Integer> uriToIDMap = new HashMap<URI, Integer>();
public EObjectOutputStream(OutputStream outputStream, Map<?, ?> options)
throws IOException {
this(outputStream, options, Version.VERSION_1_0);
}
public EObjectOutputStream(OutputStream outputStream,
Map<?, ?> options, Version version) throws IOException {
this.outputStream = outputStream;
this.options = options;
this.version = version;
writeSignature();
writeVersion();
}
protected void writeSignature() throws IOException {
// Write a signature that will be obviously corrupt
// if the binary contents end up being UTF-8 encoded
// or altered by line feed or carriage return changes.
//
writeByte('\211');
writeByte('e');
writeByte('m');
writeByte('f');
writeByte('\n');
writeByte('\r');
writeByte('\032');
writeByte('\n');
}
protected void writeVersion() throws IOException {
writeByte(version.ordinal());
}
protected EPackageData writeEPackage(EPackage ePackage)
throws IOException {
EPackageData ePackageData = ePackageDataMap.get(ePackage);
if (ePackageData == null) {
ePackageData = new EPackageData();
int id = ePackageDataMap.size();
ePackageData.id = id;
ePackageData.eClassData = new EClassData[ePackage
.getEClassifiers().size()];
writeCompressedInt(id);
writeString(ePackage.getNsURI());
writeURI(EcoreUtil.getURI(ePackage));
ePackageDataMap.put(ePackage, ePackageData);
} else {
writeCompressedInt(ePackageData.id);
}
return ePackageData;
}
protected EClassData writeEClass(EClass eClass) throws IOException {
EClassData eClassData = eClassDataMap.get(eClass);
if (eClassData == null) {
eClassData = new EClassData();
EPackageData ePackageData = writeEPackage(eClass.getEPackage());
eClassData.ePackageID = ePackageData.id;
writeCompressedInt(eClassData.id = ePackageData
.allocateEClassID());
writeString(eClass.getName());
int featureCount = eClass.getFeatureCount();
EStructuralFeatureData[] eStructuralFeaturesData = eClassData.eStructuralFeatureData = new EStructuralFeatureData[featureCount];
for (int i = 0; i < featureCount; ++i) {
EStructuralFeatureData eStructuralFeatureData = eStructuralFeaturesData[i] = new EStructuralFeatureData();
EStructuralFeature.Internal eStructuralFeature = (EStructuralFeature.Internal) eClass
.getEStructuralFeature(i);
eStructuralFeatureData.name = eStructuralFeature.getName();
eStructuralFeatureData.isTransient = eStructuralFeature
.isTransient()
|| eStructuralFeature.isContainer()
&& !eStructuralFeature.isResolveProxies();
eStructuralFeatureData.kind = FeatureKind
.get(eStructuralFeature);
if (eStructuralFeature instanceof EAttribute) {
EAttribute eAttribute = (EAttribute) eStructuralFeature;
EDataType eDataType = eAttribute.getEAttributeType();
eStructuralFeatureData.eDataType = eDataType;
eStructuralFeatureData.eFactory = eDataType
.getEPackage().getEFactoryInstance();
}
}
ePackageData.eClassData[eClassData.id] = eClassData;
eClassDataMap.put(eClass, eClassData);
} else {
writeCompressedInt(eClassData.ePackageID);
writeCompressedInt(eClassData.id);
}
return eClassData;
}
protected EStructuralFeatureData writeEStructuralFeature(
EStructuralFeature eStructuralFeature) throws IOException {
EClass eClass = eStructuralFeature.getEContainingClass();
EClassData eClassData = writeEClass(eClass);
int featureID = eClass.getFeatureID(eStructuralFeature);
EStructuralFeatureData eStructuralFeatureData = eClassData.eStructuralFeatureData[featureID];
writeCompressedInt(featureID);
if (eStructuralFeatureData.name != null) {
writeString(eStructuralFeatureData.name);
eStructuralFeatureData.name = null;
}
return eStructuralFeatureData;
}
public void saveResource(Resource resource) throws IOException {
this.resource = resource;
URI uri = resource.getURI();
if (uri != null && uri.isHierarchical() && !uri.isRelative()) {
baseURI = uri;
}
@SuppressWarnings("unchecked")
InternalEList<? extends InternalEObject> internalEList = (InternalEList<? extends InternalEObject>) (InternalEList<?>) resource
.getContents();
saveEObjects(internalEList, Check.CONTAINER);
}
public void saveEObjects(
InternalEList<? extends InternalEObject> internalEObjects,
Check check) throws IOException {
int size = internalEObjects.size();
InternalEObject[] values = allocateInternalEObjectArray(size);
internalEObjects.basicToArray(values);
writeCompressedInt(size);
for (int i = 0; i < size; ++i) {
InternalEObject internalEObject = values[i];
saveEObject(internalEObject, check);
}
recycle(values);
}
public void saveFeatureMap(FeatureMap.Internal featureMap)
throws IOException {
int size = featureMap.size();
FeatureMap.Entry.Internal[] values = allocateFeatureMapEntryArray(size);
featureMap.toArray(values);
writeCompressedInt(size);
for (int i = 0; i < size; ++i) {
FeatureMap.Entry.Internal entry = values[i];
saveFeatureMapEntry(entry);
}
recycle(values);
}
public void saveFeatureMapEntry(FeatureMap.Entry.Internal entry)
throws IOException {
EStructuralFeatureData eStructuralFeatureData = writeEStructuralFeature(entry
.getEStructuralFeature());
Object value = entry.getValue();
switch (eStructuralFeatureData.kind) {
case EOBJECT:
case EOBJECT_LIST:
case EOBJECT_CONTAINMENT:
case EOBJECT_CONTAINMENT_LIST: {
saveEObject((InternalEObject) value, Check.NOTHING);
break;
}
case EOBJECT_CONTAINMENT_PROXY_RESOLVING:
case EOBJECT_CONTAINMENT_LIST_PROXY_RESOLVING: {
saveEObject((InternalEObject) value, Check.DIRECT_RESOURCE);
break;
}
case EOBJECT_PROXY_RESOLVING:
case EOBJECT_LIST_PROXY_RESOLVING: {
saveEObject((InternalEObject) value, Check.RESOURCE);
break;
}
case BOOLEAN: {
writeBoolean((Boolean) value);
break;
}
case BYTE: {
writeByte((Byte) value);
break;
}
case CHAR: {
writeChar((Character) value);
break;
}
case DOUBLE: {
writeDouble((Double) value);
break;
}
case FLOAT: {
writeFloat((Float) value);
break;
}
case INT: {
writeInt((Integer) value);
break;
}
case LONG: {
writeLong((Long) value);
break;
}
case SHORT: {
writeShort((Short) value);
break;
}
case STRING: {
writeString((String) value);
break;
}
case DATA:
case DATA_LIST: {
String literal = eStructuralFeatureData.eFactory
.convertToString(eStructuralFeatureData.eDataType,
value);
writeString(literal);
break;
}
default: {
throw new IOException("Unhandled case "
+ eStructuralFeatureData.kind);
}
}
}
public void saveEObject(InternalEObject internalEObject, Check check)
throws IOException {
if (internalEObject == null) {
writeCompressedInt(-1);
} else {
Integer id = eObjectIDMap.get(internalEObject);
if (id == null) {
int idValue = eObjectIDMap.size();
writeCompressedInt(idValue);
eObjectIDMap.put(internalEObject, idValue);
EClass eClass = internalEObject.eClass();
EClassData eClassData = writeEClass(eClass);
switch (check) {
case DIRECT_RESOURCE: {
Internal resource = internalEObject.eDirectResource();
if (resource != null) {
writeCompressedInt(-1);
writeURI(resource.getURI(),
resource.getURIFragment(internalEObject));
return;
} else if (internalEObject.eIsProxy()) {
writeCompressedInt(-1);
writeURI(internalEObject.eProxyURI());
return;
}
break;
}
case RESOURCE: {
Resource resource = internalEObject.eResource();
if (resource != this.resource && resource != null) {
writeCompressedInt(-1);
writeURI(resource.getURI(),
resource.getURIFragment(internalEObject));
return;
} else if (internalEObject.eIsProxy()) {
writeCompressedInt(-1);
writeURI(internalEObject.eProxyURI());
return;
}
break;
}
case NOTHING:
case CONTAINER: {
break;
}
}
EStructuralFeatureData[] eStructuralFeatureData = eClassData.eStructuralFeatureData;
for (int i = 0, length = eStructuralFeatureData.length; i < length; ++i) {
EStructuralFeatureData structuralFeatureData = eStructuralFeatureData[i];
if (!structuralFeatureData.isTransient
&& (structuralFeatureData.kind != FeatureKind.EOBJECT_CONTAINER_PROXY_RESOLVING || check == Check.CONTAINER)) {
saveFeatureValue(internalEObject, i,
structuralFeatureData);
}
}
writeCompressedInt(0);
} else {
writeCompressedInt(id);
}
}
}
protected void saveFeatureValue(InternalEObject internalEObject,
int featureID, EStructuralFeatureData eStructuralFeatureData)
throws IOException {
if (internalEObject.eIsSet(featureID)) {
writeCompressedInt(featureID + 1);
if (eStructuralFeatureData.name != null) {
writeString(eStructuralFeatureData.name);
eStructuralFeatureData.name = null;
}
Object value = internalEObject.eGet(featureID, false, true);
switch (eStructuralFeatureData.kind) {
case EOBJECT:
case EOBJECT_CONTAINMENT: {
saveEObject((InternalEObject) value, Check.NOTHING);
break;
}
case EOBJECT_CONTAINER_PROXY_RESOLVING: {
saveEObject((InternalEObject) value, Check.DIRECT_RESOURCE);
break;
}
case EOBJECT_CONTAINMENT_PROXY_RESOLVING: {
saveEObject((InternalEObject) value, Check.DIRECT_RESOURCE);
break;
}
case EOBJECT_PROXY_RESOLVING: {
saveEObject((InternalEObject) value, Check.RESOURCE);
break;
}
case EOBJECT_LIST:
case EOBJECT_CONTAINMENT_LIST: {
@SuppressWarnings("unchecked")
InternalEList<? extends InternalEObject> internalEList = (InternalEList<? extends InternalEObject>) value;
saveEObjects(internalEList, Check.NOTHING);
break;
}
case EOBJECT_CONTAINMENT_LIST_PROXY_RESOLVING: {
@SuppressWarnings("unchecked")
InternalEList<? extends InternalEObject> internalEList = (InternalEList<? extends InternalEObject>) value;
saveEObjects(internalEList, Check.DIRECT_RESOURCE);
break;
}
case EOBJECT_LIST_PROXY_RESOLVING: {
@SuppressWarnings("unchecked")
InternalEList<? extends InternalEObject> internalEList = (InternalEList<? extends InternalEObject>) value;
saveEObjects(internalEList, Check.RESOURCE);
break;
}
case BOOLEAN: {
writeBoolean((Boolean) value);
break;
}
case BYTE: {
writeByte((Byte) value);
break;
}
case CHAR: {
writeChar((Character) value);
break;
}
case DOUBLE: {
writeDouble((Double) value);
break;
}
case FLOAT: {
writeFloat((Float) value);
break;
}
case INT: {
writeInt((Integer) value);
break;
}
case LONG: {
writeLong((Long) value);
break;
}
case SHORT: {
writeShort((Short) value);
break;
}
case STRING: {
writeString((String) value);
break;
}
case FEATURE_MAP: {
FeatureMap.Internal featureMap = (FeatureMap.Internal) value;
saveFeatureMap(featureMap);
break;
}
case DATA: {
String literal = eStructuralFeatureData.eFactory
.convertToString(eStructuralFeatureData.eDataType,
value);
writeString(literal);
break;
}
case DATA_LIST: {
List<?> dataValues = (List<?>) value;
int length = dataValues.size();
writeCompressedInt(length);
for (int j = 0; j < length; ++j) {
String literal = eStructuralFeatureData.eFactory
.convertToString(
eStructuralFeatureData.eDataType,
dataValues.get(j));
writeString(literal);
}
break;
}
default: {
throw new IOException("Unhandled case "
+ eStructuralFeatureData.kind);
}
}
}
}
public void writeByte(int value) throws IOException {
outputStream.write(value);
}
public void writeBoolean(boolean value) throws IOException {
writeByte(value ? 1 : 0);
}
public void writeChar(int value) throws IOException {
writeByte((byte) (value >> 8 & 0xFF));
writeByte((byte) (value & 0xFF));
}
public void writeShort(int value) throws IOException {
writeByte((byte) (value >> 8 & 0xFF));
writeByte((byte) (value & 0xFF));
}
public void writeInt(int value) throws IOException {
writeByte((byte) (value >> 24 & 0xFF));
writeByte((byte) (value >> 16 & 0xFF));
writeByte((byte) (value >> 8 & 0xFF));
writeByte((byte) (value & 0xFF));
}
public void writeLong(long value) throws IOException {
writeInt((int) (value >> 32));
writeInt((int) value);
}
public void writeFloat(float value) throws IOException {
writeInt(Float.floatToIntBits(value));
}
public void writeDouble(double value) throws IOException {
writeLong(Double.doubleToLongBits(value));
}
public void writeCompressedInt(int value) throws IOException {
++value;
int firstByte = value >> 24 & 0xFF;
int secondByte = value >> 16 & 0xFF;
int thirdByte = value >> 8 & 0xFF;
int fourthBtye = value & 0xFF;
if (firstByte > 0x3F) {
handleInvalidValue(value);
} else if (firstByte != 0 || secondByte > 0x3F) {
writeByte(firstByte | 0xC0);
writeByte(secondByte);
writeByte(thirdByte);
writeByte(fourthBtye);
} else if (secondByte != 0 || thirdByte > 0x3F) {
writeByte(secondByte | 0x80);
writeByte(thirdByte);
writeByte(fourthBtye);
} else if (thirdByte != 0 || fourthBtye > 0x3F) {
writeByte(thirdByte | 0x40);
writeByte(fourthBtye);
} else {
writeByte(fourthBtye);
}
}
private final void handleInvalidValue(int value) throws IOException {
throw new IOException("Invalid value " + value);
}
public void writeString(String value) throws IOException {
if (value == null) {
writeCompressedInt(-1);
} else {
int length = value.length();
writeCompressedInt(length);
if (characters == null || characters.length < length) {
characters = new char[length];
}
value.getChars(0, length, characters, 0);
LOOP: for (int i = 0; i < length; ++i) {
char character = characters[i];
if (character == 0 || character > 0xFF) {
writeByte((byte) 0);
writeChar(character);
while (++i < length) {
writeChar(characters[i]);
}
break LOOP;
} else {
writeByte((byte) character);
}
}
}
}
public void writeURI(URI uri) throws IOException {
writeURI(uri.trimFragment(), uri.fragment());
}
public void writeURI(URI uri, String fragment) throws IOException {
if (uri == null) {
writeCompressedInt(-1);
} else {
assert uri.fragment() == null;
Integer id = uriToIDMap.get(uri);
if (id == null) {
int idValue = uriToIDMap.size();
uriToIDMap.put(uri, idValue);
writeCompressedInt(idValue);
writeString(deresolve(uri).toString());
} else {
writeCompressedInt(id);
}
writeString(fragment);
}
}
}
public static class EObjectInputStream extends BinaryIO {
protected static class EPackageData {
public EPackage ePackage;
public EClassData[] eClassData;
public final int allocateEClassID() {
for (int i = 0, length = eClassData.length; i < length; ++i) {
EClassData eClassData = this.eClassData[i];
if (eClassData == null) {
return i;
}
}
return -1;
}
}
protected static class EClassData {
public EClass eClass;
public EFactory eFactory;
public EStructuralFeatureData[] eStructuralFeatureData;
}
protected static class EStructuralFeatureData {
public int featureID;
public EStructuralFeature eStructuralFeature;
public FeatureKind kind;
public EFactory eFactory;
public EDataType eDataType;
}
protected ResourceSet resourceSet;
protected InputStream inputStream;
protected List<EPackageData> ePackageDataList = new ArrayList<EPackageData>();
protected List<EClassData> eClassDataList = new ArrayList<EClassData>();
protected List<InternalEObject> eObjectList = new ArrayList<InternalEObject>();
protected List<URI> uriList = new ArrayList<URI>();
protected BasicEList<InternalEObject> internalEObjectList = new BasicEList<InternalEObject>();
protected BasicEList<Object> dataValueList = new BasicEList<Object>();
public EObjectInputStream(InputStream inputStream, Map<?, ?> options)
throws IOException {
this.inputStream = inputStream;
this.options = options;
readSignature();
readVersion();
}
protected void readSignature() throws IOException {
if (readByte() != (byte) '\211' || readByte() != 'e'
|| readByte() != 'm' || readByte() != 'f'
|| readByte() != '\n' || readByte() != '\r'
|| readByte() != '\032' || readByte() != '\n') {
throw new IOException(
"Invalid signature for a binary EMF serialization");
}
}
protected void readVersion() throws IOException {
version = Version.values()[readByte()];
}
protected int[][] intDataArrayBuffer = new int[50][];
protected int intDataArrayBufferCount = -1;
protected int[] allocateIntArray(int length) {
if (intDataArrayBufferCount == -1) {
return new int[length];
} else {
int[] buffer = intDataArrayBuffer[intDataArrayBufferCount];
intDataArrayBuffer[intDataArrayBufferCount--] = null;
return buffer.length >= length ? buffer : new int[length];
}
}
protected void recycle(int[] values) {
if (++intDataArrayBufferCount >= intDataArrayBuffer.length) {
int[][] newIntDataArrayBuffer = new int[intDataArrayBufferCount * 2][];
System.arraycopy(intDataArrayBuffer, 0, newIntDataArrayBuffer,
0, intDataArrayBufferCount);
intDataArrayBuffer = newIntDataArrayBuffer;
}
intDataArrayBuffer[intDataArrayBufferCount] = values;
}
protected EPackageData readEPackage() throws IOException {
int id = readCompressedInt();
if (ePackageDataList.size() < id || id < 0) {
throw new RuntimeException("Package id is not incremented by 1");
} else if (ePackageDataList.size() == id) {
EPackageData ePackageData = new EPackageData();
String nsURI = readString();
URI uri = readURI();
if (resourceSet != null) {
ePackageData.ePackage = EPackage.Registry.INSTANCE
.getEPackage(nsURI);
if (ePackageData.ePackage == null) {
ePackageData.ePackage = (EPackage) resourceSet
.getEObject(uri, true);
}
} else {
ePackageData.ePackage = EPackage.Registry.INSTANCE
.getEPackage(nsURI);
}
if (ePackageData.ePackage == null)
throw new NullPointerException("Can load package " + nsURI
+ ", " + uri.toString());
ePackageData.eClassData = new EClassData[ePackageData.ePackage
.getEClassifiers().size()];
ePackageDataList.add(ePackageData);
return ePackageData;
} else {
return ePackageDataList.get(id);
}
}
protected EClassData readEClass() throws IOException {
EPackageData ePackageData = readEPackage();
int id = readCompressedInt();
EClassData eClassData = ePackageData.eClassData[id];
if (eClassData == null) {
eClassData = ePackageData.eClassData[id] = new EClassData();
String name = readString();
eClassData.eClass = (EClass) ePackageData.ePackage
.getEClassifier(name);
eClassData.eFactory = ePackageData.ePackage
.getEFactoryInstance();
eClassData.eStructuralFeatureData = new EStructuralFeatureData[eClassData.eClass
.getFeatureCount()];
}
return eClassData;
}
protected EStructuralFeatureData readEStructuralFeature()
throws IOException {
EClassData eClassData = readEClass();
int featureID = readCompressedInt();
return getEStructuralFeatureData(eClassData, featureID);
}
protected EStructuralFeatureData getEStructuralFeatureData(
EClassData eClassData, int featureID) throws IOException {
EStructuralFeatureData eStructuralFeatureData = eClassData.eStructuralFeatureData[featureID];
if (eStructuralFeatureData == null) {
eStructuralFeatureData = eClassData.eStructuralFeatureData[featureID] = new EStructuralFeatureData();
String name = readString();
eStructuralFeatureData.eStructuralFeature = eClassData.eClass
.getEStructuralFeature(name);
eStructuralFeatureData.featureID = eClassData.eClass
.getFeatureID(eStructuralFeatureData.eStructuralFeature);
eStructuralFeatureData.kind = FeatureKind
.get(eStructuralFeatureData.eStructuralFeature);
if (eStructuralFeatureData.eStructuralFeature instanceof EAttribute) {
EAttribute eAttribute = (EAttribute) eStructuralFeatureData.eStructuralFeature;
eStructuralFeatureData.eDataType = eAttribute
.getEAttributeType();
eStructuralFeatureData.eFactory = eStructuralFeatureData.eDataType
.getEPackage().getEFactoryInstance();
}
}
return eStructuralFeatureData;
}
public void loadResource(Resource resource) throws IOException {
this.resource = resource;
this.resourceSet = resource.getResourceSet();
URI uri = resource.getURI();
if (uri != null && uri.isHierarchical() && !uri.isRelative()) {
baseURI = uri;
}
int size = readCompressedInt();
InternalEObject[] values = allocateInternalEObjectArray(size);
for (int i = 0; i < size; ++i) {
values[i] = loadEObject();
}
internalEObjectList.setData(size, values);
@SuppressWarnings("unchecked")
InternalEList<InternalEObject> internalEObjects = (InternalEList<InternalEObject>) (InternalEList<?>) resource
.getContents();
internalEObjects.addAllUnique(internalEObjectList);
recycle(values);
}
public void loadEObjects(InternalEList<InternalEObject> internalEObjects)
throws IOException {
// Read all the values into an array.
//
int size = readCompressedInt();
InternalEObject[] values = allocateInternalEObjectArray(size);
for (int i = 0; i < size; ++i) {
values[i] = loadEObject();
}
int existingSize = internalEObjects.size();
// If the list is empty, we need to add all the objects,
// otherwise, the reference is bidirectional and the list is at
// least partially populated.
//
if (existingSize == 0) {
internalEObjectList.setData(size, values);
internalEObjects.addAllUnique(internalEObjectList);
} else {
InternalEObject[] existingValues = allocateInternalEObjectArray(existingSize);
internalEObjects.basicToArray(existingValues);
int[] indices = allocateIntArray(existingSize);
int duplicateCount = 0;
LOOP: for (int i = 0; i < size; ++i) {
InternalEObject internalEObject = values[i];
for (int j = 0, count = 0; j < existingSize; ++j) {
InternalEObject existingInternalEObject = existingValues[j];
if (existingInternalEObject == internalEObject) {
if (duplicateCount != count) {
internalEObjects.move(duplicateCount, count);
}
indices[duplicateCount] = i;
++count;
++duplicateCount;
existingValues[j] = null;
continue LOOP;
} else if (existingInternalEObject != null) {
++count;
}
}
values[i - duplicateCount] = internalEObject;
}
size -= existingSize;
internalEObjectList.setData(size, values);
internalEObjects.addAllUnique(0, internalEObjectList);
for (int i = 0; i < existingSize; ++i) {
int newPosition = indices[i];
int oldPosition = size + i;
if (newPosition != oldPosition) {
internalEObjects.move(newPosition, oldPosition);
}
}
recycle(existingValues);
recycle(indices);
}
recycle(values);
}
public void loadFeatureMap(FeatureMap.Internal featureMap)
throws IOException {
// Read all the values into an array.
//
int size = readCompressedInt();
FeatureMap.Entry.Internal[] values = allocateFeatureMapEntryArray(size);
for (int i = 0; i < size; ++i) {
values[i] = loadFeatureMapEntry();
}
int existingSize = featureMap.size();
// If the list is empty, we need to add all the objects,
// otherwise, the reference is bidirectional and the list is at
// least partially populated.
//
if (existingSize == 0) {
featureMap.addAllUnique(values, 0, size);
} else {
FeatureMap.Entry.Internal[] existingValues = allocateFeatureMapEntryArray(existingSize);
featureMap.basicToArray(existingValues);
int[] indices = allocateIntArray(existingSize);
int duplicateCount = 0;
LOOP: for (int i = 0; i < size; ++i) {
FeatureMap.Entry.Internal entry = values[i];
for (int j = 0, count = 0; j < existingSize; ++j) {
FeatureMap.Entry.Internal existingEntry = existingValues[j];
if (entry.equals(existingEntry)) {
if (duplicateCount != count) {
featureMap.move(duplicateCount, count);
}
indices[duplicateCount] = i;
++count;
++duplicateCount;
existingValues[j] = null;
continue LOOP;
} else if (existingEntry != null) {
++count;
}
}
values[i - duplicateCount] = entry;
}
size -= existingSize;
internalEObjectList.setData(size, values);
featureMap.addAllUnique(0, values, 0, size);
for (int i = 0; i < existingSize; ++i) {
int newPosition = indices[i];
int oldPosition = size + i;
if (newPosition != oldPosition) {
featureMap.move(newPosition, oldPosition);
}
}
recycle(existingValues);
recycle(indices);
}
recycle(values);
}
public FeatureMap.Entry.Internal loadFeatureMapEntry()
throws IOException {
EStructuralFeatureData eStructuralFeatureData = readEStructuralFeature();
Object value;
switch (eStructuralFeatureData.kind) {
case EOBJECT_CONTAINER:
case EOBJECT_CONTAINER_PROXY_RESOLVING:
case EOBJECT:
case EOBJECT_LIST:
case EOBJECT_PROXY_RESOLVING:
case EOBJECT_LIST_PROXY_RESOLVING:
case EOBJECT_CONTAINMENT:
case EOBJECT_CONTAINMENT_LIST:
case EOBJECT_CONTAINMENT_PROXY_RESOLVING:
case EOBJECT_CONTAINMENT_LIST_PROXY_RESOLVING: {
value = loadEObject();
break;
}
case STRING: {
value = readString();
break;
}
case DATA: {
String literal = readString();
value = eStructuralFeatureData.eFactory.createFromString(
eStructuralFeatureData.eDataType, literal);
break;
}
case BOOLEAN: {
value = readBoolean();
break;
}
case BYTE: {
value = readByte();
break;
}
case CHAR: {
value = readChar();
break;
}
case DOUBLE: {
value = readDouble();
break;
}
case FLOAT: {
value = readFloat();
break;
}
case INT: {
value = readInt();
break;
}
case LONG: {
value = readLong();
break;
}
case SHORT: {
value = readShort();
break;
}
default: {
throw new IOException("Unhandled case "
+ eStructuralFeatureData.kind);
}
}
return FeatureMapUtil.createRawEntry(
eStructuralFeatureData.eStructuralFeature, value);
}
public InternalEObject loadEObject() throws IOException {
int id = readCompressedInt();
if (id == -1) {
return null;
} else {
if (eObjectList.size() <= id) {
EClassData eClassData = readEClass();
InternalEObject internalEObject = (InternalEObject) eClassData.eFactory
.create(eClassData.eClass);
eObjectList.add(internalEObject);
for (;;) {
int featureID = readCompressedInt() - 1;
if (featureID == -1) {
break;
} else if (featureID == -2) {
internalEObject.eSetProxyURI(readURI());
break;
} else {
EStructuralFeatureData eStructuralFeatureData = getEStructuralFeatureData(
eClassData, featureID);
loadFeatureValue(internalEObject,
eStructuralFeatureData);
}
}
return internalEObject;
} else {
return eObjectList.get(id);
}
}
}
protected void loadFeatureValue(InternalEObject internalEObject,
EStructuralFeatureData eStructuralFeatureData)
throws IOException {
switch (eStructuralFeatureData.kind) {
case EOBJECT_CONTAINER:
case EOBJECT_CONTAINER_PROXY_RESOLVING:
case EOBJECT:
case EOBJECT_PROXY_RESOLVING:
case EOBJECT_CONTAINMENT:
case EOBJECT_CONTAINMENT_PROXY_RESOLVING: {
internalEObject.eSet(eStructuralFeatureData.featureID,
loadEObject());
break;
}
case EOBJECT_LIST:
case EOBJECT_LIST_PROXY_RESOLVING:
case EOBJECT_CONTAINMENT_LIST:
case EOBJECT_CONTAINMENT_LIST_PROXY_RESOLVING: {
@SuppressWarnings("unchecked")
InternalEList<InternalEObject> internalEList = (InternalEList<InternalEObject>) internalEObject
.eGet(eStructuralFeatureData.featureID, false, true);
loadEObjects(internalEList);
break;
}
case STRING: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readString());
break;
}
case FEATURE_MAP: {
FeatureMap.Internal featureMap = (FeatureMap.Internal) internalEObject
.eGet(eStructuralFeatureData.featureID, false, true);
loadFeatureMap(featureMap);
break;
}
case DATA: {
String literal = readString();
internalEObject.eSet(eStructuralFeatureData.featureID,
eStructuralFeatureData.eFactory.createFromString(
eStructuralFeatureData.eDataType, literal));
break;
}
case DATA_LIST: {
int size = readCompressedInt();
dataValueList.grow(size);
Object[] dataValues = dataValueList.data();
for (int i = 0; i < size; ++i) {
String literal = readString();
dataValues[i] = eStructuralFeatureData.eFactory
.createFromString(eStructuralFeatureData.eDataType,
literal);
}
dataValueList.setData(size, dataValues);
@SuppressWarnings("unchecked")
List<Object> values = (List<Object>) internalEObject.eGet(
eStructuralFeatureData.featureID, false, true);
values.addAll(dataValueList);
break;
}
case BOOLEAN: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readBoolean());
break;
}
case BYTE: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readByte());
break;
}
case CHAR: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readChar());
break;
}
case DOUBLE: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readDouble());
break;
}
case FLOAT: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readFloat());
break;
}
case INT: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readInt());
break;
}
case LONG: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readLong());
break;
}
case SHORT: {
internalEObject.eSet(eStructuralFeatureData.featureID,
readShort());
break;
}
default: {
throw new IOException("Unhandled case "
+ eStructuralFeatureData.kind);
}
}
}
public byte readByte() throws IOException {
int result = inputStream.read();
if (result == -1) {
throw new IOException("Unexpected end of stream");
}
return (byte) result;
}
public boolean readBoolean() throws IOException {
return readByte() != 0;
}
public char readChar() throws IOException {
return (char) ((readByte() << 8) & 0xFF00 | readByte() & 0xFF);
}
public short readShort() throws IOException {
return (short) ((readByte() << 8) & 0xFF00 | readByte() & 0xFF);
}
public int readInt() throws IOException {
return (readByte() << 24) | (readByte() << 16) & 0xFF0000
| (readByte() << 8) & 0xFF00 | readByte() & 0xFF;
}
public long readLong() throws IOException {
return (long) readInt() << 32 | readInt() & 0xFFFFFFFFL;
}
public float readFloat() throws IOException {
return Float.intBitsToFloat(readInt());
}
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
public int readCompressedInt() throws IOException {
byte initialByte = readByte();
int code = (initialByte >> 6) & 0x3;
switch (code) {
case 0: {
return initialByte - 1;
}
case 1: {
return (initialByte << 8 & 0x3F00 | readByte() & 0xFF) - 1;
}
case 2: {
return ((initialByte << 16) & 0x3F0000 | (readByte() << 8)
& 0xFF00 | readByte() & 0xFF) - 1;
}
default: {
return ((initialByte << 24) & 0x3F000000 | (readByte() << 16)
& 0xFF0000 | (readByte() << 8) & 0xFF00 | readByte() & 0xFF) - 1;
}
}
}
public String readString() throws IOException {
int length = readCompressedInt();
if (length == -1) {
return null;
} else {
if (characters == null || characters.length < length) {
characters = new char[length];
}
LOOP: for (int i = 0; i < length; ++i) {
byte value = readByte();
if (value == 0) {
do {
characters[i] = readChar();
} while (++i < length);
break LOOP;
} else {
characters[i] = (char) (value & 0xFF);
}
}
return new String(characters, 0, length);
}
}
public URI readURI() throws IOException {
int id = readCompressedInt();
if (id == -1) {
return null;
} else {
URI uri;
if (uriList.size() <= id) {
String value = readString();
uri = resolve(URI.createURI(value));
uriList.add(uri);
} else {
uri = uriList.get(id);
}
String fragment = readString();
if (fragment != null) {
uri = uri.appendFragment(fragment);
}
return uri;
}
}
}
}