package php.runtime.ext.core.classes.stream; import php.runtime.Memory; import php.runtime.annotation.Reflection; import php.runtime.env.Environment; import php.runtime.memory.BinaryMemory; import php.runtime.memory.LongMemory; import php.runtime.reflection.ClassEntity; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Arrays; import static php.runtime.annotation.Reflection.*; @Name("php\\io\\FileStream") public class FileStream extends Stream { private final static String MSG_FILE_NOT_FOUND = "File '%s' not found"; protected RandomAccessFile accessFile; protected boolean canRead = true; protected long position = 0; public FileStream(Environment env, ClassEntity clazz) { super(env, clazz); } private void throwFileNotFound(Environment env){ env.exception(WrapIOException.class, MSG_FILE_NOT_FOUND, getPath()); } private void throwCannotRead(Environment env){ env.exception(WrapIOException.class, "Cannot read file"); } public RandomAccessFile getAccessFile() { return accessFile; } @Override @Signature({@Arg("path"), @Arg(value = "mode", optional = @Reflection.Optional("r"))}) public Memory __construct(Environment env, Memory... args) throws IOException { super.__construct(env, args); try { if (getMode().equals("r")) { accessFile = new RandomAccessFile(getPath(), "r"); position = 0; } else if (getMode().equals("r+")){ if (!new File(getPath()).getAbsoluteFile().exists()) throwFileNotFound(env); accessFile = new RandomAccessFile(getPath(), "rw"); } else if (getMode().equals("w")){ accessFile = new RandomAccessFile(getPath(), "rw"); accessFile.setLength(0); canRead = false; } else if (getMode().equals("w+")){ accessFile = new RandomAccessFile(getPath(), "rw"); accessFile.setLength(0); } else if (getMode().equals("a")){ accessFile = new RandomAccessFile(getPath(), "rw"); File file = new File(getPath()); if (file.getAbsoluteFile().exists()) { accessFile.seek(file.length()); position = file.length(); } canRead = false; } else if (getMode().equals("a+")){ accessFile = new RandomAccessFile(getPath(), "rw"); File file = new File(getPath()); if (file.getAbsoluteFile().exists()){ accessFile.seek(file.length()); position = file.length(); } } else if (getMode().equals("x") || getMode().equals("x+")){ File file = new File(getPath()); if (file.getAbsoluteFile().exists()) env.exception(WrapIOException.class, "File '%s' already exists (mode: %s)", getMode()); accessFile = new RandomAccessFile(getPath(), "rw"); if (getMode().equals("x")) canRead = false; } else if (getMode().equals("c") || getMode().equals("c+")){ accessFile = new RandomAccessFile(getPath(), "rw"); if (getMode().equals("c")) canRead = false; } else env.exception(WrapIOException.class, "Unsupported mode - '%s'", getMode()); } catch (FileNotFoundException e){ throwFileNotFound(env); } catch (IOException e) { env.exception(WrapIOException.class, e.getMessage()); } return Memory.NULL; } @Signature({@Arg("value"), @Arg(value = "length", optional = @Optional("NULL"))}) public Memory write(Environment env, Memory... args){ int len = args[1].toInteger(); byte[] bytes = args[0].getBinaryBytes(env.getDefaultCharset()); try { accessFile.write(bytes, 0, len == 0 ? bytes.length : len); return LongMemory.valueOf(len == 0 ? bytes.length : len); } catch (IOException e) { env.exception(WrapIOException.class, e.getMessage()); } return Memory.FALSE; } @Signature(@Arg("length")) public Memory read(Environment env, Memory... args){ if (!canRead) throwCannotRead(env); int len = args[0].toInteger(); if (len < 1) env.exception(WrapIOException.class, "Length must be greater than zero, %s given", len); byte[] buff = new byte[len]; try { int read = accessFile.read(buff, 0, len); if (read == -1) return Memory.NULL; position += read; if (read != buff.length){ buff = Arrays.copyOf(buff, read); } return new BinaryMemory(buff); } catch (IOException e) { env.exception(WrapIOException.class, e.getMessage()); return Memory.FALSE; } } @Signature public Memory readFully(Environment env, Memory... args){ if (!canRead) throwCannotRead(env); long len = 0; try { len = accessFile.length() - position; if (len <= 0) return Memory.FALSE; byte[] buff = new byte[(int)len]; accessFile.readFully(buff); position += len; return new BinaryMemory(buff); } catch (IOException e) { return Memory.FALSE; } } @Signature public Memory eof(Environment env, Memory... args){ try { return position >= accessFile.length() ? Memory.TRUE : Memory.FALSE; } catch (IOException e) { return Memory.FALSE; } } @Signature public Memory close(Environment env, Memory... args) throws IOException { accessFile.close(); return Memory.NULL; } @Signature public Memory getPosition(Environment env, Memory... args){ return LongMemory.valueOf(position); } @Signature(@Arg("position")) public Memory seek(Environment env, Memory... args) throws IOException { accessFile.seek(args[0].toLong()); return Memory.NULL; } @Signature public Memory getFilePointer(Environment env, Memory... args) throws IOException { return LongMemory.valueOf(accessFile.getFilePointer()); } @Signature public Memory length(Environment env, Memory... args) throws IOException { return LongMemory.valueOf(accessFile.length()); } @Signature(@Arg("size")) public Memory truncate(Environment env, Memory... args) throws IOException { accessFile.setLength(args[0].toLong()); return Memory.NULL; } }