|
16 | 16 |
|
17 | 17 | package com.mongodb.internal.connection;
|
18 | 18 |
|
| 19 | +import org.bson.BsonSerializationException; |
19 | 20 | import org.bson.ByteBuf;
|
20 | 21 | import org.bson.io.OutputBuffer;
|
21 | 22 |
|
|
25 | 26 | import java.util.ArrayList;
|
26 | 27 | import java.util.List;
|
27 | 28 |
|
| 29 | +import static com.mongodb.assertions.Assertions.assertFalse; |
28 | 30 | import static com.mongodb.assertions.Assertions.assertTrue;
|
29 | 31 | import static com.mongodb.assertions.Assertions.notNull;
|
| 32 | +import static java.lang.String.format; |
30 | 33 |
|
31 | 34 | /**
|
32 | 35 | * <p>This class is not part of the public API and may be removed or changed at any time</p>
|
@@ -100,6 +103,11 @@ private ByteBuf getCurrentByteBuffer() {
|
100 | 103 | return getByteBufferAtIndex(curBufferIndex);
|
101 | 104 | }
|
102 | 105 |
|
| 106 | + private ByteBuf getNextByteBuffer() { |
| 107 | + assertFalse(bufferList.get(curBufferIndex).hasRemaining()); |
| 108 | + return getByteBufferAtIndex(++curBufferIndex); |
| 109 | + } |
| 110 | + |
103 | 111 | private ByteBuf getByteBufferAtIndex(final int index) {
|
104 | 112 | if (bufferList.size() < index + 1) {
|
105 | 113 | bufferList.add(bufferProvider.getBuffer(index >= (MAX_SHIFT - INITIAL_SHIFT)
|
@@ -282,4 +290,128 @@ private static final class BufferPositionPair {
|
282 | 290 | this.position = position;
|
283 | 291 | }
|
284 | 292 | }
|
| 293 | + |
| 294 | + protected int writeCharacters(final String str, final boolean checkNullTermination) { |
| 295 | + int len = str.length(); |
| 296 | + int sp = 0; |
| 297 | + int prevPos = position; |
| 298 | + |
| 299 | + ByteBuf buf = getCurrentByteBuffer(); |
| 300 | + int currBufferPos = buf.position(); |
| 301 | + int limit = buf.limit(); |
| 302 | + int remaining = limit - currBufferPos; |
| 303 | + |
| 304 | + if (buf instanceof PowerOfTwoBufferPool.PooledByteBufNIO && buf.hasArray()) { |
| 305 | + byte[] dst = buf.array(); |
| 306 | + if (remaining >= str.length() + 1) { |
| 307 | + sp = writeOnArrayAscii(str, dst, currBufferPos, checkNullTermination); |
| 308 | + currBufferPos += sp; |
| 309 | + if (sp == len) { |
| 310 | + dst[currBufferPos++] = 0; |
| 311 | + position += sp + 1; |
| 312 | + buf.position(currBufferPos); |
| 313 | + return sp + 1; |
| 314 | + } |
| 315 | + position += sp; |
| 316 | + buf.position(currBufferPos); |
| 317 | + } |
| 318 | + } |
| 319 | + |
| 320 | + while (sp < len) { |
| 321 | + remaining = limit - currBufferPos; |
| 322 | + int c = str.charAt(sp); |
| 323 | + |
| 324 | + if (checkNullTermination && c == 0x0) { |
| 325 | + throw new BsonSerializationException( |
| 326 | + format("BSON cstring '%s' is not valid because it contains a null character " + "at index %d", str, sp)); |
| 327 | + } |
| 328 | + |
| 329 | + if (c < 0x80) { |
| 330 | + if (remaining == 0) { |
| 331 | + buf = getNextByteBuffer(); |
| 332 | + currBufferPos = 0; |
| 333 | + limit = buf.limit(); |
| 334 | + } |
| 335 | + buf.put((byte) c); |
| 336 | + currBufferPos++; |
| 337 | + position++; |
| 338 | + } else if (c < 0x800) { |
| 339 | + if (remaining < 2) { |
| 340 | + write((byte) (0xc0 + (c >> 6))); |
| 341 | + write((byte) (0x80 + (c & 0x3f))); |
| 342 | + |
| 343 | + buf = getCurrentByteBuffer(); |
| 344 | + currBufferPos = buf.position(); |
| 345 | + limit = buf.limit(); |
| 346 | + } else { |
| 347 | + buf.put((byte) (0xc0 + (c >> 6))); |
| 348 | + buf.put((byte) (0x80 + (c & 0x3f))); |
| 349 | + currBufferPos += 2; |
| 350 | + position += 2; |
| 351 | + } |
| 352 | + } else { |
| 353 | + c = Character.codePointAt(str, sp); |
| 354 | + if (c < 0x10000) { |
| 355 | + if (remaining < 3) { |
| 356 | + write((byte) (0xe0 + (c >> 12))); |
| 357 | + write((byte) (0x80 + ((c >> 6) & 0x3f))); |
| 358 | + write((byte) (0x80 + (c & 0x3f))); |
| 359 | + |
| 360 | + buf = getCurrentByteBuffer(); |
| 361 | + currBufferPos = buf.position(); |
| 362 | + limit = buf.limit(); |
| 363 | + } else { |
| 364 | + buf.put((byte) (0xe0 + (c >> 12))); |
| 365 | + buf.put((byte) (0x80 + ((c >> 6) & 0x3f))); |
| 366 | + buf.put((byte) (0x80 + (c & 0x3f))); |
| 367 | + currBufferPos += 3; |
| 368 | + position += 3; |
| 369 | + } |
| 370 | + } else { |
| 371 | + if (remaining < 4) { |
| 372 | + write((byte) (0xf0 + (c >> 18))); |
| 373 | + write((byte) (0x80 + ((c >> 12) & 0x3f))); |
| 374 | + write((byte) (0x80 + ((c >> 6) & 0x3f))); |
| 375 | + write((byte) (0x80 + (c & 0x3f))); |
| 376 | + |
| 377 | + buf = getCurrentByteBuffer(); |
| 378 | + currBufferPos = buf.position(); |
| 379 | + limit = buf.limit(); |
| 380 | + } else { |
| 381 | + buf.put((byte) (0xf0 + (c >> 18))); |
| 382 | + buf.put((byte) (0x80 + ((c >> 12) & 0x3f))); |
| 383 | + buf.put((byte) (0x80 + ((c >> 6) & 0x3f))); |
| 384 | + buf.put((byte) (0x80 + (c & 0x3f))); |
| 385 | + currBufferPos += 4; |
| 386 | + position += 4; |
| 387 | + } |
| 388 | + } |
| 389 | + } |
| 390 | + sp += Character.charCount(c); |
| 391 | + } |
| 392 | + |
| 393 | + getCurrentByteBuffer().put((byte) 0); |
| 394 | + position++; |
| 395 | + return position - prevPos; |
| 396 | + } |
| 397 | + |
| 398 | + private static int writeOnArrayAscii(final String str, |
| 399 | + final byte[] dst, |
| 400 | + final int currentPos, |
| 401 | + final boolean checkNullTermination) { |
| 402 | + int pos = currentPos; |
| 403 | + int sp = 0; |
| 404 | + for (; sp < str.length(); sp++, pos++) { |
| 405 | + char c = str.charAt(sp); |
| 406 | + if (checkNullTermination && c == 0) { |
| 407 | + throw new BsonSerializationException( |
| 408 | + format("BSON cstring '%s' is not valid because it contains a null character " + "at index %d", str, sp)); |
| 409 | + } |
| 410 | + if (c >= 0x80) { |
| 411 | + break; |
| 412 | + } |
| 413 | + dst[pos] = (byte) c; |
| 414 | + } |
| 415 | + return sp; |
| 416 | + } |
285 | 417 | }
|
0 commit comments