/**
   * Encodes this entry using the V3 encoding.
   *
   * @param buffer The buffer to encode into.
   * @throws DirectoryException If a problem occurs while attempting to encode the entry.
   */
  private void encodeV1(Entry entry, ByteStringBuilder buffer) throws DirectoryException {
    // The version number will be one byte.
    buffer.append((byte) 0x01);

    // TODO: Can we encode the DN directly into buffer?
    byte[] dnBytes = getBytes(entry.getDN().toString());
    buffer.appendBERLength(dnBytes.length);
    buffer.append(dnBytes);

    // Encode number of OCs and 0 terminated names.
    int i = 1;
    ByteStringBuilder bsb = new ByteStringBuilder();
    for (String ocName : entry.getObjectClasses().values()) {
      bsb.append(ocName);
      if (i < entry.getObjectClasses().values().size()) {
        bsb.append((byte) 0x00);
      }
      i++;
    }
    buffer.appendBERLength(bsb.length());
    buffer.append(bsb);

    // Encode the user attributes in the appropriate manner.
    encodeV1Attributes(buffer, entry.getUserAttributes());

    // The operational attributes will be encoded in the same way as
    // the user attributes.
    encodeV1Attributes(buffer, entry.getOperationalAttributes());
  }
  private void encodeV2Attributes(
      ByteStringBuilder buffer,
      Map<AttributeType, List<Attribute>> attributes,
      EntryEncodeConfig config)
      throws DirectoryException {
    int numAttributes = 0;

    // First count how many attributes are there to encode.
    for (List<Attribute> attrList : attributes.values()) {
      for (Attribute a : attrList) {
        if (a.isVirtual() || a.isEmpty()) {
          continue;
        }

        numAttributes++;
      }
    }

    // Encoded one-to-five byte number of attributes
    buffer.appendBERLength(numAttributes);

    if (config.compressAttributeDescriptions()) {
      for (List<Attribute> attrList : attributes.values()) {
        for (Attribute a : attrList) {
          if (a.isVirtual() || a.isEmpty()) {
            continue;
          }

          ByteStringBuilder bsb = new ByteStringBuilder();
          config.getCompressedSchema().encodeAttribute(bsb, a);
          buffer.appendBERLength(bsb.length());
          buffer.append(bsb);
        }
      }
    } else {
      // The attributes will be encoded as a sequence of:
      // - A UTF-8 byte representation of the attribute name.
      // - A zero delimiter
      // - A one-to-five byte number of values for the attribute
      // - A sequence of:
      //   - A one-to-five byte length for the value
      //   - A UTF-8 byte representation for the value
      for (List<Attribute> attrList : attributes.values()) {
        for (Attribute a : attrList) {
          byte[] nameBytes = getBytes(a.getNameWithOptions());
          buffer.append(nameBytes);
          buffer.append((byte) 0x00);

          buffer.appendBERLength(a.size());
          for (AttributeValue v : a) {
            buffer.appendBERLength(v.getValue().length());
            buffer.append(v.getValue());
          }
        }
      }
    }
  }
  /**
   * Encodes this entry using the V3 encoding.
   *
   * @param buffer The buffer to encode into.
   * @throws DirectoryException If a problem occurs while attempting to encode the entry.
   */
  private void encodeV2(Entry entry, ByteStringBuilder buffer, EntryEncodeConfig config)
      throws DirectoryException {
    // The version number will be one byte.
    buffer.append((byte) 0x02);

    // Get the encoded respresentation of the config.
    config.encode(buffer);

    // If we should include the DN, then it will be encoded as a
    // one-to-five byte length followed by the UTF-8 byte
    // representation.
    if (!config.excludeDN()) {
      // TODO: Can we encode the DN directly into buffer?
      byte[] dnBytes = getBytes(entry.getDN().toString());
      buffer.appendBERLength(dnBytes.length);
      buffer.append(dnBytes);
    }

    // Encode the object classes in the appropriate manner.
    if (config.compressObjectClassSets()) {
      config.getCompressedSchema().encodeObjectClasses(buffer, entry.getObjectClasses());
    } else {
      // Encode number of OCs and 0 terminated names.
      int i = 1;
      ByteStringBuilder bsb = new ByteStringBuilder();
      for (String ocName : entry.getObjectClasses().values()) {
        bsb.append(ocName);
        if (i < entry.getObjectClasses().values().size()) {
          bsb.append((byte) 0x00);
        }
        i++;
      }
      buffer.appendBERLength(bsb.length());
      buffer.append(bsb);
    }

    // Encode the user attributes in the appropriate manner.
    encodeV2Attributes(buffer, entry.getUserAttributes(), config);

    // The operational attributes will be encoded in the same way as
    // the user attributes.
    encodeV2Attributes(buffer, entry.getOperationalAttributes(), config);
  }
 /**
  * Encodes this entry encode configuration into a byte array
  * suitable for inclusion in the encoded entry.
  *
  * @param buffer The buffer to encode this configuration to.
  */
 public void encode(ByteStringBuilder buffer)
 {
   buffer.appendBERLength(1);
   buffer.append(encodedRepresentation);
 }