Refactor ExpressionFormat into generic ExpressionFormat (used by -mediainfo and -list calls) and ExpressionFileFormat (used when generating output paths) that performs all the file path validation logic (strip spaces, don't allow /\ in binding values, etc)

This commit is contained in:
Reinhard Pointner 2017-02-27 22:11:59 +08:00
parent 1d91160521
commit f28e41626f
12 changed files with 74 additions and 46 deletions

View File

@ -31,6 +31,7 @@ import net.filebot.Language;
import net.filebot.StandardRenameAction;
import net.filebot.WebServices;
import net.filebot.format.ExpressionFileFilter;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.ExpressionFilter;
import net.filebot.format.ExpressionFormat;
import net.filebot.hash.HashType;
@ -216,6 +217,10 @@ public class ArgumentBean {
return format == null ? null : new ExpressionFormat(format);
}
public ExpressionFileFormat getExpressionFileFormat() throws Exception {
return format == null ? null : new ExpressionFileFormat(format);
}
public ExpressionFilter getExpressionFilter() throws Exception {
return filter == null ? null : new ExpressionFilter(filter);
}

View File

@ -80,7 +80,7 @@ public class ArgumentProcessor {
}
if (args.rename) {
cli.rename(files, args.getRenameAction(), args.getConflictAction(), args.getAbsoluteOutputFolder(), args.getExpressionFormat(), args.getDatasource(), args.getSearchQuery(), args.getSortOrder(), args.getExpressionFilter(), args.getLanguage().getLocale(), args.isStrict());
cli.rename(files, args.getRenameAction(), args.getConflictAction(), args.getAbsoluteOutputFolder(), args.getExpressionFileFormat(), args.getDatasource(), args.getSearchQuery(), args.getSortOrder(), args.getExpressionFilter(), args.getLanguage().getLocale(), args.isStrict());
}
if (args.check) {

View File

@ -11,6 +11,7 @@ import java.util.stream.Stream;
import net.filebot.Language;
import net.filebot.RenameAction;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.ExpressionFilter;
import net.filebot.format.ExpressionFormat;
import net.filebot.hash.HashType;
@ -22,7 +23,7 @@ import net.filebot.web.SortOrder;
public interface CmdlineInterface {
List<File> rename(Collection<File> files, RenameAction action, ConflictAction conflict, File output, ExpressionFormat format, Datasource db, String query, SortOrder order, ExpressionFilter filter, Locale locale, boolean strict) throws Exception;
List<File> rename(Collection<File> files, RenameAction action, ConflictAction conflict, File output, ExpressionFileFormat format, Datasource db, String query, SortOrder order, ExpressionFilter filter, Locale locale, boolean strict) throws Exception;
List<File> rename(Map<File, File> rename, RenameAction action, ConflictAction conflict) throws Exception;

View File

@ -44,6 +44,7 @@ import net.filebot.RenameAction;
import net.filebot.StandardRenameAction;
import net.filebot.archive.Archive;
import net.filebot.archive.FileMapper;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.ExpressionFilter;
import net.filebot.format.ExpressionFormat;
import net.filebot.format.MediaBindingBean;
@ -85,7 +86,7 @@ import net.filebot.web.VideoHashSubtitleService;
public class CmdlineOperations implements CmdlineInterface {
@Override
public List<File> rename(Collection<File> files, RenameAction action, ConflictAction conflict, File output, ExpressionFormat format, Datasource db, String query, SortOrder order, ExpressionFilter filter, Locale locale, boolean strict) throws Exception {
public List<File> rename(Collection<File> files, RenameAction action, ConflictAction conflict, File output, ExpressionFileFormat format, Datasource db, String query, SortOrder order, ExpressionFilter filter, Locale locale, boolean strict) throws Exception {
// movie mode
if (db instanceof MovieIdentificationService) {
return renameMovie(files, action, conflict, output, format, (MovieIdentificationService) db, query, filter, locale, strict);

View File

@ -219,11 +219,8 @@ public abstract class ScriptShellBaseClass extends Script {
public String getMediaInfo(File file, String format) throws Exception {
ExpressionFormat formatter = new ExpressionFormat(format);
Object o = xattr.getMetaInfo(file);
File f = file.getCanonicalFile();
try {
return formatter.format(new MediaBindingBean(o, f));
return formatter.format(new MediaBindingBean(xattr.getMetaInfo(file), file));
} catch (SuppressedThrowables e) {
debug.finest(format("%s => %s", format, e.getMessage()));
}
@ -342,7 +339,7 @@ public abstract class ScriptShellBaseClass extends Script {
try {
if (files.size() > 0) {
return getCLI().rename(files, args.getRenameAction(), args.getConflictAction(), args.getAbsoluteOutputFolder(), args.getExpressionFormat(), args.getDatasource(), args.getSearchQuery(), args.getSortOrder(), args.getExpressionFilter(), args.getLanguage().getLocale(), args.isStrict());
return getCLI().rename(files, args.getRenameAction(), args.getConflictAction(), args.getAbsoluteOutputFolder(), args.getExpressionFileFormat(), args.getDatasource(), args.getSearchQuery(), args.getSortOrder(), args.getExpressionFilter(), args.getLanguage().getLocale(), args.isStrict());
}
if (map.size() > 0) {

View File

@ -0,0 +1,42 @@
package net.filebot.format;
import static net.filebot.similarity.Normalization.*;
import static net.filebot.util.FileUtilities.*;
import javax.script.Bindings;
import javax.script.ScriptException;
public class ExpressionFileFormat extends ExpressionFormat {
public ExpressionFileFormat(String expression) throws ScriptException {
super(expression);
}
@Override
public Bindings getBindings(Object value) {
return new ExpressionBindings(value) {
@Override
public Object get(Object key) {
return normalizeBindingValue(super.get(key));
}
};
}
protected Object normalizeBindingValue(Object value) {
// if the binding value is a String, then remove illegal characters (that would insert accidental directory separators)
if (value instanceof CharSequence) {
return replacePathSeparators(value.toString(), " ");
}
// if the binding value is an Object, just leave it
return value;
}
@Override
protected String normalizeResult(CharSequence value) {
// normalize unicode space characters and remove newline characters
return normalizePathSeparators(replaceSpace(value, " ").trim());
}
}

View File

@ -1,9 +1,6 @@
package net.filebot.format;
import static net.filebot.similarity.Normalization.*;
import static net.filebot.util.ExceptionUtilities.*;
import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.RegularExpressions.*;
import java.security.AccessController;
import java.text.FieldPosition;
@ -66,7 +63,7 @@ public class ExpressionFormat extends Format {
if (c == open) {
if (level == 0) {
if (token.length() > 0) {
compilation.add(NEWLINE.matcher(token).replaceAll(""));
compilation.add(token.toString());
token.setLength(0);
}
} else {
@ -124,13 +121,7 @@ public class ExpressionFormat extends Format {
}
public Bindings getBindings(Object value) {
return new ExpressionBindings(value) {
@Override
public Object get(Object key) {
return normalizeBindingValue(super.get(key));
}
};
return new ExpressionBindings(value);
}
@Override
@ -183,26 +174,15 @@ public class ExpressionFormat extends Format {
}
protected Object normalizeBindingValue(Object value) {
// if the binding value is a String, remove illegal characters
if (value instanceof CharSequence) {
return replacePathSeparators((CharSequence) value, " ").trim();
}
// if the binding value is an Object, just leave it
return value;
}
protected CharSequence normalizeExpressionValue(Object value) {
if (value == null) {
return null;
}
return normalizePathSeparators(value.toString());
return value == null ? null : value.toString();
}
protected String normalizeResult(CharSequence value) {
// normalize unicode space characters and remove newline characters
return replaceSpace(value, " ").trim();
return value.toString();
}
protected Throwable normalizeExpressionException(ScriptException exception) {

View File

@ -12,14 +12,14 @@ import java.util.logging.Level;
import javax.script.ScriptException;
import net.filebot.ApplicationFolder;
import net.filebot.format.ExpressionFormat;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.MediaBindingBean;
import net.filebot.similarity.Match;
class ExpressionFormatter implements MatchFormatter {
private final String expression;
private ExpressionFormat format;
private ExpressionFileFormat format;
private Format preview;
private Class<?> target;
@ -34,7 +34,7 @@ class ExpressionFormatter implements MatchFormatter {
this.target = target;
}
public ExpressionFormatter(ExpressionFormat format, Format preview, Class<?> target) {
public ExpressionFormatter(ExpressionFileFormat format, Format preview, Class<?> target) {
this(format.getExpression(), preview, target);
// use compiled format expression right away
@ -60,7 +60,7 @@ class ExpressionFormatter implements MatchFormatter {
public synchronized String format(Match<?, ?> match, boolean extension, Map<?, ?> context) throws ScriptException {
// lazy initialize script engine
if (format == null) {
format = new ExpressionFormat(expression);
format = new ExpressionFileFormat(expression);
}
// evaluate the expression using the given bindings

View File

@ -61,6 +61,7 @@ import net.filebot.ResourceManager;
import net.filebot.Settings;
import net.filebot.UserFiles;
import net.filebot.format.BindingException;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.ExpressionFormat;
import net.filebot.format.MediaBindingBean;
import net.filebot.format.SuppressedThrowables;
@ -87,7 +88,7 @@ import net.miginfocom.swing.MigLayout;
public class FormatDialog extends JDialog {
private boolean submit = false;
private ExpressionFormat format;
private ExpressionFileFormat format;
private Mode mode;
private boolean locked = false;
@ -398,7 +399,7 @@ public class FormatDialog extends JDialog {
// bind text to preview
addPropertyChangeListener("sample", evt -> {
newSwingWorker(() -> {
return new ExpressionFormat(format).format(sample);
return new ExpressionFileFormat(format).format(sample);
}, s -> {
formatExample.setText(s);
}).execute();
@ -449,7 +450,7 @@ public class FormatDialog extends JDialog {
private void checkFormatInBackground() {
try {
// check syntax in foreground
ExpressionFormat format = new ExpressionFormat(editor.getText().trim());
ExpressionFileFormat format = new ExpressionFileFormat(editor.getText().trim());
// activate delayed to avoid flickering when formatting takes only a couple of milliseconds
Timer progressIndicatorTimer = invokeLater(400, () -> progressIndicator.setVisible(true));
@ -666,7 +667,7 @@ public class FormatDialog extends JDialog {
protected final Action approveFormatAction = newAction("Use Format", ResourceManager.getIcon("dialog.continue"), evt -> {
try {
// check syntax
format = new ExpressionFormat(editor.getText().trim());
format = new ExpressionFileFormat(editor.getText().trim());
if (format.getExpression().isEmpty()) {
throw new ScriptException("Expression is empty");

View File

@ -15,6 +15,7 @@ import net.filebot.CachedResource.Transform;
import net.filebot.Language;
import net.filebot.StandardRenameAction;
import net.filebot.format.ExpressionFileFilter;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.ExpressionFilter;
import net.filebot.format.ExpressionFormat;
import net.filebot.media.XattrMetaInfoProvider;
@ -60,8 +61,8 @@ public class Preset {
return getInputFolder() == null ? null : getValue(includes, expression -> new ExpressionFileFilter(expression));
}
public ExpressionFormat getFormat() {
return getValue(format, ExpressionFormat::new);
public ExpressionFileFormat getFormat() {
return getValue(format, ExpressionFileFormat::new);
}
public String getMatchMode() {

View File

@ -37,8 +37,8 @@ import net.filebot.ResourceManager;
import net.filebot.StandardRenameAction;
import net.filebot.UserFiles;
import net.filebot.WebServices;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.ExpressionFilter;
import net.filebot.format.ExpressionFormat;
import net.filebot.format.MediaBindingBean;
import net.filebot.mac.MacAppUtilities;
import net.filebot.ui.HeaderPanel;
@ -181,7 +181,7 @@ public class PresetEditor extends JDialog {
String name = presetNameHeader.getTitleLabel().getText();
File path = inheritRadio.isSelected() ? null : new File(pathInput.getText());
ExpressionFilter includes = inheritRadio.isSelected() ? null : new ExpressionFilter(filterEditor.getText());
ExpressionFormat format = formatEditor.getText().trim().isEmpty() ? null : new ExpressionFormat(formatEditor.getText());
ExpressionFileFormat format = formatEditor.getText().trim().isEmpty() ? null : new ExpressionFileFormat(formatEditor.getText());
Datasource database = ((Datasource) providerCombo.getSelectedItem());
SortOrder sortOrder = sortOrderCombo.isEnabled() ? ((SortOrder) sortOrderCombo.getSelectedItem()) : null;
String matchMode = matchModeCombo.isEnabled() ? (String) matchModeCombo.getSelectedItem() : null;

View File

@ -64,7 +64,7 @@ import net.filebot.Settings;
import net.filebot.StandardRenameAction;
import net.filebot.UserFiles;
import net.filebot.WebServices;
import net.filebot.format.ExpressionFormat;
import net.filebot.format.ExpressionFileFormat;
import net.filebot.format.MediaBindingBean;
import net.filebot.mac.MacAppUtilities;
import net.filebot.media.MetaAttributes;
@ -741,7 +741,7 @@ public class RenamePanel extends JComponent {
@Override
public void actionPerformed(ActionEvent evt) {
SwingWorker<ExpressionFormatter, Void> worker = newSwingWorker(() -> {
ExpressionFormat format = preset.getFormat();
ExpressionFileFormat format = preset.getFormat();
if (format != null && preset.getDatasource() != null) {
switch (Mode.getMode(preset.getDatasource())) {