package php.runtime.ext.net; import php.runtime.Memory; import php.runtime.annotation.Reflection.*; import php.runtime.env.Environment; import php.runtime.ext.NetExtension; import php.runtime.ext.core.classes.stream.Stream; import php.runtime.memory.BinaryMemory; import php.runtime.memory.LongMemory; import php.runtime.reflection.ClassEntity; import java.io.*; import java.net.*; import java.util.Arrays; @Name(NetExtension.NAMESPACE + "NetStream") @Stream.UsePathWithProtocols public class WrapNetStream extends Stream { protected URL url; protected Proxy proxy; protected boolean eof = false; protected int position = 0; protected URLConnection urlConnection; protected InputStream currentInputStream; protected OutputStream currentOutputStream; public WrapNetStream(Environment env, URL url) { super(env); this.url = url; } public WrapNetStream(Environment env, ClassEntity clazz) { super(env, clazz); } public URLConnection getURLConnection() throws IOException { if (urlConnection == null) { if (proxy != null) { urlConnection = url.openConnection(proxy); } else { urlConnection = url.openConnection(); } urlConnection.setDoInput(false); urlConnection.setDoOutput(false); if (getMode().startsWith("r") || getMode().startsWith("w") || getMode().startsWith("a")) { urlConnection.setDoInput(true); } if (getMode().startsWith("w") || getMode().startsWith("a")) { urlConnection.setDoOutput(true); } } return urlConnection; } public HttpURLConnection getHttpURLConnection() throws IOException { return (HttpURLConnection) getURLConnection(); } public OutputStream getOutputStream() throws IOException { if (currentOutputStream == null) { currentOutputStream = getURLConnection().getOutputStream(); } return currentOutputStream; } synchronized public InputStream getInputStream() throws IOException { if (currentInputStream == null) { URLConnection urlConnection = getURLConnection(); try { currentInputStream = urlConnection.getInputStream(); if (currentInputStream == null && urlConnection instanceof HttpURLConnection) { currentInputStream = ((HttpURLConnection) urlConnection).getErrorStream(); } } catch (IOException e) { if (urlConnection instanceof HttpURLConnection) { currentInputStream = ((HttpURLConnection) urlConnection).getErrorStream(); } else { throw e; } } } if (currentInputStream == null) { throw new IOException("Unable to get input stream for connection " + getPath()); } return currentInputStream; } @Override @Signature({@Arg("path"), @Arg(value = "mode", optional = @Optional("w+"))}) public Memory __construct(Environment env, Memory... args) throws IOException { super.__construct(env, args); if (getMode() == null) { setMode("w+"); } url = new URL(args[0].toString()); getInputStream(); return Memory.NULL; } @Signature public WrapURL getURL(Environment env) throws MalformedURLException { return new WrapURL(env, new URL(getPath())); } @Override public Memory write(Environment env, Memory... args) throws IOException { int len = args[1].toInteger(); byte[] bytes = args[0].getBinaryBytes(env.getDefaultCharset()); len = len == 0 || len > bytes.length ? bytes.length : len; getOutputStream().write(bytes, 0, len); return LongMemory.valueOf(len); } @Override public Memory read(Environment env, Memory... args) throws IOException { int len = args[0].toInteger(); if (len <= 0) return Memory.FALSE; byte[] buf = new byte[len]; int read; read = getInputStream().read(buf); eof = read == -1; if (read == -1) return Memory.FALSE; position += read; return new BinaryMemory(Arrays.copyOf(buf, read)); } @Override @Signature({ @Arg(value = "bufferSize", optional = @Optional("4096")) }) public Memory readFully(Environment env, Memory... args) throws IOException { final int bufferSize = args[0].toInteger(); if (bufferSize <= 0) { return Memory.FALSE; } byte[] buff = new byte[bufferSize]; int len; ByteArrayOutputStream tmp = new ByteArrayOutputStream(); while ((len = getInputStream().read(buff)) > 0) { tmp.write(buff, 0, len); position += len; } return new BinaryMemory(tmp.toByteArray()); } @Override public Memory eof(Environment env, Memory... args) { if (urlConnection == null) { return Memory.FALSE; } return eof ? Memory.TRUE : Memory.FALSE; } @Override public Memory seek(Environment env, Memory... args) throws IOException { throw new IOException("Unavailable seek() operation"); } @Override public Memory getPosition(Environment env, Memory... args) { return LongMemory.valueOf(position); } @Override public Memory close(Environment env, Memory... args) throws IOException { if (urlConnection != null && urlConnection instanceof HttpURLConnection) { ((HttpURLConnection) urlConnection).disconnect(); } return Memory.NULL; } @Signature public void setProxy(@Nullable Proxy proxy) { this.proxy = proxy; } @Signature public Proxy getProxy() { return this.proxy; } @Signature public URLConnection getUrlConnection() throws IOException { return getURLConnection(); } @Override public boolean _isExternalResourceStream() { return true; } }