001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.mavibot.btree.serializer;
021
022
023import java.io.IOException;
024import java.nio.ByteBuffer;
025import java.util.Comparator;
026
027import org.apache.directory.mavibot.btree.comparator.ByteArrayComparator;
028import org.apache.directory.mavibot.btree.exception.SerializerCreationException;
029
030
031/**
032 * A serializer for a byte[].
033 *
034 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
035 */
036public class ByteArraySerializer extends AbstractElementSerializer<byte[]>
037{
038    /** A static instance of a BytearraySerializer */
039    public static final ByteArraySerializer INSTANCE = new ByteArraySerializer();
040
041    /**
042     * Create a new instance of ByteArraySerializer
043     */
044    private ByteArraySerializer()
045    {
046        super( ByteArrayComparator.INSTANCE );
047    }
048
049
050    /**
051     * Create a new instance of ByteArraySerializer with custom comparator
052     */
053    public ByteArraySerializer( Comparator<byte[]> comparator )
054    {
055        super( comparator );
056    }
057
058
059    /**
060     * {@inheritDoc}
061     */
062    public byte[] serialize( byte[] element )
063    {
064        int len = -1;
065
066        if ( element != null )
067        {
068            len = element.length;
069        }
070
071        byte[] bytes = null;
072
073        switch ( len )
074        {
075            case 0:
076                bytes = new byte[4];
077
078                bytes[0] = 0x00;
079                bytes[1] = 0x00;
080                bytes[2] = 0x00;
081                bytes[3] = 0x00;
082
083                break;
084
085            case -1:
086                bytes = new byte[4];
087
088                bytes[0] = ( byte ) 0xFF;
089                bytes[1] = ( byte ) 0xFF;
090                bytes[2] = ( byte ) 0xFF;
091                bytes[3] = ( byte ) 0xFF;
092
093                break;
094
095            default:
096                bytes = new byte[len + 4];
097
098                System.arraycopy( element, 0, bytes, 4, len );
099
100                bytes[0] = ( byte ) ( len >>> 24 );
101                bytes[1] = ( byte ) ( len >>> 16 );
102                bytes[2] = ( byte ) ( len >>> 8 );
103                bytes[3] = ( byte ) ( len );
104        }
105
106        return bytes;
107    }
108
109
110    /**
111     * Serialize a byte[]
112     *
113     * @param buffer the Buffer that will contain the serialized value
114     * @param start the position in the buffer we will store the serialized byte[]
115     * @param value the value to serialize
116     * @return The byte[] containing the serialized byte[]
117     */
118    public static byte[] serialize( byte[] buffer, int start, byte[] element )
119    {
120        int len = -1;
121
122        if ( element != null )
123        {
124            len = element.length;
125        }
126
127        switch ( len )
128        {
129            case 0:
130                buffer[start] = 0x00;
131                buffer[start + 1] = 0x00;
132                buffer[start + 2] = 0x00;
133                buffer[start + 3] = 0x00;
134
135                break;
136
137            case -1:
138                buffer[start] = ( byte ) 0xFF;
139                buffer[start + 1] = ( byte ) 0xFF;
140                buffer[start + 2] = ( byte ) 0xFF;
141                buffer[start + 3] = ( byte ) 0xFF;
142
143                break;
144
145            default:
146
147                buffer[start] = ( byte ) ( len >>> 24 );
148                buffer[start + 1] = ( byte ) ( len >>> 16 );
149                buffer[start + 2] = ( byte ) ( len >>> 8 );
150                buffer[start + 3] = ( byte ) ( len );
151
152                System.arraycopy( element, 0, buffer, 4 + start, len );
153        }
154
155        return buffer;
156
157    }
158
159
160    /**
161     * A static method used to deserialize a byte array from a byte array.
162     *
163     * @param in The byte array containing the byte array
164     * @return A byte[]
165     */
166    public static byte[] deserialize( byte[] in )
167    {
168        if ( ( in == null ) || ( in.length < 4 ) )
169        {
170            throw new SerializerCreationException( "Cannot extract a byte[] from a buffer with not enough bytes" );
171        }
172
173        int len = IntSerializer.deserialize( in );
174
175        switch ( len )
176        {
177            case 0:
178                return new byte[]
179                    {};
180
181            case -1:
182                return null;
183
184            default:
185                byte[] result = new byte[len];
186                System.arraycopy( in, 4, result, 0, len );
187
188                return result;
189        }
190    }
191
192
193    /**
194     * A static method used to deserialize a byte array from a byte array.
195     *
196     * @param in The byte array containing the byte array
197     * @param start the position in the byte[] we will deserialize the byte[] from
198     * @return A byte[]
199     */
200    public static byte[] deserialize( byte[] in, int start )
201    {
202        if ( ( in == null ) || ( in.length < 4 + start ) )
203        {
204            throw new SerializerCreationException( "Cannot extract a byte[] from a buffer with not enough bytes" );
205        }
206
207        int len = IntSerializer.deserialize( in, start );
208
209        switch ( len )
210        {
211            case 0:
212                return new byte[]
213                    {};
214
215            case -1:
216                return null;
217
218            default:
219                byte[] result = new byte[len];
220                System.arraycopy( in, 4 + start, result, 0, len );
221
222                return result;
223        }
224    }
225
226
227    /**
228     * A method used to deserialize a byte array from a byte array.
229     *
230     * @param in The byte array containing the byte array
231     * @return A byte[]
232     */
233    public byte[] fromBytes( byte[] in )
234    {
235        if ( ( in == null ) || ( in.length < 4 ) )
236        {
237            throw new SerializerCreationException( "Cannot extract a byte[] from a buffer with not enough bytes" );
238        }
239
240        int len = IntSerializer.deserialize( in );
241
242        switch ( len )
243        {
244            case 0:
245                return new byte[]
246                    {};
247
248            case -1:
249                return null;
250
251            default:
252                byte[] result = new byte[len];
253                System.arraycopy( in, 4, result, 0, len );
254
255                return result;
256        }
257    }
258
259
260    /**
261     * A method used to deserialize a byte array from a byte array.
262     *
263     * @param in The byte array containing the byte array
264     * @param start the position in the byte[] we will deserialize the byte[] from
265     * @return A byte[]
266     */
267    public byte[] fromBytes( byte[] in, int start )
268    {
269        if ( ( in == null ) || ( in.length < 4 + start ) )
270        {
271            throw new SerializerCreationException( "Cannot extract a byte[] from a buffer with not enough bytes" );
272        }
273
274        int len = IntSerializer.deserialize( in, start );
275
276        switch ( len )
277        {
278            case 0:
279                return new byte[]
280                    {};
281
282            case -1:
283                return null;
284
285            default:
286                byte[] result = new byte[len];
287                System.arraycopy( in, 4 + start, result, 0, len );
288
289                return result;
290        }
291    }
292
293
294    /**
295     * {@inheritDoc}
296     */
297    public byte[] deserialize( BufferHandler bufferHandler ) throws IOException
298    {
299        byte[] in = bufferHandler.read( 4 );
300
301        int len = IntSerializer.deserialize( in );
302
303        switch ( len )
304        {
305            case 0:
306                return new byte[]
307                    {};
308
309            case -1:
310                return null;
311
312            default:
313                in = bufferHandler.read( len );
314
315                return in;
316        }
317    }
318
319
320    /**
321     * {@inheritDoc}
322     */
323    public byte[] deserialize( ByteBuffer buffer ) throws IOException
324    {
325        int len = buffer.getInt();
326
327        switch ( len )
328        {
329            case 0:
330                return new byte[]
331                    {};
332
333            case -1:
334                return null;
335
336            default:
337                byte[] bytes = new byte[len];
338
339                buffer.get( bytes );
340
341                return bytes;
342        }
343    }
344}