/* * 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.CharsetEncoder; import java.nio.charset.CoderResult; /*-[ #include <iconv.h> #define BYTES_PER_CHAR (sizeof(jchar) / sizeof(jbyte)) ]-*/ /** * Native charset encoder using libiconv. * * @author Keith Stanger */ public class IconvCharsetEncoder extends CharsetEncoder { private final long iconvName; private long iconvHandle; protected IconvCharsetEncoder( Charset charset, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, long iconvName) { super(charset, averageBytesPerChar, maxBytesPerChar, replacement, /* trusted */ true); this.iconvName = iconvName; } @Override protected native void implReset() /*-[ iconv_close((iconv_t)self->iconvHandle_); self->iconvHandle_ = 0LL; ]-*/; @Override protected CoderResult implFlush(ByteBuffer out) { return encodeLoop(null, out); } @Override protected native CoderResult encodeLoop(CharBuffer inBuf, ByteBuffer outBuf) /*-[ jint inSize = 0; if (inBuf) { inSize = [inBuf remaining]; if (inSize <= 0) { return JavaNioCharsetCoderResult_get_UNDERFLOW(); } } iconv_t coder = (iconv_t)self->iconvHandle_; if (coder == NULL) { coder = iconv_open( (const char *)self->iconvName_, CFByteOrderGetCurrent() == CFByteOrderLittleEndian ? "UTF-16LE" : "UTF-16BE"); self->iconvHandle_ = (jlong)coder; } IOSCharArray *inArray = nil; char *inRaw = NULL; if (inBuf) { if ([inBuf hasArray]) { jint pos = [inBuf position]; inRaw = (char *)&[inBuf array]->buffer_[[inBuf arrayOffset] + pos]; [inBuf positionWithInt:pos + inSize]; } else { inArray = [IOSCharArray newArrayWithLength:inSize]; [inBuf getWithCharArray:inArray]; inRaw = (char *)inArray->buffer_; } } size_t inRawBytes = inSize * BYTES_PER_CHAR; jint outSize = [outBuf remaining]; IOSByteArray *outArray = nil; char *outRaw = NULL; size_t outRawBytes = outSize; if ([outBuf hasArray]) { outRaw = (char *)&[outBuf array]->buffer_[[outBuf arrayOffset] + [outBuf position]]; } else if (outSize > 0) { outArray = [IOSByteArray newArrayWithLength:outSize]; outRaw = (char *)outArray->buffer_; } size_t ret = iconv(coder, &inRaw, &inRawBytes, &outRaw, &outRawBytes); JavaNioCharsetCoderResult *result = JavaNioCharsetCoderResult_get_UNDERFLOW(); if (ret == (size_t)-1) { switch (errno) { case EILSEQ: case EINVAL: result = JavaNioCharsetCoderResult_malformedForLengthWithInt_(1); break; case E2BIG: result = JavaNioCharsetCoderResult_get_OVERFLOW(); break; } } if (inRawBytes > 0) { [inBuf positionWithInt:[inBuf position] - ((jint)inRawBytes / BYTES_PER_CHAR)]; } jint encodedBytes = outSize - (jint)outRawBytes; if (encodedBytes > 0) { if (outArray) { [outBuf putWithByteArray:outArray withInt:0 withInt:encodedBytes]; } else { [outBuf positionWithInt:[outBuf position] + encodedBytes]; } } [inArray release]; [outArray release]; return result; ]-*/; protected native void finalize() /*-[ iconv_close((iconv_t)self->iconvHandle_); ]-*/; }