1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf.micro; 32 33 import java.io.UnsupportedEncodingException; 34 35 /** 36 * Immutable array of bytes. 37 * 38 * @author crazybob (at) google.com Bob Lee 39 * @author kenton (at) google.com Kenton Varda 40 */ 41 public final class ByteStringMicro { 42 private final byte[] bytes; 43 44 private ByteStringMicro(final byte[] bytes) { 45 this.bytes = bytes; 46 } 47 48 /** 49 * Gets the byte at the given index. 50 * 51 * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size 52 */ 53 public byte byteAt(final int index) { 54 return bytes[index]; 55 } 56 57 /** 58 * Gets the number of bytes. 59 */ 60 public int size() { 61 return bytes.length; 62 } 63 64 /** 65 * Returns {@code true} if the size is {@code 0}, {@code false} otherwise. 66 */ 67 public boolean isEmpty() { 68 return bytes.length == 0; 69 } 70 71 // ================================================================= 72 // byte[] -> ByteStringMicro 73 74 /** 75 * Empty ByteStringMicro. 76 */ 77 public static final ByteStringMicro EMPTY = new ByteStringMicro(new byte[0]); 78 79 /** 80 * Copies the given bytes into a {@code ByteStringMicro}. 81 */ 82 public static ByteStringMicro copyFrom(final byte[] bytes, final int offset, 83 final int size) { 84 final byte[] copy = new byte[size]; 85 System.arraycopy(bytes, offset, copy, 0, size); 86 return new ByteStringMicro(copy); 87 } 88 89 /** 90 * Copies the given bytes into a {@code ByteStringMicro}. 91 */ 92 public static ByteStringMicro copyFrom(final byte[] bytes) { 93 return copyFrom(bytes, 0, bytes.length); 94 } 95 96 /** 97 * Encodes {@code text} into a sequence of bytes using the named charset 98 * and returns the result as a {@code ByteStringMicro}. 99 */ 100 public static ByteStringMicro copyFrom(final String text, final String charsetName) 101 throws UnsupportedEncodingException { 102 return new ByteStringMicro(text.getBytes(charsetName)); 103 } 104 105 /** 106 * Encodes {@code text} into a sequence of UTF-8 bytes and returns the 107 * result as a {@code ByteStringMicro}. 108 */ 109 public static ByteStringMicro copyFromUtf8(final String text) { 110 try { 111 return new ByteStringMicro(text.getBytes("UTF-8")); 112 } catch (UnsupportedEncodingException e) { 113 throw new RuntimeException("UTF-8 not supported?"); 114 } 115 } 116 117 // ================================================================= 118 // ByteStringMicro -> byte[] 119 120 /** 121 * Copies bytes into a buffer at the given offset. 122 * 123 * @param target buffer to copy into 124 * @param offset in the target buffer 125 */ 126 public void copyTo(final byte[] target, final int offset) { 127 System.arraycopy(bytes, 0, target, offset, bytes.length); 128 } 129 130 /** 131 * Copies bytes into a buffer. 132 * 133 * @param target buffer to copy into 134 * @param sourceOffset offset within these bytes 135 * @param targetOffset offset within the target buffer 136 * @param size number of bytes to copy 137 */ 138 public void copyTo(final byte[] target, final int sourceOffset, 139 final int targetOffset, 140 final int size) { 141 System.arraycopy(bytes, sourceOffset, target, targetOffset, size); 142 } 143 144 /** 145 * Copies bytes to a {@code byte[]}. 146 */ 147 public byte[] toByteArray() { 148 final int size = bytes.length; 149 final byte[] copy = new byte[size]; 150 System.arraycopy(bytes, 0, copy, 0, size); 151 return copy; 152 } 153 154 /** 155 * Constructs a new {@code String} by decoding the bytes using the 156 * specified charset. 157 */ 158 public String toString(final String charsetName) 159 throws UnsupportedEncodingException { 160 return new String(bytes, charsetName); 161 } 162 163 /** 164 * Constructs a new {@code String} by decoding the bytes as UTF-8. 165 */ 166 public String toStringUtf8() { 167 try { 168 return new String(bytes, "UTF-8"); 169 } catch (UnsupportedEncodingException e) { 170 throw new RuntimeException("UTF-8 not supported?"); 171 } 172 } 173 174 // ================================================================= 175 // equals() and hashCode() 176 177 //@Override for compatibility with Java 1.3 code we can't use annotations 178 public boolean equals(final Object o) { 179 if (o == this) { 180 return true; 181 } 182 183 if (!(o instanceof ByteStringMicro)) { 184 return false; 185 } 186 187 final ByteStringMicro other = (ByteStringMicro) o; 188 final int size = bytes.length; 189 if (size != other.bytes.length) { 190 return false; 191 } 192 193 final byte[] thisBytes = bytes; 194 final byte[] otherBytes = other.bytes; 195 for (int i = 0; i < size; i++) { 196 if (thisBytes[i] != otherBytes[i]) { 197 return false; 198 } 199 } 200 201 return true; 202 } 203 204 private volatile int hash = 0; 205 206 //@Override for compatibility with Java 1.3 code we can't use annotations 207 public int hashCode() { 208 int h = hash; 209 210 if (h == 0) { 211 final byte[] thisBytes = bytes; 212 final int size = bytes.length; 213 214 h = size; 215 for (int i = 0; i < size; i++) { 216 h = h * 31 + thisBytes[i]; 217 } 218 if (h == 0) { 219 h = 1; 220 } 221 222 hash = h; 223 } 224 225 return h; 226 } 227 } 228