// Copyright 2001, FreeHEP.
package org.freehep.postscript;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import org.freehep.util.io.ASCII85InputStream;
import org.freehep.util.io.ASCII85OutputStream;
import org.freehep.util.io.ASCIIHexInputStream;
import org.freehep.util.io.ASCIIHexOutputStream;
import org.freehep.util.io.DCTInputStream;
import org.freehep.util.io.FlateInputStream;
import org.freehep.util.io.FlateOutputStream;
import org.freehep.util.io.RunLengthInputStream;
import org.freehep.util.io.RunLengthOutputStream;
import org.freehep.util.io.StandardFileFilter;
/**
* File Operators for PostScript Processor
*
* @author Mark Donszelmann
* @version $Id: FileOperator.java 10178 2006-12-08 09:03:07Z duns $
*/
public class FileOperator extends PSOperator {
public static Class[] operators = {
FileFile.class, Filter.class, CloseFile.class,
Read.class, Write.class,
ReadHexString.class, WriteHexString.class,
ReadString.class, WriteString.class,
ReadLine.class, BytesAvailable.class,
Flush.class, FlushFile.class, ResetFile.class,
Status.class, Run.class, CurrentFile.class,
DeleteFile.class, RenameFile.class,
FilenameForAll.class, SetFilePosition.class, FilePosition.class,
Print.class, FileEqual.class, FileEqualEqual.class,
Stack.class, PStack.class
};
public boolean execute(OperandStack os) {
throw new RuntimeException("Cannot execute class: "+getClass());
}
}
class FileFile extends FileOperator {
{ operandTypes = new Class[] {PSString.class, PSString.class}; }
public String getName() {
return "file";
}
public boolean execute(OperandStack os) {
String access = os.popString().getValue();
String filename = os.popString().getValue();
try {
if (filename.equals("%stdin")) {
os.push(new PSInputFile(System.in, os.getDSC()));
} else if (filename.equals("%stdout")) {
os.push(new PSOutputFile(System.out));
} else if (filename.equals("%stderr")) {
os.push(new PSOutputFile(System.err));
} else if (filename.equals("%lineedit") || filename.equals("%statementedit")) {
System.err.println("%lineedit and %statementedit not supported.");
error(os, new Undefined());
} else {
// regular file
boolean rw = (access.length() > 1) && (access.charAt(1) == '+');
boolean write = (access.length() > 0) && (access.charAt(0) == 'w');
boolean append = (access.length() > 0) && (access.charAt(0) == 'a');
if (rw) {
os.push(new PSRandomAccessFile(filename, write, append, os.isSecure()));
} else {
if (write || append) {
os.push(new PSOutputFile(filename, append, os.isSecure()));
} else {
os.push(new PSInputFile(filename, os.getDSC()));
}
}
}
} catch (FileNotFoundException e) {
error(os, new UndefinedFileName());
} catch (IOException e) {
error(os, new InvalidFileAccess());
}
return true;
}
}
class Filter extends FileOperator {
{ operandTypes = new Class[] {PSName.class}; }
public boolean encode(OperandStack os, String filterName) throws IOException {
if (filterName.equals("RunLengthEncode")) {
// special parameter
int runLength = os.popInteger().getValue();
PSDictionary dict;
if (os.checkType(PSDictionary.class)) {
dict = os.popDictionary();
}
PSDataTarget target = os.popDataTarget();
// FIXME: runLength parameter is ignored
os.push(new PSOutputFile(new RunLengthOutputStream(target.getOutputStream())));
error(os, new Undefined());
return true;
} else {
// no parameters, optional dictionary
PSDictionary dict;
if (os.checkType(PSDictionary.class)) {
dict = os.popDictionary();
}
PSDataTarget target = os.popDataTarget();
if (filterName.equals("ASCIIHexEncode")) {
os.push(new PSOutputFile(new ASCIIHexOutputStream(target.getOutputStream())));
} else if (filterName.equals("ASCII85Encode")) {
os.push(new PSOutputFile(new ASCII85OutputStream(target.getOutputStream())));
} else if (filterName.equals("LZWEncode")) {
error(os, new Undefined());
return true;
} else if (filterName.equals("FlateEncode")) {
os.push(new PSOutputFile(new FlateOutputStream(target.getOutputStream())));
} else if (filterName.equals("CCITTFaxEncode")) {
error(os, new Undefined());
return true;
} else if (filterName.equals("NullEncode")) {
os.push(new PSOutputFile(target.getOutputStream()));
} else {
error(os, new Undefined());
return true;
}
}
return true;
}
public boolean decode(OperandStack os, String filterName) throws IOException {
if (filterName.equals("SubFileDecode")) {
// special parameters
error(os, new Undefined());
return true;
} else {
// no parameters, optional dictionary
PSDictionary dict;
if (os.checkType(PSDictionary.class)) {
dict = os.popDictionary();
}
PSDataSource source = os.popDataSource();
if (filterName.equals("ASCIIHexDecode")) {
os.push(new PSInputFile(new ASCIIHexInputStream(source.getInputStream()), source.getDSC()));
} else if (filterName.equals("ASCII85Decode")) {
os.push(new PSInputFile(new ASCII85InputStream(source.getInputStream()), source.getDSC()));
} else if (filterName.equals("LZWDecode")) {
error(os, new Undefined());
return true;
} else if (filterName.equals("FlateDecode")) {
os.push(new PSInputFile(new FlateInputStream(source.getInputStream()), source.getDSC()));
} else if (filterName.equals("RunLengthDecode")) {
os.push(new PSInputFile(new RunLengthInputStream(source.getInputStream()), source.getDSC()));
} else if (filterName.equals("CCITTFaxDecode")) {
error(os, new Undefined());
return true;
} else if (filterName.equals("DCTDecode")) {
os.push(new PSInputFile(new DCTInputStream(source.getInputStream()), source.getDSC()));
return true;
} else if (filterName.equals("ReusableStreamDecode")) {
// Level 3
error(os, new Undefined());
return true;
} else {
error(os, new Undefined());
return true;
}
}
if (!os.checkType(PSDataSource.class)) {
error(os, new TypeCheck());
return true;
}
return true;
}
public boolean execute(OperandStack os) {
String filterName = os.popName().getValue();
try {
return filterName.endsWith("Encode") ? encode(os, filterName) : decode(os, filterName);
} catch (ClassCastException e) {
error(os, new TypeCheck());
return true;
} catch (IOException e) {
error(os, new IOError());
return true;
}
}
}
class CloseFile extends FileOperator {
{ operandTypes = new Class[] {PSFile.class}; }
public boolean execute(OperandStack os) {
PSFile file = os.popFile();
try {
file.close();
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class Read extends FileOperator {
{ operandTypes = new Class[] {PSFile.class}; }
public boolean execute(OperandStack os) {
PSFile file = os.popFile();
try {
int b = file.read();
if (b < 0) {
os.push(false);
} else {
os.push(b);
os.push(true);
}
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class Write extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSInteger.class}; }
public boolean execute(OperandStack os) {
PSInteger b = os.popInteger();
PSFile file = os.popFile();
try {
file.write(b.getValue() & 0xFF, os.isSecure());
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class ReadHexString extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSString.class}; }
public boolean execute(OperandStack os) {
PSString string = os.popString();
PSFile file = os.popFile();
if (string.size() <= 0) {
error(os, new RangeCheck());
} else {
try {
InputStream in = new ASCIIHexInputStream(((PSInputFile)file).getInputStream(), true);
for (int i=0; i<string.size(); i++) {
int b = in.read();
if (b < 0) {
os.push(string.subString(0, i));
os.push(false);
return true;
} else {
string.set(i, b & 0xFF);
}
}
os.push(string.subString(0));
os.push(true);
} catch (IOException e) {
error(os, new IOError());
} catch (ClassCastException e) {
error(os, new InvalidAccess());
}
}
return true;
}
}
class WriteHexString extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSString.class}; }
public boolean execute(OperandStack os) {
PSString string = os.popString();
PSFile file = os.popFile();
try {
if (!os.isSecure()) throw new IOException();
OutputStream out = new ASCIIHexOutputStream(((PSOutputFile)file).getOutputStream());
for (int i=0; i<string.size(); i++) {
out.write(string.get(i));
}
} catch (IOException e) {
error(os, new IOError());
} catch (ClassCastException e) {
error(os, new InvalidAccess());
}
return true;
}
}
class ReadString extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSString.class}; }
public boolean execute(OperandStack os) {
PSString string = os.popString();
PSFile file = os.popFile();
if (string.size() <= 0) {
error(os, new RangeCheck());
} else {
try {
for (int i=0; i<string.size(); i++) {
int b = file.read();
if (b < 0) {
os.push(string.subString(0, i));
os.push(false);
return true;
} else {
string.set(i, b & 0xFF);
}
}
os.push(string.subString(0));
os.push(true);
} catch (IOException e) {
error(os, new IOError());
}
}
return true;
}
}
class WriteString extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSString.class}; }
public boolean execute(OperandStack os) {
PSString string = os.popString();
PSFile file = os.popFile();
try {
for (int i=0; i<string.size(); i++) {
file.write(string.get(i) & 0xFF, os.isSecure());
}
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class ReadLine extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSString.class}; }
public boolean execute(OperandStack os) {
PSString string = os.popString();
PSFile file = os.popFile();
try {
String line = file.readLine();
if (line == null) {
os.push(string.subString(0,0));
os.push(false);
return true;
}
if (string.size() < line.length()) {
error(os, new RangeCheck());
} else {
for (int i=0; i<line.length(); i++) {
string.set(i, line.charAt(i));
}
os.push(string.subString(0, line.length()));
os.push(true);
}
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class BytesAvailable extends FileOperator {
{ operandTypes = new Class[] {PSFile.class}; }
public boolean execute(OperandStack os) {
PSFile file = os.popFile();
try {
os.push(file.available());
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class Flush extends FileOperator {
public boolean execute(OperandStack os) {
System.out.flush();
if (System.out.checkError()) {
error(os, new IOError());
}
return true;
}
}
class FlushFile extends FileOperator {
{ operandTypes = new Class[] {PSFile.class}; }
public boolean execute(OperandStack os) {
PSFile file = os.popFile();
try {
file.flush();
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class ResetFile extends FileOperator {
{ operandTypes = new Class[] {PSFile.class}; }
public boolean execute(OperandStack os) {
PSFile file = os.popFile();
try {
file.reset();
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class Status extends FileOperator {
{ operandTypes = new Class[] {PSObject.class}; }
public boolean execute(OperandStack os) {
if (os.checkType(PSFile.class)) {
PSFile file = os.popFile();
os.push(file.isValid());
} else if (os.checkType(PSString.class)) {
PSString name = os.popString();
File file = new File(name.getValue());
if (file.exists() && file.isFile()) {
os.push(file.length()/1024); // pages
os.push(file.length()); // bytes
os.push(file.lastModified()); // referenced
os.push(file.lastModified()); // created
os.push(true);
} else {
os.push(false);
}
} else {
error(os, new TypeCheck());
}
return true;
}
}
class Run extends FileOperator implements LoopingContext {
{ operandTypes = new Class[] {PSString.class}; }
// FIXME: does not handle InvalidExit
public boolean execute(OperandStack os) {
String name = os.popString().getValue();
try {
PSFile file = new PSInputFile(name, os.getDSC());
file.setExecutable();
os.execStack().pop();
os.execStack().push(file);
return false;
} catch (FileNotFoundException e) {
error(os, new UndefinedFileName());
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class CurrentFile extends FileOperator {
public boolean execute(OperandStack os) {
os.push(os.execStack().getCurrentFile());
return true;
}
}
class DeleteFile extends FileOperator {
{ operandTypes = new Class[] {PSString.class}; }
public boolean execute(OperandStack os) {
if (!os.isSecure()) {
error(os, new InvalidFileAccess());
return true;
}
PSString name = os.popString();
if (name.get(0) == '%') {
error(os, new UndefinedFileName());
} else {
File file = new File(name.getValue());
if (!file.delete()) {
error(os, new IOError());
}
}
return true;
}
}
class RenameFile extends FileOperator {
{ operandTypes = new Class[] {PSString.class, PSString.class}; }
public boolean execute(OperandStack os) {
if (!os.isSecure()) {
error(os, new InvalidFileAccess());
return true;
}
PSString name2 = os.popString();
PSString name1 = os.popString();
if ((name1.get(0) == '%') || (name2.get(0) == '%')) {
error(os, new UndefinedFileName());
} else {
File file1 = new File(name1.getValue());
File file2 = new File(name2.getValue());
if (!file1.exists()) {
error(os, new UndefinedFileName());
} else {
if (!file1.renameTo(file2)) {
error(os, new IOError());
}
}
}
return true;
}
}
class FilenameForAll extends FileOperator implements LoopingContext {
private int index;
private String[] files;
private PSPackedArray proc;
private PSString scratch;
public FilenameForAll() {
}
private FilenameForAll(String[] f, PSPackedArray p, PSString s) {
files = f;
proc = p;
scratch = s;
index = 0;
}
// FREEHEP-128: incomplete
public boolean execute(OperandStack os) {
if (proc == null) {
if (!os.checkType(PSString.class, PSPackedArray.class, PSString.class)) {
error(os, new TypeCheck());
return true;
}
PSString s = os.popString();
PSPackedArray p = os.popPackedArray();
PSString template = os.popString();
String dir = template.getValue();
if (dir.startsWith("%")) {
System.err.println("%device%file currently not supported.");
error(os, new Undefined());
return true;
}
File directory = new File((dir.lastIndexOf("/") < 0) ? "./" : dir);
FileFilter filter = new StandardFileFilter(dir);
File[] matchedFiles = directory.listFiles(filter);
Collection matchedFileNames = new ArrayList();
for (int i=0; i<matchedFiles.length; i++) {
matchedFileNames.add(matchedFiles[i].getName());
}
String[] f = (String[])matchedFileNames.toArray();
os.execStack().pop();
os.execStack().push(new FilenameForAll(f, p, s));
return false;
}
if (index >= files.length) {
return true;
}
PSString name = scratch.set(files[index]);
os.push(name);
os.execStack().push(proc);
index++;
return true;
}
}
class SetFilePosition extends FileOperator {
{ operandTypes = new Class[] {PSFile.class, PSInteger.class}; }
public boolean execute(OperandStack os) {
PSInteger pos = os.popInteger();
PSFile file = os.popFile();
try {
file.seek(pos.getValue());
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class FilePosition extends FileOperator {
{ operandTypes = new Class[] {PSFile.class}; }
public boolean execute(OperandStack os) {
PSFile file = os.popFile();
try {
os.push(file.getFilePointer());
} catch (IOException e) {
error(os, new IOError());
}
return true;
}
}
class Print extends FileOperator {
{ operandTypes = new Class[] {PSString.class}; }
public boolean execute(OperandStack os) {
PSString s = os.popString();
System.out.print(s.getValue());
return true;
}
}
// FIXME: should be built-in function
class FileEqual extends FileOperator {
{ operandTypes = new Class[] {PSObject.class}; }
public String getName() {
return "=";
}
public boolean execute(OperandStack os) {
// FIXME: should call CvS
// there should maybe be a separate string value for objects
PSObject o = os.popObject();
System.out.println(o.toString());
return true;
}
}
// FIXME: should be built-in function
class FileEqualEqual extends FileOperator {
{ operandTypes = new Class[] {PSObject.class}; }
public String getName() {
return "==";
}
public boolean execute(OperandStack os) {
PSObject o = os.popObject();
System.out.println(o.toString());
return true;
}
}
class Stack extends FileOperator {
public boolean execute(OperandStack os) {
// FIXME: should call = operator
os.printStack();
return true;
}
}
class PStack extends FileOperator {
public boolean execute(OperandStack os) {
// FIXME: should call == operator
os.printStack();
return true;
}
}