/** Copyright 2015 Tim Engler, Rareventure LLC This file is part of Tiny Travel Tracker. Tiny Travel Tracker 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 3 of the License, or (at your option) any later version. Tiny Travel Tracker 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 Tiny Travel Tracker. If not, see <http://www.gnu.org/licenses/>. */ package com.rareventure.android.database.timmy; import java.io.IOException; import java.io.SyncFailedException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import com.rareventure.util.MultiValueHashMap; public class PropertyTimmyTable extends TimmyTable { private int nameSize; private int valueSize; public PropertyTimmyTable(String dbFilename, int nameSize, int valueSize, TimmyDatabase d) throws SyncFailedException, IOException { super(dbFilename, nameSize+valueSize, d); this.nameSize = nameSize; this.valueSize = valueSize; buf = new byte[super.getRecordSize()]; } public MultiValueHashMap<String, String> readProperties() { MultiValueHashMap<String, String> map = new MultiValueHashMap<String, String>(); for(int i = 0; i < getNextRowId(); i++) { readRecordIntoMap(i,map); } return map; } private static byte [] buf; private void readRecordIntoMap(int i, MultiValueHashMap<String, String> map) { getRecord(buf, i); String name = readField(buf, 0, nameSize); String value = readField(buf, nameSize, valueSize); //since there is no deletes, we just use an empty name to clear //out rows if(name.length() != 0) map.put(name, value); } private String readField(byte[] field, int start, int length) { int count = 0; for(; count < length; count++) if(field[start+count] == 0) break; return new String(field, start, count); } /** * Must be done within a transaction, writes out new properties set, clearing * out any existing property set * @param props * @throws IOException */ //PERF maybe add the ability to write individual properties public void writeProperties(MultiValueHashMap<String, String> props) throws IOException { int row = 0; byte[] writeBuf = new byte[super.getRecordSize()]; for(Map.Entry<String, List<String>> e : props.entrySet()) { for(String val : e.getValue()) { writeMapEntryIntoRecord(e.getKey(), val, writeBuf); if(row < getNextRowId()) updateRecord(row, writeBuf); else insertRecord(row, writeBuf); row++; } } } private void writeMapEntryIntoRecord(String name, String val, byte[] writeBuf) { writeField(writeBuf, name, 0, nameSize); writeField(writeBuf, val, nameSize, valueSize); } private void writeField(byte[] writeBuf, String val, int start, int length) { byte [] in = val.getBytes(); if(in.length > length) throw new IllegalStateException("trying to write a val that is too long to a field, val "+val+", field length "+length+" start "+start+" this "+this); System.arraycopy(in, 0, writeBuf, start, in.length); //null terminate it Arrays.fill(writeBuf, start+in.length, start+length, (byte)0); } }