/* * Copyright 2017 Brian Pellin. * * This file is part of KeePassDroid. * * KeePassDroid is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * KeePassDroid 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>. * */ package com.keepassdroid.collections; import com.keepassdroid.stream.LEDataInputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; public class VariantDictionary { private static final int VdVersion = 0x0100; private static final int VdmCritical = 0xFF00; private static final int VdmInfo = 0x00FF; private Map<String, Object> dict = new HashMap<String, Object>(); private enum VdType { None(0x00), UInt32(0x04), UInt64(0x05), Bool(0x08), Int32(0x0C), Int64(0x0D), String(0x18), ByteArray(0x42); private final byte value; VdType(int value) { this.value = (byte) value; } boolean equals(byte type) { return type == value; } byte getValue() { return value; } } public void setUInt32(String name, long value) { dict.put(name, value); } public long getUInt32(String name) { return (long)dict.get(name); } public void setUInt64(String name, long value) { dict.put(name, value); } public long getUInt64(String name) { return (long)dict.get(name); } public void setBool(String name, boolean value) { dict.put(name, value); } public void setInt32(String name, int value) { dict.put(name, value); } public void setInt64(String name, long value) { dict.put(name, value); } public void setString(String name, String value) { dict.put(name, value); } public void setByteArray(String name, byte[] value) { dict.put(name, value); } public byte[] getByteArray(String name) { return (byte[])dict.get(name); } public static VariantDictionary deserialize(LEDataInputStream lis) throws IOException { VariantDictionary d = new VariantDictionary(); int version = lis.readUShort(); if ((version & VdmCritical) > (VdVersion & VdmCritical)) { throw new IOException("Invalid format"); } while(true) { int type = lis.read(); if (type < 0) { throw new IOException(("Invalid format")); } byte bType = (byte)type; if (VdType.None.equals(bType)) { break; } int nameLen = lis.readInt(); byte[] nameBuf = lis.readBytes(nameLen); if (nameLen != nameBuf.length) { throw new IOException("Invalid format"); } String name = new String(nameBuf, "UTF-8"); int valueLen = lis.readInt(); byte[] valueBuf = lis.readBytes(valueLen); if (valueLen != valueBuf.length) { throw new IOException("Invalid format"); } if (VdType.UInt32.equals(bType)) { if (valueLen == 4) { d.setUInt32(name, LEDataInputStream.readUInt(valueBuf, 0)); } } else if (VdType.UInt64.equals(bType)) { if (valueLen == 8) { d.setUInt64(name, LEDataInputStream.readLong(valueBuf, 0)); } } else if (VdType.Bool.equals(bType)) { if (valueLen == 1) { d.setBool(name, valueBuf[0] != 0); } } else if (VdType.Int32.equals(bType)) { if (valueLen == 4) { d.setInt32(name, LEDataInputStream.readInt(valueBuf, 0)); } } else if (VdType.Int64.equals(bType)) { if (valueLen == 8) { d.setInt64(name, LEDataInputStream.readLong(valueBuf, 0)); } } else if (VdType.String.equals(bType)) { d.setString(name, new String(valueBuf, "UTF-8")); } else if (VdType.ByteArray.equals(bType)) { d.setByteArray(name, valueBuf); } else { assert(false); } } return d; } public void copyTo(VariantDictionary d) { for (Map.Entry<String, Object> entry : d.dict.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); dict.put(key, value); } } }