Skip to content

Instantly share code, notes, and snippets.

@alksily
Created March 1, 2019 12:25
Show Gist options
  • Save alksily/8f735ae7a76b4a6c556d2ed5ee796980 to your computer and use it in GitHub Desktop.
Save alksily/8f735ae7a76b4a6c556d2ed5ee796980 to your computer and use it in GitHub Desktop.
Named Data Tags
package ru.aengine.ndt;
import java.io.*;
import java.util.*;
import java.util.zip.*;
/**
* Named Data Tags (NDT) - file format for save array map.
* StreamReader class for read data from *.ndt file;
*/
public class StreamReader {
/**
* Read NDT structure from file
*
* @param file object class File with selected file.
* @return Map<String, Object> object structure.
*/
public static HashMap<String, Object> read(File file) {
try {
DataInputStream data = new DataInputStream(new GZIPInputStream(new FileInputStream(file)));
try {
return read((DataInput) data);
} finally {
data.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static HashMap<String, Object> read(DataInput in) throws IOException {
if (in.readByte() != 9) {
throw new IOException("The root tag is incorrect.");
}
String name = readString(in);
HashMap<String, Object> map = readList(in);
if (!name.isEmpty()) {
map.put("$this.name", name);
}
return map;
}
private static Object readTag(DataInput in, byte type) throws IOException {
switch (type) {
case 1:
return in.readByte();
case 2:
return in.readShort();
case 3:
return in.readInt();
case 4:
return in.readLong();
case 5:
return in.readFloat();
case 6:
return in.readDouble();
case 7:
return readString(in);
case 8:
return readList(in);
case 9:
return readArray(in);
case 10:
return readByteArray(in);
default:
throw new IOException("Wrong data NDT type tags (1-10): " + type);
}
}
private static byte[] readByteArray(DataInput in) throws IOException {
byte[] data = new byte[in.readInt()];
in.readFully(data);
return data;
}
private static String readString(DataInput in) throws IOException {
return in.readUTF();
}
private static List<Object> readArray(DataInput in) throws IOException {
byte type = in.readByte();
int length = in.readInt();
List<Object> list = new ArrayList<Object>(length);
for (int i = 0; i < length; ++i) {
Object tag = readTag(in, type);
list.add(tag);
}
return list;
}
private static HashMap<String, Object> readList(DataInput in) throws IOException {
HashMap<String, Object> map = new HashMap<String, Object>();
for (byte type; (type = in.readByte()) != 0; ) {
String name = readString(in);
Object tag = readTag(in, type);
map.put(name, tag);
}
return map;
}
}
package ru.aengine.ndt;
import java.io.*;
import java.util.*;
import java.util.zip.*;
/**
* Named Data Tags (NDT) - file format for save array map.
* StreamWriter class for write data in *.ndt file;
*/
public class StreamWriter {
/**
* Write NDT structure to file
*
* @param file object class File with selected file.
* @param map<String, Object> object with data
*/
public static void write(File file, Map<String, Object> map) {
try {
DataOutputStream data = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(file)));
try {
write((DataOutput) data, map);
} finally {
data.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void write(DataOutput out, Map<String, Object> map) throws IOException {
out.writeByte(9);
Object name = map.get("$this.name");
writeString(out, name != null ? (String) name : "");
writeList(out, map);
}
private static byte whichType(Object tag) {
if (tag instanceof Byte) return 1;
if (tag instanceof Short) return 2;
if (tag instanceof Integer) return 3;
if (tag instanceof Long) return 4;
if (tag instanceof Float) return 5;
if (tag instanceof Double) return 6;
if (tag instanceof String) return 7;
if (tag instanceof Map<?, ?>) return 8;
if (tag instanceof List<?>) return 9;
if (tag instanceof byte[]) return 10;
throw new RuntimeException("Wrong data type " + tag.getClass());
}
@SuppressWarnings("unchecked")
private static void writeTag(DataOutput out, byte type, Object tag) throws IOException {
switch (type) {
case 1:
out.writeByte((Byte) tag);
break;
case 2:
out.writeShort((Short) tag);
break;
case 3:
out.writeInt((Integer) tag);
break;
case 4:
out.writeLong((Long) tag);
break;
case 5:
out.writeFloat((Float) tag);
break;
case 6:
out.writeDouble((Double) tag);
break;
case 7:
writeString(out, (String) tag);
break;
case 8:
writeList(out, (Map<String, Object>) tag);
break;
case 9:
writeArray(out, (List<Object>) tag);
break;
case 10:
writeByteArray(out, (byte[]) tag);
break;
default:
throw new IOException("Wrong data NDT type tags (1-10): " + type);
}
}
private static void writeByteArray(DataOutput out, byte[] array) throws IOException {
out.writeInt(array.length);
out.write(array);
}
private static void writeString(DataOutput out, String str) throws IOException {
out.writeUTF(str);
}
private static void writeArray(DataOutput out, List<Object> list) throws IOException {
byte type = list.isEmpty() ? 1 : whichType(list.get(0));
out.writeByte(type);
out.writeInt(list.size());
for (Object tag : list) {
writeTag(out, type, tag);
}
}
private static void writeList(DataOutput out, Map<String, Object> map) throws IOException {
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("$this.name")) {
continue; // skip internal name
}
byte type = whichType(entry.getValue());
out.writeByte(type);
writeString(out, entry.getKey());
writeTag(out, type, entry.getValue());
}
out.writeByte(0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment