All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.protobuf.ByteString.scala Maven / Gradle / Ivy

The newest version!
package com.google.protobuf

import java.io.OutputStream
import java.io.UnsupportedEncodingException
import java.nio.charset.Charset
import java.nio.charset.UnsupportedCharsetException

import scala.collection.generic.CanBuildFrom
import scala.collection._

class ByteString private (bytesIn: Array[Byte], start: Int, len: Int)
  extends IndexedSeq[Byte] with IndexedSeqOptimized[Byte, ByteString] {

  val bytes = bytesIn

  def length: Int = len

  private lazy val hash = {
    var h = length;
    {
      val upperLimit = start + len
      var i = start
      while (i < upperLimit) {
        h = h * 31 + bytes(i)
        i += 1
      }
    }
    if (h == 0) {
      h = 1
    }
    h
  }

  override protected[this] def newBuilder: mutable.Builder[Byte, ByteString] =
    ByteString.newBuilder

  def apply(i: Int): Byte =
    if (i < 0 || i >= start + len) throw new IndexOutOfBoundsException(i.toString)
    else bytes(start + i)

  override def slice(from: Int, until: Int): ByteString = {
    val lo = math.max(from, 0)
    val hi = math.max(math.min(until, len), lo)
    new ByteString(bytes, start + lo, hi - lo)
  }

  override def equals(that: Any): Boolean = {
    that match {
      case other: ByteString =>
        other.eq(this) || (
          (length == other.length) && (
            length == 0 || (
              equalsRange(other))))
      case _ => false
    }
  }

  override def hashCode() = hash

/**
  * Check equality of the content of two ByteStrings.
  */
  private def equalsRange(other: ByteString): Boolean =
    other.length == length && {
      var thisIndex = start
      var otherIndex = 0
      val upperLimit = start + len
      while (thisIndex < upperLimit) {
        if (bytes(thisIndex) != other.bytes(otherIndex)) {
          return false
        }
        thisIndex += 1
        otherIndex += 1
      }
      true
    }

  def writeTo(out: OutputStream) = {
    out.write(bytes, start, len)
  }

  /**
    * Copies bytes into a buffer.
    *
    * @param target       buffer to copy into
    * @param sourceOffset offset within these bytes
    * @param targetOffset offset within the target buffer
    * @param numberToCopy number of bytes to copy
    * @throws IndexOutOfBoundsException if an offset or size is negative or too
    *                                   large
    */
  def copyTo(target: Array[Byte], sourceOffset: Int, targetOffset: Int, numberToCopy: Int) {
    if (sourceOffset < 0) {
      throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset)
    }
    if (targetOffset < 0) {
      throw new IndexOutOfBoundsException("Target offset < 0: " + targetOffset)
    }
    if (numberToCopy < 0) {
      throw new IndexOutOfBoundsException("Length < 0: " + numberToCopy)
    }
    if (sourceOffset + numberToCopy > size) {
      throw new IndexOutOfBoundsException("Source end offset < 0: " + (sourceOffset + numberToCopy))
    }
    if (targetOffset + numberToCopy > target.length) {
      throw new IndexOutOfBoundsException("Target end offset < 0: " + (targetOffset + numberToCopy))
    }
    if (numberToCopy > 0) {
      System.arraycopy(bytes, start + sourceOffset, target, targetOffset, numberToCopy);
    }
  }

  def newCodedInput(): CodedInputStream = CodedInputStream.newInstance(bytes)

  def newInput(): java.io.InputStream = new java.io.ByteArrayInputStream(bytes, start, len)

  private def toStringInternal(charset: Charset) = {
    new String(bytes, start, len, charset)
  }

  @throws[UnsupportedEncodingException]
  def toString(charsetName: String): String = {
    try {
      toString(Charset.forName(charsetName))
    } catch {
      case e: UnsupportedCharsetException =>
        val exception = new UnsupportedEncodingException(charsetName)
        exception.initCause(e)
        throw exception
    }
  }

  def toStringUtf8(): String = toString(Internal.UTF_8)

  /**
   * Constructs a new {@code String} by decoding the bytes using the
   * specified charset. Returns the same empty String if empty.
   *
   * @param charset encode using this charset
   * @return new string
   */
  def toString(charset: Charset): String = {
    if (isEmpty) "" else toStringInternal(charset)
  }

  def toByteArray(): Array[Byte] = {
    val dest = new Array[Byte](length)
    System.arraycopy(bytes, start, dest, 0, len)
    dest
  }
}

object ByteString {
  def newBuilder: mutable.Builder[Byte, ByteString] =
    Vector.newBuilder[Byte].mapResult {
      v: Vector[Byte] =>
        val r = new Array[Byte](v.size)
        new ByteString(v.toArray, 0, v.size)
    }

  implicit def canBuildFrom: CanBuildFrom[ByteString, Byte, ByteString] =
    new CanBuildFrom[ByteString, Byte, ByteString] {
      def apply(from: ByteString): mutable.Builder[Byte, ByteString] = newBuilder
      def apply(): mutable.Builder[Byte, ByteString] = newBuilder
    }

  def copyFrom(bytes: Array[Byte], offset: Int, size: Int) = {
    val copy: Array[Byte] = new Array[Byte](size)
    System.arraycopy(bytes, offset, copy, 0, size)
    new ByteString(copy, 0, size)
  }

  def copyFrom(bytes: Array[Byte]): ByteString = copyFrom(bytes, 0, bytes.length)

  def copyFromUtf8(text: String): ByteString = copyFrom(text.getBytes(Internal.UTF_8))

  private[protobuf] def useBuffer(bytes: Array[Byte]) =
    new ByteString(bytes, 0, bytes.length)

  final val EMPTY = new ByteString(new Array[Byte](0), 0, 0)

  def newOutput() = new Output()

  class Output extends OutputStream {
    private val bytes = new mutable.ArrayBuffer[Byte]
    
    override def write(b: Int) {
      bytes += b.toByte
    }

    override def write(b: Array[Byte], offset: Int, len: Int) {
      bytes ++= b.slice(offset, offset + len)
    }

    def toByteString(): ByteString = ByteString.copyFrom(bytes.toArray)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy