package org.eclipse.dltk.core.caching; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import org.eclipse.dltk.internal.core.util.Util; public abstract class AbstractDataSaver { private static final int MAX_STR = 65500; protected DataOutputStream out; private List<String> stringIndex = new ArrayList<>(); private final ByteArrayOutputStream data = new ByteArrayOutputStream(); /** * @since 2.0 */ public AbstractDataSaver() { this.out = new DataOutputStream(data); } protected void writeString(String value) throws IOException { if (value == null) { out.writeByte(0); return; } if (value.length() > MAX_STR) { // Split string to two strings List<String> strs = new ArrayList<>(); int len = value.length(); int pos = 0; while (len > 0) { if (len > MAX_STR) { len -= MAX_STR; strs.add(value.substring(pos, pos + MAX_STR)); pos += MAX_STR; } else { strs.add(value.substring(pos, pos + len)); len = 0; } } out.writeByte(4); out.writeInt(strs.size()); for (String part : strs) { writeString(part); } return; } int indexOf = stringIndex.indexOf(value); if (indexOf != -1) { outNum(indexOf, 1, 2); return; } else { // Try to find part of word if (value.length() > 6) { for (String base : stringIndex) { if (base.contains(value)) { // Part of string int pos = base.indexOf(value); out.writeByte(3); int basePos = stringIndex.indexOf(base); outNum(basePos, 1, 2); outNum(pos, 1, 2); outNum(value.length(), 1, 2); return; } } } stringIndex.add(value); outNum(stringIndex.size() - 1, 1, 2); return; } } protected void outNum(int indexOf, int id1, int id2) throws IOException { if (indexOf <= Byte.MAX_VALUE) { out.writeByte(id1); out.writeByte(indexOf); } else if (indexOf > Byte.MAX_VALUE) { out.writeByte(id2); out.writeInt(indexOf); } } /** * @since 2.0 */ protected void storeStringIndex(OutputStream stream) throws IOException { final DataOutputStream indexOut = new DataOutputStream(stream); // Store strings indexOut.writeInt(stringIndex.size()); for (String s : this.stringIndex) { Util.writeUTF(indexOut, s.toCharArray()); } indexOut.flush(); } /** * @param stream * @throws IOException * @since 2.0 */ protected void saveDataTo(OutputStream stream) throws IOException { data.writeTo(stream); } /** * @since 2.0 */ protected void saveTo(OutputStream stream) throws IOException { storeStringIndex(stream); data.writeTo(stream); } }