- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / java / src / main / java / com / google / protobuf / LiteralByteString.java
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;
32
33 import java.io.ByteArrayInputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.OutputStream;
37 import java.io.UnsupportedEncodingException;
38 import java.nio.ByteBuffer;
39 import java.util.ArrayList;
40 import java.util.List;
41 import java.util.NoSuchElementException;
42
43 /**
44  * This class implements a {@link com.google.protobuf.ByteString} backed by a
45  * single array of bytes, contiguous in memory. It supports substring by
46  * pointing to only a sub-range of the underlying byte array, meaning that a
47  * substring will reference the full byte-array of the string it's made from,
48  * exactly as with {@link String}.
49  *
50  * @author carlanton@google.com (Carl Haverl)
51  */
52 class LiteralByteString extends ByteString {
53
54   protected final byte[] bytes;
55
56   /**
57    * Creates a {@code LiteralByteString} backed by the given array, without
58    * copying.
59    *
60    * @param bytes array to wrap
61    */
62   LiteralByteString(byte[] bytes) {
63     this.bytes = bytes;
64   }
65
66   @Override
67   public byte byteAt(int index) {
68     // Unlike most methods in this class, this one is a direct implementation
69     // ignoring the potential offset because we need to do range-checking in the
70     // substring case anyway.
71     return bytes[index];
72   }
73
74   @Override
75   public int size() {
76     return bytes.length;
77   }
78
79   // =================================================================
80   // ByteString -> substring
81
82   @Override
83   public ByteString substring(int beginIndex, int endIndex) {
84     if (beginIndex < 0) {
85       throw new IndexOutOfBoundsException(
86           "Beginning index: " + beginIndex + " < 0");
87     }
88     if (endIndex > size()) {
89       throw new IndexOutOfBoundsException("End index: " + endIndex + " > " +
90           size());
91     }
92     int substringLength = endIndex - beginIndex;
93     if (substringLength < 0) {
94       throw new IndexOutOfBoundsException(
95           "Beginning index larger than ending index: " + beginIndex + ", "
96               + endIndex);
97     }
98
99     ByteString result;
100     if (substringLength == 0) {
101       result = ByteString.EMPTY;
102     } else {
103       result = new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex,
104           substringLength);
105     }
106     return result;
107   }
108
109   // =================================================================
110   // ByteString -> byte[]
111
112   @Override
113   protected void copyToInternal(byte[] target, int sourceOffset, 
114       int targetOffset, int numberToCopy) {
115     // Optimized form, not for subclasses, since we don't call
116     // getOffsetIntoBytes() or check the 'numberToCopy' parameter.
117     System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
118   }
119
120   @Override
121   public void copyTo(ByteBuffer target) {
122     target.put(bytes, getOffsetIntoBytes(), size());  // Copies bytes
123   }
124
125   @Override
126   public ByteBuffer asReadOnlyByteBuffer() {
127     ByteBuffer byteBuffer =
128         ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size());
129     return byteBuffer.asReadOnlyBuffer();
130   }
131
132   @Override
133   public List<ByteBuffer> asReadOnlyByteBufferList() {
134     // Return the ByteBuffer generated by asReadOnlyByteBuffer() as a singleton
135     List<ByteBuffer> result = new ArrayList<ByteBuffer>(1);
136     result.add(asReadOnlyByteBuffer());
137     return result;
138  }
139
140  @Override
141   public void writeTo(OutputStream outputStream) throws IOException {
142     outputStream.write(toByteArray());
143   }
144
145   @Override
146   public String toString(String charsetName)
147       throws UnsupportedEncodingException {
148     return new String(bytes, getOffsetIntoBytes(), size(), charsetName);
149   }
150
151   // =================================================================
152   // UTF-8 decoding
153
154   @Override
155   public boolean isValidUtf8() {
156     int offset = getOffsetIntoBytes();
157     return Utf8.isValidUtf8(bytes, offset, offset + size());
158   }
159
160   @Override
161   protected int partialIsValidUtf8(int state, int offset, int length) {
162     int index = getOffsetIntoBytes() + offset;
163     return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
164   }
165
166   // =================================================================
167   // equals() and hashCode()
168
169   @Override
170   public boolean equals(Object other) {
171     if (other == this) {
172       return true;
173     }
174     if (!(other instanceof ByteString)) {
175       return false;
176     }
177
178     if (size() != ((ByteString) other).size()) {
179       return false;
180     }
181     if (size() == 0) {
182       return true;
183     }
184
185     if (other instanceof LiteralByteString) {
186       return equalsRange((LiteralByteString) other, 0, size());
187     } else if (other instanceof RopeByteString) {
188       return other.equals(this);
189     } else {
190       throw new IllegalArgumentException(
191           "Has a new type of ByteString been created? Found "
192               + other.getClass());
193     }
194   }
195
196   /**
197    * Check equality of the substring of given length of this object starting at
198    * zero with another {@code LiteralByteString} substring starting at offset.
199    *
200    * @param other  what to compare a substring in
201    * @param offset offset into other
202    * @param length number of bytes to compare
203    * @return true for equality of substrings, else false.
204    */
205   boolean equalsRange(LiteralByteString other, int offset, int length) {
206     if (length > other.size()) {
207       throw new IllegalArgumentException(
208           "Length too large: " + length + size());
209     }
210     if (offset + length > other.size()) {
211       throw new IllegalArgumentException(
212           "Ran off end of other: " + offset + ", " + length + ", " +
213               other.size());
214     }
215
216     byte[] thisBytes = bytes;
217     byte[] otherBytes = other.bytes;
218     int thisLimit = getOffsetIntoBytes() + length;
219     for (int thisIndex = getOffsetIntoBytes(), otherIndex =
220         other.getOffsetIntoBytes() + offset;
221         (thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
222       if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
223         return false;
224       }
225     }
226     return true;
227   }
228
229   /**
230    * Cached hash value.  Intentionally accessed via a data race, which
231    * is safe because of the Java Memory Model's "no out-of-thin-air values"
232    * guarantees for ints.
233    */
234   private int hash = 0;
235
236   /**
237    * Compute the hashCode using the traditional algorithm from {@link
238    * ByteString}.
239    *
240    * @return hashCode value
241    */
242   @Override
243   public int hashCode() {
244     int h = hash;
245
246     if (h == 0) {
247       int size = size();
248       h = partialHash(size, 0, size);
249       if (h == 0) {
250         h = 1;
251       }
252       hash = h;
253     }
254     return h;
255   }
256
257   @Override
258   protected int peekCachedHashCode() {
259     return hash;
260   }
261
262   @Override
263   protected int partialHash(int h, int offset, int length) {
264     byte[] thisBytes = bytes;
265     for (int i = getOffsetIntoBytes() + offset, limit = i + length; i < limit;
266         i++) {
267       h = h * 31 + thisBytes[i];
268     }
269     return h;
270   }
271
272   // =================================================================
273   // Input stream
274
275   @Override
276   public InputStream newInput() {
277     return new ByteArrayInputStream(bytes, getOffsetIntoBytes(),
278         size());  // No copy
279   }
280
281   @Override
282   public CodedInputStream newCodedInput() {
283     // We trust CodedInputStream not to modify the bytes, or to give anyone
284     // else access to them.
285     return CodedInputStream
286         .newInstance(bytes, getOffsetIntoBytes(), size());  // No copy
287   }
288
289   // =================================================================
290   // ByteIterator
291
292   @Override
293   public ByteIterator iterator() {
294     return new LiteralByteIterator();
295   }
296
297   private class LiteralByteIterator implements ByteIterator {
298     private int position;
299     private final int limit;
300
301     private LiteralByteIterator() {
302       position = 0;
303       limit = size();
304     }
305
306     public boolean hasNext() {
307       return (position < limit);
308     }
309
310     public Byte next() {
311       // Boxing calls Byte.valueOf(byte), which does not instantiate.
312       return nextByte();
313     }
314
315     public byte nextByte() {
316       try {
317         return bytes[position++];
318       } catch (ArrayIndexOutOfBoundsException e) {
319         throw new NoSuchElementException(e.getMessage());
320       }
321     }
322
323     public void remove() {
324       throw new UnsupportedOperationException();
325     }
326   }
327
328   // =================================================================
329   // Internal methods
330
331   @Override
332   protected int getTreeDepth() {
333     return 0;
334   }
335
336   @Override
337   protected boolean isBalanced() {
338     return true;
339   }
340
341   /**
342    * Offset into {@code bytes[]} to use, non-zero for substrings.
343    *
344    * @return always 0 for this class
345    */
346   protected int getOffsetIntoBytes() {
347     return 0;
348   }
349 }