package php.runtime.ext.core.classes.stream; import php.runtime.Memory; import php.runtime.env.Environment; import php.runtime.memory.BinaryMemory; import php.runtime.memory.LongMemory; import php.runtime.reflection.ClassEntity; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import static php.runtime.annotation.Reflection.*; @Name("php\\io\\MiscStream") public class MiscStream extends Stream { protected boolean canRead = true; protected int position = 0; protected boolean eof = true; protected MemoryStream memoryStream; protected InputStream inputStream; protected OutputStream outputStream; public MiscStream(Environment env, InputStream inputStream) { super(env); this.inputStream = inputStream; } public MiscStream(Environment env, OutputStream outputStream) { super(env); this.outputStream = outputStream; } public MiscStream(Environment env, ClassEntity clazz) { super(env, clazz); } private void throwCannotRead(Environment env){ env.exception(WrapIOException.class, "Cannot read stream"); } @Override @Signature({@Arg("path"), @Arg(value = "mode", optional = @Optional("r"))}) public Memory __construct(Environment env, Memory... args) throws IOException { super.__construct(env, args); String path = getPath(); if ("memory".equals(path)){ memoryStream = new MemoryStream(); } else if ("stdout".endsWith(path)){ outputStream = System.out; } else if ("stdin".equals(path)) { inputStream = System.in; } else if ("stderr".equals(path)){ outputStream = System.err; } else env.exception(WrapIOException.class, "Unknown type stream - %s", path); return Memory.NULL; } @Signature({@Arg("value"), @Arg(value = "length", optional = @Optional("NULL"))}) public Memory write(Environment env, Memory... args) throws IOException { int len = args[1].toInteger(); byte[] bytes = args[0].getBinaryBytes(env.getDefaultCharset()); eof = false; len = len == 0 || len > bytes.length ? bytes.length : len; if (memoryStream != null){ memoryStream.write(bytes, 0, len); return LongMemory.valueOf(len); } else if (outputStream != null) { outputStream.write(bytes, 0, len); this.position += len; inputStream = null; return LongMemory.valueOf(len); } else if (inputStream != null){ env.exception(WrapIOException.class, "Cannot write to input stream"); return Memory.CONST_INT_0; } return Memory.CONST_INT_0; } @Signature(@Arg("length")) public Memory read(Environment env, Memory... args) throws IOException { if (!canRead) throwCannotRead(env); int len = args[0].toInteger(); if (len <= 0) return Memory.FALSE; if (memoryStream != null){ byte[] result = memoryStream.read(len); if (result == null) return Memory.FALSE; return new BinaryMemory(result); } else if (inputStream != null){ byte[] buf = new byte[len]; int read; read = inputStream.read(buf); eof = read == -1; if (read == -1) return Memory.FALSE; position += read; return new BinaryMemory(Arrays.copyOf(buf, read)); } else throw new IOException("Cannot read from output stream"); } @Signature public Memory readFully(Environment env, Memory... args) throws IOException { if (memoryStream != null){ byte[] result = memoryStream.readFully(); if (result != null) return new BinaryMemory(result); else return Memory.FALSE; } else if (inputStream != null) { byte[] buff = new byte[1024]; int len; ByteArrayOutputStream tmp = new ByteArrayOutputStream(); while ((len = inputStream.read(buff)) > 0) { tmp.write(buff, 0, len); } return new BinaryMemory(tmp.toByteArray()); } return Memory.NULL; } @Signature public Memory eof(Environment env, Memory... args){ if (memoryStream != null) return memoryStream.eof() ? Memory.TRUE : Memory.FALSE; return eof ? Memory.TRUE : Memory.FALSE; } @Signature public Memory close(Environment env, Memory... args) throws IOException { if (memoryStream != null){ memoryStream.close(); } if (inputStream != null) inputStream.close(); else if (outputStream != null) outputStream.close(); return Memory.NULL; } @Signature public Memory getPosition(Environment env, Memory... args){ if (memoryStream != null) return LongMemory.valueOf(position); return LongMemory.valueOf(position); } @Signature(@Arg("position")) public Memory seek(Environment env, Memory... args){ if (memoryStream != null){ if (!memoryStream.seek(args[0].toInteger())) env.exception(WrapIOException.class, "Cannot seek to %s", args[0].toInteger()); this.position = args[0].toInteger(); } else { env.exception(WrapIOException.class, "Cannot seek in input/output stream"); } return Memory.NULL; } @Signature public Memory length(Environment env, Memory... args){ if (memoryStream != null) return LongMemory.valueOf(memoryStream.length); else env.exception(WrapIOException.class, "Unsupported method for this type stream"); return Memory.NULL; } @Signature public Memory flush(Environment env, Memory... args) throws IOException { if (outputStream == null) env.exception(WrapIOException.class, "Only output stream support flush()"); else outputStream.flush(); return Memory.NULL; } }