blob: ddc83db268e0480f27956bd20222ae98b218b8d6 (
plain) (
tree)
|
|
/* __ *\
** ________ ___ / / ___ __ ____ Scala.js API **
** / __/ __// _ | / / / _ | __ / // __/ (c) 2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | |__/ /____/ **
** |/____/ **
\* */
package scala.scalajs.niocharset
import scala.annotation.tailrec
import java.nio._
import java.nio.charset._
/** This is a very specific common implementation for ISO_8859_1 and US_ASCII.
* Only a single constant changes between the two algorithms (`maxValue`).
* No attempt was made at generalizing this to other potential charsets.
*
* `maxValue` is therefore either 0xff (ISO_8859_1) or 0x7f (US_ASCII).
*/
private[niocharset] abstract class ISO_8859_1_And_US_ASCII_Common protected (
name: String, aliases: Array[String],
private val maxValue: Int) extends Charset(name, aliases) {
def contains(that: Charset): Boolean = that match {
case that: ISO_8859_1_And_US_ASCII_Common => this.maxValue >= that.maxValue
case _ => false
}
def newDecoder(): CharsetDecoder = new Decoder
def newEncoder(): CharsetEncoder = new Encoder
private class Decoder extends CharsetDecoder(
ISO_8859_1_And_US_ASCII_Common.this, 1.0f, 1.0f) {
def decodeLoop(in: ByteBuffer, out: CharBuffer): CoderResult = {
val maxValue = ISO_8859_1_And_US_ASCII_Common.this.maxValue
val inRemaining = in.remaining
if (inRemaining == 0) {
CoderResult.UNDERFLOW
} else {
val outRemaining = out.remaining
val overflow = outRemaining < inRemaining
val rem = if (overflow) outRemaining else inRemaining
if (in.hasArray && out.hasArray) {
val inArr = in.array
val inOffset = in.arrayOffset
val inStart = in.position + inOffset
val inEnd = inStart + rem
val outArr = out.array
val outOffset = out.arrayOffset
val outStart = out.position + outOffset
var inPos = inStart
var outPos = outStart
while (inPos != inEnd) {
// Apparently ignoring the bit 7 in US_ASCII is the expected behavior
outArr(outPos) = (inArr(inPos).toInt & maxValue).toChar
inPos += 1
outPos += 1
}
in.position(inPos - inOffset)
out.position(outPos - outOffset)
} else {
/* Here, it's fine to read all the remaining bytes from the input,
* because we will *always* use all of them.
*/
var i = 0
while (i != rem) {
// Apparently ignoring the bit 7 in US_ASCII is the expected behavior
out.put((in.get(i).toInt & maxValue).toChar)
i += 1
}
}
if (overflow) CoderResult.OVERFLOW
else CoderResult.UNDERFLOW
}
}
}
private class Encoder extends CharsetEncoder(
ISO_8859_1_And_US_ASCII_Common.this, 1.0f, 1.0f) {
def encodeLoop(in: CharBuffer, out: ByteBuffer): CoderResult = {
import java.lang.Character.{MIN_SURROGATE, MAX_SURROGATE}
val maxValue = ISO_8859_1_And_US_ASCII_Common.this.maxValue
val inRemaining = in.remaining
if (inRemaining == 0) {
CoderResult.UNDERFLOW
} else {
if (in.hasArray && out.hasArray) {
val outRemaining = out.remaining
val overflow = outRemaining < inRemaining
val rem = if (overflow) outRemaining else inRemaining
val inArr = in.array
val inOffset = in.arrayOffset
val inStart = in.position + inOffset
val inEnd = inStart + rem
val outArr = out.array
val outOffset = out.arrayOffset
val outStart = out.position + outOffset
@inline
@tailrec
def loop(inPos: Int, outPos: Int): CoderResult = {
@inline
def finalize(result: CoderResult): CoderResult = {
in.position(inPos - inOffset)
out.position(outPos - outOffset)
result
}
if (inPos == inEnd) {
finalize {
if (overflow) CoderResult.OVERFLOW
else CoderResult.UNDERFLOW
}
} else {
val c = inArr(inPos)
if (c <= maxValue) {
outArr(outPos) = c.toByte
loop(inPos+1, outPos+1)
} else {
finalize {
if (Character.isLowSurrogate(c)) {
CoderResult.malformedForLength(1)
} else if (Character.isHighSurrogate(c)) {
if (inPos + 1 < in.limit) {
val c2 = inArr(inPos+1)
if (Character.isLowSurrogate(c2))
CoderResult.unmappableForLength(2)
else
CoderResult.malformedForLength(1)
} else {
CoderResult.UNDERFLOW
}
} else {
CoderResult.unmappableForLength(1)
}
}
}
}
}
loop(inStart, outStart)
} else {
// Not both have arrays
@inline
@tailrec
def loop(): CoderResult = {
if (!in.hasRemaining) {
CoderResult.UNDERFLOW
} else if (!out.hasRemaining) {
CoderResult.OVERFLOW
} else {
val c = in.get()
if (c <= maxValue) {
out.put(c.toByte)
loop()
} else {
if (Character.isLowSurrogate(c)) {
in.position(in.position - 1)
CoderResult.malformedForLength(1)
} else if (Character.isHighSurrogate(c)) {
if (in.hasRemaining) {
val c2 = in.get()
in.position(in.position - 2)
if (Character.isLowSurrogate(c2)) {
CoderResult.unmappableForLength(2)
} else {
CoderResult.malformedForLength(1)
}
} else {
in.position(in.position - 1)
CoderResult.UNDERFLOW
}
} else {
in.position(in.position - 1)
CoderResult.unmappableForLength(1)
}
}
}
}
loop()
}
}
}
}
}
|