diff --git a/build.xml b/build.xml
index 49b63a4f..98c635b1 100644
--- a/build.xml
+++ b/build.xml
@@ -181,6 +181,10 @@
+
+
+
+
diff --git a/lib/native/mac-x86_64/libxattrj.dylib b/lib/native/mac-x86_64/libxattrj.dylib
new file mode 100644
index 00000000..51687e40
Binary files /dev/null and b/lib/native/mac-x86_64/libxattrj.dylib differ
diff --git a/lib/xattrj.jar b/lib/xattrj.jar
new file mode 100644
index 00000000..12ed6d4a
Binary files /dev/null and b/lib/xattrj.jar differ
diff --git a/source/net/filebot/MetaAttributeView.java b/source/net/filebot/MetaAttributeView.java
index 74dbb4ef..8a207dca 100644
--- a/source/net/filebot/MetaAttributeView.java
+++ b/source/net/filebot/MetaAttributeView.java
@@ -10,13 +10,30 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.UserDefinedFileAttributeView;
import java.util.AbstractMap;
+import java.util.Arrays;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Set;
+import org.securityvision.xattrj.Xattrj;
+
+import com.sun.jna.Platform;
+
public class MetaAttributeView extends AbstractMap {
- private final UserDefinedFileAttributeView attributeView;
- private final Charset encoding;
+ // UserDefinedFileAttributeView (for Windows and Linux) OR 3rd party Xattrj (for Mac) because UserDefinedFileAttributeView is not supported (Oracle Java 7/8)
+ private Object xattr;
+ private File file;
+ private Charset encoding;
+
+ private static Xattrj MacXattrSupport;
+
+ private static synchronized Xattrj getMacXattrSupport() throws Throwable {
+ if (MacXattrSupport == null) {
+ MacXattrSupport = new Xattrj();
+ }
+ return MacXattrSupport;
+ }
public MetaAttributeView(File file) throws IOException {
Path path = file.getCanonicalFile().toPath();
@@ -28,49 +45,98 @@ public class MetaAttributeView extends AbstractMap {
path = link;
}
- attributeView = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
- if (attributeView == null) {
- throw new IOException("UserDefinedFileAttributeView is not supported");
+ xattr = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
+
+ // try 3rd party Xattrj library
+ if (xattr == null) {
+ if (Platform.isMac()) {
+ try {
+ xattr = getMacXattrSupport();
+ } catch (Throwable e) {
+ throw new IOException("Unable to load library: xattrj", e);
+ }
+ } else {
+ throw new IOException("UserDefinedFileAttributeView is not supported");
+ }
}
- encoding = Charset.forName("UTF-8");
+
+ this.file = path.toFile();
+ this.encoding = Charset.forName("UTF-8");
}
@Override
public String get(Object key) {
try {
- ByteBuffer buffer = ByteBuffer.allocate(attributeView.size(key.toString()));
- attributeView.read(key.toString(), buffer);
- buffer.flip();
+ if (xattr instanceof UserDefinedFileAttributeView) {
+ UserDefinedFileAttributeView attributeView = (UserDefinedFileAttributeView) xattr;
+ ByteBuffer buffer = ByteBuffer.allocate(attributeView.size(key.toString()));
+ attributeView.read(key.toString(), buffer);
+ buffer.flip();
- return encoding.decode(buffer).toString();
- } catch (IOException e) {
- return null;
+ return encoding.decode(buffer).toString();
+ }
+
+ if (xattr instanceof Xattrj) {
+ Xattrj macXattr = (Xattrj) xattr;
+ return macXattr.readAttribute(file, key.toString());
+ }
+ } catch (Exception e) {
+ // ignore
}
+
+ return null;
}
@Override
public String put(String key, String value) {
try {
- if (value == null || value.isEmpty()) {
- attributeView.delete(key);
- } else {
- attributeView.write(key, encoding.encode(value));
+ if (xattr instanceof UserDefinedFileAttributeView) {
+ UserDefinedFileAttributeView attributeView = (UserDefinedFileAttributeView) xattr;
+ if (value == null || value.isEmpty()) {
+ attributeView.delete(key);
+ } else {
+ attributeView.write(key, encoding.encode(value));
+ }
}
- } catch (IOException e) {
+
+ if (xattr instanceof Xattrj) {
+ Xattrj macXattr = (Xattrj) xattr;
+ if (value == null || value.isEmpty()) {
+ macXattr.removeAttribute(file, key);
+ } else {
+ macXattr.writeAttribute(file, key, value);
+ }
+ }
+ } catch (Exception e) {
throw new IllegalStateException(e);
}
+
return null; // since we don't know the old value
}
+ public List list() throws IOException {
+ if (xattr instanceof UserDefinedFileAttributeView) {
+ UserDefinedFileAttributeView attributeView = (UserDefinedFileAttributeView) xattr;
+ return attributeView.list();
+ }
+
+ if (xattr instanceof Xattrj) {
+ Xattrj macXattr = (Xattrj) xattr;
+ return Arrays.asList(macXattr.listAttributes(file));
+ }
+
+ return null;
+ }
+
@Override
public Set> entrySet() {
try {
Set> entries = new LinkedHashSet>();
- for (String name : attributeView.list()) {
+ for (String name : this.list()) {
entries.add(new AttributeEntry(name));
}
return entries;
- } catch (IOException e) {
+ } catch (Exception e) {
throw new IllegalStateException(e);
}
}
@@ -78,28 +144,10 @@ public class MetaAttributeView extends AbstractMap {
@Override
public void clear() {
try {
- for (String it : attributeView.list()) {
- attributeView.delete(it);
+ for (String key : this.list()) {
+ this.put(key, null);
}
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public int size() {
- try {
- return attributeView.list().size();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public boolean isEmpty() {
- try {
- return attributeView.list().isEmpty();
- } catch (IOException e) {
+ } catch (Exception e) {
throw new IllegalStateException(e);
}
}
diff --git a/source/net/filebot/cli/ScriptShellMethods.java b/source/net/filebot/cli/ScriptShellMethods.java
index 26eabd56..edcc7dd1 100644
--- a/source/net/filebot/cli/ScriptShellMethods.java
+++ b/source/net/filebot/cli/ScriptShellMethods.java
@@ -24,6 +24,7 @@ import java.util.Map;
import net.filebot.MediaTypes;
import net.filebot.MetaAttributeView;
+import net.filebot.Settings;
import net.filebot.media.MediaDetection;
import net.filebot.media.MetaAttributes;
import net.filebot.similarity.NameSimilarityMetric;
@@ -362,17 +363,24 @@ public class ScriptShellMethods {
public static MetaAttributeView getXattr(File self) {
try {
- return new MetaAttributeView(self);
+ if (Settings.useExtendedFileAttributes()) {
+ return new MetaAttributeView(self);
+ }
} catch (Exception e) {
- return null;
+ // ignore
}
+ return null;
}
public static Object getMetadata(File self) {
try {
- return new MetaAttributes(self);
+ if (Settings.useExtendedFileAttributes()) {
+ return new MetaAttributes(self);
+ }
} catch (Exception e) {
- return null;
+ // ignore
}
+ return null;
}
+
}
diff --git a/source/net/filebot/media/MetaAttributes.java b/source/net/filebot/media/MetaAttributes.java
index db54c5e2..3cd67f68 100644
--- a/source/net/filebot/media/MetaAttributes.java
+++ b/source/net/filebot/media/MetaAttributes.java
@@ -61,8 +61,8 @@ public class MetaAttributes {
}
public void clear() {
- metaAttributeView.remove(FILENAME_KEY);
- metaAttributeView.remove(METADATA_KEY);
+ metaAttributeView.put(FILENAME_KEY, null);
+ metaAttributeView.put(METADATA_KEY, null);
}
}
diff --git a/source/net/filebot/ui/rename/HistoryDialog.java b/source/net/filebot/ui/rename/HistoryDialog.java
index 80b0ec26..d4ef5bc7 100644
--- a/source/net/filebot/ui/rename/HistoryDialog.java
+++ b/source/net/filebot/ui/rename/HistoryDialog.java
@@ -68,6 +68,8 @@ import net.filebot.History;
import net.filebot.History.Element;
import net.filebot.History.Sequence;
import net.filebot.ResourceManager;
+import net.filebot.Settings;
+import net.filebot.media.MetaAttributes;
import net.filebot.ui.transfer.FileExportHandler;
import net.filebot.ui.transfer.FileTransferablePolicy;
import net.filebot.ui.transfer.LoadAction;
@@ -534,8 +536,13 @@ class HistoryDialog extends JDialog {
for (Entry entry : getRenameMap(directory).entrySet()) {
try {
- moveRename(entry.getKey(), entry.getValue());
+ File destination = moveRename(entry.getKey(), entry.getValue());
count++;
+
+ // remove xattr that may have been set
+ if (Settings.useExtendedFileAttributes()) {
+ new MetaAttributes(destination).clear();
+ }
} catch (Exception e) {
Logger.getLogger(HistoryDialog.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}