001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.backends.jeb;
028
029import org.forgerock.opendj.ldap.ByteStringBuilder;
030import org.opends.server.types.DN;
031
032/**
033 * Handles the disk representation of LDAP data.
034 */
035public class JebFormat
036{
037
038  /**
039   * The format version used by this class to encode and decode a DatabaseEntry.
040   */
041  public static final byte FORMAT_VERSION = 0x01;
042
043  /**
044   * The ASN1 tag for the DatabaseEntry type.
045   */
046  public static final byte TAG_DATABASE_ENTRY = 0x60;
047
048  /**
049   * The ASN1 tag for the DirectoryServerEntry type.
050   */
051  public static final byte TAG_DIRECTORY_SERVER_ENTRY = 0x61;
052
053  /**
054   * Decode an entry ID value from its database representation. Note that
055   * this method will throw an ArrayIndexOutOfBoundsException if the bytes
056   * array length is less than 8.
057   *
058   * @param bytes The database value of the entry ID.
059   * @return The entry ID value.
060   * @see #entryIDToDatabase(long)
061   */
062  public static long entryIDFromDatabase(byte[] bytes)
063  {
064    return toLong(bytes, 0, 8);
065  }
066
067  /**
068   * Decode a long from a byte array, starting at start index and ending at end
069   * index.
070   *
071   * @param bytes
072   *          The bytes value of the long.
073   * @param start
074   *          the array index where to start computing the long
075   * @param end
076   *          the array index exclusive where to end computing the long
077   * @return the long representation of the read bytes.
078   * @throws ArrayIndexOutOfBoundsException
079   *           if the bytes array length is less than end.
080   */
081  public static long toLong(byte[] bytes, int start, int end)
082      throws ArrayIndexOutOfBoundsException
083  {
084    long v = 0;
085    for (int i = start; i < end; i++)
086    {
087      v <<= 8;
088      v |= bytes[i] & 0xFF;
089    }
090    return v;
091  }
092
093  /**
094   * Decode an entry ID count from its database representation.
095   *
096   * @param bytes The database value of the entry ID count.
097   * @return The entry ID count.
098   *  Cannot be negative if encoded with #entryIDUndefinedSizeToDatabase(long)
099   * @see #entryIDUndefinedSizeToDatabase(long)
100   */
101  public static long entryIDUndefinedSizeFromDatabase(byte[] bytes)
102  {
103    if(bytes == null)
104    {
105      return 0;
106    }
107
108    if(bytes.length == 8)
109    {
110      long v = 0;
111      v |= bytes[0] & 0x7F;
112      for (int i = 1; i < 8; i++)
113      {
114        v <<= 8;
115        v |= bytes[i] & 0xFF;
116      }
117      return v;
118    }
119    return Long.MAX_VALUE;
120  }
121
122  /**
123   * Decode an array of entry ID values from its database representation.
124   *
125   * @param bytes The raw database value, null if there is no value and
126   *              hence no entry IDs. Note that this method will throw an
127   *              ArrayIndexOutOfBoundsException if the bytes array length is
128   *              not a multiple of 8.
129   * @return An array of entry ID values.
130   * @see #entryIDListToDatabase(long[])
131   */
132  public static long[] entryIDListFromDatabase(byte[] bytes)
133  {
134    byte[] decodedBytes = bytes;
135
136    int count = decodedBytes.length / 8;
137    long[] entryIDList = new long[count];
138    for (int pos = 0, i = 0; i < count; i++)
139    {
140      long v = 0;
141      v |= (decodedBytes[pos++] & 0xFFL) << 56;
142      v |= (decodedBytes[pos++] & 0xFFL) << 48;
143      v |= (decodedBytes[pos++] & 0xFFL) << 40;
144      v |= (decodedBytes[pos++] & 0xFFL) << 32;
145      v |= (decodedBytes[pos++] & 0xFFL) << 24;
146      v |= (decodedBytes[pos++] & 0xFFL) << 16;
147      v |= (decodedBytes[pos++] & 0xFFL) << 8;
148      v |= decodedBytes[pos++] & 0xFFL;
149      entryIDList[i] = v;
150    }
151
152    return entryIDList;
153  }
154
155  /**
156   * Decode a integer array using the specified byte array read from DB.
157   *
158   * @param bytes The byte array.
159   * @return An integer array.
160   */
161  public static int[] intArrayFromDatabaseBytes(byte[] bytes) {
162    byte[] decodedBytes = bytes;
163
164    int count = decodedBytes.length / 8;
165    int[] entryIDList = new int[count];
166    for (int pos = 0, i = 0; i < count; i++) {
167      int v = 0;
168      pos +=4;
169      v |= (decodedBytes[pos++] & 0xFFL) << 24;
170      v |= (decodedBytes[pos++] & 0xFFL) << 16;
171      v |= (decodedBytes[pos++] & 0xFFL) << 8;
172      v |= decodedBytes[pos++] & 0xFFL;
173      entryIDList[i] = v;
174    }
175
176    return entryIDList;
177  }
178
179  /**
180   * Encode an entry ID value to its database representation.
181   *
182   * @param id The entry ID value to be encoded.
183   * @return The encoded database value of the entry ID.
184   * @see #entryIDFromDatabase(byte[])
185   */
186  public static byte[] entryIDToDatabase(long id)
187  {
188    byte[] bytes = new byte[8];
189    long v = id;
190    for (int i = 7; i >= 0; i--)
191    {
192      bytes[i] = (byte) (v & 0xFF);
193      v >>>= 8;
194    }
195    return bytes;
196  }
197
198  /**
199   * Encode an entry ID set count to its database representation.
200   *
201   * @param count The entry ID set count to be encoded.
202   * @return The encoded database value of the entry ID set count.
203   * @see #entryIDUndefinedSizeFromDatabase(byte[])
204   */
205  public static byte[] entryIDUndefinedSizeToDatabase(long count)
206  {
207    byte[] bytes = new byte[8];
208    long v = count;
209    for (int i = 7; i >= 1; i--)
210    {
211      bytes[i] = (byte) (v & 0xFF);
212      v >>>= 8;
213    }
214    bytes[0] = (byte) ((v | 0x80) & 0xFF);
215    return bytes;
216  }
217
218  /**
219   * Encode an array of entry ID values to its database representation.
220   *
221   * @param entryIDArray An array of entry ID values.
222   * @return The encoded database value.
223   * @see #entryIDListFromDatabase(byte[])
224   */
225  public static byte[] entryIDListToDatabase(long[] entryIDArray)
226  {
227    if (entryIDArray.length == 0)
228    {
229      // Zero values
230      return null;
231    }
232
233    byte[] bytes = new byte[8*entryIDArray.length];
234    for (int pos = 0, i = 0; i < entryIDArray.length; i++)
235    {
236      long v = entryIDArray[i];
237      bytes[pos++] = (byte) ((v >>> 56) & 0xFF);
238      bytes[pos++] = (byte) ((v >>> 48) & 0xFF);
239      bytes[pos++] = (byte) ((v >>> 40) & 0xFF);
240      bytes[pos++] = (byte) ((v >>> 32) & 0xFF);
241      bytes[pos++] = (byte) ((v >>> 24) & 0xFF);
242      bytes[pos++] = (byte) ((v >>> 16) & 0xFF);
243      bytes[pos++] = (byte) ((v >>> 8) & 0xFF);
244      bytes[pos++] = (byte) (v & 0xFF);
245    }
246
247    return bytes;
248  }
249
250  /**
251   * Find the length of bytes that represents the superior DN of the given
252   * DN key. The superior DN is represented by the initial bytes of the DN key.
253   *
254   * @param dnKey The database key value of the DN.
255   * @return The length of the superior DN or -1 if the given dn is the
256   *         root DN or 0 if the superior DN is removed.
257   */
258  public static int findDNKeyParent(byte[] dnKey)
259  {
260    return findDNKeyParent(dnKey, 0, dnKey.length);
261  }
262
263  /**
264   * Find the length of bytes that represents the superior DN of the given
265   * DN key. The superior DN is represented by the initial bytes of the DN key.
266   *
267   * @param dnKey The database key value of the DN.
268   * @param offset Starting position in the database key data.
269   * @param length The length of the database key data.
270   * @return The length of the superior DN or -1 if the given dn is the
271   *         root DN or 0 if the superior DN is removed.
272   */
273  public static int findDNKeyParent(byte[] dnKey, int offset, int length)
274  {
275    if (length == 0)
276    {
277      // This is the root or base DN
278      return -1;
279    }
280
281    // We will walk backwards through the buffer and
282    // find the first unescaped NORMALIZED_RDN_SEPARATOR
283    for (int i = offset+length - 1; i >= offset; i--)
284    {
285      if (dnKey[i] == DN.NORMALIZED_RDN_SEPARATOR && i-1 >= offset && dnKey[i-1] != DN.NORMALIZED_ESC_BYTE)
286      {
287        return i;
288      }
289    }
290    return offset;
291  }
292
293  /**
294   * Create a DN database key from an entry DN.
295   *
296   * @param dn The entry DN.
297   * @param prefixRDNs The number of prefix RDNs to remove from the encoded
298   *                   representation.
299   * @return A DatabaseEntry containing the key.
300   */
301  public static byte[] dnToDNKey(DN dn, int prefixRDNs)
302  {
303    ByteStringBuilder builder = new ByteStringBuilder();
304    int startSize = dn.size() - prefixRDNs - 1;
305    for (int i = startSize; i >= 0; i--)
306    {
307        builder.append(DN.NORMALIZED_RDN_SEPARATOR);
308        dn.getRDN(i).toNormalizedByteString(builder);
309    }
310
311    return builder.toByteArray();
312  }
313
314
315}