docs: public byte[] readRawBytes(final int size) throws IOException
      {
          if (size < 0)
          {
              throw ProtobufException.negativeSize();
          }
  
          if (totalBytesRetired + bufferPos + size > currentLimit)
          {
              // Read to the end of the stream anyway.
              skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
              // Then fail.
              throw ProtobufException.truncatedMessage();
          }
  
          if (size <= bufferSize - bufferPos)
          {
              // We have all the bytes we need already.
              final byte[] bytes = new byte[size];
              System.arraycopy(buffer, bufferPos, bytes, 0, size);
              bufferPos += size;
              return bytes;
          }
          else if (size < buffer.length)
          {
              // Reading more bytes than are in the buffer, but not an excessive number
              // of bytes. We can safely allocate the resulting array ahead of time.
  
              // First copy what we have.
              final byte[] bytes = new byte[size];
              int pos = bufferSize - bufferPos;
              System.arraycopy(buffer, bufferPos, bytes, 0, pos);
              bufferPos = bufferSize;
  
              // We want to use refillBuffer() and then copy from the buffer into our
              // byte array rather than reading directly into our byte array because
              // the input may be unbuffered.
              refillBuffer(true);
  
              while (size - pos > bufferSize)
              {
                  System.arraycopy(buffer, 0, bytes, pos, bufferSize);
                  pos += bufferSize;
                  bufferPos = bufferSize;
                  refillBuffer(true);
              }
  
              System.arraycopy(buffer, 0, bytes, pos, size - pos);
              bufferPos = size - pos;
  
              return bytes;
          }
          else
          {
              // The size is very large. For security reasons, we can't allocate the
              // entire byte array yet. The size comes directly from the input, so a
              // maliciously-crafted message could provide a bogus very large size in
              // order to trick the app into allocating a lot of memory. We avoid this
              // by allocating and reading only a small chunk at a time, so that the
              // malicious message must actually *be* extremely large to cause
              // problems. Meanwhile, we limit the allowed size of a message elsewhere.
  
              // Remember the buffer markers since we'll have to copy the bytes out of
              // it later.
              final int originalBufferPos = bufferPos;
              final int originalBufferSize = bufferSize;
  
              // Mark the current buffer consumed.
              totalBytesRetired += bufferSize;
              bufferPos = 0;
              bufferSize = 0;
  
              // Read all the rest of the bytes we need.
              int sizeLeft = size - (originalBufferSize - originalBufferPos);
              final List<byte[]> chunks = new ArrayList<byte[]>();
  
              while (sizeLeft > 0)
              {
                  final byte[] chunk = new byte[Math.min(sizeLeft, buffer.length)];
                  int pos = 0;
                  while (pos < chunk.length)
                  {
                      final int n = (input == null) ? -1 :
                              input.read(chunk, pos, chunk.length - pos);
                      if (n == -1)
                      {
                          throw ProtobufException.truncatedMessage();
                      }
                      totalBytesRetired += n;
                      pos += n;
                  }
                  sizeLeft -= chunk.length;
                  chunks.add(chunk);
              }
  
              // OK, got everything. Now concatenate it all into one buffer.
              final byte[] bytes = new byte[size];
  
              // Start by copying the leftover bytes from this.buffer.
              int pos = originalBufferSize - originalBufferPos;
              System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
  
              // And now all the chunks.
              for (final byte[] chunk : chunks)
              {
                  System.arraycopy(chunk, 0, bytes, pos, chunk.length);
                  pos += chunk.length;
              }
  
              // Done.
              return bytes;
          }
      }