/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o 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 this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.internal.handlers; import com.db4o.*; import com.db4o.ext.*; import com.db4o.foundation.*; import com.db4o.internal.*; import com.db4o.internal.delete.*; import com.db4o.internal.encoding.*; import com.db4o.internal.marshall.*; import com.db4o.internal.slots.*; import com.db4o.marshall.*; import com.db4o.reflect.*; import com.db4o.typehandlers.*; /** * @exclude */ public class StringHandler implements ValueTypeHandler, IndexableTypeHandler, BuiltinTypeHandler, VariableLengthTypeHandler, QueryableTypeHandler { private ReflectClass _classReflector; public ReflectClass classReflector(){ return _classReflector; } public void delete(DeleteContext context){ // do nothing, we are in a slot indirection anyway, the // buffer position does not need to be changed. } byte getIdentifier() { return Const4.YAPSTRING; } public boolean descendsIntoMembers() { return false; } public final Object indexEntryToObject(Context context, Object indexEntry){ if(indexEntry instanceof Slot){ Slot slot = (Slot)indexEntry; indexEntry = context.transaction().container().decryptedBufferByAddress(slot.address(), slot.length()); } return readStringNoDebug(context, (ReadBuffer)indexEntry); } /** * This readIndexEntry method reads from the parent slot. */ public Object readIndexEntryFromObjectSlot(MarshallerFamily mf, StatefulBuffer buffer) throws CorruptionException, Db4oIOException { int payLoadOffSet = buffer.readInt(); int length = buffer.readInt(); if(payLoadOffSet == 0){ return null; } return buffer.readPayloadWriter(payLoadOffSet, length); } public Object readIndexEntry(ObjectIdContext context) throws CorruptionException, Db4oIOException{ int payLoadOffSet = context.readInt(); int length = context.readInt(); if(payLoadOffSet == 0){ return null; } return ((StatefulBuffer)context.buffer()).readPayloadWriter(payLoadOffSet, length); } /** * This readIndexEntry method reads from the actual index in the file. */ public Object readIndexEntry(Context context, ByteArrayBuffer reader) { Slot s = new Slot(reader.readInt(), reader.readInt()); if (isInvalidSlot(s)){ return null; } return s; } private boolean isInvalidSlot(Slot slot) { return slot.isNull(); } public void writeIndexEntry(Context context, ByteArrayBuffer writer, Object entry) { if(entry == null){ writer.writeInt(0); writer.writeInt(0); return; } if(entry instanceof StatefulBuffer){ StatefulBuffer entryAsWriter = (StatefulBuffer)entry; writer.writeInt(entryAsWriter.getAddress()); writer.writeInt(entryAsWriter.length()); return; } if(entry instanceof Slot){ Slot s = (Slot) entry; writer.writeInt(s.address()); writer.writeInt(s.length()); return; } throw new IllegalArgumentException(); } public final void writeShort(Transaction trans, String str, ByteArrayBuffer buffer) { stringIo(trans.container()).writeLengthAndString(buffer, str); } ByteArrayBuffer val(Object obj, Context context) { if(obj instanceof ByteArrayBuffer) { return (ByteArrayBuffer)obj; } ObjectContainerBase oc = context.transaction().container(); if(obj instanceof String) { return writeToBuffer((InternalObjectContainer) oc, (String)obj); } if (obj instanceof Slot) { Slot s = (Slot) obj; return oc.decryptedBufferByAddress(s.address(), s.length()); } return null; } /** * returns: -x for left is greater and +x for right is greater * * FIXME: The returned value is the wrong way around. * * TODO: You will need collators here for different languages. */ final int compare(ByteArrayBuffer a_compare, ByteArrayBuffer a_with) { if (a_compare == null) { if (a_with == null) { return 0; } return -1; } if (a_with == null) { return 1; } return compare(a_compare._buffer, a_with._buffer); } public static final int compare(byte[] compare, byte[] with){ int min = compare.length < with.length ? compare.length : with.length; int start = Const4.INT_LENGTH; if(Deploy.debug) { start += Const4.LEADING_LENGTH; min -= Const4.BRACKETS_BYTES; } for(int i = start;i < min;i++) { if (compare[i] != with[i]) { return compare[i] - with[i]; } } return compare.length - with.length; } public void defragIndexEntry(DefragmentContextImpl context) { context.copyAddress(); // length context.incrementIntSize(); } public void write(WriteContext context, Object obj) { internalWrite((InternalObjectContainer) context.objectContainer(), context, (String) obj); } protected static void internalWrite(InternalObjectContainer objectContainer, WriteBuffer buffer, String str){ if (Deploy.debug) { Debug4.writeBegin(buffer, Const4.YAPSTRING); } stringIo(objectContainer).writeLengthAndString(buffer, str); if (Deploy.debug) { Debug4.writeEnd(buffer); } } public static ByteArrayBuffer writeToBuffer(InternalObjectContainer container, String str){ ByteArrayBuffer buffer = new ByteArrayBuffer(stringIo(container).length(str)); internalWrite(container, buffer, str); return buffer; } protected static LatinStringIO stringIo(Context context) { return stringIo((InternalObjectContainer) context.objectContainer()); } protected static LatinStringIO stringIo(InternalObjectContainer objectContainer){ return objectContainer.container().stringIO(); } public static String readString(Context context, ReadBuffer buffer) { if (Deploy.debug) { Debug4.readBegin(buffer, Const4.YAPSTRING); } String str = readStringNoDebug(context, buffer); if (Deploy.debug) { Debug4.readEnd(buffer); } return str; } public static String readStringNoDebug(Context context, ReadBuffer buffer) { return intern(context, stringIo(context).readLengthAndString(buffer)); } protected static String intern(Context context, String str){ if(context.objectContainer().ext().configure().internStrings()){ return str.intern(); } return str; } public Object read(ReadContext context) { return readString(context, context); } public void defragment(DefragmentContext context) { context.incrementOffset(linkLength()); } public PreparedComparison prepareComparison(final Context context, final Object obj) { final ByteArrayBuffer sourceBuffer = val(obj, context); return new PreparedComparison() { public int compareTo(Object target) { ByteArrayBuffer targetBuffer = val(target, context); return compare(sourceBuffer, targetBuffer); } }; } public int linkLength() { return Const4.INDIRECTION_LENGTH; } public void registerReflector(Reflector reflector) { _classReflector = reflector.forClass(String.class); } }