Files
msgpack-msgpack-c/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
T
2010-05-22 17:05:17 +09:00

427 lines
9.9 KiB
Java

//
// MessagePack for Java
//
// Copyright (C) 2009-2010 FURUHASHI Sadayuki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.msgpack;
import java.io.IOException;
import java.nio.ByteBuffer;
//import java.math.BigInteger;
abstract class BufferedUnpackerImpl extends UnpackerImpl {
int offset = 0;
int filled = 0;
byte[] buffer = null;
private ByteBuffer castBuffer = ByteBuffer.allocate(8);
abstract boolean fill() throws IOException;
final boolean next(UnpackResult result) throws IOException, UnpackException {
if(filled == 0) {
if(!fill()) {
return false;
}
}
do {
int noffset = super.execute(buffer, offset, filled);
if(noffset <= offset) {
if(!fill()) {
return false;
}
continue;
}
offset = noffset;
} while(!super.isFinished());
Object obj = super.getData();
super.reset();
result.done(obj);
return true;
}
private final void more(int require) throws IOException, UnpackException {
while(filled - offset < require) {
if(!fill()) {
// FIXME
throw new UnpackException("insufficient buffer");
}
}
}
private final boolean tryMore(int require) throws IOException, UnpackException {
while(filled - offset < require) {
if(!fill()) {
return false;
}
}
return true;
}
private final void advance(int length) {
offset += length;
}
final byte unpackByte() throws IOException, MessageTypeException {
int o = unpackInt();
if(0x7f < o || o < -0x80) {
throw new MessageTypeException();
}
return (byte)o;
}
final short unpackShort() throws IOException, MessageTypeException {
int o = unpackInt();
if(0x7fff < o || o < -0x8000) {
throw new MessageTypeException();
}
return (short)o;
}
final int unpackInt() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
if((b & 0x80) == 0 || (b & 0xe0) == 0xe0) { // Fixnum
advance(1);
return (int)b;
}
switch(b & 0xff) {
case 0xcc: // unsigned int 8
more(2);
advance(2);
return (int)((short)buffer[offset+1] & 0xff);
case 0xcd: // unsigned int 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (int)((int)castBuffer.getShort(0) & 0xffff);
case 0xce: // unsigned int 32
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
{
int o = castBuffer.getInt(0);
if(o < 0) {
throw new MessageTypeException();
}
advance(5);
return o;
}
case 0xcf: // unsigned int 64
more(9);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 8);
{
long o = castBuffer.getLong(0);
if(o < 0 || o > 0x7fffffffL) {
throw new MessageTypeException();
}
advance(9);
return (int)o;
}
case 0xd0: // signed int 8
more(2);
advance(2);
return (int)buffer[offset+1];
case 0xd1: // signed int 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (int)castBuffer.getShort(0);
case 0xd2: // signed int 32
more(4);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(4);
return (int)castBuffer.getInt(0);
case 0xd3: // signed int 64
more(9);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 8);
{
long o = castBuffer.getLong(0);
if(0x7fffffffL < o || o < -0x80000000L) {
throw new MessageTypeException();
}
advance(9);
return (int)o;
}
default:
throw new MessageTypeException();
}
}
final long unpackLong() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
if((b & 0x80) == 0 || (b & 0xe0) == 0xe0) { // Fixnum
advance(1);
return (long)b;
}
switch(b & 0xff) {
case 0xcc: // unsigned int 8
more(2);
advance(2);
return (long)((short)buffer[offset+1] & 0xff);
case 0xcd: // unsigned int 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (long)((int)castBuffer.getShort(0) & 0xffff);
case 0xce: // unsigned int 32
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(5);
return ((long)castBuffer.getInt(0) & 0xffffffffL);
case 0xcf: // unsigned int 64
more(9);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 8);
{
long o = castBuffer.getLong(0);
if(o < 0) {
// FIXME
throw new MessageTypeException("uint 64 bigger than 0x7fffffff is not supported");
}
advance(9);
return o;
}
case 0xd0: // signed int 8
more(2);
advance(2);
return (long)buffer[offset+1];
case 0xd1: // signed int 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (long)castBuffer.getShort(0);
case 0xd2: // signed int 32
more(4);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(4);
return (long)castBuffer.getInt(0);
case 0xd3: // signed int 64
more(9);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 8);
advance(9);
return (long)castBuffer.getLong(0);
default:
throw new MessageTypeException();
}
}
final float unpackFloat() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
switch(b & 0xff) {
case 0xca: // float
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(5);
return castBuffer.getFloat(0);
case 0xcb: // double
more(9);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 8);
advance(9);
// FIXME overflow check
return (float)castBuffer.getDouble(0);
default:
throw new MessageTypeException();
}
}
final double unpackDouble() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
switch(b & 0xff) {
case 0xca: // float
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(5);
return (double)castBuffer.getFloat(0);
case 0xcb: // double
more(9);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 8);
advance(9);
return castBuffer.getDouble(0);
default:
throw new MessageTypeException();
}
}
final Object unpackNull() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset] & 0xff;
if(b != 0xc0) { // nil
throw new MessageTypeException();
}
advance(1);
return null;
}
final boolean tryUnpackNull() throws IOException {
if(!tryMore(1)) {
return false;
}
int b = buffer[offset] & 0xff;
if(b != 0xc0) { // nil
return false;
}
advance(1);
return true;
}
final boolean unpackBoolean() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset] & 0xff;
if(b == 0xc2) { // false
advance(1);
return false;
} else if(b == 0xc3) { // true
advance(1);
return true;
} else {
throw new MessageTypeException();
}
}
final int unpackArray() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
if((b & 0xf0) == 0x90) { // FixArray
advance(1);
return (int)(b & 0x0f);
}
switch(b & 0xff) {
case 0xdc: // array 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (int)castBuffer.getShort(0) & 0xffff;
case 0xdd: // array 32
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(5);
// FIXME overflow check
return castBuffer.getInt(0) & 0x7fffffff;
default:
throw new MessageTypeException();
}
}
final int unpackMap() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
if((b & 0xf0) == 0x80) { // FixMap
advance(1);
return (int)(b & 0x0f);
}
switch(b & 0xff) {
case 0xde: // map 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (int)castBuffer.getShort(0) & 0xffff;
case 0xdf: // map 32
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(5);
// FIXME overflow check
return castBuffer.getInt(0) & 0x7fffffff;
default:
throw new MessageTypeException();
}
}
final int unpackRaw() throws IOException, MessageTypeException {
more(1);
int b = buffer[offset];
if((b & 0xe0) == 0xa0) { // FixRaw
advance(1);
return (int)(b & 0x1f);
}
switch(b & 0xff) {
case 0xda: // raw 16
more(3);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 2);
advance(3);
return (int)castBuffer.getShort(0) & 0xffff;
case 0xdb: // raw 32
more(5);
castBuffer.rewind();
castBuffer.put(buffer, offset+1, 4);
advance(5);
// FIXME overflow check
return castBuffer.getInt(0) & 0x7fffffff;
default:
throw new MessageTypeException();
}
}
final byte[] unpackRawBody(int length) throws IOException {
more(length);
byte[] bytes = new byte[length];
System.arraycopy(buffer, offset, bytes, 0, length);
advance(length);
return bytes;
}
final byte[] unpackByteArray() throws IOException, MessageTypeException {
int length = unpackRaw();
return unpackRawBody(length);
}
final String unpackString() throws IOException, MessageTypeException {
int length = unpackRaw();
more(length);
String s;
try {
s = new String(buffer, offset, length, "UTF-8");
} catch (Exception e) {
throw new MessageTypeException();
}
advance(length);
return s;
}
final Object unpackObject() throws IOException {
UnpackResult result = new UnpackResult();
if(!next(result)) {
super.reset();
throw new UnpackException("insufficient buffer");
}
return result.getData();
}
}