blob: f91f63d0ba8d5ef004d7a43ac28d6162293658b8 [file] [log] [blame]
package org.eclipse.equinox.metatype.impl;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
/*******************************************************************************
* Copyright (c) 2019 IBM Corporation.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
public class Persistence {
private static final int PERSISTENCE_VERSION = 0;
private static final byte NULL = 0;
private static final byte OBJECT = 1;
private static final byte INDEX = 2;
private static final byte LONG_STRING = 3;
private Persistence() {
}
public static class Reader implements Closeable {
private final Map<Integer, String> readStringCache = new HashMap<>();
private final DataInputStream in;
public Reader(DataInputStream in) {
this.in = in;
}
public boolean isValidPersistenceVersion() throws IOException {
return in.readInt() == PERSISTENCE_VERSION;
}
public void readIndexedStrings() throws IOException {
int num = in.readInt();
for (int i = 0; i < num; i++) {
readIndexedString();
}
}
private String readIndexedString() throws IOException {
String string = readString();
readStringCache.put(Integer.valueOf(in.readInt()), string);
return string;
}
public String readString() throws IOException {
byte type = in.readByte();
if (type == INDEX) {
int index = in.readInt();
return readStringCache.get(index);
}
if (type == NULL) {
return null;
}
String string;
if (type == LONG_STRING) {
int length = in.readInt();
byte[] data = new byte[length];
in.readFully(data);
string = new String(data, StandardCharsets.UTF_8);
} else {
string = in.readUTF();
}
return string;
}
public long readLong() throws IOException {
return in.readLong();
}
public int readInt() throws IOException {
return in.readInt();
}
@Override
public void close() throws IOException {
in.close();
}
public boolean readBoolean() throws IOException {
return in.readBoolean();
}
public short readShort() throws IOException {
return in.readShort();
}
public char readCharacter() throws IOException {
return in.readChar();
}
public byte readByte() throws IOException {
return in.readByte();
}
public double readDouble() throws IOException {
return in.readDouble();
}
public float readFloat() throws IOException {
return in.readFloat();
}
}
public static class Writer implements Closeable {
private final Map<String, Integer> writeStringCache = new HashMap<>();
private final DataOutputStream out;
public Writer(DataOutputStream out) {
this.out = out;
}
public void writePersistenceVersion() throws IOException {
out.writeInt(PERSISTENCE_VERSION);
}
public void writeIndexedStrings(Set<String> strings) throws IOException {
strings.remove(null); // do not index null
out.writeInt(strings.size());
for (String string : strings) {
writeIndexedString(string);
}
}
private void writeIndexedString(String string) throws IOException {
writeString(string);
addToIndex(string);
}
public void writeString(String string) throws IOException {
Integer index = string != null ? writeStringCache.get(string) : null;
if (index != null) {
out.writeByte(INDEX);
out.writeInt(index);
return;
}
if (string == null)
out.writeByte(NULL);
else {
byte[] data = string.getBytes(StandardCharsets.UTF_8);
if (data.length > 65535) {
out.writeByte(LONG_STRING);
out.writeInt(data.length);
out.write(data);
} else {
out.writeByte(OBJECT);
out.writeUTF(string);
}
}
}
private void addToIndex(String string) throws IOException {
if (string == null) {
throw new NullPointerException();
}
Integer cur = writeStringCache.get(string);
if (cur != null)
throw new IllegalStateException("String is already in the write table: " + string); //$NON-NLS-1$
Integer index = writeStringCache.size();
writeStringCache.put(string, index);
out.writeInt(index.intValue());
}
@Override
public void close() throws IOException {
out.close();
}
public void writeInt(int v) throws IOException {
out.writeInt(v);
}
public void writeLong(long v) throws IOException {
out.writeLong(v);
}
public void writeBoolean(boolean v) throws IOException {
out.writeBoolean(v);
}
public void writeShort(Short v) throws IOException {
out.writeShort(v);
}
public void writeCharacter(Character v) throws IOException {
out.writeChar(v);
}
public void writeByte(Byte v) throws IOException {
out.writeByte(v);
}
public void writeDouble(Double v) throws IOException {
out.writeDouble(v);
}
public void writeFloat(Float v) throws IOException {
out.writeFloat(v);
}
}
}