Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(781)

Side by Side Diff: third_party/protobuf/java/compatibility_tests/v2.5.0/tests/src/main/java/com/google/protobuf/test/ByteStringTest.java

Issue 2590803003: Revert "third_party/protobuf: Update to HEAD (83d681ee2c)" (Closed)
Patch Set: Created 3 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.test;
32 import com.google.protobuf.*;
33
34 import com.google.protobuf.ByteString.Output;
35
36 import junit.framework.TestCase;
37
38 import java.io.ByteArrayInputStream;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.io.OutputStream;
42 import java.io.UnsupportedEncodingException;
43 import java.nio.ByteBuffer;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.NoSuchElementException;
49 import java.util.Random;
50
51 /**
52 * Test methods with implementations in {@link ByteString}, plus do some top-lev el "integration"
53 * tests.
54 *
55 * @author carlanton@google.com (Carl Haverl)
56 */
57 public class ByteStringTest extends TestCase {
58
59 private static final String UTF_16 = "UTF-16";
60
61 static byte[] getTestBytes(int size, long seed) {
62 Random random = new Random(seed);
63 byte[] result = new byte[size];
64 random.nextBytes(result);
65 return result;
66 }
67
68 private byte[] getTestBytes(int size) {
69 return getTestBytes(size, 445566L);
70 }
71
72 private byte[] getTestBytes() {
73 return getTestBytes(1000);
74 }
75
76 // Compare the entire left array with a subset of the right array.
77 private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int l ength) {
78 boolean stillEqual = (left.length == length);
79 for (int i = 0; (stillEqual && i < length); ++i) {
80 stillEqual = (left[i] == right[rightOffset + i]);
81 }
82 return stillEqual;
83 }
84
85 // Returns true only if the given two arrays have identical contents.
86 private boolean isArray(byte[] left, byte[] right) {
87 return left.length == right.length && isArrayRange(left, right, 0, left.leng th);
88 }
89
90 public void testSubstring_BeginIndex() {
91 byte[] bytes = getTestBytes();
92 ByteString substring = ByteString.copyFrom(bytes).substring(500);
93 assertTrue("substring must contain the tail of the string",
94 isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
95 }
96
97 public void testCopyFrom_BytesOffsetSize() {
98 byte[] bytes = getTestBytes();
99 ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
100 assertTrue("copyFrom sub-range must contain the expected bytes",
101 isArrayRange(byteString.toByteArray(), bytes, 500, 200));
102 }
103
104 public void testCopyFrom_Bytes() {
105 byte[] bytes = getTestBytes();
106 ByteString byteString = ByteString.copyFrom(bytes);
107 assertTrue("copyFrom must contain the expected bytes",
108 isArray(byteString.toByteArray(), bytes));
109 }
110
111 public void testCopyFrom_ByteBufferSize() {
112 byte[] bytes = getTestBytes();
113 ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
114 byteBuffer.put(bytes);
115 byteBuffer.position(500);
116 ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
117 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
118 isArrayRange(byteString.toByteArray(), bytes, 500, 200));
119 }
120
121 public void testCopyFrom_ByteBuffer() {
122 byte[] bytes = getTestBytes();
123 ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
124 byteBuffer.put(bytes);
125 byteBuffer.position(500);
126 ByteString byteString = ByteString.copyFrom(byteBuffer);
127 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
128 isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
129 }
130
131 public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
132 String testString = "I love unicode \u1234\u5678 characters";
133 ByteString byteString = ByteString.copyFrom(testString, UTF_16);
134 byte[] testBytes = testString.getBytes(UTF_16);
135 assertTrue("copyFrom string must respect the charset",
136 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
137 }
138
139 public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
140 String testString = "I love unicode \u1234\u5678 characters";
141 ByteString byteString = ByteString.copyFromUtf8(testString);
142 byte[] testBytes = testString.getBytes("UTF-8");
143 assertTrue("copyFromUtf8 string must respect the charset",
144 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
145 }
146
147 public void testCopyFrom_Iterable() {
148 byte[] testBytes = getTestBytes(77777, 113344L);
149 final List<ByteString> pieces = makeConcretePieces(testBytes);
150 // Call copyFrom() on a Collection
151 ByteString byteString = ByteString.copyFrom(pieces);
152 assertTrue("copyFrom a List must contain the expected bytes",
153 isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
154 // Call copyFrom on an iteration that's not a collection
155 ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
156 public Iterator<ByteString> iterator() {
157 return pieces.iterator();
158 }
159 });
160 assertEquals("copyFrom from an Iteration must contain the expected bytes",
161 byteString, byteStringAlt);
162 }
163
164 public void testCopyTo_TargetOffset() {
165 byte[] bytes = getTestBytes();
166 ByteString byteString = ByteString.copyFrom(bytes);
167 byte[] target = new byte[bytes.length + 1000];
168 byteString.copyTo(target, 400);
169 assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
170 isArrayRange(bytes, target, 400, bytes.length));
171 }
172
173 public void testReadFrom_emptyStream() throws IOException {
174 ByteString byteString =
175 ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
176 assertSame("reading an empty stream must result in the EMPTY constant "
177 + "byte string", ByteString.EMPTY, byteString);
178 }
179
180 public void testReadFrom_smallStream() throws IOException {
181 assertReadFrom(getTestBytes(10));
182 }
183
184 public void testReadFrom_mutating() throws IOException {
185 byte[] capturedArray = null;
186 EvilInputStream eis = new EvilInputStream();
187 ByteString byteString = ByteString.readFrom(eis);
188
189 capturedArray = eis.capturedArray;
190 byte[] originalValue = byteString.toByteArray();
191 for (int x = 0; x < capturedArray.length; ++x) {
192 capturedArray[x] = (byte) 0;
193 }
194
195 byte[] newValue = byteString.toByteArray();
196 assertTrue("copyFrom byteBuffer must not grant access to underlying array",
197 Arrays.equals(originalValue, newValue));
198 }
199
200 // Tests sizes that are over multi-segment rope threshold.
201 public void testReadFrom_largeStream() throws IOException {
202 assertReadFrom(getTestBytes(0x100));
203 assertReadFrom(getTestBytes(0x101));
204 assertReadFrom(getTestBytes(0x110));
205 assertReadFrom(getTestBytes(0x1000));
206 assertReadFrom(getTestBytes(0x1001));
207 assertReadFrom(getTestBytes(0x1010));
208 assertReadFrom(getTestBytes(0x10000));
209 assertReadFrom(getTestBytes(0x10001));
210 assertReadFrom(getTestBytes(0x10010));
211 }
212
213 // Tests that IOExceptions propagate through ByteString.readFrom().
214 public void testReadFrom_IOExceptions() {
215 try {
216 ByteString.readFrom(new FailStream());
217 fail("readFrom must throw the underlying IOException");
218
219 } catch (IOException e) {
220 assertEquals("readFrom must throw the expected exception",
221 "synthetic failure", e.getMessage());
222 }
223 }
224
225 // Tests that ByteString.readFrom works with streams that don't
226 // always fill their buffers.
227 public void testReadFrom_reluctantStream() throws IOException {
228 final byte[] data = getTestBytes(0x1000);
229
230 ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
231 assertTrue("readFrom byte stream must contain the expected bytes",
232 isArray(byteString.toByteArray(), data));
233
234 // Same test as above, but with some specific chunk sizes.
235 assertReadFromReluctantStream(data, 100);
236 assertReadFromReluctantStream(data, 248);
237 assertReadFromReluctantStream(data, 249);
238 assertReadFromReluctantStream(data, 250);
239 assertReadFromReluctantStream(data, 251);
240 assertReadFromReluctantStream(data, 0x1000);
241 assertReadFromReluctantStream(data, 0x1001);
242 }
243
244 // Fails unless ByteString.readFrom reads the bytes correctly from a
245 // reluctant stream with the given chunkSize parameter.
246 private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
247 throws IOException {
248 ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
249 assertTrue("readFrom byte stream must contain the expected bytes",
250 isArray(b.toByteArray(), bytes));
251 }
252
253 // Tests that ByteString.readFrom works with streams that implement
254 // available().
255 public void testReadFrom_available() throws IOException {
256 final byte[] data = getTestBytes(0x1001);
257
258 ByteString byteString = ByteString.readFrom(new AvailableStream(data));
259 assertTrue("readFrom byte stream must contain the expected bytes",
260 isArray(byteString.toByteArray(), data));
261 }
262
263 // Fails unless ByteString.readFrom reads the bytes correctly.
264 private void assertReadFrom(byte[] bytes) throws IOException {
265 ByteString byteString =
266 ByteString.readFrom(new ByteArrayInputStream(bytes));
267 assertTrue("readFrom byte stream must contain the expected bytes",
268 isArray(byteString.toByteArray(), bytes));
269 }
270
271 // A stream that fails when read.
272 private static final class FailStream extends InputStream {
273 @Override public int read() throws IOException {
274 throw new IOException("synthetic failure");
275 }
276 }
277
278 // A stream that simulates blocking by only producing 250 characters
279 // per call to read(byte[]).
280 private static class ReluctantStream extends InputStream {
281 protected final byte[] data;
282 protected int pos = 0;
283
284 public ReluctantStream(byte[] data) {
285 this.data = data;
286 }
287
288 @Override public int read() {
289 if (pos == data.length) {
290 return -1;
291 } else {
292 return data[pos++];
293 }
294 }
295
296 @Override public int read(byte[] buf) {
297 return read(buf, 0, buf.length);
298 }
299
300 @Override public int read(byte[] buf, int offset, int size) {
301 if (pos == data.length) {
302 return -1;
303 }
304 int count = Math.min(Math.min(size, data.length - pos), 250);
305 System.arraycopy(data, pos, buf, offset, count);
306 pos += count;
307 return count;
308 }
309 }
310
311 // Same as above, but also implements available().
312 private static final class AvailableStream extends ReluctantStream {
313 public AvailableStream(byte[] data) {
314 super(data);
315 }
316
317 @Override public int available() {
318 return Math.min(250, data.length - pos);
319 }
320 }
321
322 // A stream which exposes the byte array passed into read(byte[], int, int).
323 private static class EvilInputStream extends InputStream {
324 public byte[] capturedArray = null;
325
326 @Override
327 public int read(byte[] buf, int off, int len) {
328 if (capturedArray != null) {
329 return -1;
330 } else {
331 capturedArray = buf;
332 for (int x = 0; x < len; ++x) {
333 buf[x] = (byte) x;
334 }
335 return len;
336 }
337 }
338
339 @Override
340 public int read() {
341 // Purposefully do nothing.
342 return -1;
343 }
344 }
345
346 // A stream which exposes the byte array passed into write(byte[], int, int).
347 private static class EvilOutputStream extends OutputStream {
348 public byte[] capturedArray = null;
349
350 @Override
351 public void write(byte[] buf, int off, int len) {
352 if (capturedArray == null) {
353 capturedArray = buf;
354 }
355 }
356
357 @Override
358 public void write(int ignored) {
359 // Purposefully do nothing.
360 }
361 }
362
363 public void testToStringUtf8() throws UnsupportedEncodingException {
364 String testString = "I love unicode \u1234\u5678 characters";
365 byte[] testBytes = testString.getBytes("UTF-8");
366 ByteString byteString = ByteString.copyFrom(testBytes);
367 assertEquals("copyToStringUtf8 must respect the charset",
368 testString, byteString.toStringUtf8());
369 }
370
371 public void testNewOutput_InitialCapacity() throws IOException {
372 byte[] bytes = getTestBytes();
373 ByteString.Output output = ByteString.newOutput(bytes.length + 100);
374 output.write(bytes);
375 ByteString byteString = output.toByteString();
376 assertTrue(
377 "String built from newOutput(int) must contain the expected bytes",
378 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
379 }
380
381 // Test newOutput() using a variety of buffer sizes and a variety of (fixed)
382 // write sizes
383 public void testNewOutput_ArrayWrite() throws IOException {
384 byte[] bytes = getTestBytes();
385 int length = bytes.length;
386 int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
387 2 * length, 3 * length};
388 int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
389
390 for (int bufferSize : bufferSizes) {
391 for (int writeSize : writeSizes) {
392 // Test writing the entire output writeSize bytes at a time.
393 ByteString.Output output = ByteString.newOutput(bufferSize);
394 for (int i = 0; i < length; i += writeSize) {
395 output.write(bytes, i, Math.min(writeSize, length - i));
396 }
397 ByteString byteString = output.toByteString();
398 assertTrue("String built from newOutput() must contain the expected byte s",
399 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
400 }
401 }
402 }
403
404 // Test newOutput() using a variety of buffer sizes, but writing all the
405 // characters using write(byte);
406 public void testNewOutput_WriteChar() throws IOException {
407 byte[] bytes = getTestBytes();
408 int length = bytes.length;
409 int[] bufferSizes = {0, 1, 128, 256, length / 2,
410 length - 1, length, length + 1,
411 2 * length, 3 * length};
412 for (int bufferSize : bufferSizes) {
413 ByteString.Output output = ByteString.newOutput(bufferSize);
414 for (byte byteValue : bytes) {
415 output.write(byteValue);
416 }
417 ByteString byteString = output.toByteString();
418 assertTrue("String built from newOutput() must contain the expected bytes" ,
419 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
420 }
421 }
422
423 // Test newOutput() in which we write the bytes using a variety of methods
424 // and sizes, and in which we repeatedly call toByteString() in the middle.
425 public void testNewOutput_Mixed() throws IOException {
426 Random rng = new Random(1);
427 byte[] bytes = getTestBytes();
428 int length = bytes.length;
429 int[] bufferSizes = {0, 1, 128, 256, length / 2,
430 length - 1, length, length + 1,
431 2 * length, 3 * length};
432
433 for (int bufferSize : bufferSizes) {
434 // Test writing the entire output using a mixture of write sizes and
435 // methods;
436 ByteString.Output output = ByteString.newOutput(bufferSize);
437 int position = 0;
438 while (position < bytes.length) {
439 if (rng.nextBoolean()) {
440 int count = 1 + rng.nextInt(bytes.length - position);
441 output.write(bytes, position, count);
442 position += count;
443 } else {
444 output.write(bytes[position]);
445 position++;
446 }
447 assertEquals("size() returns the right value", position, output.size());
448 assertTrue("newOutput() substring must have correct bytes",
449 isArrayRange(output.toByteString().toByteArray(),
450 bytes, 0, position));
451 }
452 ByteString byteString = output.toByteString();
453 assertTrue("String built from newOutput() must contain the expected bytes" ,
454 isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
455 }
456 }
457
458 public void testNewOutputEmpty() throws IOException {
459 // Make sure newOutput() correctly builds empty byte strings
460 ByteString byteString = ByteString.newOutput().toByteString();
461 assertEquals(ByteString.EMPTY, byteString);
462 }
463
464 public void testNewOutput_Mutating() throws IOException {
465 Output os = ByteString.newOutput(5);
466 os.write(new byte[] {1, 2, 3, 4, 5});
467 EvilOutputStream eos = new EvilOutputStream();
468 os.writeTo(eos);
469 byte[] capturedArray = eos.capturedArray;
470 ByteString byteString = os.toByteString();
471 byte[] oldValue = byteString.toByteArray();
472 Arrays.fill(capturedArray, (byte) 0);
473 byte[] newValue = byteString.toByteArray();
474 assertTrue("Output must not provide access to the underlying byte array",
475 Arrays.equals(oldValue, newValue));
476 }
477
478 public void testSubstringParity() {
479 byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
480 int start = 512 * 1024 - 3333;
481 int end = 512 * 1024 + 7777;
482 ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start , end);
483 boolean ok = true;
484 for (int i = start; ok && i < end; ++i) {
485 ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
486 }
487 assertTrue("Concrete substring didn't capture the right bytes", ok);
488
489 ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start) ;
490 assertTrue("Substring must be equal to literal string",
491 concreteSubstring.equals(literalString));
492 assertEquals("Substring must have same hashcode as literal string",
493 literalString.hashCode(), concreteSubstring.hashCode());
494 }
495
496 public void testCompositeSubstring() {
497 byte[] referenceBytes = getTestBytes(77748, 113344L);
498
499 List<ByteString> pieces = makeConcretePieces(referenceBytes);
500 ByteString listString = ByteString.copyFrom(pieces);
501
502 int from = 1000;
503 int to = 40000;
504 ByteString compositeSubstring = listString.substring(from, to);
505 byte[] substringBytes = compositeSubstring.toByteArray();
506 boolean stillEqual = true;
507 for (int i = 0; stillEqual && i < to - from; ++i) {
508 stillEqual = referenceBytes[from + i] == substringBytes[i];
509 }
510 assertTrue("Substring must return correct bytes", stillEqual);
511
512 stillEqual = true;
513 for (int i = 0; stillEqual && i < to - from; ++i) {
514 stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
515 }
516 assertTrue("Substring must support byteAt() correctly", stillEqual);
517
518 ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
519 assertTrue("Composite substring must equal a literal substring over the same bytes",
520 compositeSubstring.equals(literalSubstring));
521 assertTrue("Literal substring must equal a composite substring over the same bytes",
522 literalSubstring.equals(compositeSubstring));
523
524 assertEquals("We must get the same hashcodes for composite and literal subst rings",
525 literalSubstring.hashCode(), compositeSubstring.hashCode());
526
527 assertFalse("We can't be equal to a proper substring",
528 compositeSubstring.equals(literalSubstring.substring(0, literalSubstring .size() - 1)));
529 }
530
531 public void testCopyFromList() {
532 byte[] referenceBytes = getTestBytes(77748, 113344L);
533 ByteString literalString = ByteString.copyFrom(referenceBytes);
534
535 List<ByteString> pieces = makeConcretePieces(referenceBytes);
536 ByteString listString = ByteString.copyFrom(pieces);
537
538 assertTrue("Composite string must be equal to literal string",
539 listString.equals(literalString));
540 assertEquals("Composite string must have same hashcode as literal string",
541 literalString.hashCode(), listString.hashCode());
542 }
543
544 public void testConcat() {
545 byte[] referenceBytes = getTestBytes(77748, 113344L);
546 ByteString literalString = ByteString.copyFrom(referenceBytes);
547
548 List<ByteString> pieces = makeConcretePieces(referenceBytes);
549
550 Iterator<ByteString> iter = pieces.iterator();
551 ByteString concatenatedString = iter.next();
552 while (iter.hasNext()) {
553 concatenatedString = concatenatedString.concat(iter.next());
554 }
555
556 assertTrue("Concatenated string must be equal to literal string",
557 concatenatedString.equals(literalString));
558 assertEquals("Concatenated string must have same hashcode as literal string" ,
559 literalString.hashCode(), concatenatedString.hashCode());
560 }
561
562 public void testStartsWith() {
563 byte[] bytes = getTestBytes(1000, 1234L);
564 ByteString string = ByteString.copyFrom(bytes);
565 ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
566 ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
567 assertTrue(string.startsWith(ByteString.EMPTY));
568 assertTrue(string.startsWith(string));
569 assertTrue(string.startsWith(prefix));
570 assertFalse(string.startsWith(suffix));
571 assertFalse(prefix.startsWith(suffix));
572 assertFalse(suffix.startsWith(prefix));
573 assertFalse(ByteString.EMPTY.startsWith(prefix));
574 assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
575 }
576
577 static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
578 List<ByteString> pieces = new ArrayList<ByteString>();
579 // Starting length should be small enough that we'll do some concatenating b y
580 // copying if we just concatenate all these pieces together.
581 for (int start = 0, length = 16; start < referenceBytes.length; start += len gth) {
582 length = (length << 1) - 1;
583 if (start + length > referenceBytes.length) {
584 length = referenceBytes.length - start;
585 }
586 pieces.add(ByteString.copyFrom(referenceBytes, start, length));
587 }
588 return pieces;
589 }
590 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698