/**
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.communication.json;
/**
* A raw string data structure that can be efficiently serialized/deserialized
* without requiring the entire string to be processed.
*
* TODO(kalman,user): this file needs some work; efficiency, consolidation
* of StringBuffer vs StringBuilder...
*
*/
// TODO(kalman/whoever): fix efficiency of string additions, and general code
// clarity.
public class RawStringData {
private int numEntries = 0;
/**
* The position of the baseString
*/
private int[] baseStringIndex = new int[] { 0, 0};
/**
* The concatenated string of all the stored data
*/
private String serializedData;
/**
* Create a raw string data structure
*/
public RawStringData() {
serializedData = "";
}
/**
* Create a RawStringData object by parsing the given str.
*
* @param str {@see(serialize())} for the detail of the string format.
*/
public RawStringData(String str) {
int start = str.charAt(0) == '[' ? 1 : 0;
int i = start;
while (i < str.length() && (Character.isDigit(str.charAt(i)) || str.charAt(i) == ',')) {
i++;
}
String[] subString = str.substring(start, i).split(",");
if (subString.length != 3) {
throw new IllegalArgumentException("Error parsing input string " + str);
}
numEntries = Integer.parseInt(subString[0]);
baseStringIndex[0] = Integer.parseInt(subString[1]);
baseStringIndex[1] = Integer.parseInt(subString[2]);
// the begin index of the index table is 1 after the first comma
int beginIndex = i + 1;
serializedData = str.substring(beginIndex);
}
/**
* Serialize the table into a string.
*
* The format of the string is as follow:
* '[' numEntries ',' baseStringStart ',' baseStringEnd ']' RawString
*
* RawString = A concatenated string containing all the stored data in order.
*/
public String serialize() {
StringBuffer serializedIndexTable = new StringBuffer();
boolean firstIndex = true;
// insert the number of entries
serializedIndexTable.insert(0, "[" + numEntries + "," + baseStringIndex[0] +
"," + baseStringIndex[1] + "]");
serializedIndexTable.append(serializedData);
return serializedIndexTable.toString();
}
/**
* Append a string to the data store
*
* @param str
* @return a reference that can be used to retrieve the added object
*/
public String addString(String str) {
int length = serializedData.length();
int index[] = new int[] {length, length + str.length()};
serializedData += str;
numEntries++;
return convertToRef(index);
}
/**
* @param ref the String reference to extract
* @return the string stored at the given index.
*/
public String getString(String ref) {
int[] index = convertToIndex(ref);
return serializedData.substring(index[0], index[1]);
}
/**
* Set the reference for the base string of the stored data.
*
* @param ref the reference returned by addString
*/
public void setBaseStringIndex(String ref) {
baseStringIndex = convertToIndex(ref);
}
/**
* Return the index of the base string of the stored data.
*
* @return a reference that can be used to retrieve the base string by using getString.
*/
public String getBaseString() {
return getString(convertToRef(baseStringIndex));
}
/**
* @return the number of entry in the table.
*/
public int size() {
return numEntries;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RawStringData)) {
return false;
}
RawStringData other = (RawStringData) obj;
if (baseStringIndex.length != other.baseStringIndex.length) {
return false;
}
for (int i = 0; i < baseStringIndex.length; i++) {
if (baseStringIndex[i] != other.baseStringIndex[i]) {
return false;
}
}
return numEntries == other.numEntries && serializedData.equals(other.serializedData);
}
@Override
public int hashCode() {
int prime = 31;
int hash = numEntries;
hash = hash * prime + baseStringIndex.hashCode();
hash = hash * prime + serializedData.hashCode();
return hash;
}
/**
* @param ref The reference to decode
* @return the begin and end index of the reference in the serializedData
*/
private int[] convertToIndex(String ref) {
String[] str = ref.split(",");
if (str.length != baseStringIndex.length) {
throw new IllegalArgumentException("Input argument is not a index" + str);
}
return new int[] {
Integer.parseInt(str[0]), Integer.parseInt(str[1])
};
}
/**
* @param index The reference to decode
* @return the begin and end index of the reference in the serializedData
*/
private String convertToRef(int[] index) {
return index[0] + "," + index[1];
}
}