001/*
002 * Copyright 2017-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2017-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2017-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.asn1;
037
038
039
040import com.unboundid.util.Debug;
041import com.unboundid.util.NotMutable;
042import com.unboundid.util.NotNull;
043import com.unboundid.util.Nullable;
044import com.unboundid.util.ThreadSafety;
045import com.unboundid.util.ThreadSafetyLevel;
046
047import static com.unboundid.asn1.ASN1Messages.*;
048
049
050
051/**
052 * This class provides an ASN.1 bit string element, whose value represents a
053 * series of zero or more bits, where each bit is either one or zero.
054 */
055@NotMutable()
056@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
057public final class ASN1BitString
058       extends ASN1Element
059{
060  /**
061   * The serial version UID for this serializable class.
062   */
063  private static final long serialVersionUID = -5962171503831966571L;
064
065
066
067  // An array of the bits in this bit string, where true is 1 and false is 0.
068  @NotNull private final boolean[] bits;
069
070  // The bytes represented by the bits that comprise this bit string.
071  @Nullable private final byte[] bytes;
072
073
074
075  /**
076   * Creates a new ASN.1 bit string element with the default BER type and the
077   * provided set of bits.
078   *
079   * @param  bits  The bits to include in the bit string.  Each {@code boolean}
080   *               value of {@code true} represents a bit of one, and each
081   *               {@code boolean} value of {@code false} represents a bit of
082   *               zero.  It must not be {@code null} but may be empty.
083   */
084  public ASN1BitString(@NotNull final boolean... bits)
085  {
086    this(ASN1Constants.UNIVERSAL_BIT_STRING_TYPE, bits);
087  }
088
089
090
091  /**
092   * Creates a new ASN.1 bit string element with the specified BER type and the
093   * provided set of bits.
094   *
095   * @param  type  The BER type to use for this element.
096   * @param  bits  The bits to include in the bit string.  Each {@code boolean}
097   *               value of {@code true} represents a bit of one, and each
098   *               {@code boolean} value of {@code false} represents a bit of
099   *               zero.  It must not be {@code null} but may be empty.
100   */
101  public ASN1BitString(final byte type, @NotNull final boolean... bits)
102  {
103    this(type, bits, null, encodeValue(bits));
104  }
105
106
107
108  /**
109   * Creates a new ASN.1 bit string element with the provided information.
110   *
111   * @param  type          The BER type to use for this element.
112   * @param  bits          The bits to include in the bit string.  Each
113   *                       {@code boolean} value of {@code true} represents a
114   *                       bit of one, and each {@code boolean} value of
115   *                       {@code false} represents a bit of zero.  It must not
116   *                       be {@code null} but may be empty.
117   * @param  bytes         The bytes represented by the bits that comprise this
118   *                       bit string.  This may be {@code null} if it has not
119   *                       yet been determined, or if the number of bits is not
120   *                       an even multiple of eight.
121   * @param  encodedValue  The encoded value for this element.
122   */
123  private ASN1BitString(final byte type, @NotNull final boolean[] bits,
124                        @Nullable final byte[] bytes,
125                        @NotNull final byte[] encodedValue)
126  {
127    super(type, encodedValue);
128
129    this.bits = bits;
130
131    if (bytes == null)
132    {
133      if ((bits.length % 8) == 0)
134      {
135        this.bytes = new byte[bits.length / 8];
136
137        byte currentByte = 0x00;
138        int byteIndex = 0;
139        for (int i=0; i < bits.length; i++)
140        {
141          currentByte <<= 1;
142          if (bits[i])
143          {
144            currentByte |= 0x01;
145          }
146
147          if (((i + 1) % 8) == 0)
148          {
149            this.bytes[byteIndex++] = currentByte;
150            currentByte = 0x00;
151          }
152        }
153      }
154      else
155      {
156        this.bytes = null;
157      }
158    }
159    else
160    {
161      this.bytes = bytes;
162    }
163  }
164
165
166
167  /**
168   * Creates a new ASN.1 bit string with the default BER type and a value
169   * created from the provided string representation.
170   *
171   * @param  stringRepresentation  A string representation of the bit string to
172   *                               create.  It must not be {@code null}, but may
173   *                               be empty.  It must be comprised only of the
174   *                               characters '1' and '0'.
175   *
176   * @throws  ASN1Exception  If the provided string does not represent a valid
177   *                         bit string value.
178   */
179  public ASN1BitString(@NotNull final String stringRepresentation)
180         throws ASN1Exception
181  {
182    this(ASN1Constants.UNIVERSAL_BIT_STRING_TYPE, stringRepresentation);
183  }
184
185
186
187  /**
188   * Creates a new ASN.1 bit string with the default BER type and a value
189   * created from the provided string representation.
190   *
191   * @param  type                  The BER type to use for this element.
192   * @param  stringRepresentation  A string representation of the bit string to
193   *                               create.  It must not be {@code null}, but may
194   *                               be empty.  It must be comprised only of the
195   *                               characters '1' and '0'.
196   *
197   * @throws  ASN1Exception  If the provided string does not represent a valid
198   *                         bit string value.
199   */
200  public ASN1BitString(final byte type,
201                       @NotNull final String stringRepresentation)
202         throws ASN1Exception
203  {
204    this(type, getBits(stringRepresentation));
205  }
206
207
208
209  /**
210   * Decodes the provided string representation of a bit string into an array of
211   * bits.
212   *
213   * @param  s  A string representation of the bit string to create.  It must
214   *            not be {@code null}, but may be empty.  It must be comprised
215   *            only of the characters '1' and '0'.
216   *
217   * @return  An array of {@code boolean} values that correspond to the bits in
218   *          this bit string.
219   *
220   * @throws  ASN1Exception  If the provided string does not represent a valid
221   *                         bit string value.
222   */
223  @NotNull()
224  private static boolean[] getBits(@NotNull final String s)
225          throws ASN1Exception
226  {
227    final char[] chars = s.toCharArray();
228    final boolean[] bits = new boolean[chars.length];
229    for (int i=0; i < chars.length; i++)
230    {
231      if (chars[i] == '0')
232      {
233        bits[i] = false;
234      }
235      else if (chars[i] == '1')
236      {
237        bits[i] = true;
238      }
239      else
240      {
241        throw new ASN1Exception(
242             ERR_BIT_STRING_DECODE_STRING_INVALID_CHAR.get());
243      }
244    }
245
246    return bits;
247  }
248
249
250
251  /**
252   * Generates an encoded value for a bit string with the specified set of
253   * bits.
254   *
255   * @param  bits  The bits to include in the bit string.  Each {@code boolean}
256   *               value of {@code true} represents a bit of one, and each
257   *               {@code boolean} value of {@code false} represents a bit of
258   *               zero.  It must not be {@code null} but may be empty.
259   *
260   * @return  The encoded value.
261   */
262  @NotNull()
263  private static byte[] encodeValue(@NotNull final boolean... bits)
264  {
265    // A bit string value always has at least one byte, and that byte specifies
266    // the number of padding bits needed in the last byte.  The remaining bytes
267    // are used to hold the bits, with eight bits per byte.  If the number of
268    // bits provided is not a multiple of eight, then it will be assumed that
269    // there are enough extra bits of zero to make an even last byte.
270    final byte[] encodedValue;
271    final int paddingBitsNeeded;
272    final int numBitsMod8 = (bits.length % 8);
273    if (numBitsMod8 == 0)
274    {
275      paddingBitsNeeded = 0;
276      encodedValue = new byte[(bits.length / 8) + 1];
277    }
278    else
279    {
280      paddingBitsNeeded = 8 - numBitsMod8;
281      encodedValue = new byte[(bits.length / 8) + 2];
282    }
283
284    encodedValue[0] = (byte) paddingBitsNeeded;
285
286    byte currentByte = 0x00;
287    int bitIndex = 0;
288    int encodedValueIndex = 1;
289    for (final boolean bit : bits)
290    {
291      currentByte <<= 1;
292      if (bit)
293      {
294        currentByte |= 0x01;
295      }
296
297      bitIndex++;
298      if ((bitIndex % 8) == 0)
299      {
300        encodedValue[encodedValueIndex] = currentByte;
301        currentByte = 0x00;
302        encodedValueIndex++;
303      }
304    }
305
306    if (paddingBitsNeeded > 0)
307    {
308      currentByte <<= paddingBitsNeeded;
309      encodedValue[encodedValueIndex] = currentByte;
310    }
311
312    return encodedValue;
313  }
314
315
316
317  /**
318   * Retrieves an array of {@code boolean} values that correspond to the bits in
319   * this bit string.  Each {@code boolean} value of {@code true} represents a
320   * bit of one, and each {@code boolean} value of {@code false} represents a
321   * bit of zero.
322   *
323   * @return  An array of {@code boolean} values that correspond to the bits in
324   *          this bit string.
325   */
326  @NotNull()
327  public boolean[] getBits()
328  {
329    return bits;
330  }
331
332
333
334  /**
335   * Retrieves the bytes represented by the bits that comprise this bit string,
336   * if the number of bits is a multiple of eight.
337   *
338   * @return  The bytes represented by the bits that comprise this bit string.
339   *
340   * @throws  ASN1Exception  If the number of bits in this bit string is not a
341   *                         multiple of eight.
342   */
343  @NotNull()
344  public byte[] getBytes()
345         throws ASN1Exception
346  {
347    if (bytes == null)
348    {
349      throw new ASN1Exception(
350           ERR_BIT_STRING_GET_BYTES_NOT_MULTIPLE_OF_EIGHT_BITS.get(
351                bits.length));
352    }
353    else
354    {
355      return bytes;
356    }
357  }
358
359
360
361  /**
362   * Retrieves an array of booleans that represent the bits in the provided
363   * array of bytes.
364   *
365   * @param  bytes  The bytes for which to retrieve the corresponding bits.  It
366   *                must not be {@code null}.
367   *
368   * @return  An array of the bits that make up the provided bytes.
369   */
370  @NotNull()
371  public static boolean[] getBitsForBytes(@NotNull final byte... bytes)
372  {
373    final boolean[] bits = new boolean[bytes.length * 8];
374    for (int i=0; i < bytes.length; i++)
375    {
376      final byte b = bytes[i];
377      bits[i * 8] = ((b & 0x80) == 0x80);
378      bits[(i * 8) + 1] = ((b & 0x40) == 0x40);
379      bits[(i * 8) + 2] = ((b & 0x20) == 0x20);
380      bits[(i * 8) + 3] = ((b & 0x10) == 0x10);
381      bits[(i * 8) + 4] = ((b & 0x08) == 0x08);
382      bits[(i * 8) + 5] = ((b & 0x04) == 0x04);
383      bits[(i * 8) + 6] = ((b & 0x02) == 0x02);
384      bits[(i * 8) + 7] = ((b & 0x01) == 0x01);
385    }
386
387    return bits;
388  }
389
390
391
392  /**
393   * Decodes the contents of the provided byte array as a bit string element.
394   *
395   * @param  elementBytes  The byte array to decode as an ASN.1 bit string
396   *                       element.
397   *
398   * @return  The decoded ASN.1 bit string element.
399   *
400   * @throws  ASN1Exception  If the provided array cannot be decoded as a bit
401   *                         string element.
402   */
403  @NotNull()
404  public static ASN1BitString decodeAsBitString(
405              @NotNull final byte[] elementBytes)
406         throws ASN1Exception
407  {
408    try
409    {
410      int valueStartPos = 2;
411      int length = (elementBytes[1] & 0x7F);
412      if (length != elementBytes[1])
413      {
414        final int numLengthBytes = length;
415
416        length = 0;
417        for (int i=0; i < numLengthBytes; i++)
418        {
419          length <<= 8;
420          length |= (elementBytes[valueStartPos++] & 0xFF);
421        }
422      }
423
424      if ((elementBytes.length - valueStartPos) != length)
425      {
426        throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
427                                     (elementBytes.length - valueStartPos)));
428      }
429
430      final byte[] elementValue = new byte[length];
431      System.arraycopy(elementBytes, valueStartPos, elementValue, 0, length);
432      final boolean[] bits = decodeValue(elementValue);
433
434      final byte[] bytes;
435      if ((bits.length % 8) == 0)
436      {
437        bytes = new byte[elementValue.length - 1];
438        System.arraycopy(elementValue, 1, bytes, 0, bytes.length);
439      }
440      else
441      {
442        bytes = null;
443      }
444
445      return new ASN1BitString(elementBytes[0], bits, bytes, elementValue);
446    }
447    catch (final ASN1Exception ae)
448    {
449      Debug.debugException(ae);
450      throw ae;
451    }
452    catch (final Exception e)
453    {
454      Debug.debugException(e);
455      throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
456    }
457  }
458
459
460
461  /**
462   * Decodes the provided ASN.1 element as a bit string element.
463   *
464   * @param  element  The ASN.1 element to be decoded.
465   *
466   * @return  The decoded ASN.1 bit string element.
467   *
468   * @throws  ASN1Exception  If the provided element cannot be decoded as a bit
469   *                         string element.
470   */
471  @NotNull()
472  public static ASN1BitString decodeAsBitString(
473              @NotNull final ASN1Element element)
474         throws ASN1Exception
475  {
476    final byte[] elementValue = element.getValue();
477    final boolean[] bits = decodeValue(elementValue);
478
479      final byte[] bytes;
480      if ((bits.length % 8) == 0)
481      {
482        bytes = new byte[elementValue.length - 1];
483        System.arraycopy(elementValue, 1, bytes, 0, bytes.length);
484      }
485      else
486      {
487        bytes = null;
488      }
489
490    return new ASN1BitString(element.getType(), bits, bytes,
491         element.getValue());
492  }
493
494
495
496  /**
497   * Decodes the provided value into a set of bits.
498   *
499   * @param  elementValue  The bytes that comprise the encoded value for a
500   *                       bit string element.
501   *
502   * @return  An array of {@code boolean} values that correspond to the bits in
503   *          this bit string.
504   *
505   * @throws  ASN1Exception  If the provided value cannot be decoded as a valid
506   *                         bit string.
507   */
508  @NotNull()
509  private static boolean[] decodeValue(@NotNull final byte[] elementValue)
510          throws ASN1Exception
511  {
512    if (elementValue.length == 0)
513    {
514      throw new ASN1Exception(ERR_BIT_STRING_DECODE_EMPTY_VALUE.get());
515    }
516
517    final int paddingBitsNeeded = (elementValue[0] & 0xFF);
518    if (paddingBitsNeeded > 7)
519    {
520      throw new ASN1Exception(
521           ERR_BIT_STRING_DECODE_INVALID_PADDING_BIT_COUNT.get(
522                paddingBitsNeeded));
523    }
524
525    if ((paddingBitsNeeded > 0) && (elementValue.length == 1))
526    {
527      throw new ASN1Exception(
528           ERR_BIT_STRING_DECODE_NONZERO_PADDING_BIT_COUNT_WITH_NO_MORE_BYTES.
529                get());
530    }
531
532    int bitsIndex = 0;
533    final int numBits = ((elementValue.length - 1) * 8) - paddingBitsNeeded;
534    final boolean[] bits = new boolean[numBits];
535    for (int i=1; i < elementValue.length; i++)
536    {
537      byte b = elementValue[i];
538      if ((i == (elementValue.length - 1)) && (paddingBitsNeeded > 0))
539      {
540        for (int j=0; j < (8 - paddingBitsNeeded); j++)
541        {
542          bits[bitsIndex++] = ((b & 0x80) == 0x80);
543          b <<= 1;
544        }
545      }
546      else
547      {
548        bits[bitsIndex++] = ((b & 0x80) == 0x80);
549        bits[bitsIndex++] = ((b & 0x40) == 0x40);
550        bits[bitsIndex++] = ((b & 0x20) == 0x20);
551        bits[bitsIndex++] = ((b & 0x10) == 0x10);
552        bits[bitsIndex++] = ((b & 0x08) == 0x08);
553        bits[bitsIndex++] = ((b & 0x04) == 0x04);
554        bits[bitsIndex++] = ((b & 0x02) == 0x02);
555        bits[bitsIndex++] = ((b & 0x01) == 0x01);
556      }
557    }
558
559    return bits;
560  }
561
562
563
564  /**
565   * {@inheritDoc}
566   */
567  @Override()
568  public void toString(@NotNull final StringBuilder buffer)
569  {
570    buffer.ensureCapacity(buffer.length() + bits.length);
571    for (final boolean bit : bits)
572    {
573      if (bit)
574      {
575        buffer.append('1');
576      }
577      else
578      {
579        buffer.append('0');
580      }
581    }
582  }
583}