//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.vm;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import org.apache.commons.io.FileUtils;
import cmu.conditional.Conditional;
import java.util.function.Function;
import cmu.conditional.One;
import de.fosd.typechef.featureexpr.FeatureExpr;
import gov.nasa.jpf.annotation.MJI;
/**
* intercept and forward some of the filesystem access methods. This is very
* slow, if a program uses this heavily we should keep the forwarding File
* object around and modify the model class accordingly
*/
public class JPF_java_io_File extends NativePeer {
static Conditional<File> getFile(MJIEnv env, int objref, FeatureExpr ctx) {
int fnref = env.getReferenceField(ctx, objref, "path").getValue();
Conditional<String> fname = env.getStringObjectNew(ctx, fnref);
// final MJIEnv envFinal = env;
// final FeatureExpr ctxFinal = ctx;
// Conditional<Integer> fnref = env.getReferenceField(ctx, objref, "path");
// Conditional<String> fname = fnref.mapr(new Function<Integer, Conditional<String>>() {
// @Override
// public Conditional<String> apply(Integer x) {
// return envFinal.getStringObjectNew(ctxFinal, x);
// }
// });
return fname.map(new Function<String, File>() {
@Override
public File apply(String fname) {
return new File(fname);
}
});
}
static int createJPFFile(MJIEnv env, File file, FeatureExpr ctx) {
int newFileRef = env.newObject(ctx, "java.io.File");
ElementInfo fileEI = env.getModifiableElementInfo(newFileRef);
int fileNameRef = env.newString(ctx, file.getPath());
fileEI.setReferenceField(ctx, "path", new One<>(fileNameRef));
return newFileRef;
}
@MJI
public int getParentFile____Ljava_io_File_2(MJIEnv env, int objref, FeatureExpr ctx) {
File thisFile = getFile(env, objref, ctx).getValue();
File parent = thisFile.getParentFile();
return createJPFFile(env, parent, ctx);
}
@MJI
public int getAbsolutePath____Ljava_lang_String_2 (MJIEnv env, int objref, FeatureExpr ctx) {
Conditional<String> pn = getFile(env,objref, ctx).map(new Function<File, String>() {
@Override
public String apply(File file) {
return file.getAbsolutePath();
}
});
return env.newString(ctx, pn);
}
@MJI
public int getAbsoluteFile____Ljava_io_File_2 (MJIEnv env, int objref, FeatureExpr ctx) {
File absoluteFile = getFile(env, objref, ctx).getValue().getAbsoluteFile();
return createJPFFile(env, absoluteFile, ctx);
}
@MJI
public int getCanonicalPath____Ljava_lang_String_2 (MJIEnv env, int objref, FeatureExpr ctx) {
try {
String pn = getFile(env,objref, ctx).getValue().getCanonicalPath();
return env.newString(ctx, pn);
} catch (IOException iox) {
env.throwException(ctx, "java.io.IOException", iox.getMessage());
return MJIEnv.NULL;
}
}
@MJI
public int getCanonicalFile____Ljava_io_File_2(MJIEnv env, int objref, FeatureExpr ctx) {
try {
File file = getFile(env, objref, ctx).getValue();
File canonicalFile = file.getCanonicalFile();
return createJPFFile(env, canonicalFile, ctx);
} catch (IOException iox) {
env.throwException(ctx, "java.io.IOException", iox.getMessage());
return MJIEnv.NULL;
}
}
// internal helper
@MJI
public int getURLSpec____Ljava_lang_String_2 (MJIEnv env, int objref, FeatureExpr ctx){
try {
File f = getFile(env,objref, ctx).getValue();
URL url = f.toURL();
return env.newString(ctx, url.toString());
} catch (MalformedURLException mfux) {
env.throwException(ctx, "java.net.MalformedURLException", mfux.getMessage());
return MJIEnv.NULL;
}
}
@MJI
public int getURISpec____Ljava_lang_String_2 (MJIEnv env, int objref, FeatureExpr ctx){
File f = getFile(env, objref, ctx).getValue();
URI uri = f.toURI();
return env.newString(ctx, uri.toString());
}
@MJI
public boolean isAbsolute____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env, objref, ctx).getValue().isAbsolute();
}
@MJI
public boolean isDirectory____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().isDirectory();
// return getFile(env, objref, ctx).map(new Function<File, Boolean>() {
// @Override
// public Boolean apply(File x) {
// return x.isDirectory();
// }
// });
}
@MJI
public boolean isFile____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().isFile();
}
@MJI
public Conditional<Boolean> delete____Z (MJIEnv env, int objref, FeatureExpr ctx) {
Conditional<File> file = getFile(env,objref, ctx).simplify(ctx);
return file.mapr(new Function<File, Conditional<Boolean>>() {
@Override
public Conditional<Boolean> apply(File file) {
return One.valueOf(file.delete());
}
});
}
@MJI
public Conditional<Long> length____J (MJIEnv env, int objref, FeatureExpr ctx) {
// return getFile(env,objref, ctx).getValue().length();
Conditional<File> files = getFile(env, objref, ctx);
Conditional<Long> lengths = files.map(new Function<File, Long>() {
@Override
public Long apply(File x) {
return x.length();
}
});
return lengths;
}
@MJI
public boolean canRead____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().canRead();
}
@MJI
public boolean canWrite____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().canWrite();
}
@MJI
public boolean exists____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().exists();
}
@MJI
public boolean createNewFile____Z(MJIEnv env, int objref, FeatureExpr ctx) {
File fileToCreate = getFile(env, objref, ctx).getValue();
try {
return fileToCreate.createNewFile();
} catch (IOException iox) {
env.throwException(ctx, "java.io.IOException", iox.getMessage());
return false;
}
}
@MJI
public int list_____3Ljava_lang_String_2(MJIEnv env, int objref, FeatureExpr ctx){
File f=getFile(env,objref, ctx).getValue();
if (f.isDirectory()){
String[] farr=f.list();
return env.newStringArray(ctx, farr);
} else {
return MJIEnv.NULL;
}
}
@MJI
public int listRoots_____3Ljava_io_File_2(MJIEnv env, int classRef, FeatureExpr ctx) {
File[] roots = File.listRoots();
int rootResultRef = env.newObjectArray("java.io.File", roots.length);
ElementInfo rootsEI = env.getModifiableElementInfo(rootResultRef);
for (int i = 0; i < roots.length; i++) {
int rootFileRef = createJPFFile(env, roots[i], ctx);
rootsEI.setReferenceElement(ctx, i, new One<>(rootFileRef));
}
return rootResultRef;
}
@MJI
public boolean mkdir____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().mkdir();
}
@MJI
public boolean mkdirs____Z (MJIEnv env, int objref, FeatureExpr ctx) {
return getFile(env,objref, ctx).getValue().mkdirs();
}
@MJI
public int listFiles_____3Ljava_io_File_2(MJIEnv env, int objref, FeatureExpr ctx) {
File file = getFile(env,objref, ctx).getValue();
File[] files = file.listFiles();
int filesRef = env.newObjectArray("java.io.File", files.length);
ElementInfo rootsEI = env.getModifiableElementInfo(filesRef);
for (int i = 0; i < files.length; i++) {
int rootFileRef = createJPFFile(env, files[i], ctx);
rootsEI.setReferenceElement(ctx, i, new One<>(rootFileRef));
}
return filesRef;
}
@MJI
public Conditional<Boolean> renameTo__Ljava_io_File_2__Z(MJIEnv env, int objref, int toRef, FeatureExpr ctx) {
// TODO implement variability-aware io
final File file = getFile(env,objref, ctx).getValue();
Conditional<File> toFile = getFile(env,toRef, ctx).simplify(ctx);
if (toFile instanceof One) {
return One.valueOf(file.renameTo(toFile.getValue()));
}
Conditional<Boolean> returnValue = toFile.mapr(new Function<File, Conditional<Boolean>>() {
@Override
public Conditional<Boolean> apply(File toFile) {
try {
FileUtils.copyFile(file, toFile);
} catch (IOException e) {
e.printStackTrace();
return One.FALSE;
}
return One.TRUE;
}
});
if (ctx.isTautology()) {
file.delete();
}
return returnValue;
}
// <2do> ..and lots more
}