/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Copyright (c) 2009 by Trifork
*
* 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 erjang.driver;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.BindException;
import java.net.ConnectException;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.zip.GZIPOutputStream;
import erjang.EBinary;
import erjang.ERT;
import erjang.driver.efile.Posix;
/**
*
*/
public class IO {
/**
*
*/
public static final Charset ISO_LATIN_1 = Charset.forName("ISO-8859-1");
public static final Charset UTF8 = Charset.forName("UTF8");
public static final Charset UTF16 = Charset.forName("UTF-16BE");
public static final Charset UTF32 = Charset.forName("UTF-32BE");
static public class BARR extends ByteArrayOutputStream {
public ByteBuffer wrap() {
return ByteBuffer.wrap(super.buf, 0, super.count);
}
}
/**
* Write src[position .. limit]. Set position to limit.
*
* @param out
* @param src
* @throws IOException
*/
public static void write(OutputStream out, ByteBuffer src)
throws IOException {
out.write(src.array(), src.arrayOffset() + src.position(), src
.remaining());
src.position(src.limit());
}
/**
* @param fd
* @param byteBuffer
* @return
* @throws InterruptedException
*/
public static long gzwrite(WritableByteChannel fd, ByteBuffer src)
throws IOException {
long result = src.remaining();
BARR barr = new BARR();
GZIPOutputStream go = new GZIPOutputStream(barr);
IO.write(go, src);
go.close();
src = barr.wrap();
writeFully(fd, src);
if (src.hasRemaining()) {
throw new Error("should not happen");
}
return result;
}
public static long writeFully(WritableByteChannel fd, ByteBuffer src)
throws IOException {
long written = 0;
written += fd.write(src);
if (src.hasRemaining()) {
while (src.hasRemaining()) {
// FIXME: use Thread.sleep() in stead?
Thread.yield();
written += fd.write(src);
}
}
return written;
}
/**
* @param e
* @return
*/
public static int exception_to_posix_code(IOException e) {
if (e instanceof java.nio.channels.ClosedChannelException) {
return Posix.ENOTCONN;
}
if ("Broken pipe".equals(e.getMessage())
|| "Connection reset by peer".equals(e.getMessage())) {
return Posix.ENOTCONN;
}
if (e instanceof ConnectException) {
if ("Connection refused".equals(e.getMessage())) {
return Posix.ECONNREFUSED;
}
}
if (e instanceof BindException) {
if ("Can't assign requested address".equals(e.getMessage())) {
return Posix.EADDRNOTAVAIL;
}
}
if (e instanceof java.net.SocketException) {
if ("Network is unreachable".equals (e.getMessage())) {
return Posix.ENETUNREACH;
}
}
if (e instanceof java.nio.file.FileSystemException) {
if (e.getMessage().indexOf("Not a directory") != -1) {
return Posix.ENOTDIR;
}
}
if (e instanceof java.nio.file.NoSuchFileException) {
return Posix.ENOENT;
}
if (e instanceof java.nio.file.FileAlreadyExistsException) {
return Posix.EEXIST;
}
ERT.log.warning("unknown exception: "+ e.getClass().getName() + " " + e.getMessage());
ERT.log.log(Level.FINE, "details: ", e);
// TODO: implement some more error codes here
return Posix.EUNKNOWN;
}
public static long writev(GatheringByteChannel fd, ByteBuffer[] iov)
throws IOException {
int cnt = 0;
long written = 0;
while (cnt < iov.length) {
int b = iov.length - cnt;
if (iov[cnt].hasRemaining()) {
if (b == 1) {
written += fd.write(iov[cnt]);
} else {
written += fd.write(iov, cnt, b);
}
} else {
cnt++;
}
}
return written;
}
/**
* Do a strcpy on ByteBuffer. Assuming
*
* @param data
* @return
*/
public static String strcpy(ByteBuffer data) {
int end_pos;
for (end_pos = data.position(); end_pos < data.limit(); end_pos++) {
if (data.get(end_pos) == 0) {
byte[] bb = data.array();
int arr_off = data.arrayOffset() + data.position();
int len = end_pos - data.position();
String result = new String(bb, arr_off, len, ISO_LATIN_1);
data.position(end_pos + 1);
return result;
}
}
throw ERT.badarg();
}
/**
* @param buf
* @param err
*/
public static void putstr(ByteBuffer buf, String err, boolean term) {
for (int i = 0; i < err.length(); i++) {
buf.put((byte) err.charAt(i));
}
if (term) {
buf.put((byte) 0);
}
}
public static String getstr(ByteBuffer buf, boolean term) {
if (term) {
/* TODO: charset! */
StringBuilder sb = new StringBuilder();
byte b;
while (buf.hasRemaining() && (b=buf.get()) != 0) {
sb.append((char)(0xff & b));
}
return sb.toString();
} else {
String str = new String(buf.array(), buf.arrayOffset()+buf.position(), buf
.remaining(), ISO_LATIN_1);
buf.position(buf.limit());
return str;
}
}
static private class BARR2 extends ByteArrayOutputStream {
EBinary asBinary() {
return new EBinary(super.buf, 0, super.count);
}
}
public static EBinary istream2binary(InputStream in) throws IOException {
BARR2 out = new BARR2();
byte[] buf = new byte[4 * 1024];
int read;
while ((read = in.read(buf)) > 0) {
out.write(buf, 0, read);
}
return out.asBinary();
}
public static byte[] istream2bytearray(InputStream in) throws IOException {
BARR2 out = new BARR2();
byte[] buf = new byte[4 * 1024];
int read;
while ((read = in.read(buf)) > 0) {
out.write(buf, 0, read);
}
return out.toByteArray();
}
}