001/* 002 * Copyright 2008 ZXing authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.itextpdf.text.pdf.qrcode; 018 019/** 020 * JAVAPORT: This should be combined with BitArray in the future, although that class is not yet 021 * dynamically resizeable. This implementation is reasonable but there is a lot of function calling 022 * in loops I'd like to get rid of. 023 * 024 * @author satorux@google.com (Satoru Takabayashi) - creator 025 * @author dswitkin@google.com (Daniel Switkin) - ported from C++ 026 * @since 5.0.2 027 */ 028public final class BitVector { 029 030 private int sizeInBits; 031 private byte[] array; 032 033 // For efficiency, start out with some room to work. 034 private static final int DEFAULT_SIZE_IN_BYTES = 32; 035 036 public BitVector() { 037 sizeInBits = 0; 038 array = new byte[DEFAULT_SIZE_IN_BYTES]; 039 } 040 041 // Return the bit value at "index". 042 public int at(int index) { 043 if (index < 0 || index >= sizeInBits) { 044 throw new IllegalArgumentException("Bad index: " + index); 045 } 046 int value = array[index >> 3] & 0xff; 047 return (value >> (7 - (index & 0x7))) & 1; 048 } 049 050 // Return the number of bits in the bit vector. 051 public int size() { 052 return sizeInBits; 053 } 054 055 // Return the number of bytes in the bit vector. 056 public int sizeInBytes() { 057 return (sizeInBits + 7) >> 3; 058 } 059 060 // Append one bit to the bit vector. 061 public void appendBit(int bit) { 062 if (!(bit == 0 || bit == 1)) { 063 throw new IllegalArgumentException("Bad bit"); 064 } 065 int numBitsInLastByte = sizeInBits & 0x7; 066 // We'll expand array if we don't have bits in the last byte. 067 if (numBitsInLastByte == 0) { 068 appendByte(0); 069 sizeInBits -= 8; 070 } 071 // Modify the last byte. 072 array[sizeInBits >> 3] |= (bit << (7 - numBitsInLastByte)); 073 ++sizeInBits; 074 } 075 076 // Append "numBits" bits in "value" to the bit vector. 077 // REQUIRES: 0<= numBits <= 32. 078 // 079 // Examples: 080 // - appendBits(0x00, 1) adds 0. 081 // - appendBits(0x00, 4) adds 0000. 082 // - appendBits(0xff, 8) adds 11111111. 083 public void appendBits(int value, int numBits) { 084 if (numBits < 0 || numBits > 32) { 085 throw new IllegalArgumentException("Num bits must be between 0 and 32"); 086 } 087 int numBitsLeft = numBits; 088 while (numBitsLeft > 0) { 089 // Optimization for byte-oriented appending. 090 if ((sizeInBits & 0x7) == 0 && numBitsLeft >= 8) { 091 int newByte = (value >> (numBitsLeft - 8)) & 0xff; 092 appendByte(newByte); 093 numBitsLeft -= 8; 094 } else { 095 int bit = (value >> (numBitsLeft - 1)) & 1; 096 appendBit(bit); 097 --numBitsLeft; 098 } 099 } 100 } 101 102 // Append "bits". 103 public void appendBitVector(BitVector bits) { 104 int size = bits.size(); 105 for (int i = 0; i < size; ++i) { 106 appendBit(bits.at(i)); 107 } 108 } 109 110 // Modify the bit vector by XOR'ing with "other" 111 public void xor(BitVector other) { 112 if (sizeInBits != other.size()) { 113 throw new IllegalArgumentException("BitVector sizes don't match"); 114 } 115 int sizeInBytes = (sizeInBits + 7) >> 3; 116 for (int i = 0; i < sizeInBytes; ++i) { 117 // The last byte could be incomplete (i.e. not have 8 bits in 118 // it) but there is no problem since 0 XOR 0 == 0. 119 array[i] ^= other.array[i]; 120 } 121 } 122 123 // Return String like "01110111" for debugging. 124 public String toString() { 125 StringBuffer result = new StringBuffer(sizeInBits); 126 for (int i = 0; i < sizeInBits; ++i) { 127 if (at(i) == 0) { 128 result.append('0'); 129 } else if (at(i) == 1) { 130 result.append('1'); 131 } else { 132 throw new IllegalArgumentException("Byte isn't 0 or 1"); 133 } 134 } 135 return result.toString(); 136 } 137 138 // Callers should not assume that array.length is the exact number of bytes needed to hold 139 // sizeInBits - it will typically be larger for efficiency. 140 public byte[] getArray() { 141 return array; 142 } 143 144 // Add a new byte to the end, possibly reallocating and doubling the size of the array if we've 145 // run out of room. 146 private void appendByte(int value) { 147 if ((sizeInBits >> 3) == array.length) { 148 byte[] newArray = new byte[(array.length << 1)]; 149 System.arraycopy(array, 0, newArray, 0, array.length); 150 array = newArray; 151 } 152 array[sizeInBits >> 3] = (byte) value; 153 sizeInBits += 8; 154 } 155 156}