/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 com.google.j2objc.nio.charset;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.UnsupportedCharsetException;
/**
* iOS native charset decoder.
*
* @author Tom Ball
*/
public class IOSCharsetDecoder extends CharsetDecoder {
private byte[] inBuffer;
private char[] charBuffer;
private int outIndex;
protected IOSCharsetDecoder(Charset charset) {
super(charset, 1, 4);
}
@Override
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
if (charBuffer != null) {
while (out.hasRemaining() && outIndex < charBuffer.length) {
out.put(charBuffer[outIndex++]);
}
if (outIndex == charBuffer.length){
charBuffer = null;
}
} else if (in.hasRemaining()) {
String s = decodeImpl(in);
if (s.isEmpty()) {
return CoderResult.UNDERFLOW;
}
if (out.remaining() < s.length()) {
charBuffer = s.toCharArray();
outIndex = 0;
return decodeLoop(in, out);
} else {
out.put(s);
}
}
return CoderResult.UNDERFLOW; // All input data was decoded.
}
private String decodeImpl(ByteBuffer in) {
Charset cs = charset();
if (!(cs instanceof IOSCharset)) {
throw new UnsupportedCharsetException(cs.name());
}
byte[] bytes;
int i;
if (inBuffer != null) {
i = inBuffer.length;
bytes = new byte[i + in.remaining()];
System.arraycopy(inBuffer, 0, bytes, 0, inBuffer.length);
inBuffer = null;
} else {
i = 0;
bytes = new byte[in.remaining()];
}
in.get(bytes, i, bytes.length - i);
String s = decode(bytes, ((IOSCharset) cs).nsEncoding());
if (s.isEmpty()) {
inBuffer = bytes;
} else {
inBuffer = null;
}
return s;
}
private static native String decode(byte[] in, long encoding) /*-[
NSString *result = AUTORELEASE([[NSString alloc] initWithBytes:inArg->buffer_
length:inArg->size_
encoding:(NSStringEncoding) encoding]);
// NSString will return nil if the byte sequence can't be encoded. Since
// that may happen when a byte sequence is larger than a buffer, return
// an empty string so that the caller stashes the partial buffer.
return result ? result : @"";
]-*/;
public int available() {
return charBuffer != null ? (charBuffer.length - outIndex) : 0;
}
}