diff --git a/.idea/fileTemplates/includes/File Header.java b/.idea/fileTemplates/includes/File Header.java
index 8d4bd925..e1971c44 100644
--- a/.idea/fileTemplates/includes/File Header.java
+++ b/.idea/fileTemplates/includes/File Header.java
@@ -1,13 +1,13 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/.idea/fileTemplates/internal/AnnotationType.java b/.idea/fileTemplates/internal/AnnotationType.java
index 955855ec..82b9a3fb 100644
--- a/.idea/fileTemplates/internal/AnnotationType.java
+++ b/.idea/fileTemplates/internal/AnnotationType.java
@@ -1,6 +1,6 @@
-#parse("File Header.java")
-
-#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
-
-public @interface ${NAME} {
-}
+#parse("File Header.java")
+
+#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
+
+public @interface ${NAME} {
+}
diff --git a/.idea/fileTemplates/internal/Class.java b/.idea/fileTemplates/internal/Class.java
index 151bb0a3..3b155ef5 100644
--- a/.idea/fileTemplates/internal/Class.java
+++ b/.idea/fileTemplates/internal/Class.java
@@ -1,6 +1,6 @@
-#parse("File Header.java")
-
-#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
-
-public class ${NAME} {
-}
+#parse("File Header.java")
+
+#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
+
+public class ${NAME} {
+}
diff --git a/.idea/fileTemplates/internal/Enum.java b/.idea/fileTemplates/internal/Enum.java
index 65929d41..d9173074 100644
--- a/.idea/fileTemplates/internal/Enum.java
+++ b/.idea/fileTemplates/internal/Enum.java
@@ -1,6 +1,6 @@
-#parse("File Header.java")
-
-#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
-
-public enum ${NAME} {
-}
+#parse("File Header.java")
+
+#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
+
+public enum ${NAME} {
+}
diff --git a/.idea/fileTemplates/internal/Interface.java b/.idea/fileTemplates/internal/Interface.java
index f2ea5005..74b9d657 100644
--- a/.idea/fileTemplates/internal/Interface.java
+++ b/.idea/fileTemplates/internal/Interface.java
@@ -1,6 +1,6 @@
-#parse("File Header.java")
-
-#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
-
-public interface ${NAME} {
-}
+#parse("File Header.java")
+
+#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
+
+public interface ${NAME} {
+}
diff --git a/.idea/fileTemplates/internal/module-info.java b/.idea/fileTemplates/internal/module-info.java
index be19fd74..57a05c6f 100644
--- a/.idea/fileTemplates/internal/module-info.java
+++ b/.idea/fileTemplates/internal/module-info.java
@@ -1,4 +1,4 @@
-#parse("File Header.java")
-
-module #[[$MODULE_NAME$]]# {
+#parse("File Header.java")
+
+module #[[$MODULE_NAME$]]# {
}
\ No newline at end of file
diff --git a/.idea/fileTemplates/internal/package-info.java b/.idea/fileTemplates/internal/package-info.java
index fec26d0d..e0371453 100644
--- a/.idea/fileTemplates/internal/package-info.java
+++ b/.idea/fileTemplates/internal/package-info.java
@@ -1,3 +1,3 @@
-#parse("File Header.java")
-
+#parse("File Header.java")
+
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
\ No newline at end of file
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/ClientServerRef.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/ClientServerRef.java
index 3a26add1..90b97492 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/ClientServerRef.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/ClientServerRef.java
@@ -1,90 +1,90 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.api;
-
-
-import com.intellij.openapi.util.Comparing;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * This class is used as a reference to a connection object.
- * It is mostly used by the caches, so that it can persist to which
- * connection it applies.
- *
- * It can directly be displayed to the user with a {@link #toString()}
- * call.
- */
-public final class ClientServerRef {
- private final P4ServerName serverName;
- private final String clientName;
-
-
- // Like P4ServerName, this class could potentially be cached, like String.intern, but that
- // might lead to additional memory problems beyond what we already have.
-
- public ClientServerRef(@NotNull final P4ServerName serverName, @Nullable final String clientName) {
- this.serverName = serverName;
- this.clientName = clientName;
- }
-
-
- @NotNull
- public P4ServerName getServerName() {
- return serverName;
- }
-
-
- @NotNull
- public String getServerDisplayId() {
- return getServerName().getDisplayName();
- }
-
-
- @Nullable
- public String getClientName() {
- return clientName;
- }
-
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o == null) {
- return false;
- }
- if (o.getClass().equals(getClass())) {
- ClientServerRef that = (ClientServerRef) o;
- return that.serverName.equals(serverName) &&
- Comparing.equal(that.clientName, clientName);
- }
- return false;
- }
-
-
- @Override
- public int hashCode() {
- return (serverName.hashCode() << 3) +
- (clientName == null ? 0 : clientName.hashCode());
- }
-
-
- @Override
- public String toString() {
- return clientName + "@" + serverName.getDisplayName();
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.api;
+
+
+import com.intellij.openapi.util.Comparing;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * This class is used as a reference to a connection object.
+ * It is mostly used by the caches, so that it can persist to which
+ * connection it applies.
+ *
+ * It can directly be displayed to the user with a {@link #toString()}
+ * call.
+ */
+public final class ClientServerRef {
+ private final P4ServerName serverName;
+ private final String clientName;
+
+
+ // Like P4ServerName, this class could potentially be cached, like String.intern, but that
+ // might lead to additional memory problems beyond what we already have.
+
+ public ClientServerRef(@NotNull final P4ServerName serverName, @Nullable final String clientName) {
+ this.serverName = serverName;
+ this.clientName = clientName;
+ }
+
+
+ @NotNull
+ public P4ServerName getServerName() {
+ return serverName;
+ }
+
+
+ @NotNull
+ public String getServerDisplayId() {
+ return getServerName().getDisplayName();
+ }
+
+
+ @Nullable
+ public String getClientName() {
+ return clientName;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o == null) {
+ return false;
+ }
+ if (o.getClass().equals(getClass())) {
+ ClientServerRef that = (ClientServerRef) o;
+ return that.serverName.equals(serverName) &&
+ Comparing.equal(that.clientName, clientName);
+ }
+ return false;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return (serverName.hashCode() << 3) +
+ (clientName == null ? 0 : clientName.hashCode());
+ }
+
+
+ @Override
+ public String toString() {
+ return clientName + "@" + serverName.getDisplayName();
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/P4PluginVersion.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/P4PluginVersion.java
index 9707024c..caee38ef 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/P4PluginVersion.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/P4PluginVersion.java
@@ -1,85 +1,85 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.api;
-
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.InputStream;
-
-/**
- * Loads the plugin version from the plugin.xml file.
- */
-public class P4PluginVersion {
- private static final Logger LOG = Logger.getInstance(P4PluginVersion.class);
-
- private static volatile String version;
-
- public static String getPluginVersion() {
- if (version == null) {
- synchronized (P4PluginVersion.class) {
- version = loadPluginVersion();
- }
- if (LOG.isDebugEnabled()) {
- LOG.debug("Running plugin version " + version);
- }
- }
- return version;
- }
-
-
- @NotNull
- private static String loadPluginVersion() {
- ClassLoader cl = getClassLoader();
- if (cl == null) {
- // Can't find the version.
- return "1";
- }
- try {
- final InputStream res = cl.getResourceAsStream("p4ic-version.txt");
- if (res == null) {
- return "3";
- }
- try {
- StringBuilder sb = new StringBuilder();
- byte[] buff = new byte[4096];
- int len;
- while ((len = res.read(buff)) > 0) {
- // TODO encoding
- sb.append(new String(buff, 0, len));
- }
- return sb.toString().trim();
- } finally {
- res.close();
- }
- } catch (Exception e) {
- LOG.info("Cannot read p4ic-version.txt", e);
- return "2";
- }
- }
-
- @Nullable
- private static ClassLoader getClassLoader() {
- // Do not fetch the class loader from the thread context; we want
- // the plugin's class loader, not whatever context this is running
- // in.
- final ClassLoader ret = P4PluginVersion.class.getClassLoader();
- if (ret != null) {
- return ret;
- }
- return null;
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.api;
+
+import com.intellij.openapi.diagnostic.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.InputStream;
+
+/**
+ * Loads the plugin version from the plugin.xml file.
+ */
+public class P4PluginVersion {
+ private static final Logger LOG = Logger.getInstance(P4PluginVersion.class);
+
+ private static volatile String version;
+
+ public static String getPluginVersion() {
+ if (version == null) {
+ synchronized (P4PluginVersion.class) {
+ version = loadPluginVersion();
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Running plugin version " + version);
+ }
+ }
+ return version;
+ }
+
+
+ @NotNull
+ private static String loadPluginVersion() {
+ ClassLoader cl = getClassLoader();
+ if (cl == null) {
+ // Can't find the version.
+ return "1";
+ }
+ try {
+ final InputStream res = cl.getResourceAsStream("p4ic-version.txt");
+ if (res == null) {
+ return "3";
+ }
+ try {
+ StringBuilder sb = new StringBuilder();
+ byte[] buff = new byte[4096];
+ int len;
+ while ((len = res.read(buff)) > 0) {
+ // TODO encoding
+ sb.append(new String(buff, 0, len));
+ }
+ return sb.toString().trim();
+ } finally {
+ res.close();
+ }
+ } catch (Exception e) {
+ LOG.info("Cannot read p4ic-version.txt", e);
+ return "2";
+ }
+ }
+
+ @Nullable
+ private static ClassLoader getClassLoader() {
+ // Do not fetch the class loader from the thread context; we want
+ // the plugin's class loader, not whatever context this is running
+ // in.
+ final ClassLoader ret = P4PluginVersion.class.getClassLoader();
+ if (ret != null) {
+ return ret;
+ }
+ return null;
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/commands/file/AddEditAction.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/commands/file/AddEditAction.java
index ff215467..0502ba29 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/commands/file/AddEditAction.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/commands/file/AddEditAction.java
@@ -1,106 +1,106 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.api.commands.file;
-
-import com.intellij.openapi.vcs.FilePath;
-import net.groboclown.p4.server.api.P4CommandRunner;
-import net.groboclown.p4.server.api.commands.AbstractAction;
-import net.groboclown.p4.server.api.values.P4ChangelistId;
-import net.groboclown.p4.server.api.values.P4FileType;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.List;
-
-public class AddEditAction extends AbstractAction implements P4CommandRunner.ClientAction {
- private final String actionId;
- private final FilePath file;
- private final P4FileType type;
- private final P4ChangelistId changelistId;
- private final String charset;
-
- public AddEditAction(@NotNull FilePath file, @Nullable P4FileType type,
- @NotNull P4ChangelistId changelistId, @Nullable String charset) {
- this(createActionId(AddEditAction.class), file, type, changelistId, charset);
- }
-
- public AddEditAction(@NotNull String actionId, @NotNull FilePath file, @Nullable P4FileType type,
- P4ChangelistId changelistId, String charset) {
- this.actionId = actionId;
- this.file = file;
- this.type = type;
- this.changelistId = changelistId;
- this.charset = charset;
- }
-
- public AddEditAction(@NotNull FilePath file, @Nullable P4FileType type,
- @Nullable P4ChangelistId changelistId, @Nullable Charset charset) {
- this(file, type, changelistId, charset == null ? null : charset.name());
- }
-
- @NotNull
- @Override
- public Class extends AddEditResult> getResultType() {
- return AddEditResult.class;
- }
-
- @Override
- public P4CommandRunner.ClientActionCmd getCmd() {
- return P4CommandRunner.ClientActionCmd.ADD_EDIT_FILE;
- }
-
- @NotNull
- @Override
- public String getActionId() {
- return actionId;
- }
-
- @NotNull
- public FilePath getFile() {
- return file;
- }
-
- @Nullable
- public P4FileType getFileType() {
- return type;
- }
-
- @Nullable
- public P4ChangelistId getChangelistId() {
- return changelistId;
- }
-
- @Nullable
- public String getCharset() {
- return charset;
- }
-
- @NotNull
- @Override
- public String[] getDisplayParameters() {
- if (changelistId != null) {
- return new String[] { changeId(changelistId) };
- }
- return EMPTY;
- }
-
- @NotNull
- @Override
- public List getAffectedFiles() {
- return Collections.singletonList(file);
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.api.commands.file;
+
+import com.intellij.openapi.vcs.FilePath;
+import net.groboclown.p4.server.api.P4CommandRunner;
+import net.groboclown.p4.server.api.commands.AbstractAction;
+import net.groboclown.p4.server.api.values.P4ChangelistId;
+import net.groboclown.p4.server.api.values.P4FileType;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+
+public class AddEditAction extends AbstractAction implements P4CommandRunner.ClientAction {
+ private final String actionId;
+ private final FilePath file;
+ private final P4FileType type;
+ private final P4ChangelistId changelistId;
+ private final String charset;
+
+ public AddEditAction(@NotNull FilePath file, @Nullable P4FileType type,
+ @NotNull P4ChangelistId changelistId, @Nullable String charset) {
+ this(createActionId(AddEditAction.class), file, type, changelistId, charset);
+ }
+
+ public AddEditAction(@NotNull String actionId, @NotNull FilePath file, @Nullable P4FileType type,
+ P4ChangelistId changelistId, String charset) {
+ this.actionId = actionId;
+ this.file = file;
+ this.type = type;
+ this.changelistId = changelistId;
+ this.charset = charset;
+ }
+
+ public AddEditAction(@NotNull FilePath file, @Nullable P4FileType type,
+ @Nullable P4ChangelistId changelistId, @Nullable Charset charset) {
+ this(file, type, changelistId, charset == null ? null : charset.name());
+ }
+
+ @NotNull
+ @Override
+ public Class extends AddEditResult> getResultType() {
+ return AddEditResult.class;
+ }
+
+ @Override
+ public P4CommandRunner.ClientActionCmd getCmd() {
+ return P4CommandRunner.ClientActionCmd.ADD_EDIT_FILE;
+ }
+
+ @NotNull
+ @Override
+ public String getActionId() {
+ return actionId;
+ }
+
+ @NotNull
+ public FilePath getFile() {
+ return file;
+ }
+
+ @Nullable
+ public P4FileType getFileType() {
+ return type;
+ }
+
+ @Nullable
+ public P4ChangelistId getChangelistId() {
+ return changelistId;
+ }
+
+ @Nullable
+ public String getCharset() {
+ return charset;
+ }
+
+ @NotNull
+ @Override
+ public String[] getDisplayParameters() {
+ if (changelistId != null) {
+ return new String[] { changeId(changelistId) };
+ }
+ return EMPTY;
+ }
+
+ @NotNull
+ @Override
+ public List getAffectedFiles() {
+ return Collections.singletonList(file);
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ClientConfig.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ClientConfig.java
index 71019579..3f857eaf 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ClientConfig.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ClientConfig.java
@@ -1,189 +1,189 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.config;
-
-import net.groboclown.p4.server.api.ClientServerRef;
-import net.groboclown.p4.server.api.config.part.ConfigPart;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.annotation.concurrent.Immutable;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static org.apache.commons.lang3.StringUtils.isBlank;
-
-/**
- * Stores information regarding a server configuration and the specific client/workspace in that
- * server.
- *
- * This is used for server commands that require a valid client workspace.
- *
- * This class MUST be immutable.
- */
-@Immutable
-public final class ClientConfig {
- // Just some character that won't appear in any real text, but
- // is still viewable in a debugger.
- static final char SEP = (char) 0x263a;
-
- private static final AtomicInteger COUNT = new AtomicInteger(0);
-
- private final int configVersion;
- private final ServerConfig serverConfig;
- private final String clientName;
- private final String clientHostName;
- private final String defaultCharSet;
- private final String ignoreFileName;
-
- private final ClientServerRef clientServerRef;
- private final String clientServerUniqueId;
-
- @NotNull
- public static ClientConfig createFrom(@NotNull ServerConfig serverConfig, @NotNull ConfigPart data) {
- if (!isValidClientConfig(serverConfig, data)) {
- throw new IllegalArgumentException("did not validate data");
- }
- return new ClientConfig(serverConfig, data);
- }
-
-
- public static boolean isValidClientConfig(@Nullable ServerConfig serverConfig, @Nullable ConfigPart part) {
- if (serverConfig == null || part == null || part.hasError()) {
- return false;
- }
- if (isBlank(part.getClientname())) {
- return false;
- }
- if (isBlank(serverConfig.getUsername())) {
- return false;
- }
- return true;
- }
-
-
- private ClientConfig(@NotNull ServerConfig serverConfig, @NotNull ConfigPart data) {
- // Not needed anymore, because the calling class (P4ProjectConfigStack) does this check, and we don't
- // want a misleading double exception in the logs.
- /*
- if (! serverConfig.isSameServerConnection(data)) {
- LOG.error("Server config " + serverConfig +
- " does not match data config " + ConfigPropertiesUtil.toProperties(data));
- }
- */
- this.configVersion = COUNT.incrementAndGet();
-
- this.serverConfig = serverConfig;
- this.clientName =
- data.hasClientnameSet()
- ? data.getClientname()
- : null;
- this.clientHostName =
- data.hasClientHostnameSet()
- ? data.getClientHostname()
- : null;
- this.defaultCharSet =
- data.hasDefaultCharsetSet()
- ? data.getDefaultCharset()
- : null;
- this.ignoreFileName =
- data.hasIgnoreFileNameSet()
- ? data.getIgnoreFileName()
- : null;
-
- this.clientServerUniqueId = serverConfig.getServerId() + SEP +
- this.clientName + SEP +
- this.clientHostName + SEP +
- this.ignoreFileName + SEP +
- this.defaultCharSet + SEP;
- // root directories are not listed, because all client configs
- // for the same client and server should be a shared object.
- this.clientServerRef = new ClientServerRef(serverConfig.getServerName(), clientName);
- }
-
- public int getConfigVersion() {
- return this.configVersion;
- }
-
- /**
- *
- * @return unique ID for this client, which is shared for all clients with the
- * same setup.
- */
- @NotNull
- public String getClientServerUniqueId() {
- return clientServerUniqueId;
- }
-
- @NotNull
- public ServerConfig getServerConfig() {
- return serverConfig;
- }
-
- @Nullable
- public String getClientname() {
- return clientName;
- }
-
- @Nullable
- public String getClientHostName() {
- return clientHostName;
- }
-
- @Nullable
- public String getIgnoreFileName() {
- return ignoreFileName;
- }
-
- @Nullable
- public String getDefaultCharSet() {
- return defaultCharSet;
- }
-
- @NotNull
- public ClientServerRef getClientServerRef() {
- return clientServerRef;
- }
-
- public boolean isIn(@NotNull ServerConfig config) {
- return getServerConfig().getServerId().equals(config.getServerId());
- }
-
- @Override
- public String toString() {
- if (clientName != null) {
- return serverConfig.getServerName().getDisplayName() + "@" + clientName;
- }
- return serverConfig.getServerName().getDisplayName();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (obj == this) {
- return true;
- }
- if (! (obj instanceof ClientConfig)) {
- return false;
- }
- ClientConfig that = (ClientConfig) obj;
- return getClientServerUniqueId().equals(that.getClientServerUniqueId());
- }
-
- @Override
- public int hashCode() {
- return clientServerUniqueId.hashCode();
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.config;
+
+import net.groboclown.p4.server.api.ClientServerRef;
+import net.groboclown.p4.server.api.config.part.ConfigPart;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.annotation.concurrent.Immutable;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
+/**
+ * Stores information regarding a server configuration and the specific client/workspace in that
+ * server.
+ *
+ * This is used for server commands that require a valid client workspace.
+ *
+ * This class MUST be immutable.
+ */
+@Immutable
+public final class ClientConfig {
+ // Just some character that won't appear in any real text, but
+ // is still viewable in a debugger.
+ static final char SEP = (char) 0x263a;
+
+ private static final AtomicInteger COUNT = new AtomicInteger(0);
+
+ private final int configVersion;
+ private final ServerConfig serverConfig;
+ private final String clientName;
+ private final String clientHostName;
+ private final String defaultCharSet;
+ private final String ignoreFileName;
+
+ private final ClientServerRef clientServerRef;
+ private final String clientServerUniqueId;
+
+ @NotNull
+ public static ClientConfig createFrom(@NotNull ServerConfig serverConfig, @NotNull ConfigPart data) {
+ if (!isValidClientConfig(serverConfig, data)) {
+ throw new IllegalArgumentException("did not validate data");
+ }
+ return new ClientConfig(serverConfig, data);
+ }
+
+
+ public static boolean isValidClientConfig(@Nullable ServerConfig serverConfig, @Nullable ConfigPart part) {
+ if (serverConfig == null || part == null || part.hasError()) {
+ return false;
+ }
+ if (isBlank(part.getClientname())) {
+ return false;
+ }
+ if (isBlank(serverConfig.getUsername())) {
+ return false;
+ }
+ return true;
+ }
+
+
+ private ClientConfig(@NotNull ServerConfig serverConfig, @NotNull ConfigPart data) {
+ // Not needed anymore, because the calling class (P4ProjectConfigStack) does this check, and we don't
+ // want a misleading double exception in the logs.
+ /*
+ if (! serverConfig.isSameServerConnection(data)) {
+ LOG.error("Server config " + serverConfig +
+ " does not match data config " + ConfigPropertiesUtil.toProperties(data));
+ }
+ */
+ this.configVersion = COUNT.incrementAndGet();
+
+ this.serverConfig = serverConfig;
+ this.clientName =
+ data.hasClientnameSet()
+ ? data.getClientname()
+ : null;
+ this.clientHostName =
+ data.hasClientHostnameSet()
+ ? data.getClientHostname()
+ : null;
+ this.defaultCharSet =
+ data.hasDefaultCharsetSet()
+ ? data.getDefaultCharset()
+ : null;
+ this.ignoreFileName =
+ data.hasIgnoreFileNameSet()
+ ? data.getIgnoreFileName()
+ : null;
+
+ this.clientServerUniqueId = serverConfig.getServerId() + SEP +
+ this.clientName + SEP +
+ this.clientHostName + SEP +
+ this.ignoreFileName + SEP +
+ this.defaultCharSet + SEP;
+ // root directories are not listed, because all client configs
+ // for the same client and server should be a shared object.
+ this.clientServerRef = new ClientServerRef(serverConfig.getServerName(), clientName);
+ }
+
+ public int getConfigVersion() {
+ return this.configVersion;
+ }
+
+ /**
+ *
+ * @return unique ID for this client, which is shared for all clients with the
+ * same setup.
+ */
+ @NotNull
+ public String getClientServerUniqueId() {
+ return clientServerUniqueId;
+ }
+
+ @NotNull
+ public ServerConfig getServerConfig() {
+ return serverConfig;
+ }
+
+ @Nullable
+ public String getClientname() {
+ return clientName;
+ }
+
+ @Nullable
+ public String getClientHostName() {
+ return clientHostName;
+ }
+
+ @Nullable
+ public String getIgnoreFileName() {
+ return ignoreFileName;
+ }
+
+ @Nullable
+ public String getDefaultCharSet() {
+ return defaultCharSet;
+ }
+
+ @NotNull
+ public ClientServerRef getClientServerRef() {
+ return clientServerRef;
+ }
+
+ public boolean isIn(@NotNull ServerConfig config) {
+ return getServerConfig().getServerId().equals(config.getServerId());
+ }
+
+ @Override
+ public String toString() {
+ if (clientName != null) {
+ return serverConfig.getServerName().getDisplayName() + "@" + clientName;
+ }
+ return serverConfig.getServerName().getDisplayName();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (! (obj instanceof ClientConfig)) {
+ return false;
+ }
+ ClientConfig that = (ClientConfig) obj;
+ return getClientServerUniqueId().equals(that.getClientServerUniqueId());
+ }
+
+ @Override
+ public int hashCode() {
+ return clientServerUniqueId.hashCode();
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ServerConfig.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ServerConfig.java
index 4a0ad5e2..f6e51856 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ServerConfig.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/config/ServerConfig.java
@@ -1,364 +1,364 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.config;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.io.FileUtil;
-import net.groboclown.p4.server.api.ApplicationPasswordRegistry;
-import net.groboclown.p4.server.api.P4ServerName;
-import net.groboclown.p4.server.api.config.part.ConfigPart;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static net.groboclown.p4.server.api.util.EqualUtil.isEqual;
-import static org.apache.commons.lang3.StringUtils.isBlank;
-
-
-/**
- * Stores the connection information related to a specific Perforce
- * server. It only keeps track of information required to identify the
- * server, which means it needs the username, password, auth ticket file,
- * trust ticket file, and server fingerprint.
- *
- * Implementations must specify {@link #equals(Object)} and
- * {@link #hashCode()}, to indicate whether the server connection
- * properties are the same; it should not match on online mode.
- *
- * If the configuration specified a password, then it is stored externally
- * in the {@link ApplicationPasswordRegistry}. This also allows for keeping
- * in one place the password in case the user enters it manually, which would
- * break immutability.
- *
- * This is used for running server commands that do not require a client,
- * but do require a username. There are limited commands that no not require a
- * username, and for those, the {@link P4ServerName} is sufficient for connectivity.
- *
- * This class MUST be immutable.
- */
-@Immutable
-public final class ServerConfig {
- private static final Logger LOG = Logger.getInstance(ServerConfig.class);
-
- // Just some character that won't appear in any real text, but
- // is still viewable in a debugger.
- static final char SEP = (char) 0x263b;
-
- private static final AtomicInteger COUNT = new AtomicInteger(0);
-
- private final int configVersion;
- private final P4ServerName serverName;
- private final String username;
- private final File authTicket;
- private final File trustTicket;
- private final String serverFingerprint;
- private final String loginSso;
-
- private final String serverId;
-
- private final boolean usesPassword;
-
- @NotNull
- static String getServerIdForDataPart(@NotNull ConfigPart part) {
- StringBuilder sb = new StringBuilder();
- if (part.hasServerNameSet() && part.getServerName() != null) {
- sb.append(part.getServerName().getFullPort());
- } else {
- sb.append((String) null);
- }
- // Note: does not include password information.
- sb.append(SEP)
- .append(part.hasUsernameSet() ? part.getUsername() : null)
- .append(SEP)
- .append(part.hasAuthTicketFileSet() ? part.getAuthTicketFile() : null)
- .append(SEP)
- .append(part.hasTrustTicketFileSet() ? part.getTrustTicketFile() : null)
- .append(SEP)
- .append(part.hasServerFingerprintSet() ? part.getServerFingerprint() : null);
- // These may be common enough that we want to save memory by interning the strings.
- return sb.toString().intern();
- }
-
-
-
- @NotNull
- public static ServerConfig createFrom(@NotNull ConfigPart part) {
- return new ServerConfig(part);
- }
-
- public static boolean isValidServerConfig(@Nullable ConfigPart part) {
- if (part == null || part.hasError()) {
- return false;
- }
-
- // This should be included with the above config problems.
- if (part.getServerName() == null || isBlank(part.getServerName().getFullPort())) {
- return false;
- }
-
- if (isBlank(part.getUsername())) {
- return false;
- }
-
- return true;
- }
-
- private ServerConfig(@NotNull ConfigPart part) {
- if (! isValidServerConfig(part)) {
- throw new IllegalArgumentException("Did not check validity before creating");
- }
- this.configVersion = COUNT.incrementAndGet();
-
- assert part.hasServerNameSet();
- this.serverName = part.getServerName();
- assert part.hasUsernameSet();
- this.username = part.getUsername();
- this.authTicket =
- part.hasAuthTicketFileSet()
- ? part.getAuthTicketFile()
- : null;
- this.trustTicket =
- part.hasTrustTicketFileSet()
- ? part.getTrustTicketFile()
- : null;
- this.serverFingerprint =
- part.hasServerFingerprintSet()
- ? part.getServerFingerprint()
- : null;
- this.loginSso =
- part.hasLoginSsoSet()
- ? part.getLoginSso()
- : null;
- this.usesPassword = part.requiresUserEnteredPassword() || part.hasPasswordSet();
-
- this.serverId = getServerIdForDataPart(part);
-
- // Must be done at the very end.
- // This logic is carefully constructed to only store the password if it's supplied by the
- // user, and the user does not require that it is manually entered into the UI.
- // This class never stores the password in itself.
- if (!part.requiresUserEnteredPassword() && part.hasPasswordSet() && part.getPlaintextPassword() != null) {
- LOG.info("Storing user password in password store");
- // DEBUG
- // ApplicationPasswordRegistry.getInstance().store(this, part.getPlaintextPassword().toCharArray(), false);
- ApplicationPasswordRegistry instance = ApplicationPasswordRegistry.getInstance();
- String passwd = part.getPlaintextPassword();
- char[] passwdChars = passwd.toCharArray();
- instance.store(this, passwdChars, false);
- }
- }
-
-
- public int getConfigVersion() {
- return this.configVersion;
- }
-
- /**
- *
- * @return true if the user supplies a password, either through plaintext, or through the UI asking for it.
- */
- public boolean usesStoredPassword() {
- return usesPassword;
- }
-
- @NotNull
- public P4ServerName getServerName() {
- return serverName;
- }
-
- @NotNull
- public String getUsername() {
- return username;
- }
-
- @Nullable
- public File getAuthTicket() {
- return authTicket;
- }
-
- @Nullable
- public File getTrustTicket() {
- return trustTicket;
- }
-
- @Nullable
- public String getServerFingerprint() {
- return serverFingerprint;
- }
-
- @Nullable
- public String getLoginSso() {
- return loginSso;
- }
-
- public boolean hasServerFingerprint() {
- return getServerFingerprint() != null && getServerFingerprint().length() > 0;
- }
-
- public boolean hasAuthTicket() {
- return getAuthTicket() != null;
- }
-
- public boolean hasTrustTicket() {
- return getTrustTicket() != null;
- }
-
- public boolean hasLoginSso() {
- return getLoginSso() != null;
- }
-
- /**
- *
- * @return unique identifier for the server connection settings.
- */
- @NotNull
- public String getServerId() {
- return serverId;
- }
-
- /**
- * Checks if the {@literal part} connects to the same server
- * in the same way as this server configuration. For identifying
- * if the server itself is the same, then compare the
- * {@link P4ServerName} values.
- *
- * @param part configuration to compare
- * @return true if the {@literal part} and this config connect to
- * the same server the same way.
- */
- boolean isSameServerConnection(@Nullable ConfigPart part) {
- if (part == null) {
- LOG.debug("isSameServerConnection: input is null");
- return false;
- }
-
- if (! isEqual(getServerName(), part.getServerName())) {
- if (LOG.isDebugEnabled()) {
- if (part.getServerName() == null) {
- LOG.debug("isSameServerConnection: input server name is null");
- } else {
- LOG.debug("isSameServerConnection: server doesn't match: "
- + getServerName().getServerPort() + "::" + getServerName().getServerProtocol() + " <> "
- + part.getServerName().getServerPort() + "::" + part.getServerName().getServerProtocol());
- }
- }
- return false;
- }
-
- if (! filesEqual(hasAuthTicket(), getAuthTicket(), part.hasAuthTicketFileSet(), part.getAuthTicketFile())) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("isSameServerConnection: auth ticket doesn't match: "
- + getAuthTicket() + " <> " + part.getAuthTicketFile());
- }
- return false;
- }
-
- if (! filesEqual(hasTrustTicket(), getTrustTicket(), part.hasTrustTicketFileSet(), part.getTrustTicketFile())) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("isSameServerConnection: trust ticket doesn't match: "
- + getTrustTicket() + " <> " + part.getTrustTicketFile());
- }
- return false;
- }
-
- if (hasServerFingerprint() != part.hasServerFingerprintSet()) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("isSameServerConnection: has server fingerprint mismatch: "
- + hasServerFingerprint() + " <> " + part.hasServerFingerprintSet());
- }
- return false;
- }
- if (hasServerFingerprint() && ! isEqual(getServerFingerprint(), part.getServerFingerprint())) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("isSameServerConnection: server fingerprint mismatch: "
- + getServerFingerprint() + " <> " + part.getServerFingerprint());
- }
- return false;
- }
-
- if (! isEqual(getUsername(), part.getUsername())) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("isSameServerConnection: username mismatch: "
- + getUsername() + " <> " + part.getUsername());
- }
- return false;
- }
-
- // password usage is a bit more complex.
- if (
- (usesStoredPassword() && (!part.requiresUserEnteredPassword() && !part.hasPasswordSet()))
- || (!usesStoredPassword() && (part.requiresUserEnteredPassword() || part.hasPasswordSet()))
- ) {
- return false;
- }
-
- return true;
- }
-
- @NotNull
- private Map toProperties() {
- return ConfigPropertiesUtil.toProperties(this, "(unset)", "(empty)", "(set)");
- }
-
- @TestOnly
- @Override
- public String toString() {
- return toProperties().toString();
- }
-
-
- // equals only cares about the information that connects
- // to the server, not the individual server setup. Note that
- // this might have the potential to lose information.
- @Override
- public boolean equals(Object other) {
- if (other == null) {
- return false;
- }
- if (this == other) {
- return true;
- }
- if (!(other instanceof ServerConfig)) {
- return false;
- }
- ServerConfig sc = (ServerConfig) other;
- return sc.getServerId().equals(getServerId());
- }
-
- @Override
- public int hashCode() {
- return getServerId().hashCode();
- }
-
-
- private static boolean filesEqual(boolean aSet, @Nullable File aFile, boolean bSet, @Nullable File bFile) {
- return FileUtil.filesEqual(scrubFile(aSet, aFile), scrubFile(bSet, bFile));
- }
-
- @Nullable
- private static File scrubFile(boolean isSet, @Nullable File file) {
- if (! isSet || file == null) {
- return null;
- }
- if (file.exists() && file.isFile()) {
- return file;
- }
- return null;
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.config;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.io.FileUtil;
+import net.groboclown.p4.server.api.ApplicationPasswordRegistry;
+import net.groboclown.p4.server.api.P4ServerName;
+import net.groboclown.p4.server.api.config.part.ConfigPart;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+
+import javax.annotation.concurrent.Immutable;
+import java.io.File;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static net.groboclown.p4.server.api.util.EqualUtil.isEqual;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+
+
+/**
+ * Stores the connection information related to a specific Perforce
+ * server. It only keeps track of information required to identify the
+ * server, which means it needs the username, password, auth ticket file,
+ * trust ticket file, and server fingerprint.
+ *
+ * Implementations must specify {@link #equals(Object)} and
+ * {@link #hashCode()}, to indicate whether the server connection
+ * properties are the same; it should not match on online mode.
+ *
+ * If the configuration specified a password, then it is stored externally
+ * in the {@link ApplicationPasswordRegistry}. This also allows for keeping
+ * in one place the password in case the user enters it manually, which would
+ * break immutability.
+ *
+ * This is used for running server commands that do not require a client,
+ * but do require a username. There are limited commands that no not require a
+ * username, and for those, the {@link P4ServerName} is sufficient for connectivity.
+ *
+ * This class MUST be immutable.
+ */
+@Immutable
+public final class ServerConfig {
+ private static final Logger LOG = Logger.getInstance(ServerConfig.class);
+
+ // Just some character that won't appear in any real text, but
+ // is still viewable in a debugger.
+ static final char SEP = (char) 0x263b;
+
+ private static final AtomicInteger COUNT = new AtomicInteger(0);
+
+ private final int configVersion;
+ private final P4ServerName serverName;
+ private final String username;
+ private final File authTicket;
+ private final File trustTicket;
+ private final String serverFingerprint;
+ private final String loginSso;
+
+ private final String serverId;
+
+ private final boolean usesPassword;
+
+ @NotNull
+ static String getServerIdForDataPart(@NotNull ConfigPart part) {
+ StringBuilder sb = new StringBuilder();
+ if (part.hasServerNameSet() && part.getServerName() != null) {
+ sb.append(part.getServerName().getFullPort());
+ } else {
+ sb.append((String) null);
+ }
+ // Note: does not include password information.
+ sb.append(SEP)
+ .append(part.hasUsernameSet() ? part.getUsername() : null)
+ .append(SEP)
+ .append(part.hasAuthTicketFileSet() ? part.getAuthTicketFile() : null)
+ .append(SEP)
+ .append(part.hasTrustTicketFileSet() ? part.getTrustTicketFile() : null)
+ .append(SEP)
+ .append(part.hasServerFingerprintSet() ? part.getServerFingerprint() : null);
+ // These may be common enough that we want to save memory by interning the strings.
+ return sb.toString().intern();
+ }
+
+
+
+ @NotNull
+ public static ServerConfig createFrom(@NotNull ConfigPart part) {
+ return new ServerConfig(part);
+ }
+
+ public static boolean isValidServerConfig(@Nullable ConfigPart part) {
+ if (part == null || part.hasError()) {
+ return false;
+ }
+
+ // This should be included with the above config problems.
+ if (part.getServerName() == null || isBlank(part.getServerName().getFullPort())) {
+ return false;
+ }
+
+ if (isBlank(part.getUsername())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private ServerConfig(@NotNull ConfigPart part) {
+ if (! isValidServerConfig(part)) {
+ throw new IllegalArgumentException("Did not check validity before creating");
+ }
+ this.configVersion = COUNT.incrementAndGet();
+
+ assert part.hasServerNameSet();
+ this.serverName = part.getServerName();
+ assert part.hasUsernameSet();
+ this.username = part.getUsername();
+ this.authTicket =
+ part.hasAuthTicketFileSet()
+ ? part.getAuthTicketFile()
+ : null;
+ this.trustTicket =
+ part.hasTrustTicketFileSet()
+ ? part.getTrustTicketFile()
+ : null;
+ this.serverFingerprint =
+ part.hasServerFingerprintSet()
+ ? part.getServerFingerprint()
+ : null;
+ this.loginSso =
+ part.hasLoginSsoSet()
+ ? part.getLoginSso()
+ : null;
+ this.usesPassword = part.requiresUserEnteredPassword() || part.hasPasswordSet();
+
+ this.serverId = getServerIdForDataPart(part);
+
+ // Must be done at the very end.
+ // This logic is carefully constructed to only store the password if it's supplied by the
+ // user, and the user does not require that it is manually entered into the UI.
+ // This class never stores the password in itself.
+ if (!part.requiresUserEnteredPassword() && part.hasPasswordSet() && part.getPlaintextPassword() != null) {
+ LOG.info("Storing user password in password store");
+ // DEBUG
+ // ApplicationPasswordRegistry.getInstance().store(this, part.getPlaintextPassword().toCharArray(), false);
+ ApplicationPasswordRegistry instance = ApplicationPasswordRegistry.getInstance();
+ String passwd = part.getPlaintextPassword();
+ char[] passwdChars = passwd.toCharArray();
+ instance.store(this, passwdChars, false);
+ }
+ }
+
+
+ public int getConfigVersion() {
+ return this.configVersion;
+ }
+
+ /**
+ *
+ * @return true if the user supplies a password, either through plaintext, or through the UI asking for it.
+ */
+ public boolean usesStoredPassword() {
+ return usesPassword;
+ }
+
+ @NotNull
+ public P4ServerName getServerName() {
+ return serverName;
+ }
+
+ @NotNull
+ public String getUsername() {
+ return username;
+ }
+
+ @Nullable
+ public File getAuthTicket() {
+ return authTicket;
+ }
+
+ @Nullable
+ public File getTrustTicket() {
+ return trustTicket;
+ }
+
+ @Nullable
+ public String getServerFingerprint() {
+ return serverFingerprint;
+ }
+
+ @Nullable
+ public String getLoginSso() {
+ return loginSso;
+ }
+
+ public boolean hasServerFingerprint() {
+ return getServerFingerprint() != null && getServerFingerprint().length() > 0;
+ }
+
+ public boolean hasAuthTicket() {
+ return getAuthTicket() != null;
+ }
+
+ public boolean hasTrustTicket() {
+ return getTrustTicket() != null;
+ }
+
+ public boolean hasLoginSso() {
+ return getLoginSso() != null;
+ }
+
+ /**
+ *
+ * @return unique identifier for the server connection settings.
+ */
+ @NotNull
+ public String getServerId() {
+ return serverId;
+ }
+
+ /**
+ * Checks if the {@literal part} connects to the same server
+ * in the same way as this server configuration. For identifying
+ * if the server itself is the same, then compare the
+ * {@link P4ServerName} values.
+ *
+ * @param part configuration to compare
+ * @return true if the {@literal part} and this config connect to
+ * the same server the same way.
+ */
+ boolean isSameServerConnection(@Nullable ConfigPart part) {
+ if (part == null) {
+ LOG.debug("isSameServerConnection: input is null");
+ return false;
+ }
+
+ if (! isEqual(getServerName(), part.getServerName())) {
+ if (LOG.isDebugEnabled()) {
+ if (part.getServerName() == null) {
+ LOG.debug("isSameServerConnection: input server name is null");
+ } else {
+ LOG.debug("isSameServerConnection: server doesn't match: "
+ + getServerName().getServerPort() + "::" + getServerName().getServerProtocol() + " <> "
+ + part.getServerName().getServerPort() + "::" + part.getServerName().getServerProtocol());
+ }
+ }
+ return false;
+ }
+
+ if (! filesEqual(hasAuthTicket(), getAuthTicket(), part.hasAuthTicketFileSet(), part.getAuthTicketFile())) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("isSameServerConnection: auth ticket doesn't match: "
+ + getAuthTicket() + " <> " + part.getAuthTicketFile());
+ }
+ return false;
+ }
+
+ if (! filesEqual(hasTrustTicket(), getTrustTicket(), part.hasTrustTicketFileSet(), part.getTrustTicketFile())) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("isSameServerConnection: trust ticket doesn't match: "
+ + getTrustTicket() + " <> " + part.getTrustTicketFile());
+ }
+ return false;
+ }
+
+ if (hasServerFingerprint() != part.hasServerFingerprintSet()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("isSameServerConnection: has server fingerprint mismatch: "
+ + hasServerFingerprint() + " <> " + part.hasServerFingerprintSet());
+ }
+ return false;
+ }
+ if (hasServerFingerprint() && ! isEqual(getServerFingerprint(), part.getServerFingerprint())) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("isSameServerConnection: server fingerprint mismatch: "
+ + getServerFingerprint() + " <> " + part.getServerFingerprint());
+ }
+ return false;
+ }
+
+ if (! isEqual(getUsername(), part.getUsername())) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("isSameServerConnection: username mismatch: "
+ + getUsername() + " <> " + part.getUsername());
+ }
+ return false;
+ }
+
+ // password usage is a bit more complex.
+ if (
+ (usesStoredPassword() && (!part.requiresUserEnteredPassword() && !part.hasPasswordSet()))
+ || (!usesStoredPassword() && (part.requiresUserEnteredPassword() || part.hasPasswordSet()))
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @NotNull
+ private Map toProperties() {
+ return ConfigPropertiesUtil.toProperties(this, "(unset)", "(empty)", "(set)");
+ }
+
+ @TestOnly
+ @Override
+ public String toString() {
+ return toProperties().toString();
+ }
+
+
+ // equals only cares about the information that connects
+ // to the server, not the individual server setup. Note that
+ // this might have the potential to lose information.
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof ServerConfig)) {
+ return false;
+ }
+ ServerConfig sc = (ServerConfig) other;
+ return sc.getServerId().equals(getServerId());
+ }
+
+ @Override
+ public int hashCode() {
+ return getServerId().hashCode();
+ }
+
+
+ private static boolean filesEqual(boolean aSet, @Nullable File aFile, boolean bSet, @Nullable File bFile) {
+ return FileUtil.filesEqual(scrubFile(aSet, aFile), scrubFile(bSet, bFile));
+ }
+
+ @Nullable
+ private static File scrubFile(boolean isSet, @Nullable File file) {
+ if (! isSet || file == null) {
+ return null;
+ }
+ if (file.exists() && file.isFile()) {
+ return file;
+ }
+ return null;
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ApiException.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ApiException.java
index 13c4f2de..33b81e7c 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ApiException.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ApiException.java
@@ -1,32 +1,32 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.exceptions;
-
-import com.perforce.p4java.exception.P4JavaError;
-import com.perforce.p4java.exception.P4JavaException;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * An underlying problem happened with the p4java extension that we don't know how to handle.
- * It indicates an error in the plugin code.
- */
-public class P4ApiException extends P4ServerException {
- public P4ApiException(@NotNull P4JavaError e) {
- super(e, false);
- }
-
- public P4ApiException(@NotNull P4JavaException e) {
- super(e, false);
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.exceptions;
+
+import com.perforce.p4java.exception.P4JavaError;
+import com.perforce.p4java.exception.P4JavaException;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An underlying problem happened with the p4java extension that we don't know how to handle.
+ * It indicates an error in the plugin code.
+ */
+public class P4ApiException extends P4ServerException {
+ public P4ApiException(@NotNull P4JavaError e) {
+ super(e, false);
+ }
+
+ public P4ApiException(@NotNull P4JavaException e) {
+ super(e, false);
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4FileException.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4FileException.java
index cd702862..f76b8b01 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4FileException.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4FileException.java
@@ -1,37 +1,37 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.exceptions;
-
-import com.intellij.openapi.vcs.FilePath;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.perforce.p4java.core.file.IFileSpec;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-public abstract class P4FileException extends P4ServerException {
- private final List affectedVirtualFiles;
- private final List affectedFilePaths;
- private final List affectedServerFiles;
-
- public P4FileException(@NotNull Throwable cause, boolean isWarning, VirtualFile... affected) {
- super(cause, isWarning);
- affectedVirtualFiles = Collections.unmodifiableList(Arrays.asList(affected));
- affectedFilePaths = Collections.emptyList();
- affectedServerFiles = Collections.emptyList();
- }
-
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.exceptions;
+
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.perforce.p4java.core.file.IFileSpec;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class P4FileException extends P4ServerException {
+ private final List affectedVirtualFiles;
+ private final List affectedFilePaths;
+ private final List affectedServerFiles;
+
+ public P4FileException(@NotNull Throwable cause, boolean isWarning, VirtualFile... affected) {
+ super(cause, isWarning);
+ affectedVirtualFiles = Collections.unmodifiableList(Arrays.asList(affected));
+ affectedFilePaths = Collections.emptyList();
+ affectedServerFiles = Collections.emptyList();
+ }
+
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ServerException.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ServerException.java
index 78afd3be..6c376eb8 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ServerException.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4ServerException.java
@@ -1,24 +1,24 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.exceptions;
-
-import com.intellij.openapi.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-public abstract class P4ServerException
- extends VcsException {
- public P4ServerException(@NotNull Throwable t, boolean isWarning) {
- super(t, isWarning);
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.exceptions;
+
+import com.intellij.openapi.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class P4ServerException
+ extends VcsException {
+ public P4ServerException(@NotNull Throwable t, boolean isWarning) {
+ super(t, isWarning);
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4VcsConnectionException.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4VcsConnectionException.java
index 68a3cc02..680cb542 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4VcsConnectionException.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/P4VcsConnectionException.java
@@ -1,52 +1,52 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.exceptions;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.VcsConnectionProblem;
-import net.groboclown.p4.server.api.ClientServerRef;
-import net.groboclown.p4.server.api.messagebus.ReconnectRequestMessage;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * A problem occurred because the user was disconnected from the server.
- * This is not related to the connection request being wrong.
- */
-public class P4VcsConnectionException extends VcsConnectionProblem {
- @Nullable
- private final Project project;
-
- @NotNull
- private final ClientServerRef ref;
-
- public P4VcsConnectionException(@Nullable Project project, @NotNull ClientServerRef ref) {
- super("Connection to server " + ref.getServerDisplayId() + " failed");
- this.project = project;
- this.ref = ref;
- }
-
- public P4VcsConnectionException(@Nullable Project project, @NotNull ClientServerRef ref, @NotNull Throwable cause) {
- this(project, ref);
- initCause(cause);
- }
-
- @Override
- public boolean attemptQuickFix(boolean mayDisplayDialogs) {
- if (project != null) {
- ReconnectRequestMessage.requestReconnectToClient(project, ref, mayDisplayDialogs);
- }
- return false;
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.exceptions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsConnectionProblem;
+import net.groboclown.p4.server.api.ClientServerRef;
+import net.groboclown.p4.server.api.messagebus.ReconnectRequestMessage;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A problem occurred because the user was disconnected from the server.
+ * This is not related to the connection request being wrong.
+ */
+public class P4VcsConnectionException extends VcsConnectionProblem {
+ @Nullable
+ private final Project project;
+
+ @NotNull
+ private final ClientServerRef ref;
+
+ public P4VcsConnectionException(@Nullable Project project, @NotNull ClientServerRef ref) {
+ super("Connection to server " + ref.getServerDisplayId() + " failed");
+ this.project = project;
+ this.ref = ref;
+ }
+
+ public P4VcsConnectionException(@Nullable Project project, @NotNull ClientServerRef ref, @NotNull Throwable cause) {
+ this(project, ref);
+ initCause(cause);
+ }
+
+ @Override
+ public boolean attemptQuickFix(boolean mayDisplayDialogs) {
+ if (project != null) {
+ ReconnectRequestMessage.requestReconnectToClient(project, ref, mayDisplayDialogs);
+ }
+ return false;
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/VcsInterruptedException.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/VcsInterruptedException.java
index 26b23716..a98ea6f7 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/VcsInterruptedException.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/exceptions/VcsInterruptedException.java
@@ -1,35 +1,35 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.api.exceptions;
-
-import com.intellij.openapi.vcs.VcsException;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.concurrent.CancellationException;
-
-public class VcsInterruptedException extends VcsException {
- public VcsInterruptedException(@NotNull InterruptedException ex) {
- super(ex);
- }
- public VcsInterruptedException(
- @NotNull @Nls(capitalization = Nls.Capitalization.Sentence) String operation,
- @NotNull InterruptedException ex) {
- super(operation, ex);
- }
- public VcsInterruptedException(@NotNull CancellationException ex) {
- super(ex);
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.api.exceptions;
+
+import com.intellij.openapi.vcs.VcsException;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.CancellationException;
+
+public class VcsInterruptedException extends VcsException {
+ public VcsInterruptedException(@NotNull InterruptedException ex) {
+ super(ex);
+ }
+ public VcsInterruptedException(
+ @NotNull @Nls(capitalization = Nls.Capitalization.Sentence) String operation,
+ @NotNull InterruptedException ex) {
+ super(operation, ex);
+ }
+ public VcsInterruptedException(@NotNull CancellationException ex) {
+ super(ex);
+ }
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/JobStatusNames.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/JobStatusNames.java
index 7c550eca..2769a8e5 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/JobStatusNames.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/JobStatusNames.java
@@ -1,33 +1,33 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.api.values;
-
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import java.util.Set;
-
-/**
- * The valid job statuses that can be set for a job.
- */
-@Immutable
-public interface JobStatusNames {
- @NotNull
- Set getJobStatusNames();
-
- @Nullable
- JobStatus toJobStatus(String name);
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.api.values;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import java.util.Set;
+
+/**
+ * The valid job statuses that can be set for a job.
+ */
+@Immutable
+public interface JobStatusNames {
+ @NotNull
+ Set getJobStatusNames();
+
+ @Nullable
+ JobStatus toJobStatus(String name);
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4ChangelistId.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4ChangelistId.java
index 60d3dd65..a4cf241c 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4ChangelistId.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4ChangelistId.java
@@ -1,75 +1,75 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.api.values;
-
-import com.intellij.openapi.vcs.history.VcsRevisionNumber;
-import net.groboclown.p4.server.api.ClientServerRef;
-import net.groboclown.p4.server.api.P4ServerName;
-import net.groboclown.p4.server.api.config.ServerConfig;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.concurrent.Immutable;
-
-/**
- * Perforce changelists must be identified by their ID and their origin
- * server.
- *
- * For a changelist that is pending creation, this object will not change. Instead, when the
- * creation finishes, the cached version should be refreshed to reflect the new changelist.
- */
-@Immutable
-public interface P4ChangelistId extends VcsRevisionNumber {
- enum State {
- /** The changelist is a formally created changelist on the server, and not a default changelist. */
- NUMBERED,
- /** The changelist is the unnumbered, "default" changelist for the client, stored on the server. */
- DEFAULT,
- /** The changelist is pending creation on the server. */
- PENDING_CREATION
- }
-
- int getChangelistId();
-
- @NotNull
- P4ServerName getServerName();
-
- /**
- * The client that created the changelist.
- *
- * @return the name of the client that created the changelist.
- */
- @NotNull
- String getClientname();
-
- @NotNull
- ClientServerRef getClientServerRef();
-
- @NotNull
- State getState();
-
- /**
- *
- * @return true if this is the default changelist for the client.
- */
- boolean isDefaultChangelist();
-
- /**
- * Is this changelist in the given client? Matches on the client name
- * and the server config id.
- *
- * @param serverConfig server to check
- * @return true if the given client matches the server config and client name.
- */
- boolean isIn(@NotNull ServerConfig serverConfig);
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.api.values;
+
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import net.groboclown.p4.server.api.ClientServerRef;
+import net.groboclown.p4.server.api.P4ServerName;
+import net.groboclown.p4.server.api.config.ServerConfig;
+import org.jetbrains.annotations.NotNull;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Perforce changelists must be identified by their ID and their origin
+ * server.
+ *
+ * For a changelist that is pending creation, this object will not change. Instead, when the
+ * creation finishes, the cached version should be refreshed to reflect the new changelist.
+ */
+@Immutable
+public interface P4ChangelistId extends VcsRevisionNumber {
+ enum State {
+ /** The changelist is a formally created changelist on the server, and not a default changelist. */
+ NUMBERED,
+ /** The changelist is the unnumbered, "default" changelist for the client, stored on the server. */
+ DEFAULT,
+ /** The changelist is pending creation on the server. */
+ PENDING_CREATION
+ }
+
+ int getChangelistId();
+
+ @NotNull
+ P4ServerName getServerName();
+
+ /**
+ * The client that created the changelist.
+ *
+ * @return the name of the client that created the changelist.
+ */
+ @NotNull
+ String getClientname();
+
+ @NotNull
+ ClientServerRef getClientServerRef();
+
+ @NotNull
+ State getState();
+
+ /**
+ *
+ * @return true if this is the default changelist for the client.
+ */
+ boolean isDefaultChangelist();
+
+ /**
+ * Is this changelist in the given client? Matches on the client name
+ * and the server config id.
+ *
+ * @param serverConfig server to check
+ * @return true if the given client matches the server config and client name.
+ */
+ boolean isIn(@NotNull ServerConfig serverConfig);
+}
diff --git a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4Job.java b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4Job.java
index b334a8c1..2ea4c87b 100644
--- a/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4Job.java
+++ b/idea-p4server/api/src/main/java/net/groboclown/p4/server/api/values/P4Job.java
@@ -1,45 +1,45 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.api.values;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.annotation.concurrent.Immutable;
-import java.util.Map;
-
-/**
- * An immutable view of a Perforce Job. The details might contain additional
- * whitespace that the user did not originally include when creating the job.
- * To display to the end user, the {@link P4JobSpec} should be used.
- *
- * @see P4Job
- */
-@Immutable
-public interface P4Job {
- @NotNull
- String getJobId();
-
- @NotNull
- Map getRawDetails();
-
- /**
- *
- * @return the description as stored on the server. It might have extra whitespace
- * that the user did not intentionally add.
- */
- @Nullable
- String getDescription();
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.api.values;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.annotation.concurrent.Immutable;
+import java.util.Map;
+
+/**
+ * An immutable view of a Perforce Job. The details might contain additional
+ * whitespace that the user did not originally include when creating the job.
+ * To display to the end user, the {@link P4JobSpec} should be used.
+ *
+ * @see P4Job
+ */
+@Immutable
+public interface P4Job {
+ @NotNull
+ String getJobId();
+
+ @NotNull
+ Map getRawDetails();
+
+ /**
+ *
+ * @return the description as stored on the server. It might have extra whitespace
+ * that the user did not intentionally add.
+ */
+ @Nullable
+ String getDescription();
+}
diff --git a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/config/win/PreferencesWinRegistry.java b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/config/win/PreferencesWinRegistry.java
index f3d11a35..d72b6d5a 100644
--- a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/config/win/PreferencesWinRegistry.java
+++ b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/config/win/PreferencesWinRegistry.java
@@ -1,279 +1,279 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package net.groboclown.p4.server.impl.config.win;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.prefs.Preferences;
-
-
-/**
- * Taken from
- * http://svn.apache.org/repos/asf/incubator/npanday/trunk/components/dotnet-registry/src/main/java/npanday/registry/impl/WinRegistry.java
- * It's been modified to remove the external dependencies and not allow writing to the
- * registry.
- *
- * It takes advantage of the Preferences class' ability to inspect the Windows registry.
- * Note that this may not be compatible with all Java versions.
- * Indeed, this doesn't work for JDK 11.
- */
-public class PreferencesWinRegistry {
- public static final int HKEY_CURRENT_USER = 0x80000001;
-
- public static final int HKEY_LOCAL_MACHINE = 0x80000002;
-
- public static final int REG_SUCCESS = 0;
-
- private static final int KEY_ALL_ACCESS = 0xf003f;
-
- private static final int KEY_READ = 0x20019;
-
- private static Preferences userRoot = Preferences.userRoot();
-
- private static Preferences systemRoot = Preferences.systemRoot();
-
- private static Class extends Preferences> userClass = userRoot.getClass();
-
- private static Method regOpenKey = null;
-
- private static Method regCloseKey = null;
-
- private static Method regQueryValueEx = null;
-
- private static Method regEnumValue = null;
-
- private static Method regQueryInfoKey = null;
-
- private static Method regEnumKeyEx = null;
-
-
- static {
- try {
- regOpenKey = userClass.getDeclaredMethod(
- "WindowsRegOpenKey",
- int.class, byte[].class, int.class);
- regOpenKey.setAccessible(true);
- regCloseKey = userClass.getDeclaredMethod("WindowsRegCloseKey",
- int.class);
- regCloseKey.setAccessible(true);
- regQueryValueEx = userClass.getDeclaredMethod(
- "WindowsRegQueryValueEx",
- int.class, byte[].class);
- regQueryValueEx.setAccessible(true);
- regEnumValue = userClass.getDeclaredMethod(
- "WindowsRegEnumValue",
- int.class, int.class, int.class);
- regEnumValue.setAccessible(true);
- regQueryInfoKey = userClass.getDeclaredMethod("WindowsRegQueryInfoKey1",
- int.class);
- regQueryInfoKey.setAccessible(true);
- regEnumKeyEx = userClass.getDeclaredMethod(
- "WindowsRegEnumKeyEx",
- int.class, int.class, int.class);
- regEnumKeyEx.setAccessible(true);
- } catch (NoSuchMethodException e) {
- // we are not on windows, then!
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-
- public static boolean isAvailable() {
- return regOpenKey != null
- && regCloseKey != null
- && regQueryValueEx != null
- && regEnumValue != null
- && regQueryInfoKey != null
- && regEnumKeyEx != null;
- }
-
-
- /**
- * Read a value from key and value name
- *
- * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
- * @param key
- * @param valueName
- * @return the value
- * @throws IllegalArgumentException
- * @throws IllegalAccessException
- * @throws InvocationTargetException
- */
- public static String readString(int hkey, String key, String valueName) throws
- IllegalArgumentException,
- IllegalAccessException,
- InvocationTargetException {
- if (hkey == HKEY_LOCAL_MACHINE) {
- return readString(systemRoot, hkey, key, valueName);
- } else if (hkey == HKEY_CURRENT_USER) {
- return readString(userRoot, hkey, key, valueName);
- } else {
- throw new IllegalArgumentException("hkey=" + hkey);
- }
- }
-
- /**
- * Read value(s) and value name(s) form given key
- *
- * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
- * @param key
- * @return the value name(s) plus the value(s)
- * @throws IllegalArgumentException
- * @throws IllegalAccessException
- * @throws InvocationTargetException
- */
- public static Map readStringValues(int hkey, String key) throws
- IllegalArgumentException,
- IllegalAccessException,
- InvocationTargetException {
- if (hkey == HKEY_LOCAL_MACHINE) {
- return readStringValues(systemRoot, hkey, key);
- } else if (hkey == HKEY_CURRENT_USER) {
- return readStringValues(userRoot, hkey, key);
- } else {
- throw new IllegalArgumentException("hkey=" + hkey);
- }
- }
-
- /**
- * Read the value name(s) from a given key
- *
- * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
- * @param key
- * @return the value name(s)
- * @throws IllegalArgumentException
- * @throws IllegalAccessException
- * @throws InvocationTargetException
- */
- public static List readStringSubKeys(int hkey, String key) throws
- IllegalArgumentException,
- IllegalAccessException,
- InvocationTargetException {
- if (hkey == HKEY_LOCAL_MACHINE) {
- return readStringSubKeys(systemRoot, hkey, key);
- } else if (hkey == HKEY_CURRENT_USER) {
- return readStringSubKeys(userRoot, hkey, key);
- } else {
- throw new IllegalArgumentException("hkey=" + hkey);
- }
- }
-
-
- // =====================
-
-
- private static String readString(Preferences root, int hkey, String key, String value) throws
- IllegalArgumentException,
- IllegalAccessException,
- InvocationTargetException {
- int[] handles = (int[]) regOpenKey.invoke(
- root, new Object[]{
- hkey, toCstr(key), KEY_READ
- }
- );
- if (handles[1] != REG_SUCCESS) {
- return null;
- }
- byte[] valb = (byte[]) regQueryValueEx.invoke(
- root, new Object[]{ handles[0], toCstr(value)}
- );
- regCloseKey.invoke(root, handles[0]);
- return (valb != null ? new String(valb, Charset.defaultCharset()).trim() : null);
- }
-
- private static Map readStringValues(Preferences root, int hkey, String key) throws
- IllegalArgumentException,
- IllegalAccessException,
- InvocationTargetException {
- HashMap results = new HashMap();
- int[] handles = (int[]) regOpenKey.invoke(
- root, new Object[]{
- hkey, toCstr(key), KEY_READ
- }
- );
- if (handles[1] != REG_SUCCESS) {
- return null;
- }
- int[] info = (int[]) regQueryInfoKey.invoke(root, new Object[]{ handles[0] });
-
- int count = info[2]; // count
- int maxlen = info[3]; // value length max
- for (int index = 0; index < count; index++) {
- byte[] name = (byte[]) regEnumValue.invoke(
- root, new Object[] {
- handles[0], index, maxlen + 1
- }
- );
- if (name != null) {
- String nameText = new String(name, Charset.defaultCharset());
- final String value = readString(hkey, key, nameText);
- results.put(nameText.trim(), value);
- }
- }
- regCloseKey.invoke(root, handles[0]);
- return results;
- }
-
- private static List readStringSubKeys(Preferences root, int hkey, String key) throws
- IllegalArgumentException,
- IllegalAccessException,
- InvocationTargetException {
- List results = new ArrayList();
- int[] handles = (int[]) regOpenKey.invoke(
- root, new Object[]{
- hkey, toCstr(key), KEY_READ
- }
- );
- if (handles[1] != REG_SUCCESS) {
- return null;
- }
- int[] info = (int[]) regQueryInfoKey.invoke(root, new Object[]{ handles[0] });
-
- int count = info[0]; // count
- int maxlen = info[3]; // value length max
- for (int index = 0; index < count; index++) {
- byte[] name = (byte[]) regEnumKeyEx.invoke(
- root, new Object[]{
- handles[0], index, maxlen + 1
- }
- );
- results.add(new String(name, Charset.defaultCharset()).trim());
- }
- regCloseKey.invoke(root, handles[0]);
- return results;
- }
-
-
- // utility
- private static byte[] toCstr(String str) {
- byte[] result = new byte[str.length() + 1];
-
- for (int i = 0; i < str.length(); i++) {
- result[i] = (byte) str.charAt(i);
- }
- result[str.length()] = 0;
- return result;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package net.groboclown.p4.server.impl.config.win;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.prefs.Preferences;
+
+
+/**
+ * Taken from
+ * http://svn.apache.org/repos/asf/incubator/npanday/trunk/components/dotnet-registry/src/main/java/npanday/registry/impl/WinRegistry.java
+ * It's been modified to remove the external dependencies and not allow writing to the
+ * registry.
+ *
+ * It takes advantage of the Preferences class' ability to inspect the Windows registry.
+ * Note that this may not be compatible with all Java versions.
+ * Indeed, this doesn't work for JDK 11.
+ */
+public class PreferencesWinRegistry {
+ public static final int HKEY_CURRENT_USER = 0x80000001;
+
+ public static final int HKEY_LOCAL_MACHINE = 0x80000002;
+
+ public static final int REG_SUCCESS = 0;
+
+ private static final int KEY_ALL_ACCESS = 0xf003f;
+
+ private static final int KEY_READ = 0x20019;
+
+ private static Preferences userRoot = Preferences.userRoot();
+
+ private static Preferences systemRoot = Preferences.systemRoot();
+
+ private static Class extends Preferences> userClass = userRoot.getClass();
+
+ private static Method regOpenKey = null;
+
+ private static Method regCloseKey = null;
+
+ private static Method regQueryValueEx = null;
+
+ private static Method regEnumValue = null;
+
+ private static Method regQueryInfoKey = null;
+
+ private static Method regEnumKeyEx = null;
+
+
+ static {
+ try {
+ regOpenKey = userClass.getDeclaredMethod(
+ "WindowsRegOpenKey",
+ int.class, byte[].class, int.class);
+ regOpenKey.setAccessible(true);
+ regCloseKey = userClass.getDeclaredMethod("WindowsRegCloseKey",
+ int.class);
+ regCloseKey.setAccessible(true);
+ regQueryValueEx = userClass.getDeclaredMethod(
+ "WindowsRegQueryValueEx",
+ int.class, byte[].class);
+ regQueryValueEx.setAccessible(true);
+ regEnumValue = userClass.getDeclaredMethod(
+ "WindowsRegEnumValue",
+ int.class, int.class, int.class);
+ regEnumValue.setAccessible(true);
+ regQueryInfoKey = userClass.getDeclaredMethod("WindowsRegQueryInfoKey1",
+ int.class);
+ regQueryInfoKey.setAccessible(true);
+ regEnumKeyEx = userClass.getDeclaredMethod(
+ "WindowsRegEnumKeyEx",
+ int.class, int.class, int.class);
+ regEnumKeyEx.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ // we are not on windows, then!
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public static boolean isAvailable() {
+ return regOpenKey != null
+ && regCloseKey != null
+ && regQueryValueEx != null
+ && regEnumValue != null
+ && regQueryInfoKey != null
+ && regEnumKeyEx != null;
+ }
+
+
+ /**
+ * Read a value from key and value name
+ *
+ * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+ * @param key
+ * @param valueName
+ * @return the value
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public static String readString(int hkey, String key, String valueName) throws
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException {
+ if (hkey == HKEY_LOCAL_MACHINE) {
+ return readString(systemRoot, hkey, key, valueName);
+ } else if (hkey == HKEY_CURRENT_USER) {
+ return readString(userRoot, hkey, key, valueName);
+ } else {
+ throw new IllegalArgumentException("hkey=" + hkey);
+ }
+ }
+
+ /**
+ * Read value(s) and value name(s) form given key
+ *
+ * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+ * @param key
+ * @return the value name(s) plus the value(s)
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public static Map readStringValues(int hkey, String key) throws
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException {
+ if (hkey == HKEY_LOCAL_MACHINE) {
+ return readStringValues(systemRoot, hkey, key);
+ } else if (hkey == HKEY_CURRENT_USER) {
+ return readStringValues(userRoot, hkey, key);
+ } else {
+ throw new IllegalArgumentException("hkey=" + hkey);
+ }
+ }
+
+ /**
+ * Read the value name(s) from a given key
+ *
+ * @param hkey HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+ * @param key
+ * @return the value name(s)
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public static List readStringSubKeys(int hkey, String key) throws
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException {
+ if (hkey == HKEY_LOCAL_MACHINE) {
+ return readStringSubKeys(systemRoot, hkey, key);
+ } else if (hkey == HKEY_CURRENT_USER) {
+ return readStringSubKeys(userRoot, hkey, key);
+ } else {
+ throw new IllegalArgumentException("hkey=" + hkey);
+ }
+ }
+
+
+ // =====================
+
+
+ private static String readString(Preferences root, int hkey, String key, String value) throws
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException {
+ int[] handles = (int[]) regOpenKey.invoke(
+ root, new Object[]{
+ hkey, toCstr(key), KEY_READ
+ }
+ );
+ if (handles[1] != REG_SUCCESS) {
+ return null;
+ }
+ byte[] valb = (byte[]) regQueryValueEx.invoke(
+ root, new Object[]{ handles[0], toCstr(value)}
+ );
+ regCloseKey.invoke(root, handles[0]);
+ return (valb != null ? new String(valb, Charset.defaultCharset()).trim() : null);
+ }
+
+ private static Map readStringValues(Preferences root, int hkey, String key) throws
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException {
+ HashMap results = new HashMap();
+ int[] handles = (int[]) regOpenKey.invoke(
+ root, new Object[]{
+ hkey, toCstr(key), KEY_READ
+ }
+ );
+ if (handles[1] != REG_SUCCESS) {
+ return null;
+ }
+ int[] info = (int[]) regQueryInfoKey.invoke(root, new Object[]{ handles[0] });
+
+ int count = info[2]; // count
+ int maxlen = info[3]; // value length max
+ for (int index = 0; index < count; index++) {
+ byte[] name = (byte[]) regEnumValue.invoke(
+ root, new Object[] {
+ handles[0], index, maxlen + 1
+ }
+ );
+ if (name != null) {
+ String nameText = new String(name, Charset.defaultCharset());
+ final String value = readString(hkey, key, nameText);
+ results.put(nameText.trim(), value);
+ }
+ }
+ regCloseKey.invoke(root, handles[0]);
+ return results;
+ }
+
+ private static List readStringSubKeys(Preferences root, int hkey, String key) throws
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException {
+ List results = new ArrayList();
+ int[] handles = (int[]) regOpenKey.invoke(
+ root, new Object[]{
+ hkey, toCstr(key), KEY_READ
+ }
+ );
+ if (handles[1] != REG_SUCCESS) {
+ return null;
+ }
+ int[] info = (int[]) regQueryInfoKey.invoke(root, new Object[]{ handles[0] });
+
+ int count = info[0]; // count
+ int maxlen = info[3]; // value length max
+ for (int index = 0; index < count; index++) {
+ byte[] name = (byte[]) regEnumKeyEx.invoke(
+ root, new Object[]{
+ handles[0], index, maxlen + 1
+ }
+ );
+ results.add(new String(name, Charset.defaultCharset()).trim());
+ }
+ regCloseKey.invoke(root, handles[0]);
+ return results;
+ }
+
+
+ // utility
+ private static byte[] toCstr(String str) {
+ byte[] result = new byte[str.length() + 1];
+
+ for (int i = 0; i < str.length(); i++) {
+ result[i] = (byte) str.charAt(i);
+ }
+ result[str.length()] = 0;
+ return result;
+ }
+}
diff --git a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFilePattern.java b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFilePattern.java
index ba5fb5a9..0737b53a 100644
--- a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFilePattern.java
+++ b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFilePattern.java
@@ -1,621 +1,621 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.impl.ignore;
-
-import com.intellij.openapi.util.SystemInfo;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents a single line from an ignore file.
- */
-public class IgnoreFilePattern {
- private static final String[] EMPTY = new String[0];
-
- private final String basePattern;
- private final PathPart rootPart;
- private final boolean isNegative;
-
-
- // the parse file is contained in this class to keep the parse logic for the file in one
- // place.
- static List parseFile(@NotNull Reader reader) throws IOException {
- BufferedReader lineReader =
- reader instanceof BufferedReader
- ? (BufferedReader) reader
- : new BufferedReader(reader);
- // Note: there is now a "p4 ignores" command, and "p4 ignore" is now
- // also built into the API for newer servers. For caching and UI display, we still need this.
-
- // File format:
- // (from https://www.perforce.com/perforce/r15.2/manuals/cmdref/P4IGNORE.html)
- // (Clarifications at http://forums.perforce.com/index.php?/topic/4492-new-p4-ignore-functionality/page__gopid__18940#entry18940)
- // The syntax for ignore rules is not the same as Perforce syntax. Instead, it is similar to that used
- // by other versioning systems:
- //
- // * Rules are specified using local filepath syntax. Unix style paths will work on Windows for cross
- // platform file support.
- //
- // * A # character at the beginning of a line denotes a comment
- //
- // * A ! character at the beginning of a line line excludes the file specification.These exclusions override rules
- // defined above it in the P4IGNORE file, but may be overridden by later rules.
- //
- // * A / (or \ on Windows) character at the beginning of a line causes the file specification to be
- // considered relative to the P4IGNORE file. This is useful when the rule must apply to files at
- // particular depots of the directory tree.
- //
- // * A / (or \ on Windows) character at the end of a line causes the file specification to only match
- // directories, and not files of the same name.
- //
- // * The * wildcard matches substrings. Like the Perforce wildcard equivalent, it does not match path
- // separators; however, if it is not used as part of a path, the directory scanning nature of the rule may
- // make it appear to perform like the Perforce "..." wildcard.
- //
- // * The ** wildcard matches substrings including path separators. It is equivalent to the Perforce "..."
- // wildcard, which is not permitted. (Note: the "**" must match at least 1 wild card)
- //
- // For example:
- //
- // # Ignore.p4ignore files
- // .p4ignore
- //
- // # Ignore object files, shared libraries, executables
- // *.dll
- // *.so
- // *.exe
- // *.o
- //
- // # Ignore all HTML files except the readme file
- // *.html
- // !readme.html
- //
- // # Ignore the bin directory
- // bin/
- //
- // # Ignore the build.properties file in this directory
- // /build.properties
- //
- // # Ignore all text files in test directories
- // test/**.txt
- //
-
-
- // This description unfortunately does not describe these circumstances:
- // - if a "!" is found after the matcher, is it still a match?
- // (does the first match force a result?)
- // TODO It looks like last match?
- // - if a path is specified ("temp/*.tmp"), is it relative to the
- // ignore file? Assuming not; as per the .gitignore format
- // (if a file matcher starts with a '/', then it is relative to
- // the ignore files).
-
- List ret = new ArrayList<>();
-
- String line;
- while ((line = lineReader.readLine()) != null) {
- IgnoreFilePattern ifp = parseLinePattern(line);
- if (ifp != null) {
- ret.add(ifp);
- }
- }
- return ret;
- }
-
- @Nullable
- static IgnoreFilePattern parseLinePattern(final String line) {
- String pattern = line.trim();
- if (pattern.length() <= 0 || pattern.charAt(0) == '#') {
- return null;
- }
- boolean isNegative = false;
- if (pattern.charAt(0) == '!' && pattern.length() > 1) {
- isNegative = true;
- pattern = pattern.substring(1).trim();
- }
- if (pattern.length() > 0) {
- return new IgnoreFilePattern(line, createPattern(pattern), isNegative);
- }
- return null;
- }
-
-
- IgnoreFilePattern(@NotNull PathPart rootPart, boolean isNegative) {
- this(null, rootPart, isNegative);
- }
-
-
- IgnoreFilePattern(@Nullable String original, @NotNull PathPart rootPart, boolean isNegative) {
- this.basePattern = original;
- this.rootPart = rootPart;
- this.isNegative = isNegative;
- }
-
-
- public boolean isIgnoreMatchType() {
- return ! isNegative;
- }
-
- @Override
- public String toString() {
- return basePattern;
- }
-
-
- /**
- *
- * @param pathParts the path of the file to check, relative to the source ignore file. Each
- * path element is its own item in the list.
- * @return true if the file matches this pattern; it does not mean that it's ignored.
- */
- public boolean matches(final List pathParts) {
- PathPart next = rootPart;
- for (String pathPart: pathParts) {
- if (next == null) {
- return false;
- }
- PathNameMatchResult result = next.match(pathPart);
- if (result.isLastElementMatch) {
- return true;
- }
- if (!result.isMatch) {
- return false;
- }
- next = result.next;
- }
- return false;
- }
-
- private enum ParseState {
- END_PATH,
- STAR_PATH,
- JUST_FOUND_STAR_AT_END,
- JUST_FOUND_STAR_IN_MIDDLE,
- JUST_FOUND_STAR_STAR_AT_END,
- JUST_FOUND_STAR_STAR_IN_MIDDLE,
- TEXT_PATH
- }
-
-
- @NotNull
- static PathPart createPattern(@NotNull final String pattern) {
- if (pattern.length() <= 0) {
- throw new IllegalArgumentException("pattern cannot be empty");
- }
-
- // Split the pattern based on the path separator. From there,
- // parse each part based on the '*' inclusion.
-
- // In order to make the splitting easier for us, just change separators to a single format.
- char[] pat = pattern.replace('\\', '/').replace(File.separatorChar, '/').toCharArray();
- int lastPos = pat.length - 1;
-
- // Special case: if the pattern starts with a '/', then start it with a StarStar matcher.
- boolean isAbsolute = false;
- int startPos = 0;
- while (startPos <= lastPos && pat[startPos] == '/' ) {
- isAbsolute = true;
- startPos++;
- }
-
- // work backwards through the pattern to assemble the parts with the next wiring correctly.
- PathPart ret = null;
-
- ParseState state = ParseState.END_PATH;
- // Special case: trailing slash means an implicit directory.
- {
- boolean isDir = false;
- while (lastPos > startPos && pat[lastPos] == '/') {
- isDir = true;
- lastPos--;
- }
- if (isDir) {
- ret = new StrictStarStarPart(null);
- }
- }
-
- List pieces = new ArrayList<>();
- int lastPartPos = lastPos;
- while (lastPos >= startPos) {
- char c = pat[lastPos];
- switch (state) {
- case END_PATH:
- if (c == '/') {
- // double slashes - count as just one slash.
- // adjust the positions to count this as the new end.
- // don't need to adjust the pieces or state.
- lastPartPos = lastPos;
- } else if (c == '*') {
- pieces.add(0, "*");
- lastPartPos = lastPos;
- state = ParseState.JUST_FOUND_STAR_AT_END;
- } else {
- state = ParseState.TEXT_PATH;
- }
- break;
- case JUST_FOUND_STAR_AT_END:
- if (c == '*') {
- // double star at end.
- ret = new StrictStarStarPart(ret);
- lastPartPos = lastPos;
- pieces.clear();
- state = ParseState.JUST_FOUND_STAR_STAR_AT_END;
- } else if (c == '/') {
- ret = new SingleAnyMatchPart(ret);
- pieces.clear();
- lastPartPos = lastPos;
- state = ParseState.END_PATH;
- } else {
- state = ParseState.STAR_PATH;
- }
- break;
- case JUST_FOUND_STAR_IN_MIDDLE:
- if (c == '*') {
- // found a star star, with stuff after it.
- // keep the stuff after it, marking it as a *a type.
- ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
- lastPartPos = lastPos;
- pieces.clear();
- ret = new StrictStarStarPart(ret);
- state = ParseState.JUST_FOUND_STAR_STAR_IN_MIDDLE;
- } else if (c == '/') {
- ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
- lastPartPos = lastPos;
- pieces.clear();
- state = ParseState.END_PATH;
- } else {
- state = ParseState.STAR_PATH;
- }
- break;
- case JUST_FOUND_STAR_STAR_AT_END:
- case JUST_FOUND_STAR_STAR_IN_MIDDLE:
- if (c == '*') {
- // ***, which is weird. But okay.
- pieces.add(0, "*");
- lastPartPos = lastPos;
- state = ParseState.JUST_FOUND_STAR_AT_END;
- } else if (c == '/') {
- // only star star in path.
- lastPartPos = lastPos;
- pieces.clear();
- state = ParseState.END_PATH;
- } else {
- // counts as a* format.
- lastPartPos = lastPos;
- pieces.add(0, "*");
- state = ParseState.STAR_PATH;
- }
- break;
- case STAR_PATH:
- if (c == '*') {
- pieces.add(0, new String(pat, lastPos + 1, lastPartPos - lastPos - 1));
- pieces.add(0, "*");
- lastPartPos = lastPos;
- state = ParseState.JUST_FOUND_STAR_IN_MIDDLE;
- } else if (c == '/') {
- pieces.add(0, new String(pat, lastPos, lastPartPos - lastPos - 1));
- ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
- lastPartPos = lastPos;
- pieces.clear();
- state = ParseState.END_PATH;
- }
- // else just keep going.
- break;
- case TEXT_PATH:
- if (c == '*') {
- pieces.add(0, new String(pat, lastPos + 1, lastPartPos - lastPos));
- pieces.add(0, "*");
- lastPartPos = lastPos;
- state = ParseState.JUST_FOUND_STAR_IN_MIDDLE;
- } else if (c == '/') {
- ret = new ExactMatchPart(ret,
- new String(pat, lastPos + 1, lastPartPos - lastPos),
- isFileSystemCaseSensitive());
- lastPartPos = lastPos;
- pieces.clear();
- state = ParseState.END_PATH;
- }
- // else just keep going
- break;
- }
- lastPos--;
- }
- switch (state) {
- case JUST_FOUND_STAR_AT_END:
- ret = new SingleAnyMatchPart(ret);
- break;
- case JUST_FOUND_STAR_IN_MIDDLE:
- ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
- break;
- case STAR_PATH:
- pieces.add(0, new String(pat, startPos, lastPartPos - startPos));
- ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
- break;
- case TEXT_PATH:
- ret = new ExactMatchPart(ret, new String(pat, startPos, lastPartPos - startPos),
- isFileSystemCaseSensitive());
- break;
- case JUST_FOUND_STAR_STAR_AT_END:
- case JUST_FOUND_STAR_STAR_IN_MIDDLE:
- case END_PATH:
- // do nothing
- break;
- }
- if ((!isAbsolute && !(ret instanceof StrictStarStarPart)) || (isAbsolute && ret == null)) {
- ret = new StrictStarStarPart(ret);
- }
- if (ret == null) {
- // Weird state. Allow it, though.
- ret = new ExactMatchPart(null, "", isFileSystemCaseSensitive());
- }
- return ret;
- }
-
-
- private static boolean isFileSystemCaseSensitive() {
- // This isn't 100% true - you can configure windows file system to be case sensitive.
- return !SystemInfo.isWindows;
- }
-
- static class PathNameMatchResult {
- final boolean isMatch;
- final boolean requiresMore;
- final boolean isLastElementMatch;
- final PathPart next;
-
- PathNameMatchResult(boolean isMatch, @Nullable PathPart next) {
- this(isMatch, next != null, next);
- }
-
- PathNameMatchResult(boolean isMatch, boolean requiresMore, @Nullable PathPart next) {
- this.isMatch = isMatch;
- this.requiresMore = requiresMore;
- this.next = next;
- this.isLastElementMatch = isMatch && (next == null || !requiresMore);
- }
- }
-
- private static final PathNameMatchResult NOT_MATCH = new PathNameMatchResult(false, false, null);
-
- abstract static class PathPart {
- final PathPart next;
-
- protected PathPart(@Nullable PathPart next) {
- this.next = next;
- }
-
- @NotNull
- abstract PathNameMatchResult match(@NotNull String name);
- }
-
-
- // Matching patterns:
- // if a pattern ends with a '/', then use StrictStarStarPart with no next.
- // /a/ -> ExactMatchPart
- // /*/ -> SingleAnyMatchPart
- // /**/ -> StrictStarStarPart
- // /a**b/ -> /a*/**/*b/ -> StarMatchPart, StrictStarStarPart, StarMatchPart
- // /a**/ -> /a*/**/ -> StarMatchPart, StrictStarStarPart
- // /**b/ -> /**/*b/ -> StrictStarStarPart, StarMatchPart
- // /a*/ -> StarMatchPart
- // /*b/ -> StarMatchPart
- // /a*b/ -> StarMatchPart
- // /*a*/ -> StarMatchPart
-
-
- static class SingleAnyMatchPart extends PathPart {
- protected SingleAnyMatchPart(@Nullable PathPart next) {
- super(next);
- }
-
- @NotNull
- @Override
- PathNameMatchResult match(@NotNull String name) {
- return new PathNameMatchResult(true, next);
- }
- }
-
-
- static class ExactMatchPart extends PathPart {
- private final String match;
- private final boolean caseInsensitive;
-
- protected ExactMatchPart(@Nullable PathPart next, @NotNull String match, boolean caseInsensitive) {
- super(next);
- this.match = match;
- this.caseInsensitive = caseInsensitive;
- }
-
- @NotNull
- @Override
- PathNameMatchResult match(@NotNull String name) {
- boolean isMatch = caseInsensitive ? name.equalsIgnoreCase(match) : name.equals(match);
- return isMatch ? new PathNameMatchResult(true, next) : NOT_MATCH;
- }
- }
-
- // If P4 ignore ever learns character sets ([ab] meaning a or b), then this will need to take something
- // other than String for the matches.
- static class StarMatchPart extends PathPart {
- final String[] matches;
- private final boolean caseInsensitive;
-
- // matches implies a '*' at the end, but it isn't there.
- StarMatchPart(@Nullable PathPart next, @NotNull String[] matches, boolean caseInsensitive) {
- super(next);
- if (matches.length < 2) {
- throw new IllegalArgumentException("matches must have at least one star and one non-star");
- }
- this.matches = matches;
- this.caseInsensitive = caseInsensitive;
- if (caseInsensitive) {
- for (int i = 0; i < matches.length; i++) {
- matches[i] = matches[i].toLowerCase();
- }
- }
- }
-
- @NotNull
- @Override
- PathNameMatchResult match(@NotNull String name) {
- String remaining = caseInsensitive ? name.toLowerCase() : name;
- return isRecursiveMatches(0, matches.length - 1, remaining)
- ? new PathNameMatchResult(true, next)
- : NOT_MATCH;
- }
-
-
- boolean isRecursiveMatches(int startMatchPos, int endMatchPos, String remaining) {
- assert startMatchPos >= 0;
- assert endMatchPos < matches.length;
- assert startMatchPos <= endMatchPos;
-
- // peel away until we get to a non-star.
- // - If match is [a, *], the hasStartStar loop will first not increment startMatchPos.
- // It will see that remaining starts with the 'a' (if not, quit), so increment to the
- // '*'. This equals the endMatchPos, but we'll keep looping.
- // The second loop will match a star, and keep looking. Now the startMatchPos > end,
- // so it will quit with a yes.
- // - If match is [*, a], the hasStartStar will just stop with a hasStartStar = true.
- // Then, the hasEndStar will find a non-star at the end, find that remaining
- // matches the end string (if not, quit), so decrement the end by one (start == end now), and loop again.
- // The second hasEndStar loop will find a star, decrement the end (start > end now), and quit with a yes.
- // - If the match is [*, a, *], the hasStartStar will end with startMatchPos = 1, and hasStartStar = true.
- // The hasEndStar will end with endMatchPos = 1, and hasEndStar = true.
- // - If the match is [a, *, b, *] or [*, b, *, a], then it's essentially just like the [*, a, *] pattern.
- // - If the match is [*, a, *, b, *], or something more complicated, now we're in trouble. The
- // "complicated" section enters with start pointing at "a" and end pointing at "b".
- // Now we need to recurse for each "a" and "b" position within the remaining string, where the
- // "a" position < "b" position.
-
-
- boolean hasStartStar = false;
- while (!hasStartStar) {
- while (startMatchPos <= endMatchPos && "*".equals(matches[startMatchPos])) {
- startMatchPos++;
- hasStartStar = true;
- }
- if (startMatchPos > endMatchPos) {
- // It's just stars
- return true;
- }
- if (!hasStartStar) {
- if (!remaining.startsWith(matches[startMatchPos])) {
- return false;
- }
- remaining = remaining.substring(matches[startMatchPos].length());
- startMatchPos++;
- }
- }
-
- // it's possible at this point to have start pos == end pos.
-
- boolean hasEndStar = false;
- while (!hasEndStar) {
- while (endMatchPos >= startMatchPos && "*".equals(matches[endMatchPos])) {
- endMatchPos--;
- hasEndStar = true;
- }
- if (startMatchPos > endMatchPos) {
- // It's just stars
- return true;
- }
- if (!hasEndStar) {
- if (!remaining.endsWith(matches[endMatchPos])) {
- return false;
- }
- remaining = remaining.substring(0, remaining.length() - matches[endMatchPos].length());
- endMatchPos--;
- }
- }
-
- // Easy out. Stars surrounding a single string.
- if (startMatchPos == endMatchPos) {
- // Stars surrounding a single text bit.
- return remaining.contains(matches[startMatchPos]);
- }
-
- // Complicated.
- // Find all the indexes of the startMatchPos within remaining, and find all the indexes of the
- // endMatchPos within remaining. Then, run a recurse match on each combination where
- // start index < end index.
-
- List startMatchIndicies = matchPositions(remaining, matches[startMatchPos]);
- List endMatchIndicies = matchPositions(remaining, matches[endMatchPos]);
- for (int si = 0; si < startMatchIndicies.size(); si++) {
- // Point the starting string index to where the match completes.
- int sip = startMatchIndicies.get(si) + matches[startMatchPos].length();
- for (int ei = 0; ei < endMatchIndicies.size(); ei++) {
- // Point the ending string index to where the match starts.
- int eip = endMatchIndicies.get(ei);
- if (sip <= eip) {
- if (isRecursiveMatches(startMatchPos + 1, endMatchPos - 1,
- remaining.substring(sip, eip))) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
-
- List matchPositions(String str, String match) {
- int len = str.length();
- List ret = new ArrayList<>(len);
- int p = 0;
- while (p < len) {
- int mp = str.indexOf(match, p);
- if (mp >= p) {
- ret.add(mp);
- p = mp + 1;
- } else {
- break;
- }
- }
- return ret;
- }
- }
-
- /** slash '**' slash. Note that anything that has something '**' something can be split into this and others. */
- static class StrictStarStarPart extends PathPart {
- StrictStarStarPart(@Nullable PathPart next) {
- super(next);
- }
-
- @NotNull
- @Override
- PathNameMatchResult match(@NotNull String name) {
- if (next == null) {
- // Any child will do
- return new PathNameMatchResult(true, false, this);
- }
- // Totally non-greedy match.
- PathNameMatchResult nextMatch = next.match(name);
- if (nextMatch.isMatch) {
- return nextMatch;
- }
- // Because we have a next-match, this requires another path element.
- return new PathNameMatchResult(true, true, this);
- }
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.impl.ignore;
+
+import com.intellij.openapi.util.SystemInfo;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a single line from an ignore file.
+ */
+public class IgnoreFilePattern {
+ private static final String[] EMPTY = new String[0];
+
+ private final String basePattern;
+ private final PathPart rootPart;
+ private final boolean isNegative;
+
+
+ // the parse file is contained in this class to keep the parse logic for the file in one
+ // place.
+ static List parseFile(@NotNull Reader reader) throws IOException {
+ BufferedReader lineReader =
+ reader instanceof BufferedReader
+ ? (BufferedReader) reader
+ : new BufferedReader(reader);
+ // Note: there is now a "p4 ignores" command, and "p4 ignore" is now
+ // also built into the API for newer servers. For caching and UI display, we still need this.
+
+ // File format:
+ // (from https://www.perforce.com/perforce/r15.2/manuals/cmdref/P4IGNORE.html)
+ // (Clarifications at http://forums.perforce.com/index.php?/topic/4492-new-p4-ignore-functionality/page__gopid__18940#entry18940)
+ // The syntax for ignore rules is not the same as Perforce syntax. Instead, it is similar to that used
+ // by other versioning systems:
+ //
+ // * Rules are specified using local filepath syntax. Unix style paths will work on Windows for cross
+ // platform file support.
+ //
+ // * A # character at the beginning of a line denotes a comment
+ //
+ // * A ! character at the beginning of a line line excludes the file specification.These exclusions override rules
+ // defined above it in the P4IGNORE file, but may be overridden by later rules.
+ //
+ // * A / (or \ on Windows) character at the beginning of a line causes the file specification to be
+ // considered relative to the P4IGNORE file. This is useful when the rule must apply to files at
+ // particular depots of the directory tree.
+ //
+ // * A / (or \ on Windows) character at the end of a line causes the file specification to only match
+ // directories, and not files of the same name.
+ //
+ // * The * wildcard matches substrings. Like the Perforce wildcard equivalent, it does not match path
+ // separators; however, if it is not used as part of a path, the directory scanning nature of the rule may
+ // make it appear to perform like the Perforce "..." wildcard.
+ //
+ // * The ** wildcard matches substrings including path separators. It is equivalent to the Perforce "..."
+ // wildcard, which is not permitted. (Note: the "**" must match at least 1 wild card)
+ //
+ // For example:
+ //
+ // # Ignore.p4ignore files
+ // .p4ignore
+ //
+ // # Ignore object files, shared libraries, executables
+ // *.dll
+ // *.so
+ // *.exe
+ // *.o
+ //
+ // # Ignore all HTML files except the readme file
+ // *.html
+ // !readme.html
+ //
+ // # Ignore the bin directory
+ // bin/
+ //
+ // # Ignore the build.properties file in this directory
+ // /build.properties
+ //
+ // # Ignore all text files in test directories
+ // test/**.txt
+ //
+
+
+ // This description unfortunately does not describe these circumstances:
+ // - if a "!" is found after the matcher, is it still a match?
+ // (does the first match force a result?)
+ // TODO It looks like last match?
+ // - if a path is specified ("temp/*.tmp"), is it relative to the
+ // ignore file? Assuming not; as per the .gitignore format
+ // (if a file matcher starts with a '/', then it is relative to
+ // the ignore files).
+
+ List ret = new ArrayList<>();
+
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ IgnoreFilePattern ifp = parseLinePattern(line);
+ if (ifp != null) {
+ ret.add(ifp);
+ }
+ }
+ return ret;
+ }
+
+ @Nullable
+ static IgnoreFilePattern parseLinePattern(final String line) {
+ String pattern = line.trim();
+ if (pattern.length() <= 0 || pattern.charAt(0) == '#') {
+ return null;
+ }
+ boolean isNegative = false;
+ if (pattern.charAt(0) == '!' && pattern.length() > 1) {
+ isNegative = true;
+ pattern = pattern.substring(1).trim();
+ }
+ if (pattern.length() > 0) {
+ return new IgnoreFilePattern(line, createPattern(pattern), isNegative);
+ }
+ return null;
+ }
+
+
+ IgnoreFilePattern(@NotNull PathPart rootPart, boolean isNegative) {
+ this(null, rootPart, isNegative);
+ }
+
+
+ IgnoreFilePattern(@Nullable String original, @NotNull PathPart rootPart, boolean isNegative) {
+ this.basePattern = original;
+ this.rootPart = rootPart;
+ this.isNegative = isNegative;
+ }
+
+
+ public boolean isIgnoreMatchType() {
+ return ! isNegative;
+ }
+
+ @Override
+ public String toString() {
+ return basePattern;
+ }
+
+
+ /**
+ *
+ * @param pathParts the path of the file to check, relative to the source ignore file. Each
+ * path element is its own item in the list.
+ * @return true if the file matches this pattern; it does not mean that it's ignored.
+ */
+ public boolean matches(final List pathParts) {
+ PathPart next = rootPart;
+ for (String pathPart: pathParts) {
+ if (next == null) {
+ return false;
+ }
+ PathNameMatchResult result = next.match(pathPart);
+ if (result.isLastElementMatch) {
+ return true;
+ }
+ if (!result.isMatch) {
+ return false;
+ }
+ next = result.next;
+ }
+ return false;
+ }
+
+ private enum ParseState {
+ END_PATH,
+ STAR_PATH,
+ JUST_FOUND_STAR_AT_END,
+ JUST_FOUND_STAR_IN_MIDDLE,
+ JUST_FOUND_STAR_STAR_AT_END,
+ JUST_FOUND_STAR_STAR_IN_MIDDLE,
+ TEXT_PATH
+ }
+
+
+ @NotNull
+ static PathPart createPattern(@NotNull final String pattern) {
+ if (pattern.length() <= 0) {
+ throw new IllegalArgumentException("pattern cannot be empty");
+ }
+
+ // Split the pattern based on the path separator. From there,
+ // parse each part based on the '*' inclusion.
+
+ // In order to make the splitting easier for us, just change separators to a single format.
+ char[] pat = pattern.replace('\\', '/').replace(File.separatorChar, '/').toCharArray();
+ int lastPos = pat.length - 1;
+
+ // Special case: if the pattern starts with a '/', then start it with a StarStar matcher.
+ boolean isAbsolute = false;
+ int startPos = 0;
+ while (startPos <= lastPos && pat[startPos] == '/' ) {
+ isAbsolute = true;
+ startPos++;
+ }
+
+ // work backwards through the pattern to assemble the parts with the next wiring correctly.
+ PathPart ret = null;
+
+ ParseState state = ParseState.END_PATH;
+ // Special case: trailing slash means an implicit directory.
+ {
+ boolean isDir = false;
+ while (lastPos > startPos && pat[lastPos] == '/') {
+ isDir = true;
+ lastPos--;
+ }
+ if (isDir) {
+ ret = new StrictStarStarPart(null);
+ }
+ }
+
+ List pieces = new ArrayList<>();
+ int lastPartPos = lastPos;
+ while (lastPos >= startPos) {
+ char c = pat[lastPos];
+ switch (state) {
+ case END_PATH:
+ if (c == '/') {
+ // double slashes - count as just one slash.
+ // adjust the positions to count this as the new end.
+ // don't need to adjust the pieces or state.
+ lastPartPos = lastPos;
+ } else if (c == '*') {
+ pieces.add(0, "*");
+ lastPartPos = lastPos;
+ state = ParseState.JUST_FOUND_STAR_AT_END;
+ } else {
+ state = ParseState.TEXT_PATH;
+ }
+ break;
+ case JUST_FOUND_STAR_AT_END:
+ if (c == '*') {
+ // double star at end.
+ ret = new StrictStarStarPart(ret);
+ lastPartPos = lastPos;
+ pieces.clear();
+ state = ParseState.JUST_FOUND_STAR_STAR_AT_END;
+ } else if (c == '/') {
+ ret = new SingleAnyMatchPart(ret);
+ pieces.clear();
+ lastPartPos = lastPos;
+ state = ParseState.END_PATH;
+ } else {
+ state = ParseState.STAR_PATH;
+ }
+ break;
+ case JUST_FOUND_STAR_IN_MIDDLE:
+ if (c == '*') {
+ // found a star star, with stuff after it.
+ // keep the stuff after it, marking it as a *a type.
+ ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
+ lastPartPos = lastPos;
+ pieces.clear();
+ ret = new StrictStarStarPart(ret);
+ state = ParseState.JUST_FOUND_STAR_STAR_IN_MIDDLE;
+ } else if (c == '/') {
+ ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
+ lastPartPos = lastPos;
+ pieces.clear();
+ state = ParseState.END_PATH;
+ } else {
+ state = ParseState.STAR_PATH;
+ }
+ break;
+ case JUST_FOUND_STAR_STAR_AT_END:
+ case JUST_FOUND_STAR_STAR_IN_MIDDLE:
+ if (c == '*') {
+ // ***, which is weird. But okay.
+ pieces.add(0, "*");
+ lastPartPos = lastPos;
+ state = ParseState.JUST_FOUND_STAR_AT_END;
+ } else if (c == '/') {
+ // only star star in path.
+ lastPartPos = lastPos;
+ pieces.clear();
+ state = ParseState.END_PATH;
+ } else {
+ // counts as a* format.
+ lastPartPos = lastPos;
+ pieces.add(0, "*");
+ state = ParseState.STAR_PATH;
+ }
+ break;
+ case STAR_PATH:
+ if (c == '*') {
+ pieces.add(0, new String(pat, lastPos + 1, lastPartPos - lastPos - 1));
+ pieces.add(0, "*");
+ lastPartPos = lastPos;
+ state = ParseState.JUST_FOUND_STAR_IN_MIDDLE;
+ } else if (c == '/') {
+ pieces.add(0, new String(pat, lastPos, lastPartPos - lastPos - 1));
+ ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
+ lastPartPos = lastPos;
+ pieces.clear();
+ state = ParseState.END_PATH;
+ }
+ // else just keep going.
+ break;
+ case TEXT_PATH:
+ if (c == '*') {
+ pieces.add(0, new String(pat, lastPos + 1, lastPartPos - lastPos));
+ pieces.add(0, "*");
+ lastPartPos = lastPos;
+ state = ParseState.JUST_FOUND_STAR_IN_MIDDLE;
+ } else if (c == '/') {
+ ret = new ExactMatchPart(ret,
+ new String(pat, lastPos + 1, lastPartPos - lastPos),
+ isFileSystemCaseSensitive());
+ lastPartPos = lastPos;
+ pieces.clear();
+ state = ParseState.END_PATH;
+ }
+ // else just keep going
+ break;
+ }
+ lastPos--;
+ }
+ switch (state) {
+ case JUST_FOUND_STAR_AT_END:
+ ret = new SingleAnyMatchPart(ret);
+ break;
+ case JUST_FOUND_STAR_IN_MIDDLE:
+ ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
+ break;
+ case STAR_PATH:
+ pieces.add(0, new String(pat, startPos, lastPartPos - startPos));
+ ret = new StarMatchPart(ret, pieces.toArray(EMPTY), isFileSystemCaseSensitive());
+ break;
+ case TEXT_PATH:
+ ret = new ExactMatchPart(ret, new String(pat, startPos, lastPartPos - startPos),
+ isFileSystemCaseSensitive());
+ break;
+ case JUST_FOUND_STAR_STAR_AT_END:
+ case JUST_FOUND_STAR_STAR_IN_MIDDLE:
+ case END_PATH:
+ // do nothing
+ break;
+ }
+ if ((!isAbsolute && !(ret instanceof StrictStarStarPart)) || (isAbsolute && ret == null)) {
+ ret = new StrictStarStarPart(ret);
+ }
+ if (ret == null) {
+ // Weird state. Allow it, though.
+ ret = new ExactMatchPart(null, "", isFileSystemCaseSensitive());
+ }
+ return ret;
+ }
+
+
+ private static boolean isFileSystemCaseSensitive() {
+ // This isn't 100% true - you can configure windows file system to be case sensitive.
+ return !SystemInfo.isWindows;
+ }
+
+ static class PathNameMatchResult {
+ final boolean isMatch;
+ final boolean requiresMore;
+ final boolean isLastElementMatch;
+ final PathPart next;
+
+ PathNameMatchResult(boolean isMatch, @Nullable PathPart next) {
+ this(isMatch, next != null, next);
+ }
+
+ PathNameMatchResult(boolean isMatch, boolean requiresMore, @Nullable PathPart next) {
+ this.isMatch = isMatch;
+ this.requiresMore = requiresMore;
+ this.next = next;
+ this.isLastElementMatch = isMatch && (next == null || !requiresMore);
+ }
+ }
+
+ private static final PathNameMatchResult NOT_MATCH = new PathNameMatchResult(false, false, null);
+
+ abstract static class PathPart {
+ final PathPart next;
+
+ protected PathPart(@Nullable PathPart next) {
+ this.next = next;
+ }
+
+ @NotNull
+ abstract PathNameMatchResult match(@NotNull String name);
+ }
+
+
+ // Matching patterns:
+ // if a pattern ends with a '/', then use StrictStarStarPart with no next.
+ // /a/ -> ExactMatchPart
+ // /*/ -> SingleAnyMatchPart
+ // /**/ -> StrictStarStarPart
+ // /a**b/ -> /a*/**/*b/ -> StarMatchPart, StrictStarStarPart, StarMatchPart
+ // /a**/ -> /a*/**/ -> StarMatchPart, StrictStarStarPart
+ // /**b/ -> /**/*b/ -> StrictStarStarPart, StarMatchPart
+ // /a*/ -> StarMatchPart
+ // /*b/ -> StarMatchPart
+ // /a*b/ -> StarMatchPart
+ // /*a*/ -> StarMatchPart
+
+
+ static class SingleAnyMatchPart extends PathPart {
+ protected SingleAnyMatchPart(@Nullable PathPart next) {
+ super(next);
+ }
+
+ @NotNull
+ @Override
+ PathNameMatchResult match(@NotNull String name) {
+ return new PathNameMatchResult(true, next);
+ }
+ }
+
+
+ static class ExactMatchPart extends PathPart {
+ private final String match;
+ private final boolean caseInsensitive;
+
+ protected ExactMatchPart(@Nullable PathPart next, @NotNull String match, boolean caseInsensitive) {
+ super(next);
+ this.match = match;
+ this.caseInsensitive = caseInsensitive;
+ }
+
+ @NotNull
+ @Override
+ PathNameMatchResult match(@NotNull String name) {
+ boolean isMatch = caseInsensitive ? name.equalsIgnoreCase(match) : name.equals(match);
+ return isMatch ? new PathNameMatchResult(true, next) : NOT_MATCH;
+ }
+ }
+
+ // If P4 ignore ever learns character sets ([ab] meaning a or b), then this will need to take something
+ // other than String for the matches.
+ static class StarMatchPart extends PathPart {
+ final String[] matches;
+ private final boolean caseInsensitive;
+
+ // matches implies a '*' at the end, but it isn't there.
+ StarMatchPart(@Nullable PathPart next, @NotNull String[] matches, boolean caseInsensitive) {
+ super(next);
+ if (matches.length < 2) {
+ throw new IllegalArgumentException("matches must have at least one star and one non-star");
+ }
+ this.matches = matches;
+ this.caseInsensitive = caseInsensitive;
+ if (caseInsensitive) {
+ for (int i = 0; i < matches.length; i++) {
+ matches[i] = matches[i].toLowerCase();
+ }
+ }
+ }
+
+ @NotNull
+ @Override
+ PathNameMatchResult match(@NotNull String name) {
+ String remaining = caseInsensitive ? name.toLowerCase() : name;
+ return isRecursiveMatches(0, matches.length - 1, remaining)
+ ? new PathNameMatchResult(true, next)
+ : NOT_MATCH;
+ }
+
+
+ boolean isRecursiveMatches(int startMatchPos, int endMatchPos, String remaining) {
+ assert startMatchPos >= 0;
+ assert endMatchPos < matches.length;
+ assert startMatchPos <= endMatchPos;
+
+ // peel away until we get to a non-star.
+ // - If match is [a, *], the hasStartStar loop will first not increment startMatchPos.
+ // It will see that remaining starts with the 'a' (if not, quit), so increment to the
+ // '*'. This equals the endMatchPos, but we'll keep looping.
+ // The second loop will match a star, and keep looking. Now the startMatchPos > end,
+ // so it will quit with a yes.
+ // - If match is [*, a], the hasStartStar will just stop with a hasStartStar = true.
+ // Then, the hasEndStar will find a non-star at the end, find that remaining
+ // matches the end string (if not, quit), so decrement the end by one (start == end now), and loop again.
+ // The second hasEndStar loop will find a star, decrement the end (start > end now), and quit with a yes.
+ // - If the match is [*, a, *], the hasStartStar will end with startMatchPos = 1, and hasStartStar = true.
+ // The hasEndStar will end with endMatchPos = 1, and hasEndStar = true.
+ // - If the match is [a, *, b, *] or [*, b, *, a], then it's essentially just like the [*, a, *] pattern.
+ // - If the match is [*, a, *, b, *], or something more complicated, now we're in trouble. The
+ // "complicated" section enters with start pointing at "a" and end pointing at "b".
+ // Now we need to recurse for each "a" and "b" position within the remaining string, where the
+ // "a" position < "b" position.
+
+
+ boolean hasStartStar = false;
+ while (!hasStartStar) {
+ while (startMatchPos <= endMatchPos && "*".equals(matches[startMatchPos])) {
+ startMatchPos++;
+ hasStartStar = true;
+ }
+ if (startMatchPos > endMatchPos) {
+ // It's just stars
+ return true;
+ }
+ if (!hasStartStar) {
+ if (!remaining.startsWith(matches[startMatchPos])) {
+ return false;
+ }
+ remaining = remaining.substring(matches[startMatchPos].length());
+ startMatchPos++;
+ }
+ }
+
+ // it's possible at this point to have start pos == end pos.
+
+ boolean hasEndStar = false;
+ while (!hasEndStar) {
+ while (endMatchPos >= startMatchPos && "*".equals(matches[endMatchPos])) {
+ endMatchPos--;
+ hasEndStar = true;
+ }
+ if (startMatchPos > endMatchPos) {
+ // It's just stars
+ return true;
+ }
+ if (!hasEndStar) {
+ if (!remaining.endsWith(matches[endMatchPos])) {
+ return false;
+ }
+ remaining = remaining.substring(0, remaining.length() - matches[endMatchPos].length());
+ endMatchPos--;
+ }
+ }
+
+ // Easy out. Stars surrounding a single string.
+ if (startMatchPos == endMatchPos) {
+ // Stars surrounding a single text bit.
+ return remaining.contains(matches[startMatchPos]);
+ }
+
+ // Complicated.
+ // Find all the indexes of the startMatchPos within remaining, and find all the indexes of the
+ // endMatchPos within remaining. Then, run a recurse match on each combination where
+ // start index < end index.
+
+ List startMatchIndicies = matchPositions(remaining, matches[startMatchPos]);
+ List endMatchIndicies = matchPositions(remaining, matches[endMatchPos]);
+ for (int si = 0; si < startMatchIndicies.size(); si++) {
+ // Point the starting string index to where the match completes.
+ int sip = startMatchIndicies.get(si) + matches[startMatchPos].length();
+ for (int ei = 0; ei < endMatchIndicies.size(); ei++) {
+ // Point the ending string index to where the match starts.
+ int eip = endMatchIndicies.get(ei);
+ if (sip <= eip) {
+ if (isRecursiveMatches(startMatchPos + 1, endMatchPos - 1,
+ remaining.substring(sip, eip))) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+ List matchPositions(String str, String match) {
+ int len = str.length();
+ List ret = new ArrayList<>(len);
+ int p = 0;
+ while (p < len) {
+ int mp = str.indexOf(match, p);
+ if (mp >= p) {
+ ret.add(mp);
+ p = mp + 1;
+ } else {
+ break;
+ }
+ }
+ return ret;
+ }
+ }
+
+ /** slash '**' slash. Note that anything that has something '**' something can be split into this and others. */
+ static class StrictStarStarPart extends PathPart {
+ StrictStarStarPart(@Nullable PathPart next) {
+ super(next);
+ }
+
+ @NotNull
+ @Override
+ PathNameMatchResult match(@NotNull String name) {
+ if (next == null) {
+ // Any child will do
+ return new PathNameMatchResult(true, false, this);
+ }
+ // Totally non-greedy match.
+ PathNameMatchResult nextMatch = next.match(name);
+ if (nextMatch.isMatch) {
+ return nextMatch;
+ }
+ // Because we have a next-match, this requires another path element.
+ return new PathNameMatchResult(true, true, this);
+ }
+ }
+}
diff --git a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFiles.java b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFiles.java
index f93015d9..0689a6a4 100644
--- a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFiles.java
+++ b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/ignore/IgnoreFiles.java
@@ -1,94 +1,94 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.p4.server.impl.ignore;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.vcs.FilePath;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.IOException;
-
-/**
- * A hybrid local cached file. The ignore file is stored entirely on the client (it can be in Perforce,
- * but the storage will still be considered local), but we'll treat it like the local cache.
- */
-public class IgnoreFiles {
- private static final Logger LOG = Logger.getInstance(IgnoreFiles.class);
-
- private final String ignoreFileName;
-
- public IgnoreFiles(@Nullable final String ignoreFileName) {
- this.ignoreFileName = ignoreFileName;
- }
-
- @Nullable
- public String getIgnoreFileName() {
- return ignoreFileName;
- }
-
- @Nullable
- public VirtualFile getIgnoreFileForPath(@Nullable final VirtualFile path) {
- if (path == null) {
- return null;
- }
- String ignoreFileName = getIgnoreFileName();
- if (ignoreFileName != null) {
- VirtualFile prevDir = path;
- VirtualFile f = prevDir.getParent();
- while (f != null && f.isDirectory() && !f.equals(prevDir)) {
- VirtualFile ignoreFile = f.findChild(ignoreFileName);
- if (ignoreFile != null && ignoreFile.exists() && !ignoreFile.isDirectory()) {
- return ignoreFile;
- }
- prevDir = f;
- f = f.getParent();
- }
- }
- return null;
- }
-
- public boolean isFileIgnored(@Nullable final FilePath file) {
- if (file == null || file.getVirtualFile() == null) {
- return true;
- }
- final VirtualFile ignoreFile = getIgnoreFileForPath(file.getVirtualFile());
- return isMatch(file, ignoreFile);
- }
-
- private boolean isMatch(@NotNull final FilePath file, @Nullable final VirtualFile ignoreFile) {
- LOG.debug("Checking ignore status on " + file + " against ignore file " + ignoreFile);
- if (ignoreFile == null || ignoreFile.isDirectory()) {
- return false;
- }
- VirtualFile vf = file.getVirtualFile();
- if (vf == null) {
- return false;
- }
-
- // TODO look at caching these ignore file results.
- // It would mean needing to be aware of file reload events, though.
-
- try {
- final IgnoreFileSet patterns = IgnoreFileSet.create(ignoreFile);
- return patterns.isCoveredByIgnoreFile(vf) && patterns.isIgnored(vf);
- } catch (IOException e) {
- // problem reading; assume it's not ignored
- LOG.info(e);
- return false;
- }
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.p4.server.impl.ignore;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+
+/**
+ * A hybrid local cached file. The ignore file is stored entirely on the client (it can be in Perforce,
+ * but the storage will still be considered local), but we'll treat it like the local cache.
+ */
+public class IgnoreFiles {
+ private static final Logger LOG = Logger.getInstance(IgnoreFiles.class);
+
+ private final String ignoreFileName;
+
+ public IgnoreFiles(@Nullable final String ignoreFileName) {
+ this.ignoreFileName = ignoreFileName;
+ }
+
+ @Nullable
+ public String getIgnoreFileName() {
+ return ignoreFileName;
+ }
+
+ @Nullable
+ public VirtualFile getIgnoreFileForPath(@Nullable final VirtualFile path) {
+ if (path == null) {
+ return null;
+ }
+ String ignoreFileName = getIgnoreFileName();
+ if (ignoreFileName != null) {
+ VirtualFile prevDir = path;
+ VirtualFile f = prevDir.getParent();
+ while (f != null && f.isDirectory() && !f.equals(prevDir)) {
+ VirtualFile ignoreFile = f.findChild(ignoreFileName);
+ if (ignoreFile != null && ignoreFile.exists() && !ignoreFile.isDirectory()) {
+ return ignoreFile;
+ }
+ prevDir = f;
+ f = f.getParent();
+ }
+ }
+ return null;
+ }
+
+ public boolean isFileIgnored(@Nullable final FilePath file) {
+ if (file == null || file.getVirtualFile() == null) {
+ return true;
+ }
+ final VirtualFile ignoreFile = getIgnoreFileForPath(file.getVirtualFile());
+ return isMatch(file, ignoreFile);
+ }
+
+ private boolean isMatch(@NotNull final FilePath file, @Nullable final VirtualFile ignoreFile) {
+ LOG.debug("Checking ignore status on " + file + " against ignore file " + ignoreFile);
+ if (ignoreFile == null || ignoreFile.isDirectory()) {
+ return false;
+ }
+ VirtualFile vf = file.getVirtualFile();
+ if (vf == null) {
+ return false;
+ }
+
+ // TODO look at caching these ignore file results.
+ // It would mean needing to be aware of file reload events, though.
+
+ try {
+ final IgnoreFileSet patterns = IgnoreFileSet.create(ignoreFile);
+ return patterns.isCoveredByIgnoreFile(vf) && patterns.isIgnored(vf);
+ } catch (IOException e) {
+ // problem reading; assume it's not ignored
+ LOG.info(e);
+ return false;
+ }
+ }
+}
diff --git a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/tasks/TempFileWatchDog.java b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/tasks/TempFileWatchDog.java
index 11a7cc7d..eb1047c0 100644
--- a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/tasks/TempFileWatchDog.java
+++ b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/tasks/TempFileWatchDog.java
@@ -1,140 +1,140 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.impl.tasks;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.ConcurrencyUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A background task that monitors the temporary files created by
- * the P4 java API.
- */
-public class TempFileWatchDog {
- private static final Logger LOG = Logger.getInstance(TempFileWatchDog.class);
- private static final ScheduledExecutorService SCHEDULER =
- ConcurrencyUtil.newSingleScheduledThreadExecutor("P4 Temp File Cleanup");
- private static final FilenameFilter TEMP_FILE_FILTER = new TempFileFilter();
- private static final long INTERVAL_SECONDS = 10L;
- private static final String PREFIX = "p4j";
- private static final String SUFFIX = ".tmp";
-
- private final File tempDir;
- private ScheduledFuture> cleanup;
-
-
- private static File getDefaultTempDir() {
- try {
- return Files.createTempDirectory("tmp").toFile();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
-
- public TempFileWatchDog() {
- this(getDefaultTempDir());
- }
-
-
- public TempFileWatchDog(@NotNull File tempDir) {
- if (! tempDir.isDirectory() || ! tempDir.canRead()) {
- throw new IllegalArgumentException(tempDir.getAbsolutePath());
- }
- this.tempDir = tempDir;
- }
-
-
- @NotNull
- public File getTempDir() {
- return tempDir;
- }
-
-
- public synchronized void start() {
- if (cleanup == null) {
- cleanup = SCHEDULER.scheduleWithFixedDelay(new Watcher(), INTERVAL_SECONDS, INTERVAL_SECONDS, TimeUnit.SECONDS);
- }
- }
-
-
- public synchronized void stop() {
- if (cleanup != null) {
- cleanup.cancel(false);
- cleanup = null;
- }
- }
-
-
- private void cleanUpFiles() {
- File[] contents = tempDir.listFiles(TEMP_FILE_FILTER);
- if (contents != null) {
- for (File file : contents) {
- if (!file.delete()) {
- LOG.info("Could not delete temporary Perforce file " + file);
- }
- }
- }
- }
-
-
- public void cleanUpTempDir() {
- File[] contents = tempDir.listFiles();
- if (contents != null) {
- for (File file: contents) {
- // Ignore result. We do the final check by trying to
- // delete the directory, which will fail if it's not
- // empty.
- file.delete();
- }
- }
- if (! tempDir.delete()) {
- LOG.info("Could not delete temporary directory " + tempDir);
- }
- }
-
-
-
- private class Watcher implements Runnable {
- @Override
- public void run() {
- try {
- cleanUpFiles();
- } catch (Exception ex) {
- LOG.warn(ex);
- }
- }
- }
-
-
- private static class TempFileFilter implements FilenameFilter {
-
- @Override
- public boolean accept(File dir, String name) {
- if (name == null) {
- return false;
- }
- String lName = name.toLowerCase();
- return lName.startsWith(PREFIX) && lName.endsWith(SUFFIX);
- }
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.impl.tasks;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.ConcurrencyUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A background task that monitors the temporary files created by
+ * the P4 java API.
+ */
+public class TempFileWatchDog {
+ private static final Logger LOG = Logger.getInstance(TempFileWatchDog.class);
+ private static final ScheduledExecutorService SCHEDULER =
+ ConcurrencyUtil.newSingleScheduledThreadExecutor("P4 Temp File Cleanup");
+ private static final FilenameFilter TEMP_FILE_FILTER = new TempFileFilter();
+ private static final long INTERVAL_SECONDS = 10L;
+ private static final String PREFIX = "p4j";
+ private static final String SUFFIX = ".tmp";
+
+ private final File tempDir;
+ private ScheduledFuture> cleanup;
+
+
+ private static File getDefaultTempDir() {
+ try {
+ return Files.createTempDirectory("tmp").toFile();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+
+ public TempFileWatchDog() {
+ this(getDefaultTempDir());
+ }
+
+
+ public TempFileWatchDog(@NotNull File tempDir) {
+ if (! tempDir.isDirectory() || ! tempDir.canRead()) {
+ throw new IllegalArgumentException(tempDir.getAbsolutePath());
+ }
+ this.tempDir = tempDir;
+ }
+
+
+ @NotNull
+ public File getTempDir() {
+ return tempDir;
+ }
+
+
+ public synchronized void start() {
+ if (cleanup == null) {
+ cleanup = SCHEDULER.scheduleWithFixedDelay(new Watcher(), INTERVAL_SECONDS, INTERVAL_SECONDS, TimeUnit.SECONDS);
+ }
+ }
+
+
+ public synchronized void stop() {
+ if (cleanup != null) {
+ cleanup.cancel(false);
+ cleanup = null;
+ }
+ }
+
+
+ private void cleanUpFiles() {
+ File[] contents = tempDir.listFiles(TEMP_FILE_FILTER);
+ if (contents != null) {
+ for (File file : contents) {
+ if (!file.delete()) {
+ LOG.info("Could not delete temporary Perforce file " + file);
+ }
+ }
+ }
+ }
+
+
+ public void cleanUpTempDir() {
+ File[] contents = tempDir.listFiles();
+ if (contents != null) {
+ for (File file: contents) {
+ // Ignore result. We do the final check by trying to
+ // delete the directory, which will fail if it's not
+ // empty.
+ file.delete();
+ }
+ }
+ if (! tempDir.delete()) {
+ LOG.info("Could not delete temporary directory " + tempDir);
+ }
+ }
+
+
+
+ private class Watcher implements Runnable {
+ @Override
+ public void run() {
+ try {
+ cleanUpFiles();
+ } catch (Exception ex) {
+ LOG.warn(ex);
+ }
+ }
+ }
+
+
+ private static class TempFileFilter implements FilenameFilter {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ if (name == null) {
+ return false;
+ }
+ String lName = name.toLowerCase();
+ return lName.startsWith(PREFIX) && lName.endsWith(SUFFIX);
+ }
+ }
+}
diff --git a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/values/P4AnnotatedLineImpl.java b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/values/P4AnnotatedLineImpl.java
index 57a51ad6..3cd5f3b3 100644
--- a/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/values/P4AnnotatedLineImpl.java
+++ b/idea-p4server/impl/src/main/java/net/groboclown/p4/server/impl/values/P4AnnotatedLineImpl.java
@@ -1,100 +1,100 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.groboclown.p4.server.impl.values;
-
-import com.intellij.openapi.vcs.FilePath;
-import com.perforce.p4java.core.file.IFileAnnotation;
-import com.perforce.p4java.core.file.IFileRevisionData;
-import net.groboclown.p4.server.api.ClientServerRef;
-import net.groboclown.p4.server.api.values.P4AnnotatedLine;
-import net.groboclown.p4.server.api.values.P4ChangelistId;
-import net.groboclown.p4.server.api.values.P4FileRevision;
-import net.groboclown.p4.server.api.values.P4RemoteFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Date;
-
-public class P4AnnotatedLineImpl implements P4AnnotatedLine {
- private final FilePath baseFile;
- private final P4RemoteFile depotPath;
- private final IFileAnnotation ann;
- private final int lineNumber;
- private final IFileRevisionData revisionData;
- private final P4ChangelistId changelistId;
- private final P4FileRevision rev;
-
- public P4AnnotatedLineImpl(@NotNull ClientServerRef ref, @NotNull FilePath baseFile, int lineNumber,
- @NotNull IFileAnnotation ann,
- @NotNull IFileRevisionData data) {
- this.baseFile = baseFile;
- this.depotPath = new P4RemoteFileImpl(ann);
- this.ann = ann;
- this.revisionData = data;
- this.lineNumber = lineNumber;
- this.changelistId = new P4ChangelistIdImpl(revisionData.getChangelistId(), ref);
- this.rev = new P4FileRevisionImpl(ref, data);
- }
-
- @Override
- @NotNull
- public P4FileRevision getRev() {
- return rev;
- }
-
- @Override
- public P4ChangelistId getChangelist() {
- return changelistId;
- }
-
- @Override
- @Nullable
- public String getAuthor() {
- return revisionData.getUserName();
- }
-
- @Override
- @Nullable
- public Date getDate() {
- return revisionData.getDate();
- }
-
- @Override
- @Nullable
- public String getComment() {
- return revisionData.getDescription();
- }
-
- @Override
- @NotNull
- public IFileRevisionData getRevisionData() {
- return revisionData;
- }
-
- @Override
- @NotNull
- public P4RemoteFile getDepotPath() {
- return depotPath;
- }
-
- @Override
- public int getLineNumber() {
- return lineNumber;
- }
-
- @Override
- public int getRevNumber() {
- return revisionData.getRevision();
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.groboclown.p4.server.impl.values;
+
+import com.intellij.openapi.vcs.FilePath;
+import com.perforce.p4java.core.file.IFileAnnotation;
+import com.perforce.p4java.core.file.IFileRevisionData;
+import net.groboclown.p4.server.api.ClientServerRef;
+import net.groboclown.p4.server.api.values.P4AnnotatedLine;
+import net.groboclown.p4.server.api.values.P4ChangelistId;
+import net.groboclown.p4.server.api.values.P4FileRevision;
+import net.groboclown.p4.server.api.values.P4RemoteFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Date;
+
+public class P4AnnotatedLineImpl implements P4AnnotatedLine {
+ private final FilePath baseFile;
+ private final P4RemoteFile depotPath;
+ private final IFileAnnotation ann;
+ private final int lineNumber;
+ private final IFileRevisionData revisionData;
+ private final P4ChangelistId changelistId;
+ private final P4FileRevision rev;
+
+ public P4AnnotatedLineImpl(@NotNull ClientServerRef ref, @NotNull FilePath baseFile, int lineNumber,
+ @NotNull IFileAnnotation ann,
+ @NotNull IFileRevisionData data) {
+ this.baseFile = baseFile;
+ this.depotPath = new P4RemoteFileImpl(ann);
+ this.ann = ann;
+ this.revisionData = data;
+ this.lineNumber = lineNumber;
+ this.changelistId = new P4ChangelistIdImpl(revisionData.getChangelistId(), ref);
+ this.rev = new P4FileRevisionImpl(ref, data);
+ }
+
+ @Override
+ @NotNull
+ public P4FileRevision getRev() {
+ return rev;
+ }
+
+ @Override
+ public P4ChangelistId getChangelist() {
+ return changelistId;
+ }
+
+ @Override
+ @Nullable
+ public String getAuthor() {
+ return revisionData.getUserName();
+ }
+
+ @Override
+ @Nullable
+ public Date getDate() {
+ return revisionData.getDate();
+ }
+
+ @Override
+ @Nullable
+ public String getComment() {
+ return revisionData.getDescription();
+ }
+
+ @Override
+ @NotNull
+ public IFileRevisionData getRevisionData() {
+ return revisionData;
+ }
+
+ @Override
+ @NotNull
+ public P4RemoteFile getDepotPath() {
+ return depotPath;
+ }
+
+ @Override
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ @Override
+ public int getRevNumber() {
+ return revisionData.getRevision();
+ }
+}
diff --git a/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFilePath.java b/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFilePath.java
index 60a37e05..a2572997 100644
--- a/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFilePath.java
+++ b/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFilePath.java
@@ -1,150 +1,150 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.idea.altmock;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.FilePath;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.nio.charset.Charset;
-
-public class MockFilePath implements FilePath {
- private final File f;
- private final VirtualFile vf;
-
- public MockFilePath(final File f) {
- this.f = f;
- this.vf = new MockVirtualFile(f);
- }
-
- @Nullable
- @Override
- public VirtualFile getVirtualFile() {
- return vf;
- }
-
- @Nullable
- @Override
- public VirtualFile getVirtualFileParent() {
- return vf.getParent();
- }
-
- @NotNull
- @Override
- public File getIOFile() {
- return f;
- }
-
- @NotNull
- @Override
- public String getName() {
- return vf.getName();
- }
-
- @NotNull
- @Override
- public String getPresentableUrl() {
- return f.toURI().toASCIIString();
- }
-
- @Deprecated
- @Nullable
- @Override
- public Document getDocument() {
- return null;
- }
-
- @NotNull
- @Override
- public Charset getCharset() {
- return Charset.defaultCharset();
- }
-
- @NotNull
- @Override
- public Charset getCharset(@Nullable final Project project) {
- return Charset.defaultCharset();
- }
-
- @NotNull
- @Override
- public FileType getFileType() {
- return MockFileType.MOCK;
- }
-
- @Deprecated
- @Override
- public void refresh() {
-
- }
-
- @Deprecated
- @Override
- public void hardRefresh() {
-
- }
-
- @NotNull
- @Override
- public String getPath() {
- return vf.getPath();
- }
-
- @Override
- public boolean isDirectory() {
- return vf.isDirectory();
- }
-
- @Override
- public boolean isUnder(@NotNull final FilePath filePath, final boolean b) {
- // not implemented here
- return false;
- }
-
- @Nullable
- @Override
- public FilePath getParentPath() {
- File parent = f.getParentFile();
- if (parent == null) {
- return null;
- }
- return new MockFilePath(parent);
- }
-
- @Override
- public boolean isNonLocal() {
- return false;
- }
-
- @Override
- public int hashCode() {
- return vf.getPath().hashCode() + vf.getName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof FilePath && vf.equals(((FilePath) obj).getVirtualFile());
- }
-
- @Override
- public String toString() {
- return f.toString();
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.idea.altmock;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+public class MockFilePath implements FilePath {
+ private final File f;
+ private final VirtualFile vf;
+
+ public MockFilePath(final File f) {
+ this.f = f;
+ this.vf = new MockVirtualFile(f);
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getVirtualFile() {
+ return vf;
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getVirtualFileParent() {
+ return vf.getParent();
+ }
+
+ @NotNull
+ @Override
+ public File getIOFile() {
+ return f;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return vf.getName();
+ }
+
+ @NotNull
+ @Override
+ public String getPresentableUrl() {
+ return f.toURI().toASCIIString();
+ }
+
+ @Deprecated
+ @Nullable
+ @Override
+ public Document getDocument() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Charset getCharset() {
+ return Charset.defaultCharset();
+ }
+
+ @NotNull
+ @Override
+ public Charset getCharset(@Nullable final Project project) {
+ return Charset.defaultCharset();
+ }
+
+ @NotNull
+ @Override
+ public FileType getFileType() {
+ return MockFileType.MOCK;
+ }
+
+ @Deprecated
+ @Override
+ public void refresh() {
+
+ }
+
+ @Deprecated
+ @Override
+ public void hardRefresh() {
+
+ }
+
+ @NotNull
+ @Override
+ public String getPath() {
+ return vf.getPath();
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return vf.isDirectory();
+ }
+
+ @Override
+ public boolean isUnder(@NotNull final FilePath filePath, final boolean b) {
+ // not implemented here
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public FilePath getParentPath() {
+ File parent = f.getParentFile();
+ if (parent == null) {
+ return null;
+ }
+ return new MockFilePath(parent);
+ }
+
+ @Override
+ public boolean isNonLocal() {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return vf.getPath().hashCode() + vf.getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FilePath && vf.equals(((FilePath) obj).getVirtualFile());
+ }
+
+ @Override
+ public String toString() {
+ return f.toString();
+ }
+}
diff --git a/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFileType.java b/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFileType.java
index 781ae3bf..7eca5208 100644
--- a/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFileType.java
+++ b/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockFileType.java
@@ -1,66 +1,66 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.idea.altmock;
-
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-public class MockFileType implements FileType {
- public static final FileType MOCK = new MockFileType();
-
- @NotNull
- @Override
- public String getName() {
- return "mock";
- }
-
- @NotNull
- @Override
- public String getDescription() {
- return "mock";
- }
-
- @NotNull
- @Override
- public String getDefaultExtension() {
- return ".mock";
- }
-
- @Nullable
- @Override
- public Icon getIcon() {
- return null;
- }
-
- @Override
- public boolean isBinary() {
- return false;
- }
-
- @Override
- public boolean isReadOnly() {
- return false;
- }
-
- @Nullable
- @Override
- public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) {
- return null;
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.idea.altmock;
+
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class MockFileType implements FileType {
+ public static final FileType MOCK = new MockFileType();
+
+ @NotNull
+ @Override
+ public String getName() {
+ return "mock";
+ }
+
+ @NotNull
+ @Override
+ public String getDescription() {
+ return "mock";
+ }
+
+ @NotNull
+ @Override
+ public String getDefaultExtension() {
+ return ".mock";
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return null;
+ }
+
+ @Override
+ public boolean isBinary() {
+ return false;
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public String getCharset(@NotNull VirtualFile file, @NotNull byte[] content) {
+ return null;
+ }
+}
diff --git a/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockVirtualFile.java b/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockVirtualFile.java
index fd93a248..1f26784b 100644
--- a/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockVirtualFile.java
+++ b/idea-test-core/src/main/java/net/groboclown/idea/altmock/MockVirtualFile.java
@@ -1,144 +1,144 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.idea.altmock;
-
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileSystem;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-public class MockVirtualFile extends VirtualFile {
- private static final VirtualFile[] EMPTY = new VirtualFile[0];
- private final File f;
-
- public MockVirtualFile(@NotNull File f) {
- this.f = f;
- }
-
- @NotNull
- @Override
- public String getName() {
- return f.getName();
- }
-
- @NotNull
- @Override
- public VirtualFileSystem getFileSystem() {
- throw new IllegalStateException("not implemented");
- }
-
- @NotNull
- @Override
- public String getPath() {
- return f.getPath();
- }
-
- @Override
- public boolean isWritable() {
- return f.canWrite();
- }
-
- @Override
- public boolean isDirectory() {
- return f.isDirectory();
- }
-
- @Override
- public boolean isValid() {
- return true;
- }
-
- @Override
- public VirtualFile getParent() {
- return new MockVirtualFile(f.getParentFile());
- }
-
- @Override
- public VirtualFile[] getChildren() {
- if (! f.isDirectory()) {
- return EMPTY;
- }
- File[] files = f.listFiles();
- if (files == null) {
- return EMPTY;
- }
- List ret = new ArrayList<>();
- for (File f : files) {
- ret.add(new MockVirtualFile(f));
- }
- return ret.toArray(EMPTY);
- }
-
- @NotNull
- @Override
- public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp)
- throws IOException {
- return new FileOutputStream(f);
- }
-
- @NotNull
- @Override
- public byte[] contentsToByteArray()
- throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (InputStream inp = getInputStream()) {
- byte[] buff = new byte[4096];
- int len;
- while ((len = inp.read(buff, 0, 4096)) > 0) {
- out.write(buff, 0, len);
- }
- }
- return out.toByteArray();
- }
-
- @Override
- public long getTimeStamp() {
- if (f.exists()) {
- return f.lastModified();
- }
- return 0;
- }
-
- @Override
- public long getLength() {
- if (f.isFile()) {
- return f.length();
- }
- return 0;
- }
-
- @Override
- public void refresh(boolean asynchronous, boolean recursive, @Nullable Runnable postRunnable) {
- if (postRunnable != null) {
- postRunnable.run();
- }
- }
-
- @Override
- public InputStream getInputStream()
- throws IOException {
- return new FileInputStream(f);
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.idea.altmock;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileSystem;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MockVirtualFile extends VirtualFile {
+ private static final VirtualFile[] EMPTY = new VirtualFile[0];
+ private final File f;
+
+ public MockVirtualFile(@NotNull File f) {
+ this.f = f;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return f.getName();
+ }
+
+ @NotNull
+ @Override
+ public VirtualFileSystem getFileSystem() {
+ throw new IllegalStateException("not implemented");
+ }
+
+ @NotNull
+ @Override
+ public String getPath() {
+ return f.getPath();
+ }
+
+ @Override
+ public boolean isWritable() {
+ return f.canWrite();
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return f.isDirectory();
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ @Override
+ public VirtualFile getParent() {
+ return new MockVirtualFile(f.getParentFile());
+ }
+
+ @Override
+ public VirtualFile[] getChildren() {
+ if (! f.isDirectory()) {
+ return EMPTY;
+ }
+ File[] files = f.listFiles();
+ if (files == null) {
+ return EMPTY;
+ }
+ List ret = new ArrayList<>();
+ for (File f : files) {
+ ret.add(new MockVirtualFile(f));
+ }
+ return ret.toArray(EMPTY);
+ }
+
+ @NotNull
+ @Override
+ public OutputStream getOutputStream(Object requestor, long newModificationStamp, long newTimeStamp)
+ throws IOException {
+ return new FileOutputStream(f);
+ }
+
+ @NotNull
+ @Override
+ public byte[] contentsToByteArray()
+ throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (InputStream inp = getInputStream()) {
+ byte[] buff = new byte[4096];
+ int len;
+ while ((len = inp.read(buff, 0, 4096)) > 0) {
+ out.write(buff, 0, len);
+ }
+ }
+ return out.toByteArray();
+ }
+
+ @Override
+ public long getTimeStamp() {
+ if (f.exists()) {
+ return f.lastModified();
+ }
+ return 0;
+ }
+
+ @Override
+ public long getLength() {
+ if (f.isFile()) {
+ return f.length();
+ }
+ return 0;
+ }
+
+ @Override
+ public void refresh(boolean asynchronous, boolean recursive, @Nullable Runnable postRunnable) {
+ if (postRunnable != null) {
+ postRunnable.run();
+ }
+ }
+
+ @Override
+ public InputStream getInputStream()
+ throws IOException {
+ return new FileInputStream(f);
+ }
+}
diff --git a/idea-test-core/src/main/java/net/groboclown/idea/mock/IOFilePath.java b/idea-test-core/src/main/java/net/groboclown/idea/mock/IOFilePath.java
index 6ca4cfb5..a1e06081 100644
--- a/idea-test-core/src/main/java/net/groboclown/idea/mock/IOFilePath.java
+++ b/idea-test-core/src/main/java/net/groboclown/idea/mock/IOFilePath.java
@@ -1,150 +1,150 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.idea.mock;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.FilePath;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.nio.charset.Charset;
-
-public class IOFilePath
- implements FilePath {
- private final File f;
- private final VirtualFile vf;
- private final boolean isDirectory;
-
- public IOFilePath(final File f) {
- this.f = f;
- this.vf = new IOVirtualFile(f);
- this.isDirectory = f.isDirectory();
- }
-
- public IOFilePath(final File f, boolean isDirectory) {
- this.f = f;
- this.vf = new IOVirtualFile(f);
- this.isDirectory = isDirectory;
- }
-
- @Nullable
- @Override
- public VirtualFile getVirtualFile() {
- return vf;
- }
-
- @Nullable
- @Override
- public VirtualFile getVirtualFileParent() {
- return vf.getParent();
- }
-
- @NotNull
- @Override
- public File getIOFile() {
- return f;
- }
-
- @NotNull
- @Override
- public String getName() {
- return vf.getName();
- }
-
- @NotNull
- @Override
- public String getPresentableUrl() {
- return f.toURI().toASCIIString();
- }
-
- @Deprecated
- @Nullable
- @Override
- public Document getDocument() {
- return null;
- }
-
- @NotNull
- @Override
- public Charset getCharset() {
- return Charset.defaultCharset();
- }
-
- @NotNull
- @Override
- public Charset getCharset(@Nullable final Project project) {
- return Charset.defaultCharset();
- }
-
- @NotNull
- @Override
- public FileType getFileType() {
- return MockFileType.MOCK;
- }
-
- @Deprecated
- @Override
- public void refresh() {
-
- }
-
- @Deprecated
- @Override
- public void hardRefresh() {
-
- }
-
- @NotNull
- @Override
- public String getPath() {
- return vf.getPath();
- }
-
- @Override
- public boolean isDirectory() {
- return isDirectory;
- }
-
- @Override
- public boolean isUnder(@NotNull final FilePath filePath, final boolean b) {
- // not implemented here
- return false;
- }
-
- @Nullable
- @Override
- public FilePath getParentPath() {
- return new IOFilePath(f.getParentFile());
- }
-
- @Override
- public boolean isNonLocal() {
- return false;
- }
-
- @Override
- public int hashCode() {
- return vf.getPath().hashCode() + vf.getName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof FilePath && vf.equals(((FilePath) obj).getVirtualFile());
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.idea.mock;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+public class IOFilePath
+ implements FilePath {
+ private final File f;
+ private final VirtualFile vf;
+ private final boolean isDirectory;
+
+ public IOFilePath(final File f) {
+ this.f = f;
+ this.vf = new IOVirtualFile(f);
+ this.isDirectory = f.isDirectory();
+ }
+
+ public IOFilePath(final File f, boolean isDirectory) {
+ this.f = f;
+ this.vf = new IOVirtualFile(f);
+ this.isDirectory = isDirectory;
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getVirtualFile() {
+ return vf;
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getVirtualFileParent() {
+ return vf.getParent();
+ }
+
+ @NotNull
+ @Override
+ public File getIOFile() {
+ return f;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return vf.getName();
+ }
+
+ @NotNull
+ @Override
+ public String getPresentableUrl() {
+ return f.toURI().toASCIIString();
+ }
+
+ @Deprecated
+ @Nullable
+ @Override
+ public Document getDocument() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Charset getCharset() {
+ return Charset.defaultCharset();
+ }
+
+ @NotNull
+ @Override
+ public Charset getCharset(@Nullable final Project project) {
+ return Charset.defaultCharset();
+ }
+
+ @NotNull
+ @Override
+ public FileType getFileType() {
+ return MockFileType.MOCK;
+ }
+
+ @Deprecated
+ @Override
+ public void refresh() {
+
+ }
+
+ @Deprecated
+ @Override
+ public void hardRefresh() {
+
+ }
+
+ @NotNull
+ @Override
+ public String getPath() {
+ return vf.getPath();
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return isDirectory;
+ }
+
+ @Override
+ public boolean isUnder(@NotNull final FilePath filePath, final boolean b) {
+ // not implemented here
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public FilePath getParentPath() {
+ return new IOFilePath(f.getParentFile());
+ }
+
+ @Override
+ public boolean isNonLocal() {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return vf.getPath().hashCode() + vf.getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FilePath && vf.equals(((FilePath) obj).getVirtualFile());
+ }
+}
diff --git a/idea-test-core/src/main/java/net/groboclown/idea/mock/P4Request.java b/idea-test-core/src/main/java/net/groboclown/idea/mock/P4Request.java
index 49712ee4..e754208d 100644
--- a/idea-test-core/src/main/java/net/groboclown/idea/mock/P4Request.java
+++ b/idea-test-core/src/main/java/net/groboclown/idea/mock/P4Request.java
@@ -1,116 +1,116 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.idea.mock;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Arrays;
-import java.util.Map;
-
-public final class P4Request {
- private final String cmd;
- private final String[] args;
- private final Map request;
- private final String inputData;
-
- public P4Request(@NotNull String cmd, @NotNull String[] args, @Nullable Map request,
- @Nullable String inputData) {
- this.cmd = cmd;
- this.args = args;
- this.request = request;
- this.inputData = inputData;
- }
-
- public P4Request(@NotNull String cmd, @NotNull String... args) {
- this.cmd = cmd;
- this.args = args;
- this.request = null;
- this.inputData = null;
- }
-
- @NotNull
- public String getCmd() {
- return cmd;
- }
-
- @NotNull
- public String[] getArgs() {
- return args;
- }
-
- @Nullable
- public Map getRequest() {
- return request;
- }
-
- @Nullable
- public String getInputData() {
- return inputData;
- }
-
- @Override
- public int hashCode() {
- int ret = cmd.hashCode() + Arrays.hashCode(args);
- if (request != null && ! request.isEmpty()) {
- ret += request.hashCode();
- }
- if (inputData != null && inputData.length() > 0) {
- ret += inputData.hashCode();
- }
- return ret;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null) {
- return false;
- }
- if (! (o.getClass().equals(P4Request.class))) {
- return false;
- }
- P4Request that = (P4Request) o;
- if (request == null || request.isEmpty()) {
- if (that.request != null && ! that.request.isEmpty()) {
- return false;
- }
- }
- if (inputData == null || inputData.length() <= 0) {
- if (that.inputData != null && that.inputData.length() > 0) {
- return false;
- }
- }
- return cmd.equals(that.cmd) &&
- Arrays.equals(args, that.args);
- }
-
- @Override
- public String toString() {
- StringBuilder ret = new StringBuilder(cmd);
- for (String arg : args) {
- ret.append(' ').append(arg);
- }
- if (request != null) {
- ret.append(' ').append(request);
- }
- if (inputData != null) {
- ret.append(" [").append(inputData).append(']');
- }
- return ret.toString();
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.idea.mock;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.Map;
+
+public final class P4Request {
+ private final String cmd;
+ private final String[] args;
+ private final Map request;
+ private final String inputData;
+
+ public P4Request(@NotNull String cmd, @NotNull String[] args, @Nullable Map request,
+ @Nullable String inputData) {
+ this.cmd = cmd;
+ this.args = args;
+ this.request = request;
+ this.inputData = inputData;
+ }
+
+ public P4Request(@NotNull String cmd, @NotNull String... args) {
+ this.cmd = cmd;
+ this.args = args;
+ this.request = null;
+ this.inputData = null;
+ }
+
+ @NotNull
+ public String getCmd() {
+ return cmd;
+ }
+
+ @NotNull
+ public String[] getArgs() {
+ return args;
+ }
+
+ @Nullable
+ public Map getRequest() {
+ return request;
+ }
+
+ @Nullable
+ public String getInputData() {
+ return inputData;
+ }
+
+ @Override
+ public int hashCode() {
+ int ret = cmd.hashCode() + Arrays.hashCode(args);
+ if (request != null && ! request.isEmpty()) {
+ ret += request.hashCode();
+ }
+ if (inputData != null && inputData.length() > 0) {
+ ret += inputData.hashCode();
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null) {
+ return false;
+ }
+ if (! (o.getClass().equals(P4Request.class))) {
+ return false;
+ }
+ P4Request that = (P4Request) o;
+ if (request == null || request.isEmpty()) {
+ if (that.request != null && ! that.request.isEmpty()) {
+ return false;
+ }
+ }
+ if (inputData == null || inputData.length() <= 0) {
+ if (that.inputData != null && that.inputData.length() > 0) {
+ return false;
+ }
+ }
+ return cmd.equals(that.cmd) &&
+ Arrays.equals(args, that.args);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder ret = new StringBuilder(cmd);
+ for (String arg : args) {
+ ret.append(' ').append(arg);
+ }
+ if (request != null) {
+ ret.append(' ').append(request);
+ }
+ if (inputData != null) {
+ ret.append(" [").append(inputData).append(']');
+ }
+ return ret.toString();
+ }
+}
diff --git a/idea-test-core/src/main/java/net/groboclown/idea/mock/VFFilePath.java b/idea-test-core/src/main/java/net/groboclown/idea/mock/VFFilePath.java
index 840233be..96dfa60a 100644
--- a/idea-test-core/src/main/java/net/groboclown/idea/mock/VFFilePath.java
+++ b/idea-test-core/src/main/java/net/groboclown/idea/mock/VFFilePath.java
@@ -1,154 +1,154 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.groboclown.idea.mock;
-
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.FilePath;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.nio.charset.Charset;
-
-/**
- * Simulation of a FilePath, for when the API causes an error with using the correct
- * API. Mostly, this is used for lightweight unit tests that don't want to mock the
- * world.
- */
-public class VFFilePath
- implements FilePath {
- private final VirtualFile vf;
-
- public VFFilePath(@NotNull final VirtualFile vf) {
- this.vf = vf;
- }
-
- @Nullable
- @Override
- public VirtualFile getVirtualFile() {
- return vf;
- }
-
- @Nullable
- @Override
- public VirtualFile getVirtualFileParent() {
- return vf.getParent();
- }
-
- @NotNull
- @Override
- public File getIOFile() {
- return new File(vf.getPath());
- }
-
- @NotNull
- @Override
- public String getName() {
- return vf.getName();
- }
-
- @NotNull
- @Override
- public String getPresentableUrl() {
- return getIOFile().toURI().toASCIIString();
- }
-
- @Deprecated
- @Nullable
- @Override
- public Document getDocument() {
- return null;
- }
-
- @NotNull
- @Override
- public Charset getCharset() {
- return Charset.defaultCharset();
- }
-
- @NotNull
- @Override
- public Charset getCharset(@Nullable final Project project) {
- return Charset.defaultCharset();
- }
-
- @NotNull
- @Override
- public FileType getFileType() {
- return MockFileType.MOCK;
- }
-
- @Deprecated
- @Override
- public void refresh() {
-
- }
-
- @Deprecated
- @Override
- public void hardRefresh() {
-
- }
-
- @NotNull
- @Override
- public String getPath() {
- return vf.getPath();
- }
-
- @Override
- public boolean isDirectory() {
- return vf.isDirectory();
- }
-
- @Override
- public boolean isUnder(@NotNull final FilePath filePath, final boolean b) {
- // not implemented here
- return false;
- }
-
- @Nullable
- @Override
- public FilePath getParentPath() {
- if (vf.getParent() == null) {
- return null;
- }
- return new VFFilePath(vf.getParent());
- }
-
- @Override
- public boolean isNonLocal() {
- return false;
- }
-
- @Override
- public int hashCode() {
- return vf.getPath().hashCode() + vf.getName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- }
- if (obj == this) {
- return true;
- }
- return obj instanceof FilePath && vf.equals(((FilePath) obj).getVirtualFile());
- }
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.groboclown.idea.mock;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+/**
+ * Simulation of a FilePath, for when the API causes an error with using the correct
+ * API. Mostly, this is used for lightweight unit tests that don't want to mock the
+ * world.
+ */
+public class VFFilePath
+ implements FilePath {
+ private final VirtualFile vf;
+
+ public VFFilePath(@NotNull final VirtualFile vf) {
+ this.vf = vf;
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getVirtualFile() {
+ return vf;
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getVirtualFileParent() {
+ return vf.getParent();
+ }
+
+ @NotNull
+ @Override
+ public File getIOFile() {
+ return new File(vf.getPath());
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return vf.getName();
+ }
+
+ @NotNull
+ @Override
+ public String getPresentableUrl() {
+ return getIOFile().toURI().toASCIIString();
+ }
+
+ @Deprecated
+ @Nullable
+ @Override
+ public Document getDocument() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Charset getCharset() {
+ return Charset.defaultCharset();
+ }
+
+ @NotNull
+ @Override
+ public Charset getCharset(@Nullable final Project project) {
+ return Charset.defaultCharset();
+ }
+
+ @NotNull
+ @Override
+ public FileType getFileType() {
+ return MockFileType.MOCK;
+ }
+
+ @Deprecated
+ @Override
+ public void refresh() {
+
+ }
+
+ @Deprecated
+ @Override
+ public void hardRefresh() {
+
+ }
+
+ @NotNull
+ @Override
+ public String getPath() {
+ return vf.getPath();
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return vf.isDirectory();
+ }
+
+ @Override
+ public boolean isUnder(@NotNull final FilePath filePath, final boolean b) {
+ // not implemented here
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public FilePath getParentPath() {
+ if (vf.getParent() == null) {
+ return null;
+ }
+ return new VFFilePath(vf.getParent());
+ }
+
+ @Override
+ public boolean isNonLocal() {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return vf.getPath().hashCode() + vf.getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ return obj instanceof FilePath && vf.equals(((FilePath) obj).getVirtualFile());
+ }
+}
diff --git a/p4java/r14-1/src/main/java/com/jcraft/jzlib/ZStreamException.java b/p4java/r14-1/src/main/java/com/jcraft/jzlib/ZStreamException.java
index 424b74b7..308bb8a1 100644
--- a/p4java/r14-1/src/main/java/com/jcraft/jzlib/ZStreamException.java
+++ b/p4java/r14-1/src/main/java/com/jcraft/jzlib/ZStreamException.java
@@ -1,44 +1,44 @@
-/* -*-mode:java; c-basic-offset:2; -*- */
-/*
-Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the distribution.
-
- 3. The names of the authors may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
-INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
-OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * This program is based on zlib-1.1.3, so all credit should go authors
- * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
- * and contributors of zlib.
- */
-
-package com.jcraft.jzlib;
-
-public class ZStreamException extends java.io.IOException {
- public ZStreamException() {
- super();
- }
- public ZStreamException(String s) {
- super(s);
- }
-}
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+public class ZStreamException extends java.io.IOException {
+ public ZStreamException() {
+ super();
+ }
+ public ZStreamException(String s) {
+ super(s);
+ }
+}
diff --git a/p4java/r14-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java b/p4java/r14-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
index 955735f4..75e9be6e 100644
--- a/p4java/r14-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
+++ b/p4java/r14-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
@@ -1,118 +1,118 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
-import com.perforce.p4java.io.apple.AppleFileData;
-import com.perforce.p4java.io.apple.AppleFileDecoder;
-
-/**
- * Helper class for handling Apple files.
- */
-public class AppleFileHelper {
-
- /**
- * Extract the data fork and the resource fork from the Apple file.
- *
- * @param file the Apple file
- */
- public static void extractFile(RpcPerforceFile file) {
- if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
- FileOutputStream fosData = null;
- FileOutputStream fosResource = null;
- try {
- byte[] data = AppleFileHelper.getBytesFromFile(file);
- AppleFileData fileData = new AppleFileData(data);
- AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
- appleFile.extract();
- fosData = new FileOutputStream(file);
- AppleFileData forkData = appleFile.getDataFork();
- if (forkData != AppleFileData.EMPTY_FILE_DATA) {
- fosData.write(forkData.getBytes());
- }
- String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
- RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
- fosResource = new FileOutputStream(targetResourceFile);
- AppleFileData forkResource = appleFile.getResourceFork();
- if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
- fosResource.write(forkResource.getBytes());
- }
- } catch (IOException e) {
- Log.error("Problem handling the Apple file: " + file.getName());
- } catch (FileDecoderException e) {
- Log.error("Problem decoding the Apple file: " + file.getName());
- } finally {
- if (fosData != null) {
- try {
- fosData.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- if (fosResource != null) {
- try {
- fosResource.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- }
- }
- }
-
- /**
- * Gets the bytes from file.
- *
- * @param file
- * the file
- * @return the bytes from file
- * @throws IOException
- * Signals that an I/O exception has occurred.
- */
- public static byte[] getBytesFromFile(File file) throws IOException {
- InputStream is = new FileInputStream(file);
-
- long length = file.length();
- if (length > Integer.MAX_VALUE) {
- // File is too large
- throw new IOException("Apple file too large for decoding.");
- }
-
- byte[] bytes = new byte[(int) length];
- int offset = 0;
- int numRead = 0;
-
- try {
- while (offset < bytes.length
- && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
- offset += numRead;
- }
- // Ensure all the bytes have been read in
- if (offset < bytes.length) {
- throw new IOException(
- "Could not completely read the Apple file "
- + file.getName());
- }
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- // Do nothing
- }
- }
- }
-
- return bytes;
- }
-}
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
+import com.perforce.p4java.io.apple.AppleFileData;
+import com.perforce.p4java.io.apple.AppleFileDecoder;
+
+/**
+ * Helper class for handling Apple files.
+ */
+public class AppleFileHelper {
+
+ /**
+ * Extract the data fork and the resource fork from the Apple file.
+ *
+ * @param file the Apple file
+ */
+ public static void extractFile(RpcPerforceFile file) {
+ if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
+ FileOutputStream fosData = null;
+ FileOutputStream fosResource = null;
+ try {
+ byte[] data = AppleFileHelper.getBytesFromFile(file);
+ AppleFileData fileData = new AppleFileData(data);
+ AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
+ appleFile.extract();
+ fosData = new FileOutputStream(file);
+ AppleFileData forkData = appleFile.getDataFork();
+ if (forkData != AppleFileData.EMPTY_FILE_DATA) {
+ fosData.write(forkData.getBytes());
+ }
+ String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
+ RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
+ fosResource = new FileOutputStream(targetResourceFile);
+ AppleFileData forkResource = appleFile.getResourceFork();
+ if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
+ fosResource.write(forkResource.getBytes());
+ }
+ } catch (IOException e) {
+ Log.error("Problem handling the Apple file: " + file.getName());
+ } catch (FileDecoderException e) {
+ Log.error("Problem decoding the Apple file: " + file.getName());
+ } finally {
+ if (fosData != null) {
+ try {
+ fosData.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ if (fosResource != null) {
+ try {
+ fosResource.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the bytes from file.
+ *
+ * @param file
+ * the file
+ * @return the bytes from file
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+
+ long length = file.length();
+ if (length > Integer.MAX_VALUE) {
+ // File is too large
+ throw new IOException("Apple file too large for decoding.");
+ }
+
+ byte[] bytes = new byte[(int) length];
+ int offset = 0;
+ int numRead = 0;
+
+ try {
+ while (offset < bytes.length
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException(
+ "Could not completely read the Apple file "
+ + file.getName());
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+
+ return bytes;
+ }
+}
diff --git a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
index 5b89f33a..615bfcc9 100644
--- a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
+++ b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
@@ -1,735 +1,735 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This abstract class handles AppleSingle/Double files. It contains a common
- * method to verify the Apple file, and figure out if it is an AppleSingle or
- * AppleDouble formatted file.
- *
- *
- * The AppleSingle format is a representation of Macintosh files as one
- * consecutive stream of bytes. AppleSingle combines the data fork, resource
- * fork and the related Finder meta-file information into a single file.
- *
- *
- * The AppleDouble format stores the data fork, resource fork as two separate
- * files. AppleDouble leaves the data fork in its original format, and the
- * resource fork and Finder information were combined into a second file.
- *
- *
- * Apple defined the magic number for the AppleSingle format as 0x00051600, and
- * the magic number for the AppleDouble format as 0x00051607.
- *
- *
- * AppleSingle file header:
- *
- * Field Length
- * ----- ------
- * Magic number ------- 4 bytes
- * Version number ------ 4 bytes
- * Filler ------------- 16 bytes
- * Number of entries ----- 2 bytes
- *
- * Entry descriptor for each entry:
- * Entry ID ------ 4 bytes
- * Offset -------- 4 bytes
- * Length -------- 4 bytes
- *
- * Apple reserved entry IDs:
- *
- * Data Fork -------- 1 Data fork
- * Resource Fork ----- 2 Resource fork
- * Real Name -------- 3 File's name as created on home file system
- * Comment --------- 4 Standard Macintosh comment
- * Icon, B&W -------- 5 Standard Macintosh black and white icon
- * Icon, Color -------- 6 Macintosh color icon
- * File Dates Info ------8 File creation date, modification date, and so on
- * Finder Info -------- 9 Standard Macintosh Finder information
- * Macintosh File Info ---10 Macintosh file information, attributes, and so on
- * ProDOS File Info -----11 ProDOS file information, attributes, and so on
- * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
- * Short Name --------13 AFP short name
- * AFP File Info ------- 14 AFP file information, attributes, and so on
- * Directory ID --------15 AFP directory ID
- *
- *
- * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
- */
-public abstract class AppleFile {
-
- /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
- protected FileFormat format = FileFormat.UNKNOWN;
-
- /** The raw Apple file. */
- protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 1: Data fork. */
- protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 2: Resource fork. */
- protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 3: File's name as created on home file system. */
- protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 4: Standard Macintosh comment. */
- protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 5: Standard Macintosh black and white icon. */
- protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 6: Macintosh color icon. */
- protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 8: File creation date, modification date, and so on. */
- protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** The file dates info entry. */
- protected FileDatesInfoEntry fileDatesInfoEntry = null;
-
- /** Entry 9: Standard Macintosh Finder information. */
- protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 10: Macintosh file information, attributes, and so on. */
- protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 11: ProDOS file information, attributes, and so on. */
- protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 12: MS-DOS file information, attributes, and so on. */
- protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 13: AFP short name. */
- protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 14: AFP file information, attributes, and so on. */
- protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 15: AFP directory ID. */
- protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
-
- /** The num entries. */
- protected int numEntries = 0;
-
- /**
- * The Apple file format.
- */
- public enum FileFormat {
-
- APPLE_SINGLE,
- APPLE_DOUBLE,
- UNKNOWN;
-
- /**
- * Return a suitable Apple file format as inferred from the passed-in
- * string. Otherwise return the UNKNOWN file format.
- *
- * @param fileFormat
- * the file format
- * @return the FileFormat
- */
- public static FileFormat fromString(String fileFormat) {
- if (fileFormat == null) {
- return null;
- }
-
- try {
- return FileFormat.valueOf(fileFormat.toUpperCase());
- } catch (IllegalArgumentException iae) {
- Log.error("Bad conversion attempt in FileFormat.fromString; string: "
- + fileFormat + "; message: " + iae.getMessage());
- Log.exception(iae);
- return UNKNOWN;
- }
- }
- };
-
- /**
- * This class represents the file dates.
- */
- public class FileDatesInfoEntry {
-
- /** The create time. */
- private int createTime = Integer.MIN_VALUE;
-
- /** The modify time. */
- private int modifyTime = Integer.MIN_VALUE;
-
- /** The backup time. */
- private int backupTime = Integer.MIN_VALUE;
-
- /** The access time. */
- private int accessTime = Integer.MIN_VALUE;
-
- /**
- * Instantiates a new file dates info entry.
- */
- public FileDatesInfoEntry() {
-
- }
-
- /**
- * Gets the creates the time.
- *
- * @return the creates the time
- */
- public int getCreateTime() {
- return createTime;
- }
-
- /**
- * Sets the creates the time.
- *
- * @param createTime
- * the new creates the time
- */
- public void setCreateTime(int createTime) {
- this.createTime = createTime;
- }
-
- /**
- * Gets the modify time.
- *
- * @return the modify time
- */
- public int getModifyTime() {
- return modifyTime;
- }
-
- /**
- * Sets the modify time.
- *
- * @param modifyTime
- * the new modify time
- */
- public void setModifyTime(int modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- /**
- * Gets the backup time.
- *
- * @return the backup time
- */
- public int getBackupTime() {
- return backupTime;
- }
-
- /**
- * Sets the backup time.
- *
- * @param backupTime
- * the new backup time
- */
- public void setBackupTime(int backupTime) {
- this.backupTime = backupTime;
- }
-
- /**
- * Gets the access time.
- *
- * @return the access time
- */
- public int getAccessTime() {
- return accessTime;
- }
-
- /**
- * Sets the access time.
- *
- * @param accessTime
- * the new access time
- */
- public void setAccessTime(int accessTime) {
- this.accessTime = accessTime;
- }
- }
-
- /**
- * Sets the num entries.
- *
- * @param numEntries
- * the new num entries
- */
- public void setNumEntries(int numEntries) {
- this.numEntries = numEntries;
- }
-
- /**
- * Verify the validity of the Apple file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- protected void verify() throws FileDecoderException {
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int position = offset;
- if (length < 26) {
- throw new FileDecoderException("File is too short");
- }
-
- /* Magic number */
- int magic = 0;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
-
- /* Check Apple file format: AppleSingle or AppleDobule */
- if (magic == 0x00051600) {
- this.format = FileFormat.APPLE_SINGLE;
- } else if (magic == 0x00051607) {
- this.format = FileFormat.APPLE_DOUBLE;
- } else {
- throw new FileDecoderException("Invalid Apple file magic number.");
- }
-
- /* Version number */
- int version = 0;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- if (version != 0x00020000) {
- throw new FileDecoderException("Unknown Apple file version");
- }
-
- /* Filler */
- position += 16;
-
- /* Number of entries */
- this.numEntries = 0;
- this.numEntries |= data[(position++)] & 0xFF;
- this.numEntries <<= 8;
- this.numEntries |= data[(position++)] & 0xFF;
- if (length < 26 + 12 * this.numEntries) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
-
- /* Check entries */
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- int contentPosition = 26 + 12 * this.numEntries;
- for (int i = 0; i < this.numEntries; i++) {
- position = 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
- if ((entryOffset < contentPosition)
- || (length < entryOffset + entryLength)) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
- }
- }
-
- /**
- * Extract file dates.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- protected void extractFileDates(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
-
- int position = offset;
-
- int createTime = 0;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- int modifyTime = 0;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- int backupTime = 0;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- int accessTime = 0;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
-
- this.fileDatesInfoEntry = new FileDatesInfoEntry();
- fileDatesInfoEntry.setCreateTime(createTime);
- fileDatesInfoEntry.setModifyTime(modifyTime);
- fileDatesInfoEntry.setBackupTime(backupTime);
- fileDatesInfoEntry.setAccessTime(accessTime);
- }
-
- /**
- * Gets the format.
- *
- * @return the format
- */
- public FileFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the format.
- *
- * @param format
- * the new format
- */
- public void setFormat(FileFormat format) {
- this.format = format;
- }
-
- /**
- * Gets the file data.
- *
- * @return the file data
- */
- public AppleFileData getFileData() {
- return fileData;
- }
-
- /**
- * Sets the file data.
- *
- * @param fileData
- * the new file data
- */
- public void setFileData(AppleFileData fileData) {
- this.fileData = fileData;
- }
-
- /**
- * Gets the data fork.
- *
- * @return the data fork
- */
- public AppleFileData getDataFork() {
- return dataFork;
- }
-
- /**
- * Sets the data fork.
- *
- * @param dataFork
- * the new data fork
- */
- public void setDataFork(AppleFileData dataFork) {
- this.dataFork = dataFork;
- }
-
- /**
- * Gets the resource fork.
- *
- * @return the resource fork
- */
- public AppleFileData getResourceFork() {
- return resourceFork;
- }
-
- /**
- * Sets the resource fork.
- *
- * @param resourceFork
- * the new resource fork
- */
- public void setResourceFork(AppleFileData resourceFork) {
- this.resourceFork = resourceFork;
- }
-
- /**
- * Gets the real name.
- *
- * @return the real name
- */
- public AppleFileData getRealName() {
- return realName;
- }
-
- /**
- * Sets the real name.
- *
- * @param realName
- * the new real name
- */
- public void setRealName(AppleFileData realName) {
- this.realName = realName;
- }
-
- /**
- * Gets the comment.
- *
- * @return the comment
- */
- public AppleFileData getComment() {
- return comment;
- }
-
- /**
- * Sets the comment.
- *
- * @param comment
- * the new comment
- */
- public void setComment(AppleFileData comment) {
- this.comment = comment;
- }
-
- /**
- * Gets the icon bw.
- *
- * @return the icon bw
- */
- public AppleFileData getIconBW() {
- return iconBW;
- }
-
- /**
- * Sets the icon bw.
- *
- * @param iconBW
- * the new icon bw
- */
- public void setIconBW(AppleFileData iconBW) {
- this.iconBW = iconBW;
- }
-
- /**
- * Gets the icon color.
- *
- * @return the icon color
- */
- public AppleFileData getIconColor() {
- return iconColor;
- }
-
- /**
- * Sets the icon color.
- *
- * @param iconColor
- * the new icon color
- */
- public void setIconColor(AppleFileData iconColor) {
- this.iconColor = iconColor;
- }
-
- /**
- * Gets the file dates info.
- *
- * @return the file dates info
- */
- public AppleFileData getFileDatesInfo() {
- return fileDatesInfo;
- }
-
- /**
- * Sets the file dates info.
- *
- * @param fileDatesInfo
- * the new file dates info
- */
- public void setFileDatesInfo(AppleFileData fileDatesInfo) {
- this.fileDatesInfo = fileDatesInfo;
- }
-
- /**
- * Gets the finder info.
- *
- * @return the finder info
- */
- public AppleFileData getFinderInfo() {
- return finderInfo;
- }
-
- /**
- * Sets the finder info.
- *
- * @param finderInfo
- * the new finder info
- */
- public void setFinderInfo(AppleFileData finderInfo) {
- this.finderInfo = finderInfo;
- }
-
- /**
- * Gets the macintosh info.
- *
- * @return the macintosh info
- */
- public AppleFileData getMacintoshInfo() {
- return macintoshInfo;
- }
-
- /**
- * Sets the macintosh info.
- *
- * @param macintoshInfo
- * the new macintosh info
- */
- public void setMacintoshInfo(AppleFileData macintoshInfo) {
- this.macintoshInfo = macintoshInfo;
- }
-
- /**
- * Gets the pro dos file info.
- *
- * @return the pro dos file info
- */
- public AppleFileData getProDOSFileInfo() {
- return proDOSFileInfo;
- }
-
- /**
- * Sets the pro dos file info.
- *
- * @param proDOSFileInfo
- * the new pro dos file info
- */
- public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
- this.proDOSFileInfo = proDOSFileInfo;
- }
-
- /**
- * Gets the ms dos file info.
- *
- * @return the ms dos file info
- */
- public AppleFileData getMsDOSFileInfo() {
- return msDOSFileInfo;
- }
-
- /**
- * Sets the ms dos file info.
- *
- * @param msDOSFileInfo
- * the new ms dos file info
- */
- public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
- this.msDOSFileInfo = msDOSFileInfo;
- }
-
- /**
- * Gets the short name.
- *
- * @return the short name
- */
- public AppleFileData getShortName() {
- return shortName;
- }
-
- /**
- * Sets the short name.
- *
- * @param shortName
- * the new short name
- */
- public void setShortName(AppleFileData shortName) {
- this.shortName = shortName;
- }
-
- /**
- * Gets the afp file info.
- *
- * @return the afp file info
- */
- public AppleFileData getAfpFileInfo() {
- return afpFileInfo;
- }
-
- /**
- * Sets the afp file info.
- *
- * @param afpFileInfo
- * the new afp file info
- */
- public void setAfpFileInfo(AppleFileData afpFileInfo) {
- this.afpFileInfo = afpFileInfo;
- }
-
- /**
- * Gets the directory id.
- *
- * @return the directory id
- */
- public AppleFileData getDirectoryID() {
- return directoryID;
- }
-
- /**
- * Sets the directory id.
- *
- * @param directoryID
- * the new directory id
- */
- public void setDirectoryID(AppleFileData directoryID) {
- this.directoryID = directoryID;
- }
-
- /**
- * Gets the num entries.
- *
- * @return the num entries
- */
- public int getNumEntries() {
- return numEntries;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This abstract class handles AppleSingle/Double files. It contains a common
+ * method to verify the Apple file, and figure out if it is an AppleSingle or
+ * AppleDouble formatted file.
+ *
+ *
+ * The AppleSingle format is a representation of Macintosh files as one
+ * consecutive stream of bytes. AppleSingle combines the data fork, resource
+ * fork and the related Finder meta-file information into a single file.
+ *
+ *
+ * The AppleDouble format stores the data fork, resource fork as two separate
+ * files. AppleDouble leaves the data fork in its original format, and the
+ * resource fork and Finder information were combined into a second file.
+ *
+ *
+ * Apple defined the magic number for the AppleSingle format as 0x00051600, and
+ * the magic number for the AppleDouble format as 0x00051607.
+ *
+ *
+ * AppleSingle file header:
+ *
+ * Field Length
+ * ----- ------
+ * Magic number ------- 4 bytes
+ * Version number ------ 4 bytes
+ * Filler ------------- 16 bytes
+ * Number of entries ----- 2 bytes
+ *
+ * Entry descriptor for each entry:
+ * Entry ID ------ 4 bytes
+ * Offset -------- 4 bytes
+ * Length -------- 4 bytes
+ *
+ * Apple reserved entry IDs:
+ *
+ * Data Fork -------- 1 Data fork
+ * Resource Fork ----- 2 Resource fork
+ * Real Name -------- 3 File's name as created on home file system
+ * Comment --------- 4 Standard Macintosh comment
+ * Icon, B&W -------- 5 Standard Macintosh black and white icon
+ * Icon, Color -------- 6 Macintosh color icon
+ * File Dates Info ------8 File creation date, modification date, and so on
+ * Finder Info -------- 9 Standard Macintosh Finder information
+ * Macintosh File Info ---10 Macintosh file information, attributes, and so on
+ * ProDOS File Info -----11 ProDOS file information, attributes, and so on
+ * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
+ * Short Name --------13 AFP short name
+ * AFP File Info ------- 14 AFP file information, attributes, and so on
+ * Directory ID --------15 AFP directory ID
+ *
+ *
+ * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
+ */
+public abstract class AppleFile {
+
+ /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
+ protected FileFormat format = FileFormat.UNKNOWN;
+
+ /** The raw Apple file. */
+ protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 1: Data fork. */
+ protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 2: Resource fork. */
+ protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 3: File's name as created on home file system. */
+ protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 4: Standard Macintosh comment. */
+ protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 5: Standard Macintosh black and white icon. */
+ protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 6: Macintosh color icon. */
+ protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 8: File creation date, modification date, and so on. */
+ protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The file dates info entry. */
+ protected FileDatesInfoEntry fileDatesInfoEntry = null;
+
+ /** Entry 9: Standard Macintosh Finder information. */
+ protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 10: Macintosh file information, attributes, and so on. */
+ protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 11: ProDOS file information, attributes, and so on. */
+ protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 12: MS-DOS file information, attributes, and so on. */
+ protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 13: AFP short name. */
+ protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 14: AFP file information, attributes, and so on. */
+ protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 15: AFP directory ID. */
+ protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The num entries. */
+ protected int numEntries = 0;
+
+ /**
+ * The Apple file format.
+ */
+ public enum FileFormat {
+
+ APPLE_SINGLE,
+ APPLE_DOUBLE,
+ UNKNOWN;
+
+ /**
+ * Return a suitable Apple file format as inferred from the passed-in
+ * string. Otherwise return the UNKNOWN file format.
+ *
+ * @param fileFormat
+ * the file format
+ * @return the FileFormat
+ */
+ public static FileFormat fromString(String fileFormat) {
+ if (fileFormat == null) {
+ return null;
+ }
+
+ try {
+ return FileFormat.valueOf(fileFormat.toUpperCase());
+ } catch (IllegalArgumentException iae) {
+ Log.error("Bad conversion attempt in FileFormat.fromString; string: "
+ + fileFormat + "; message: " + iae.getMessage());
+ Log.exception(iae);
+ return UNKNOWN;
+ }
+ }
+ };
+
+ /**
+ * This class represents the file dates.
+ */
+ public class FileDatesInfoEntry {
+
+ /** The create time. */
+ private int createTime = Integer.MIN_VALUE;
+
+ /** The modify time. */
+ private int modifyTime = Integer.MIN_VALUE;
+
+ /** The backup time. */
+ private int backupTime = Integer.MIN_VALUE;
+
+ /** The access time. */
+ private int accessTime = Integer.MIN_VALUE;
+
+ /**
+ * Instantiates a new file dates info entry.
+ */
+ public FileDatesInfoEntry() {
+
+ }
+
+ /**
+ * Gets the creates the time.
+ *
+ * @return the creates the time
+ */
+ public int getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * Sets the creates the time.
+ *
+ * @param createTime
+ * the new creates the time
+ */
+ public void setCreateTime(int createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * Gets the modify time.
+ *
+ * @return the modify time
+ */
+ public int getModifyTime() {
+ return modifyTime;
+ }
+
+ /**
+ * Sets the modify time.
+ *
+ * @param modifyTime
+ * the new modify time
+ */
+ public void setModifyTime(int modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ /**
+ * Gets the backup time.
+ *
+ * @return the backup time
+ */
+ public int getBackupTime() {
+ return backupTime;
+ }
+
+ /**
+ * Sets the backup time.
+ *
+ * @param backupTime
+ * the new backup time
+ */
+ public void setBackupTime(int backupTime) {
+ this.backupTime = backupTime;
+ }
+
+ /**
+ * Gets the access time.
+ *
+ * @return the access time
+ */
+ public int getAccessTime() {
+ return accessTime;
+ }
+
+ /**
+ * Sets the access time.
+ *
+ * @param accessTime
+ * the new access time
+ */
+ public void setAccessTime(int accessTime) {
+ this.accessTime = accessTime;
+ }
+ }
+
+ /**
+ * Sets the num entries.
+ *
+ * @param numEntries
+ * the new num entries
+ */
+ public void setNumEntries(int numEntries) {
+ this.numEntries = numEntries;
+ }
+
+ /**
+ * Verify the validity of the Apple file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ protected void verify() throws FileDecoderException {
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int position = offset;
+ if (length < 26) {
+ throw new FileDecoderException("File is too short");
+ }
+
+ /* Magic number */
+ int magic = 0;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+
+ /* Check Apple file format: AppleSingle or AppleDobule */
+ if (magic == 0x00051600) {
+ this.format = FileFormat.APPLE_SINGLE;
+ } else if (magic == 0x00051607) {
+ this.format = FileFormat.APPLE_DOUBLE;
+ } else {
+ throw new FileDecoderException("Invalid Apple file magic number.");
+ }
+
+ /* Version number */
+ int version = 0;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ if (version != 0x00020000) {
+ throw new FileDecoderException("Unknown Apple file version");
+ }
+
+ /* Filler */
+ position += 16;
+
+ /* Number of entries */
+ this.numEntries = 0;
+ this.numEntries |= data[(position++)] & 0xFF;
+ this.numEntries <<= 8;
+ this.numEntries |= data[(position++)] & 0xFF;
+ if (length < 26 + 12 * this.numEntries) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+
+ /* Check entries */
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ int contentPosition = 26 + 12 * this.numEntries;
+ for (int i = 0; i < this.numEntries; i++) {
+ position = 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+ if ((entryOffset < contentPosition)
+ || (length < entryOffset + entryLength)) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+ }
+ }
+
+ /**
+ * Extract file dates.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ protected void extractFileDates(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+
+ int position = offset;
+
+ int createTime = 0;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ int modifyTime = 0;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ int backupTime = 0;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ int accessTime = 0;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+
+ this.fileDatesInfoEntry = new FileDatesInfoEntry();
+ fileDatesInfoEntry.setCreateTime(createTime);
+ fileDatesInfoEntry.setModifyTime(modifyTime);
+ fileDatesInfoEntry.setBackupTime(backupTime);
+ fileDatesInfoEntry.setAccessTime(accessTime);
+ }
+
+ /**
+ * Gets the format.
+ *
+ * @return the format
+ */
+ public FileFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Sets the format.
+ *
+ * @param format
+ * the new format
+ */
+ public void setFormat(FileFormat format) {
+ this.format = format;
+ }
+
+ /**
+ * Gets the file data.
+ *
+ * @return the file data
+ */
+ public AppleFileData getFileData() {
+ return fileData;
+ }
+
+ /**
+ * Sets the file data.
+ *
+ * @param fileData
+ * the new file data
+ */
+ public void setFileData(AppleFileData fileData) {
+ this.fileData = fileData;
+ }
+
+ /**
+ * Gets the data fork.
+ *
+ * @return the data fork
+ */
+ public AppleFileData getDataFork() {
+ return dataFork;
+ }
+
+ /**
+ * Sets the data fork.
+ *
+ * @param dataFork
+ * the new data fork
+ */
+ public void setDataFork(AppleFileData dataFork) {
+ this.dataFork = dataFork;
+ }
+
+ /**
+ * Gets the resource fork.
+ *
+ * @return the resource fork
+ */
+ public AppleFileData getResourceFork() {
+ return resourceFork;
+ }
+
+ /**
+ * Sets the resource fork.
+ *
+ * @param resourceFork
+ * the new resource fork
+ */
+ public void setResourceFork(AppleFileData resourceFork) {
+ this.resourceFork = resourceFork;
+ }
+
+ /**
+ * Gets the real name.
+ *
+ * @return the real name
+ */
+ public AppleFileData getRealName() {
+ return realName;
+ }
+
+ /**
+ * Sets the real name.
+ *
+ * @param realName
+ * the new real name
+ */
+ public void setRealName(AppleFileData realName) {
+ this.realName = realName;
+ }
+
+ /**
+ * Gets the comment.
+ *
+ * @return the comment
+ */
+ public AppleFileData getComment() {
+ return comment;
+ }
+
+ /**
+ * Sets the comment.
+ *
+ * @param comment
+ * the new comment
+ */
+ public void setComment(AppleFileData comment) {
+ this.comment = comment;
+ }
+
+ /**
+ * Gets the icon bw.
+ *
+ * @return the icon bw
+ */
+ public AppleFileData getIconBW() {
+ return iconBW;
+ }
+
+ /**
+ * Sets the icon bw.
+ *
+ * @param iconBW
+ * the new icon bw
+ */
+ public void setIconBW(AppleFileData iconBW) {
+ this.iconBW = iconBW;
+ }
+
+ /**
+ * Gets the icon color.
+ *
+ * @return the icon color
+ */
+ public AppleFileData getIconColor() {
+ return iconColor;
+ }
+
+ /**
+ * Sets the icon color.
+ *
+ * @param iconColor
+ * the new icon color
+ */
+ public void setIconColor(AppleFileData iconColor) {
+ this.iconColor = iconColor;
+ }
+
+ /**
+ * Gets the file dates info.
+ *
+ * @return the file dates info
+ */
+ public AppleFileData getFileDatesInfo() {
+ return fileDatesInfo;
+ }
+
+ /**
+ * Sets the file dates info.
+ *
+ * @param fileDatesInfo
+ * the new file dates info
+ */
+ public void setFileDatesInfo(AppleFileData fileDatesInfo) {
+ this.fileDatesInfo = fileDatesInfo;
+ }
+
+ /**
+ * Gets the finder info.
+ *
+ * @return the finder info
+ */
+ public AppleFileData getFinderInfo() {
+ return finderInfo;
+ }
+
+ /**
+ * Sets the finder info.
+ *
+ * @param finderInfo
+ * the new finder info
+ */
+ public void setFinderInfo(AppleFileData finderInfo) {
+ this.finderInfo = finderInfo;
+ }
+
+ /**
+ * Gets the macintosh info.
+ *
+ * @return the macintosh info
+ */
+ public AppleFileData getMacintoshInfo() {
+ return macintoshInfo;
+ }
+
+ /**
+ * Sets the macintosh info.
+ *
+ * @param macintoshInfo
+ * the new macintosh info
+ */
+ public void setMacintoshInfo(AppleFileData macintoshInfo) {
+ this.macintoshInfo = macintoshInfo;
+ }
+
+ /**
+ * Gets the pro dos file info.
+ *
+ * @return the pro dos file info
+ */
+ public AppleFileData getProDOSFileInfo() {
+ return proDOSFileInfo;
+ }
+
+ /**
+ * Sets the pro dos file info.
+ *
+ * @param proDOSFileInfo
+ * the new pro dos file info
+ */
+ public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
+ this.proDOSFileInfo = proDOSFileInfo;
+ }
+
+ /**
+ * Gets the ms dos file info.
+ *
+ * @return the ms dos file info
+ */
+ public AppleFileData getMsDOSFileInfo() {
+ return msDOSFileInfo;
+ }
+
+ /**
+ * Sets the ms dos file info.
+ *
+ * @param msDOSFileInfo
+ * the new ms dos file info
+ */
+ public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
+ this.msDOSFileInfo = msDOSFileInfo;
+ }
+
+ /**
+ * Gets the short name.
+ *
+ * @return the short name
+ */
+ public AppleFileData getShortName() {
+ return shortName;
+ }
+
+ /**
+ * Sets the short name.
+ *
+ * @param shortName
+ * the new short name
+ */
+ public void setShortName(AppleFileData shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * Gets the afp file info.
+ *
+ * @return the afp file info
+ */
+ public AppleFileData getAfpFileInfo() {
+ return afpFileInfo;
+ }
+
+ /**
+ * Sets the afp file info.
+ *
+ * @param afpFileInfo
+ * the new afp file info
+ */
+ public void setAfpFileInfo(AppleFileData afpFileInfo) {
+ this.afpFileInfo = afpFileInfo;
+ }
+
+ /**
+ * Gets the directory id.
+ *
+ * @return the directory id
+ */
+ public AppleFileData getDirectoryID() {
+ return directoryID;
+ }
+
+ /**
+ * Sets the directory id.
+ *
+ * @param directoryID
+ * the new directory id
+ */
+ public void setDirectoryID(AppleFileData directoryID) {
+ this.directoryID = directoryID;
+ }
+
+ /**
+ * Gets the num entries.
+ *
+ * @return the num entries
+ */
+ public int getNumEntries() {
+ return numEntries;
+ }
}
\ No newline at end of file
diff --git a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
index f28c979a..d89471e2 100644
--- a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
+++ b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
@@ -1,91 +1,91 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-/**
- * This class is for representing the AppleSingle/Double file or its file forks
- * (data fork and resource fork) and the related Finder meta-file information.
- */
-public final class AppleFileData {
-
- public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
- private byte[] data;
- private int offset;
- private int length;
-
- /**
- * Instantiates a new apple file data.
- */
- public AppleFileData() {
- this.data = new byte[0];
- this.offset = 0;
- this.length = 0;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- */
- public AppleFileData(byte[] data) {
- this.data = data;
- this.offset = 0;
- this.length = data.length;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- public AppleFileData(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- /**
- * Gets the bytes.
- *
- * @return the bytes
- */
- public byte[] getBytes() {
- byte[] data = new byte[this.length];
- System.arraycopy(this.data, this.offset, data, 0, this.length);
- return data;
- }
-
- /**
- * Gets the data.
- *
- * @return the data
- */
- public byte[] getData() {
- return this.data;
- }
-
- /**
- * Gets the offset.
- *
- * @return the offset
- */
- public int getOffset() {
- return this.offset;
- }
-
- /**
- * Gets the length.
- *
- * @return the length
- */
- public int getLength() {
- return this.length;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+/**
+ * This class is for representing the AppleSingle/Double file or its file forks
+ * (data fork and resource fork) and the related Finder meta-file information.
+ */
+public final class AppleFileData {
+
+ public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
+ private byte[] data;
+ private int offset;
+ private int length;
+
+ /**
+ * Instantiates a new apple file data.
+ */
+ public AppleFileData() {
+ this.data = new byte[0];
+ this.offset = 0;
+ this.length = 0;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ */
+ public AppleFileData(byte[] data) {
+ this.data = data;
+ this.offset = 0;
+ this.length = data.length;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ public AppleFileData(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the bytes.
+ *
+ * @return the bytes
+ */
+ public byte[] getBytes() {
+ byte[] data = new byte[this.length];
+ System.arraycopy(this.data, this.offset, data, 0, this.length);
+ return data;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * Gets the offset.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ /**
+ * Gets the length.
+ *
+ * @return the length
+ */
+ public int getLength() {
+ return this.length;
+ }
}
\ No newline at end of file
diff --git a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
index 3248f85d..aa7b0363 100644
--- a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
+++ b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
@@ -1,143 +1,143 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This class handles the extraction of the data fork, resource fork and other
- * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
- * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
- * file type is a compressed AppleDouble (Mac resource fork) file.
- */
-public class AppleFileDecoder extends AppleFile {
-
- /**
- * Instantiates a new apple file decoder.
- *
- * @param fileData
- * the file data
- */
- public AppleFileDecoder(AppleFileData fileData) {
- if (fileData != null) {
- this.fileData = fileData;
- }
- }
-
- /**
- * Extract the data fork, resource fork and other entries from the Apple
- * file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- public void extract() throws FileDecoderException {
- // Verify the validity of the Apple file
- verify();
-
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int contentPosition = 0;
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- for (int i = 0; i < this.numEntries; i++) {
- contentPosition = offset + 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
-
- switch (entryId) {
- case 1:
- this.dataFork = new AppleFileData(data, offset + entryOffset,
- entryLength);
- break;
- case 2:
- this.resourceFork = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 3:
- this.realName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 4:
- this.comment = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 5:
- this.iconBW = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 6:
- this.iconColor = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 8:
- this.fileDatesInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- extractFileDates(data, offset + entryOffset, entryLength);
- break;
- case 9:
- this.finderInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 10:
- this.macintoshInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 11:
- this.proDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 12:
- this.msDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 13:
- this.shortName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 14:
- this.afpFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 15:
- this.directoryID = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- default:
- Log.warn("Apple file entry ID: " + entryId + " is not handled.");
-
- }
- }
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This class handles the extraction of the data fork, resource fork and other
+ * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
+ * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
+ * file type is a compressed AppleDouble (Mac resource fork) file.
+ */
+public class AppleFileDecoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @param fileData
+ * the file data
+ */
+ public AppleFileDecoder(AppleFileData fileData) {
+ if (fileData != null) {
+ this.fileData = fileData;
+ }
+ }
+
+ /**
+ * Extract the data fork, resource fork and other entries from the Apple
+ * file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ public void extract() throws FileDecoderException {
+ // Verify the validity of the Apple file
+ verify();
+
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int contentPosition = 0;
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ for (int i = 0; i < this.numEntries; i++) {
+ contentPosition = offset + 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+
+ switch (entryId) {
+ case 1:
+ this.dataFork = new AppleFileData(data, offset + entryOffset,
+ entryLength);
+ break;
+ case 2:
+ this.resourceFork = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 3:
+ this.realName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 4:
+ this.comment = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 5:
+ this.iconBW = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 6:
+ this.iconColor = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 8:
+ this.fileDatesInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ extractFileDates(data, offset + entryOffset, entryLength);
+ break;
+ case 9:
+ this.finderInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 10:
+ this.macintoshInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 11:
+ this.proDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 12:
+ this.msDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 13:
+ this.shortName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 14:
+ this.afpFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 15:
+ this.directoryID = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ default:
+ Log.warn("Apple file entry ID: " + entryId + " is not handled.");
+
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
index 7c5d0a04..abdfed59 100644
--- a/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
+++ b/p4java/r14-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
@@ -1,300 +1,300 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.exception.FileEncoderException;
-
-/**
- * This class handles the combination of the data fork, resource fork and other
- * entries into an AppleSingle/Double file.
- *
+ *
+ * Note that if it is an AppleDouble, the data fork is a separate file external
+ * to this file.
+ */
+public class AppleFileEncoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @throws FileEncoderException
+ */
+ public AppleFileEncoder(FileFormat fileFormat) throws FileEncoderException {
+ if (fileFormat == null) {
+ throw new FileEncoderException("Null file format passed to the AppleFileEncoder constructor.");
+ }
+ if (fileFormat == FileFormat.UNKNOWN) {
+ throw new FileEncoderException("Unknown file format passed to the AppleFileEncoder constructor.");
+ }
+ }
+
+ /**
+ * Combine the data fork, resource fork and other entries into an
+ * AppleSingle/Double file.
+ *
+ * @throws FileEncoderException
+ * the file encoder exception
+ */
+ @SuppressWarnings("unused")
+ public void combine() throws FileEncoderException {
+
+ boolean isAppleSingle = (this.format == FileFormat.APPLE_SINGLE);
+ boolean isAppleDouble = (this.format == FileFormat.APPLE_DOUBLE);
+
+ boolean hasDataFork = (this.dataFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasResourceFork = (this.resourceFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasRealName = (this.realName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasComment = (this.comment != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconBW = (this.iconBW != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconColor = (this.iconColor != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasFileDatesInfo = (this.fileDatesInfoEntry != null);
+ boolean hasFinderInfo = (this.finderInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMacintoshInfo = (this.macintoshInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasProDOSFileInfo = (this.proDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMsDOSFileInfo = (this.msDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasShortName = (this.shortName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasAfpFileInfo = (this.afpFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasDirectoryID = (this.directoryID != AppleFileData.EMPTY_FILE_DATA);
+
+ this.fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ int length = 90 + this.realName.getLength()
+ + this.resourceFork.getLength();
+
+ /* AppleSingle includes the data fork */
+ if (isAppleSingle) {
+ length += this.dataFork.getLength();
+ }
+
+ byte[] data = new byte[length];
+ int position = 0;
+
+ /* Magic number for AppleSingle or AppleDouble */
+ if (isAppleDouble) {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 0;
+ } else {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 7;
+ }
+
+ /* Version number */
+ data[(position++)] = 0;
+ data[(position++)] = 2;
+ data[(position++)] = 0;
+ data[(position++)] = 0;
+
+ /* Filler */
+
+ for (int k = 0; k < 16; k++) {
+ data[(position++)] = 0;
+ }
+
+ /* Number of entries */
+ this.numEntries = 0;
+ if (hasRealName) {
+ this.numEntries += 1;
+ }
+ if (hasFileDatesInfo) {
+ this.numEntries += 1;
+ }
+ if (hasResourceFork) {
+ this.numEntries += 1;
+ }
+ if ((hasDataFork) && (isAppleSingle)) {
+ this.numEntries += 1;
+ }
+ data[(position++)] = ((byte) (this.numEntries >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.numEntries & 0xFF));
+
+ /* Header information for the entries */
+
+ /* Real name entry header */
+ int realNamePosition = 0;
+ if (hasRealName) {
+ int realNameEntryId = 3;
+ int realNameEntryOffset = 0;
+ int realNameEntryLength = this.realName.getLength();
+ data[(position++)] = ((byte) (realNameEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 0 & 0xFF));
+ realNamePosition = position;
+ data[(position++)] = ((byte) (realNameEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 0 & 0xFF));
+ }
+
+ /* File dates info entry header */
+ int fileDatesInfoPosition = 0;
+ if (hasFileDatesInfo) {
+ int fileDatesInfoEntryId = 8;
+ int fileDatesInfoEntryOffset = 0;
+ int fileDatesInfoEntryLength = 16;
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 0 & 0xFF));
+ fileDatesInfoPosition = position;
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 0 & 0xFF));
+ }
+
+ /* Resource fork entry header */
+ int resourceForkPosition = 0;
+ if (hasResourceFork) {
+ int resourceForkEntryId = 2;
+ int resourceForkEntryOffset = 0;
+ int resourceFokrEntryLength = this.resourceFork.getLength();
+ data[(position++)] = ((byte) (resourceForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 0 & 0xFF));
+ resourceForkPosition = position;
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 0 & 0xFF));
+ }
+
+ /* Data fork entry header */
+ int dataForkPosition = 0;
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkEntryId = 1;
+ int dataForkEntryOffset = 0;
+ int dataForkEntryLength = this.dataFork.getLength();
+ data[(position++)] = ((byte) (dataForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 0 & 0xFF));
+ dataForkPosition = position;
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 0 & 0xFF));
+ }
+
+ /* Content for the entries */
+
+ /* Real name content */
+ if (hasRealName) {
+ int realNamePositionCurrent = position;
+ position = realNamePosition;
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 0 & 0xFF));
+ position = realNamePositionCurrent;
+ byte[] realNameData = this.realName.getData();
+ int realNameOffset = this.realName.getOffset();
+ int realNameLength = this.realName.getLength();
+ System.arraycopy(realNameData, realNameOffset, data, position,
+ realNameLength);
+ position += realNameLength;
+ }
+
+ /* File dates info content */
+ if (hasFileDatesInfo) {
+ int fileDatesInfoPositionCurrent = position;
+ position = fileDatesInfoPosition;
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 0 & 0xFF));
+ position = fileDatesInfoPositionCurrent;
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 0 & 0xFF));
+ }
+
+ /* Resource fork content */
+ if (hasResourceFork) {
+ int resourceForkPositionCurrent = position;
+ position = resourceForkPosition;
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 0 & 0xFF));
+ position = resourceForkPositionCurrent;
+ byte[] resourceForkData = this.resourceFork.getData();
+ int resourceForkOffset = this.resourceFork.getOffset();
+ int resourceForkLength = this.resourceFork.getLength();
+ System.arraycopy(resourceForkData, resourceForkOffset, data,
+ position, resourceForkLength);
+ position += resourceForkLength;
+ }
+
+ /* Data fork content */
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkPosition2 = position;
+ position = dataForkPosition;
+ data[(position++)] = ((byte) (dataForkPosition2 >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 0 & 0xFF));
+ position = dataForkPosition2;
+ byte[] dataForkData = this.dataFork.getData();
+ int dataForkOffset = this.dataFork.getOffset();
+ int dataForkLength = this.dataFork.getLength();
+ System.arraycopy(dataForkData, dataForkOffset, data, position,
+ dataForkLength);
+ position += dataForkLength;
+ }
+
+ /* Create the Apple file data */
+ this.fileData = new AppleFileData(data, 0, position);
+ }
}
\ No newline at end of file
diff --git a/p4java/r17-2/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java b/p4java/r17-2/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
index 955735f4..75e9be6e 100644
--- a/p4java/r17-2/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
+++ b/p4java/r17-2/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
@@ -1,118 +1,118 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
-import com.perforce.p4java.io.apple.AppleFileData;
-import com.perforce.p4java.io.apple.AppleFileDecoder;
-
-/**
- * Helper class for handling Apple files.
- */
-public class AppleFileHelper {
-
- /**
- * Extract the data fork and the resource fork from the Apple file.
- *
- * @param file the Apple file
- */
- public static void extractFile(RpcPerforceFile file) {
- if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
- FileOutputStream fosData = null;
- FileOutputStream fosResource = null;
- try {
- byte[] data = AppleFileHelper.getBytesFromFile(file);
- AppleFileData fileData = new AppleFileData(data);
- AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
- appleFile.extract();
- fosData = new FileOutputStream(file);
- AppleFileData forkData = appleFile.getDataFork();
- if (forkData != AppleFileData.EMPTY_FILE_DATA) {
- fosData.write(forkData.getBytes());
- }
- String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
- RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
- fosResource = new FileOutputStream(targetResourceFile);
- AppleFileData forkResource = appleFile.getResourceFork();
- if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
- fosResource.write(forkResource.getBytes());
- }
- } catch (IOException e) {
- Log.error("Problem handling the Apple file: " + file.getName());
- } catch (FileDecoderException e) {
- Log.error("Problem decoding the Apple file: " + file.getName());
- } finally {
- if (fosData != null) {
- try {
- fosData.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- if (fosResource != null) {
- try {
- fosResource.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- }
- }
- }
-
- /**
- * Gets the bytes from file.
- *
- * @param file
- * the file
- * @return the bytes from file
- * @throws IOException
- * Signals that an I/O exception has occurred.
- */
- public static byte[] getBytesFromFile(File file) throws IOException {
- InputStream is = new FileInputStream(file);
-
- long length = file.length();
- if (length > Integer.MAX_VALUE) {
- // File is too large
- throw new IOException("Apple file too large for decoding.");
- }
-
- byte[] bytes = new byte[(int) length];
- int offset = 0;
- int numRead = 0;
-
- try {
- while (offset < bytes.length
- && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
- offset += numRead;
- }
- // Ensure all the bytes have been read in
- if (offset < bytes.length) {
- throw new IOException(
- "Could not completely read the Apple file "
- + file.getName());
- }
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- // Do nothing
- }
- }
- }
-
- return bytes;
- }
-}
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
+import com.perforce.p4java.io.apple.AppleFileData;
+import com.perforce.p4java.io.apple.AppleFileDecoder;
+
+/**
+ * Helper class for handling Apple files.
+ */
+public class AppleFileHelper {
+
+ /**
+ * Extract the data fork and the resource fork from the Apple file.
+ *
+ * @param file the Apple file
+ */
+ public static void extractFile(RpcPerforceFile file) {
+ if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
+ FileOutputStream fosData = null;
+ FileOutputStream fosResource = null;
+ try {
+ byte[] data = AppleFileHelper.getBytesFromFile(file);
+ AppleFileData fileData = new AppleFileData(data);
+ AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
+ appleFile.extract();
+ fosData = new FileOutputStream(file);
+ AppleFileData forkData = appleFile.getDataFork();
+ if (forkData != AppleFileData.EMPTY_FILE_DATA) {
+ fosData.write(forkData.getBytes());
+ }
+ String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
+ RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
+ fosResource = new FileOutputStream(targetResourceFile);
+ AppleFileData forkResource = appleFile.getResourceFork();
+ if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
+ fosResource.write(forkResource.getBytes());
+ }
+ } catch (IOException e) {
+ Log.error("Problem handling the Apple file: " + file.getName());
+ } catch (FileDecoderException e) {
+ Log.error("Problem decoding the Apple file: " + file.getName());
+ } finally {
+ if (fosData != null) {
+ try {
+ fosData.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ if (fosResource != null) {
+ try {
+ fosResource.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the bytes from file.
+ *
+ * @param file
+ * the file
+ * @return the bytes from file
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+
+ long length = file.length();
+ if (length > Integer.MAX_VALUE) {
+ // File is too large
+ throw new IOException("Apple file too large for decoding.");
+ }
+
+ byte[] bytes = new byte[(int) length];
+ int offset = 0;
+ int numRead = 0;
+
+ try {
+ while (offset < bytes.length
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException(
+ "Could not completely read the Apple file "
+ + file.getName());
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+
+ return bytes;
+ }
+}
diff --git a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFile.java b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
index 5b89f33a..615bfcc9 100644
--- a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
+++ b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
@@ -1,735 +1,735 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This abstract class handles AppleSingle/Double files. It contains a common
- * method to verify the Apple file, and figure out if it is an AppleSingle or
- * AppleDouble formatted file.
- *
- *
- * The AppleSingle format is a representation of Macintosh files as one
- * consecutive stream of bytes. AppleSingle combines the data fork, resource
- * fork and the related Finder meta-file information into a single file.
- *
- *
- * The AppleDouble format stores the data fork, resource fork as two separate
- * files. AppleDouble leaves the data fork in its original format, and the
- * resource fork and Finder information were combined into a second file.
- *
- *
- * Apple defined the magic number for the AppleSingle format as 0x00051600, and
- * the magic number for the AppleDouble format as 0x00051607.
- *
- *
- * AppleSingle file header:
- *
- * Field Length
- * ----- ------
- * Magic number ------- 4 bytes
- * Version number ------ 4 bytes
- * Filler ------------- 16 bytes
- * Number of entries ----- 2 bytes
- *
- * Entry descriptor for each entry:
- * Entry ID ------ 4 bytes
- * Offset -------- 4 bytes
- * Length -------- 4 bytes
- *
- * Apple reserved entry IDs:
- *
- * Data Fork -------- 1 Data fork
- * Resource Fork ----- 2 Resource fork
- * Real Name -------- 3 File's name as created on home file system
- * Comment --------- 4 Standard Macintosh comment
- * Icon, B&W -------- 5 Standard Macintosh black and white icon
- * Icon, Color -------- 6 Macintosh color icon
- * File Dates Info ------8 File creation date, modification date, and so on
- * Finder Info -------- 9 Standard Macintosh Finder information
- * Macintosh File Info ---10 Macintosh file information, attributes, and so on
- * ProDOS File Info -----11 ProDOS file information, attributes, and so on
- * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
- * Short Name --------13 AFP short name
- * AFP File Info ------- 14 AFP file information, attributes, and so on
- * Directory ID --------15 AFP directory ID
- *
- *
- * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
- */
-public abstract class AppleFile {
-
- /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
- protected FileFormat format = FileFormat.UNKNOWN;
-
- /** The raw Apple file. */
- protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 1: Data fork. */
- protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 2: Resource fork. */
- protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 3: File's name as created on home file system. */
- protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 4: Standard Macintosh comment. */
- protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 5: Standard Macintosh black and white icon. */
- protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 6: Macintosh color icon. */
- protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 8: File creation date, modification date, and so on. */
- protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** The file dates info entry. */
- protected FileDatesInfoEntry fileDatesInfoEntry = null;
-
- /** Entry 9: Standard Macintosh Finder information. */
- protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 10: Macintosh file information, attributes, and so on. */
- protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 11: ProDOS file information, attributes, and so on. */
- protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 12: MS-DOS file information, attributes, and so on. */
- protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 13: AFP short name. */
- protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 14: AFP file information, attributes, and so on. */
- protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 15: AFP directory ID. */
- protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
-
- /** The num entries. */
- protected int numEntries = 0;
-
- /**
- * The Apple file format.
- */
- public enum FileFormat {
-
- APPLE_SINGLE,
- APPLE_DOUBLE,
- UNKNOWN;
-
- /**
- * Return a suitable Apple file format as inferred from the passed-in
- * string. Otherwise return the UNKNOWN file format.
- *
- * @param fileFormat
- * the file format
- * @return the FileFormat
- */
- public static FileFormat fromString(String fileFormat) {
- if (fileFormat == null) {
- return null;
- }
-
- try {
- return FileFormat.valueOf(fileFormat.toUpperCase());
- } catch (IllegalArgumentException iae) {
- Log.error("Bad conversion attempt in FileFormat.fromString; string: "
- + fileFormat + "; message: " + iae.getMessage());
- Log.exception(iae);
- return UNKNOWN;
- }
- }
- };
-
- /**
- * This class represents the file dates.
- */
- public class FileDatesInfoEntry {
-
- /** The create time. */
- private int createTime = Integer.MIN_VALUE;
-
- /** The modify time. */
- private int modifyTime = Integer.MIN_VALUE;
-
- /** The backup time. */
- private int backupTime = Integer.MIN_VALUE;
-
- /** The access time. */
- private int accessTime = Integer.MIN_VALUE;
-
- /**
- * Instantiates a new file dates info entry.
- */
- public FileDatesInfoEntry() {
-
- }
-
- /**
- * Gets the creates the time.
- *
- * @return the creates the time
- */
- public int getCreateTime() {
- return createTime;
- }
-
- /**
- * Sets the creates the time.
- *
- * @param createTime
- * the new creates the time
- */
- public void setCreateTime(int createTime) {
- this.createTime = createTime;
- }
-
- /**
- * Gets the modify time.
- *
- * @return the modify time
- */
- public int getModifyTime() {
- return modifyTime;
- }
-
- /**
- * Sets the modify time.
- *
- * @param modifyTime
- * the new modify time
- */
- public void setModifyTime(int modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- /**
- * Gets the backup time.
- *
- * @return the backup time
- */
- public int getBackupTime() {
- return backupTime;
- }
-
- /**
- * Sets the backup time.
- *
- * @param backupTime
- * the new backup time
- */
- public void setBackupTime(int backupTime) {
- this.backupTime = backupTime;
- }
-
- /**
- * Gets the access time.
- *
- * @return the access time
- */
- public int getAccessTime() {
- return accessTime;
- }
-
- /**
- * Sets the access time.
- *
- * @param accessTime
- * the new access time
- */
- public void setAccessTime(int accessTime) {
- this.accessTime = accessTime;
- }
- }
-
- /**
- * Sets the num entries.
- *
- * @param numEntries
- * the new num entries
- */
- public void setNumEntries(int numEntries) {
- this.numEntries = numEntries;
- }
-
- /**
- * Verify the validity of the Apple file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- protected void verify() throws FileDecoderException {
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int position = offset;
- if (length < 26) {
- throw new FileDecoderException("File is too short");
- }
-
- /* Magic number */
- int magic = 0;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
-
- /* Check Apple file format: AppleSingle or AppleDobule */
- if (magic == 0x00051600) {
- this.format = FileFormat.APPLE_SINGLE;
- } else if (magic == 0x00051607) {
- this.format = FileFormat.APPLE_DOUBLE;
- } else {
- throw new FileDecoderException("Invalid Apple file magic number.");
- }
-
- /* Version number */
- int version = 0;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- if (version != 0x00020000) {
- throw new FileDecoderException("Unknown Apple file version");
- }
-
- /* Filler */
- position += 16;
-
- /* Number of entries */
- this.numEntries = 0;
- this.numEntries |= data[(position++)] & 0xFF;
- this.numEntries <<= 8;
- this.numEntries |= data[(position++)] & 0xFF;
- if (length < 26 + 12 * this.numEntries) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
-
- /* Check entries */
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- int contentPosition = 26 + 12 * this.numEntries;
- for (int i = 0; i < this.numEntries; i++) {
- position = 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
- if ((entryOffset < contentPosition)
- || (length < entryOffset + entryLength)) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
- }
- }
-
- /**
- * Extract file dates.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- protected void extractFileDates(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
-
- int position = offset;
-
- int createTime = 0;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- int modifyTime = 0;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- int backupTime = 0;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- int accessTime = 0;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
-
- this.fileDatesInfoEntry = new FileDatesInfoEntry();
- fileDatesInfoEntry.setCreateTime(createTime);
- fileDatesInfoEntry.setModifyTime(modifyTime);
- fileDatesInfoEntry.setBackupTime(backupTime);
- fileDatesInfoEntry.setAccessTime(accessTime);
- }
-
- /**
- * Gets the format.
- *
- * @return the format
- */
- public FileFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the format.
- *
- * @param format
- * the new format
- */
- public void setFormat(FileFormat format) {
- this.format = format;
- }
-
- /**
- * Gets the file data.
- *
- * @return the file data
- */
- public AppleFileData getFileData() {
- return fileData;
- }
-
- /**
- * Sets the file data.
- *
- * @param fileData
- * the new file data
- */
- public void setFileData(AppleFileData fileData) {
- this.fileData = fileData;
- }
-
- /**
- * Gets the data fork.
- *
- * @return the data fork
- */
- public AppleFileData getDataFork() {
- return dataFork;
- }
-
- /**
- * Sets the data fork.
- *
- * @param dataFork
- * the new data fork
- */
- public void setDataFork(AppleFileData dataFork) {
- this.dataFork = dataFork;
- }
-
- /**
- * Gets the resource fork.
- *
- * @return the resource fork
- */
- public AppleFileData getResourceFork() {
- return resourceFork;
- }
-
- /**
- * Sets the resource fork.
- *
- * @param resourceFork
- * the new resource fork
- */
- public void setResourceFork(AppleFileData resourceFork) {
- this.resourceFork = resourceFork;
- }
-
- /**
- * Gets the real name.
- *
- * @return the real name
- */
- public AppleFileData getRealName() {
- return realName;
- }
-
- /**
- * Sets the real name.
- *
- * @param realName
- * the new real name
- */
- public void setRealName(AppleFileData realName) {
- this.realName = realName;
- }
-
- /**
- * Gets the comment.
- *
- * @return the comment
- */
- public AppleFileData getComment() {
- return comment;
- }
-
- /**
- * Sets the comment.
- *
- * @param comment
- * the new comment
- */
- public void setComment(AppleFileData comment) {
- this.comment = comment;
- }
-
- /**
- * Gets the icon bw.
- *
- * @return the icon bw
- */
- public AppleFileData getIconBW() {
- return iconBW;
- }
-
- /**
- * Sets the icon bw.
- *
- * @param iconBW
- * the new icon bw
- */
- public void setIconBW(AppleFileData iconBW) {
- this.iconBW = iconBW;
- }
-
- /**
- * Gets the icon color.
- *
- * @return the icon color
- */
- public AppleFileData getIconColor() {
- return iconColor;
- }
-
- /**
- * Sets the icon color.
- *
- * @param iconColor
- * the new icon color
- */
- public void setIconColor(AppleFileData iconColor) {
- this.iconColor = iconColor;
- }
-
- /**
- * Gets the file dates info.
- *
- * @return the file dates info
- */
- public AppleFileData getFileDatesInfo() {
- return fileDatesInfo;
- }
-
- /**
- * Sets the file dates info.
- *
- * @param fileDatesInfo
- * the new file dates info
- */
- public void setFileDatesInfo(AppleFileData fileDatesInfo) {
- this.fileDatesInfo = fileDatesInfo;
- }
-
- /**
- * Gets the finder info.
- *
- * @return the finder info
- */
- public AppleFileData getFinderInfo() {
- return finderInfo;
- }
-
- /**
- * Sets the finder info.
- *
- * @param finderInfo
- * the new finder info
- */
- public void setFinderInfo(AppleFileData finderInfo) {
- this.finderInfo = finderInfo;
- }
-
- /**
- * Gets the macintosh info.
- *
- * @return the macintosh info
- */
- public AppleFileData getMacintoshInfo() {
- return macintoshInfo;
- }
-
- /**
- * Sets the macintosh info.
- *
- * @param macintoshInfo
- * the new macintosh info
- */
- public void setMacintoshInfo(AppleFileData macintoshInfo) {
- this.macintoshInfo = macintoshInfo;
- }
-
- /**
- * Gets the pro dos file info.
- *
- * @return the pro dos file info
- */
- public AppleFileData getProDOSFileInfo() {
- return proDOSFileInfo;
- }
-
- /**
- * Sets the pro dos file info.
- *
- * @param proDOSFileInfo
- * the new pro dos file info
- */
- public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
- this.proDOSFileInfo = proDOSFileInfo;
- }
-
- /**
- * Gets the ms dos file info.
- *
- * @return the ms dos file info
- */
- public AppleFileData getMsDOSFileInfo() {
- return msDOSFileInfo;
- }
-
- /**
- * Sets the ms dos file info.
- *
- * @param msDOSFileInfo
- * the new ms dos file info
- */
- public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
- this.msDOSFileInfo = msDOSFileInfo;
- }
-
- /**
- * Gets the short name.
- *
- * @return the short name
- */
- public AppleFileData getShortName() {
- return shortName;
- }
-
- /**
- * Sets the short name.
- *
- * @param shortName
- * the new short name
- */
- public void setShortName(AppleFileData shortName) {
- this.shortName = shortName;
- }
-
- /**
- * Gets the afp file info.
- *
- * @return the afp file info
- */
- public AppleFileData getAfpFileInfo() {
- return afpFileInfo;
- }
-
- /**
- * Sets the afp file info.
- *
- * @param afpFileInfo
- * the new afp file info
- */
- public void setAfpFileInfo(AppleFileData afpFileInfo) {
- this.afpFileInfo = afpFileInfo;
- }
-
- /**
- * Gets the directory id.
- *
- * @return the directory id
- */
- public AppleFileData getDirectoryID() {
- return directoryID;
- }
-
- /**
- * Sets the directory id.
- *
- * @param directoryID
- * the new directory id
- */
- public void setDirectoryID(AppleFileData directoryID) {
- this.directoryID = directoryID;
- }
-
- /**
- * Gets the num entries.
- *
- * @return the num entries
- */
- public int getNumEntries() {
- return numEntries;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This abstract class handles AppleSingle/Double files. It contains a common
+ * method to verify the Apple file, and figure out if it is an AppleSingle or
+ * AppleDouble formatted file.
+ *
+ *
+ * The AppleSingle format is a representation of Macintosh files as one
+ * consecutive stream of bytes. AppleSingle combines the data fork, resource
+ * fork and the related Finder meta-file information into a single file.
+ *
+ *
+ * The AppleDouble format stores the data fork, resource fork as two separate
+ * files. AppleDouble leaves the data fork in its original format, and the
+ * resource fork and Finder information were combined into a second file.
+ *
+ *
+ * Apple defined the magic number for the AppleSingle format as 0x00051600, and
+ * the magic number for the AppleDouble format as 0x00051607.
+ *
+ *
+ * AppleSingle file header:
+ *
+ * Field Length
+ * ----- ------
+ * Magic number ------- 4 bytes
+ * Version number ------ 4 bytes
+ * Filler ------------- 16 bytes
+ * Number of entries ----- 2 bytes
+ *
+ * Entry descriptor for each entry:
+ * Entry ID ------ 4 bytes
+ * Offset -------- 4 bytes
+ * Length -------- 4 bytes
+ *
+ * Apple reserved entry IDs:
+ *
+ * Data Fork -------- 1 Data fork
+ * Resource Fork ----- 2 Resource fork
+ * Real Name -------- 3 File's name as created on home file system
+ * Comment --------- 4 Standard Macintosh comment
+ * Icon, B&W -------- 5 Standard Macintosh black and white icon
+ * Icon, Color -------- 6 Macintosh color icon
+ * File Dates Info ------8 File creation date, modification date, and so on
+ * Finder Info -------- 9 Standard Macintosh Finder information
+ * Macintosh File Info ---10 Macintosh file information, attributes, and so on
+ * ProDOS File Info -----11 ProDOS file information, attributes, and so on
+ * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
+ * Short Name --------13 AFP short name
+ * AFP File Info ------- 14 AFP file information, attributes, and so on
+ * Directory ID --------15 AFP directory ID
+ *
+ *
+ * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
+ */
+public abstract class AppleFile {
+
+ /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
+ protected FileFormat format = FileFormat.UNKNOWN;
+
+ /** The raw Apple file. */
+ protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 1: Data fork. */
+ protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 2: Resource fork. */
+ protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 3: File's name as created on home file system. */
+ protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 4: Standard Macintosh comment. */
+ protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 5: Standard Macintosh black and white icon. */
+ protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 6: Macintosh color icon. */
+ protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 8: File creation date, modification date, and so on. */
+ protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The file dates info entry. */
+ protected FileDatesInfoEntry fileDatesInfoEntry = null;
+
+ /** Entry 9: Standard Macintosh Finder information. */
+ protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 10: Macintosh file information, attributes, and so on. */
+ protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 11: ProDOS file information, attributes, and so on. */
+ protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 12: MS-DOS file information, attributes, and so on. */
+ protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 13: AFP short name. */
+ protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 14: AFP file information, attributes, and so on. */
+ protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 15: AFP directory ID. */
+ protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The num entries. */
+ protected int numEntries = 0;
+
+ /**
+ * The Apple file format.
+ */
+ public enum FileFormat {
+
+ APPLE_SINGLE,
+ APPLE_DOUBLE,
+ UNKNOWN;
+
+ /**
+ * Return a suitable Apple file format as inferred from the passed-in
+ * string. Otherwise return the UNKNOWN file format.
+ *
+ * @param fileFormat
+ * the file format
+ * @return the FileFormat
+ */
+ public static FileFormat fromString(String fileFormat) {
+ if (fileFormat == null) {
+ return null;
+ }
+
+ try {
+ return FileFormat.valueOf(fileFormat.toUpperCase());
+ } catch (IllegalArgumentException iae) {
+ Log.error("Bad conversion attempt in FileFormat.fromString; string: "
+ + fileFormat + "; message: " + iae.getMessage());
+ Log.exception(iae);
+ return UNKNOWN;
+ }
+ }
+ };
+
+ /**
+ * This class represents the file dates.
+ */
+ public class FileDatesInfoEntry {
+
+ /** The create time. */
+ private int createTime = Integer.MIN_VALUE;
+
+ /** The modify time. */
+ private int modifyTime = Integer.MIN_VALUE;
+
+ /** The backup time. */
+ private int backupTime = Integer.MIN_VALUE;
+
+ /** The access time. */
+ private int accessTime = Integer.MIN_VALUE;
+
+ /**
+ * Instantiates a new file dates info entry.
+ */
+ public FileDatesInfoEntry() {
+
+ }
+
+ /**
+ * Gets the creates the time.
+ *
+ * @return the creates the time
+ */
+ public int getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * Sets the creates the time.
+ *
+ * @param createTime
+ * the new creates the time
+ */
+ public void setCreateTime(int createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * Gets the modify time.
+ *
+ * @return the modify time
+ */
+ public int getModifyTime() {
+ return modifyTime;
+ }
+
+ /**
+ * Sets the modify time.
+ *
+ * @param modifyTime
+ * the new modify time
+ */
+ public void setModifyTime(int modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ /**
+ * Gets the backup time.
+ *
+ * @return the backup time
+ */
+ public int getBackupTime() {
+ return backupTime;
+ }
+
+ /**
+ * Sets the backup time.
+ *
+ * @param backupTime
+ * the new backup time
+ */
+ public void setBackupTime(int backupTime) {
+ this.backupTime = backupTime;
+ }
+
+ /**
+ * Gets the access time.
+ *
+ * @return the access time
+ */
+ public int getAccessTime() {
+ return accessTime;
+ }
+
+ /**
+ * Sets the access time.
+ *
+ * @param accessTime
+ * the new access time
+ */
+ public void setAccessTime(int accessTime) {
+ this.accessTime = accessTime;
+ }
+ }
+
+ /**
+ * Sets the num entries.
+ *
+ * @param numEntries
+ * the new num entries
+ */
+ public void setNumEntries(int numEntries) {
+ this.numEntries = numEntries;
+ }
+
+ /**
+ * Verify the validity of the Apple file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ protected void verify() throws FileDecoderException {
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int position = offset;
+ if (length < 26) {
+ throw new FileDecoderException("File is too short");
+ }
+
+ /* Magic number */
+ int magic = 0;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+
+ /* Check Apple file format: AppleSingle or AppleDobule */
+ if (magic == 0x00051600) {
+ this.format = FileFormat.APPLE_SINGLE;
+ } else if (magic == 0x00051607) {
+ this.format = FileFormat.APPLE_DOUBLE;
+ } else {
+ throw new FileDecoderException("Invalid Apple file magic number.");
+ }
+
+ /* Version number */
+ int version = 0;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ if (version != 0x00020000) {
+ throw new FileDecoderException("Unknown Apple file version");
+ }
+
+ /* Filler */
+ position += 16;
+
+ /* Number of entries */
+ this.numEntries = 0;
+ this.numEntries |= data[(position++)] & 0xFF;
+ this.numEntries <<= 8;
+ this.numEntries |= data[(position++)] & 0xFF;
+ if (length < 26 + 12 * this.numEntries) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+
+ /* Check entries */
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ int contentPosition = 26 + 12 * this.numEntries;
+ for (int i = 0; i < this.numEntries; i++) {
+ position = 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+ if ((entryOffset < contentPosition)
+ || (length < entryOffset + entryLength)) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+ }
+ }
+
+ /**
+ * Extract file dates.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ protected void extractFileDates(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+
+ int position = offset;
+
+ int createTime = 0;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ int modifyTime = 0;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ int backupTime = 0;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ int accessTime = 0;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+
+ this.fileDatesInfoEntry = new FileDatesInfoEntry();
+ fileDatesInfoEntry.setCreateTime(createTime);
+ fileDatesInfoEntry.setModifyTime(modifyTime);
+ fileDatesInfoEntry.setBackupTime(backupTime);
+ fileDatesInfoEntry.setAccessTime(accessTime);
+ }
+
+ /**
+ * Gets the format.
+ *
+ * @return the format
+ */
+ public FileFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Sets the format.
+ *
+ * @param format
+ * the new format
+ */
+ public void setFormat(FileFormat format) {
+ this.format = format;
+ }
+
+ /**
+ * Gets the file data.
+ *
+ * @return the file data
+ */
+ public AppleFileData getFileData() {
+ return fileData;
+ }
+
+ /**
+ * Sets the file data.
+ *
+ * @param fileData
+ * the new file data
+ */
+ public void setFileData(AppleFileData fileData) {
+ this.fileData = fileData;
+ }
+
+ /**
+ * Gets the data fork.
+ *
+ * @return the data fork
+ */
+ public AppleFileData getDataFork() {
+ return dataFork;
+ }
+
+ /**
+ * Sets the data fork.
+ *
+ * @param dataFork
+ * the new data fork
+ */
+ public void setDataFork(AppleFileData dataFork) {
+ this.dataFork = dataFork;
+ }
+
+ /**
+ * Gets the resource fork.
+ *
+ * @return the resource fork
+ */
+ public AppleFileData getResourceFork() {
+ return resourceFork;
+ }
+
+ /**
+ * Sets the resource fork.
+ *
+ * @param resourceFork
+ * the new resource fork
+ */
+ public void setResourceFork(AppleFileData resourceFork) {
+ this.resourceFork = resourceFork;
+ }
+
+ /**
+ * Gets the real name.
+ *
+ * @return the real name
+ */
+ public AppleFileData getRealName() {
+ return realName;
+ }
+
+ /**
+ * Sets the real name.
+ *
+ * @param realName
+ * the new real name
+ */
+ public void setRealName(AppleFileData realName) {
+ this.realName = realName;
+ }
+
+ /**
+ * Gets the comment.
+ *
+ * @return the comment
+ */
+ public AppleFileData getComment() {
+ return comment;
+ }
+
+ /**
+ * Sets the comment.
+ *
+ * @param comment
+ * the new comment
+ */
+ public void setComment(AppleFileData comment) {
+ this.comment = comment;
+ }
+
+ /**
+ * Gets the icon bw.
+ *
+ * @return the icon bw
+ */
+ public AppleFileData getIconBW() {
+ return iconBW;
+ }
+
+ /**
+ * Sets the icon bw.
+ *
+ * @param iconBW
+ * the new icon bw
+ */
+ public void setIconBW(AppleFileData iconBW) {
+ this.iconBW = iconBW;
+ }
+
+ /**
+ * Gets the icon color.
+ *
+ * @return the icon color
+ */
+ public AppleFileData getIconColor() {
+ return iconColor;
+ }
+
+ /**
+ * Sets the icon color.
+ *
+ * @param iconColor
+ * the new icon color
+ */
+ public void setIconColor(AppleFileData iconColor) {
+ this.iconColor = iconColor;
+ }
+
+ /**
+ * Gets the file dates info.
+ *
+ * @return the file dates info
+ */
+ public AppleFileData getFileDatesInfo() {
+ return fileDatesInfo;
+ }
+
+ /**
+ * Sets the file dates info.
+ *
+ * @param fileDatesInfo
+ * the new file dates info
+ */
+ public void setFileDatesInfo(AppleFileData fileDatesInfo) {
+ this.fileDatesInfo = fileDatesInfo;
+ }
+
+ /**
+ * Gets the finder info.
+ *
+ * @return the finder info
+ */
+ public AppleFileData getFinderInfo() {
+ return finderInfo;
+ }
+
+ /**
+ * Sets the finder info.
+ *
+ * @param finderInfo
+ * the new finder info
+ */
+ public void setFinderInfo(AppleFileData finderInfo) {
+ this.finderInfo = finderInfo;
+ }
+
+ /**
+ * Gets the macintosh info.
+ *
+ * @return the macintosh info
+ */
+ public AppleFileData getMacintoshInfo() {
+ return macintoshInfo;
+ }
+
+ /**
+ * Sets the macintosh info.
+ *
+ * @param macintoshInfo
+ * the new macintosh info
+ */
+ public void setMacintoshInfo(AppleFileData macintoshInfo) {
+ this.macintoshInfo = macintoshInfo;
+ }
+
+ /**
+ * Gets the pro dos file info.
+ *
+ * @return the pro dos file info
+ */
+ public AppleFileData getProDOSFileInfo() {
+ return proDOSFileInfo;
+ }
+
+ /**
+ * Sets the pro dos file info.
+ *
+ * @param proDOSFileInfo
+ * the new pro dos file info
+ */
+ public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
+ this.proDOSFileInfo = proDOSFileInfo;
+ }
+
+ /**
+ * Gets the ms dos file info.
+ *
+ * @return the ms dos file info
+ */
+ public AppleFileData getMsDOSFileInfo() {
+ return msDOSFileInfo;
+ }
+
+ /**
+ * Sets the ms dos file info.
+ *
+ * @param msDOSFileInfo
+ * the new ms dos file info
+ */
+ public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
+ this.msDOSFileInfo = msDOSFileInfo;
+ }
+
+ /**
+ * Gets the short name.
+ *
+ * @return the short name
+ */
+ public AppleFileData getShortName() {
+ return shortName;
+ }
+
+ /**
+ * Sets the short name.
+ *
+ * @param shortName
+ * the new short name
+ */
+ public void setShortName(AppleFileData shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * Gets the afp file info.
+ *
+ * @return the afp file info
+ */
+ public AppleFileData getAfpFileInfo() {
+ return afpFileInfo;
+ }
+
+ /**
+ * Sets the afp file info.
+ *
+ * @param afpFileInfo
+ * the new afp file info
+ */
+ public void setAfpFileInfo(AppleFileData afpFileInfo) {
+ this.afpFileInfo = afpFileInfo;
+ }
+
+ /**
+ * Gets the directory id.
+ *
+ * @return the directory id
+ */
+ public AppleFileData getDirectoryID() {
+ return directoryID;
+ }
+
+ /**
+ * Sets the directory id.
+ *
+ * @param directoryID
+ * the new directory id
+ */
+ public void setDirectoryID(AppleFileData directoryID) {
+ this.directoryID = directoryID;
+ }
+
+ /**
+ * Gets the num entries.
+ *
+ * @return the num entries
+ */
+ public int getNumEntries() {
+ return numEntries;
+ }
}
\ No newline at end of file
diff --git a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
index f28c979a..d89471e2 100644
--- a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
+++ b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
@@ -1,91 +1,91 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-/**
- * This class is for representing the AppleSingle/Double file or its file forks
- * (data fork and resource fork) and the related Finder meta-file information.
- */
-public final class AppleFileData {
-
- public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
- private byte[] data;
- private int offset;
- private int length;
-
- /**
- * Instantiates a new apple file data.
- */
- public AppleFileData() {
- this.data = new byte[0];
- this.offset = 0;
- this.length = 0;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- */
- public AppleFileData(byte[] data) {
- this.data = data;
- this.offset = 0;
- this.length = data.length;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- public AppleFileData(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- /**
- * Gets the bytes.
- *
- * @return the bytes
- */
- public byte[] getBytes() {
- byte[] data = new byte[this.length];
- System.arraycopy(this.data, this.offset, data, 0, this.length);
- return data;
- }
-
- /**
- * Gets the data.
- *
- * @return the data
- */
- public byte[] getData() {
- return this.data;
- }
-
- /**
- * Gets the offset.
- *
- * @return the offset
- */
- public int getOffset() {
- return this.offset;
- }
-
- /**
- * Gets the length.
- *
- * @return the length
- */
- public int getLength() {
- return this.length;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+/**
+ * This class is for representing the AppleSingle/Double file or its file forks
+ * (data fork and resource fork) and the related Finder meta-file information.
+ */
+public final class AppleFileData {
+
+ public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
+ private byte[] data;
+ private int offset;
+ private int length;
+
+ /**
+ * Instantiates a new apple file data.
+ */
+ public AppleFileData() {
+ this.data = new byte[0];
+ this.offset = 0;
+ this.length = 0;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ */
+ public AppleFileData(byte[] data) {
+ this.data = data;
+ this.offset = 0;
+ this.length = data.length;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ public AppleFileData(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the bytes.
+ *
+ * @return the bytes
+ */
+ public byte[] getBytes() {
+ byte[] data = new byte[this.length];
+ System.arraycopy(this.data, this.offset, data, 0, this.length);
+ return data;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * Gets the offset.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ /**
+ * Gets the length.
+ *
+ * @return the length
+ */
+ public int getLength() {
+ return this.length;
+ }
}
\ No newline at end of file
diff --git a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
index 3248f85d..aa7b0363 100644
--- a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
+++ b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
@@ -1,143 +1,143 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This class handles the extraction of the data fork, resource fork and other
- * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
- * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
- * file type is a compressed AppleDouble (Mac resource fork) file.
- */
-public class AppleFileDecoder extends AppleFile {
-
- /**
- * Instantiates a new apple file decoder.
- *
- * @param fileData
- * the file data
- */
- public AppleFileDecoder(AppleFileData fileData) {
- if (fileData != null) {
- this.fileData = fileData;
- }
- }
-
- /**
- * Extract the data fork, resource fork and other entries from the Apple
- * file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- public void extract() throws FileDecoderException {
- // Verify the validity of the Apple file
- verify();
-
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int contentPosition = 0;
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- for (int i = 0; i < this.numEntries; i++) {
- contentPosition = offset + 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
-
- switch (entryId) {
- case 1:
- this.dataFork = new AppleFileData(data, offset + entryOffset,
- entryLength);
- break;
- case 2:
- this.resourceFork = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 3:
- this.realName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 4:
- this.comment = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 5:
- this.iconBW = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 6:
- this.iconColor = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 8:
- this.fileDatesInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- extractFileDates(data, offset + entryOffset, entryLength);
- break;
- case 9:
- this.finderInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 10:
- this.macintoshInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 11:
- this.proDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 12:
- this.msDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 13:
- this.shortName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 14:
- this.afpFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 15:
- this.directoryID = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- default:
- Log.warn("Apple file entry ID: " + entryId + " is not handled.");
-
- }
- }
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This class handles the extraction of the data fork, resource fork and other
+ * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
+ * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
+ * file type is a compressed AppleDouble (Mac resource fork) file.
+ */
+public class AppleFileDecoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @param fileData
+ * the file data
+ */
+ public AppleFileDecoder(AppleFileData fileData) {
+ if (fileData != null) {
+ this.fileData = fileData;
+ }
+ }
+
+ /**
+ * Extract the data fork, resource fork and other entries from the Apple
+ * file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ public void extract() throws FileDecoderException {
+ // Verify the validity of the Apple file
+ verify();
+
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int contentPosition = 0;
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ for (int i = 0; i < this.numEntries; i++) {
+ contentPosition = offset + 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+
+ switch (entryId) {
+ case 1:
+ this.dataFork = new AppleFileData(data, offset + entryOffset,
+ entryLength);
+ break;
+ case 2:
+ this.resourceFork = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 3:
+ this.realName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 4:
+ this.comment = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 5:
+ this.iconBW = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 6:
+ this.iconColor = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 8:
+ this.fileDatesInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ extractFileDates(data, offset + entryOffset, entryLength);
+ break;
+ case 9:
+ this.finderInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 10:
+ this.macintoshInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 11:
+ this.proDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 12:
+ this.msDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 13:
+ this.shortName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 14:
+ this.afpFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 15:
+ this.directoryID = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ default:
+ Log.warn("Apple file entry ID: " + entryId + " is not handled.");
+
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
index 7c5d0a04..abdfed59 100644
--- a/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
+++ b/p4java/r17-2/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
@@ -1,300 +1,300 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.exception.FileEncoderException;
-
-/**
- * This class handles the combination of the data fork, resource fork and other
- * entries into an AppleSingle/Double file.
- *
+ *
+ * Note that if it is an AppleDouble, the data fork is a separate file external
+ * to this file.
+ */
+public class AppleFileEncoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @throws FileEncoderException
+ */
+ public AppleFileEncoder(FileFormat fileFormat) throws FileEncoderException {
+ if (fileFormat == null) {
+ throw new FileEncoderException("Null file format passed to the AppleFileEncoder constructor.");
+ }
+ if (fileFormat == FileFormat.UNKNOWN) {
+ throw new FileEncoderException("Unknown file format passed to the AppleFileEncoder constructor.");
+ }
+ }
+
+ /**
+ * Combine the data fork, resource fork and other entries into an
+ * AppleSingle/Double file.
+ *
+ * @throws FileEncoderException
+ * the file encoder exception
+ */
+ @SuppressWarnings("unused")
+ public void combine() throws FileEncoderException {
+
+ boolean isAppleSingle = (this.format == FileFormat.APPLE_SINGLE);
+ boolean isAppleDouble = (this.format == FileFormat.APPLE_DOUBLE);
+
+ boolean hasDataFork = (this.dataFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasResourceFork = (this.resourceFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasRealName = (this.realName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasComment = (this.comment != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconBW = (this.iconBW != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconColor = (this.iconColor != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasFileDatesInfo = (this.fileDatesInfoEntry != null);
+ boolean hasFinderInfo = (this.finderInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMacintoshInfo = (this.macintoshInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasProDOSFileInfo = (this.proDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMsDOSFileInfo = (this.msDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasShortName = (this.shortName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasAfpFileInfo = (this.afpFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasDirectoryID = (this.directoryID != AppleFileData.EMPTY_FILE_DATA);
+
+ this.fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ int length = 90 + this.realName.getLength()
+ + this.resourceFork.getLength();
+
+ /* AppleSingle includes the data fork */
+ if (isAppleSingle) {
+ length += this.dataFork.getLength();
+ }
+
+ byte[] data = new byte[length];
+ int position = 0;
+
+ /* Magic number for AppleSingle or AppleDouble */
+ if (isAppleDouble) {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 0;
+ } else {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 7;
+ }
+
+ /* Version number */
+ data[(position++)] = 0;
+ data[(position++)] = 2;
+ data[(position++)] = 0;
+ data[(position++)] = 0;
+
+ /* Filler */
+
+ for (int k = 0; k < 16; k++) {
+ data[(position++)] = 0;
+ }
+
+ /* Number of entries */
+ this.numEntries = 0;
+ if (hasRealName) {
+ this.numEntries += 1;
+ }
+ if (hasFileDatesInfo) {
+ this.numEntries += 1;
+ }
+ if (hasResourceFork) {
+ this.numEntries += 1;
+ }
+ if ((hasDataFork) && (isAppleSingle)) {
+ this.numEntries += 1;
+ }
+ data[(position++)] = ((byte) (this.numEntries >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.numEntries & 0xFF));
+
+ /* Header information for the entries */
+
+ /* Real name entry header */
+ int realNamePosition = 0;
+ if (hasRealName) {
+ int realNameEntryId = 3;
+ int realNameEntryOffset = 0;
+ int realNameEntryLength = this.realName.getLength();
+ data[(position++)] = ((byte) (realNameEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 0 & 0xFF));
+ realNamePosition = position;
+ data[(position++)] = ((byte) (realNameEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 0 & 0xFF));
+ }
+
+ /* File dates info entry header */
+ int fileDatesInfoPosition = 0;
+ if (hasFileDatesInfo) {
+ int fileDatesInfoEntryId = 8;
+ int fileDatesInfoEntryOffset = 0;
+ int fileDatesInfoEntryLength = 16;
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 0 & 0xFF));
+ fileDatesInfoPosition = position;
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 0 & 0xFF));
+ }
+
+ /* Resource fork entry header */
+ int resourceForkPosition = 0;
+ if (hasResourceFork) {
+ int resourceForkEntryId = 2;
+ int resourceForkEntryOffset = 0;
+ int resourceFokrEntryLength = this.resourceFork.getLength();
+ data[(position++)] = ((byte) (resourceForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 0 & 0xFF));
+ resourceForkPosition = position;
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 0 & 0xFF));
+ }
+
+ /* Data fork entry header */
+ int dataForkPosition = 0;
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkEntryId = 1;
+ int dataForkEntryOffset = 0;
+ int dataForkEntryLength = this.dataFork.getLength();
+ data[(position++)] = ((byte) (dataForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 0 & 0xFF));
+ dataForkPosition = position;
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 0 & 0xFF));
+ }
+
+ /* Content for the entries */
+
+ /* Real name content */
+ if (hasRealName) {
+ int realNamePositionCurrent = position;
+ position = realNamePosition;
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 0 & 0xFF));
+ position = realNamePositionCurrent;
+ byte[] realNameData = this.realName.getData();
+ int realNameOffset = this.realName.getOffset();
+ int realNameLength = this.realName.getLength();
+ System.arraycopy(realNameData, realNameOffset, data, position,
+ realNameLength);
+ position += realNameLength;
+ }
+
+ /* File dates info content */
+ if (hasFileDatesInfo) {
+ int fileDatesInfoPositionCurrent = position;
+ position = fileDatesInfoPosition;
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 0 & 0xFF));
+ position = fileDatesInfoPositionCurrent;
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 0 & 0xFF));
+ }
+
+ /* Resource fork content */
+ if (hasResourceFork) {
+ int resourceForkPositionCurrent = position;
+ position = resourceForkPosition;
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 0 & 0xFF));
+ position = resourceForkPositionCurrent;
+ byte[] resourceForkData = this.resourceFork.getData();
+ int resourceForkOffset = this.resourceFork.getOffset();
+ int resourceForkLength = this.resourceFork.getLength();
+ System.arraycopy(resourceForkData, resourceForkOffset, data,
+ position, resourceForkLength);
+ position += resourceForkLength;
+ }
+
+ /* Data fork content */
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkPosition2 = position;
+ position = dataForkPosition;
+ data[(position++)] = ((byte) (dataForkPosition2 >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 0 & 0xFF));
+ position = dataForkPosition2;
+ byte[] dataForkData = this.dataFork.getData();
+ int dataForkOffset = this.dataFork.getOffset();
+ int dataForkLength = this.dataFork.getLength();
+ System.arraycopy(dataForkData, dataForkOffset, data, position,
+ dataForkLength);
+ position += dataForkLength;
+ }
+
+ /* Create the Apple file data */
+ this.fileData = new AppleFileData(data, 0, position);
+ }
}
\ No newline at end of file
diff --git a/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java b/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java
index 59a9a133..1c224364 100644
--- a/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java
+++ b/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java
@@ -1,54 +1,54 @@
-package com.perforce.p4java.tests.dev.unit.bug.r132;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-
-import org.junit.jupiter.api.Test;
-import org.junit.platform.runner.JUnitPlatform;
-import org.junit.runner.RunWith;
-
-import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
-import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
-
-/**
- * Test create symbolic link with non-existing target.
- */
-@RunWith(JUnitPlatform.class)
-public class CreateSymbolicLinkTest extends P4JavaTestCase {
- /**
- * Test create symbolic link with non-existing target.
- */
- @Test
- public void testCreateSymbolicLink() throws IOException {
- // Check if symlink capable (JDK 7 or above)
- if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
- String target = File.createTempFile("link-to-me", ".tmp").getAbsolutePath();
- String link = System.getProperty("java.io.tmpdir") + "/p4java-bin-" + getRandomInt();
-
- // Create symbolic link
- debugPrint("Creating link " + link + " to " + target);
- String path = SymbolicLinkHelper.createSymbolicLink(link, target);
- assertNotNull("Failed to create a symbolic link from " + link + " to " + target);
- assertTrue(path + " is not a symbolic link", SymbolicLinkHelper.isSymbolicLink(path));
-
- debugPrint("Creating a new file object for " + path);
- File file = new File(path);
- assertTrue("A new File object to " + path + " is not reported as a symbolic link.",
- Files.isSymbolicLink(file.toPath()));
- assertTrue("A new File object to " + path + " is not reported as not existing.",
- file.exists());
-
- debugPrint("Checking the parent path " + path);
- String parentPath = file.getParent();
- assertNotNull(file + " has not parent path.", parentPath);
-
- debugPrint("Deleting " + file);
- assertTrue("Failed to delete " + file.toPath(), Files.deleteIfExists(file.toPath()));
- }
- }
-
-}
+package com.perforce.p4java.tests.dev.unit.bug.r132;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import org.junit.jupiter.api.Test;
+import org.junit.platform.runner.JUnitPlatform;
+import org.junit.runner.RunWith;
+
+import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
+import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
+
+/**
+ * Test create symbolic link with non-existing target.
+ */
+@RunWith(JUnitPlatform.class)
+public class CreateSymbolicLinkTest extends P4JavaTestCase {
+ /**
+ * Test create symbolic link with non-existing target.
+ */
+ @Test
+ public void testCreateSymbolicLink() throws IOException {
+ // Check if symlink capable (JDK 7 or above)
+ if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
+ String target = File.createTempFile("link-to-me", ".tmp").getAbsolutePath();
+ String link = System.getProperty("java.io.tmpdir") + "/p4java-bin-" + getRandomInt();
+
+ // Create symbolic link
+ debugPrint("Creating link " + link + " to " + target);
+ String path = SymbolicLinkHelper.createSymbolicLink(link, target);
+ assertNotNull("Failed to create a symbolic link from " + link + " to " + target);
+ assertTrue(path + " is not a symbolic link", SymbolicLinkHelper.isSymbolicLink(path));
+
+ debugPrint("Creating a new file object for " + path);
+ File file = new File(path);
+ assertTrue("A new File object to " + path + " is not reported as a symbolic link.",
+ Files.isSymbolicLink(file.toPath()));
+ assertTrue("A new File object to " + path + " is not reported as not existing.",
+ file.exists());
+
+ debugPrint("Checking the parent path " + path);
+ String parentPath = file.getParent();
+ assertNotNull(file + " has not parent path.", parentPath);
+
+ debugPrint("Deleting " + file);
+ assertTrue("Failed to delete " + file.toPath(), Files.deleteIfExists(file.toPath()));
+ }
+ }
+
+}
diff --git a/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java b/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
index bab7e806..978db638 100644
--- a/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
+++ b/p4java/r17-2/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
@@ -1,83 +1,83 @@
-/**
- * Copyright (c) 2012 Perforce Software. All rights reserved.
- */
-package com.perforce.p4java.tests.dev.unit.features123;
-
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
-import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
-
-/**
- * Test symbolic link helper (JDK 7 or above)
- */
-public class SymbolicLinkHelperTest extends P4JavaTestCase {
-
- /**
- * @BeforeClass annotation to a method to be run before all the tests in a
- * class.
- */
- @BeforeClass
- public static void oneTimeSetUp() {
- // one-time initialization code (before all the tests).
- }
-
- /**
- * @AfterClass annotation to a method to be run after all the tests in a
- * class.
- */
- @AfterClass
- public static void oneTimeTearDown() {
- // one-time cleanup code (after all the tests).
- }
-
- /**
- * @Before annotation to a method to be run before each test in a class.
- */
- @Before
- public void setUp() {
- // initialization code (before each test).
- }
-
- /**
- * @After annotation to a method to be run after each test in a class.
- */
- @After
- public void tearDown() {
- // cleanup code (after each test).
- }
-
- /**
- * Test symbolic link
- */
- @Test
- public void tesSymbolicLink() {
- // Check if symlink capable
- if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
-
- String target = "/usr/bin";
- String link = "/tmp/user-bin-" + getRandomInt();
-
- // Create symbolic link
- Object path = SymbolicLinkHelper.createSymbolicLink(link, target);
-
- boolean isSymlink = SymbolicLinkHelper.isSymbolicLink(path
- .toString());
- assertTrue(isSymlink);
-
- File file = new File(path.toString());
- if (file.exists()) {
- file.delete();
- }
- }
- }
-
-}
+/**
+ * Copyright (c) 2012 Perforce Software. All rights reserved.
+ */
+package com.perforce.p4java.tests.dev.unit.features123;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
+import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
+
+/**
+ * Test symbolic link helper (JDK 7 or above)
+ */
+public class SymbolicLinkHelperTest extends P4JavaTestCase {
+
+ /**
+ * @BeforeClass annotation to a method to be run before all the tests in a
+ * class.
+ */
+ @BeforeClass
+ public static void oneTimeSetUp() {
+ // one-time initialization code (before all the tests).
+ }
+
+ /**
+ * @AfterClass annotation to a method to be run after all the tests in a
+ * class.
+ */
+ @AfterClass
+ public static void oneTimeTearDown() {
+ // one-time cleanup code (after all the tests).
+ }
+
+ /**
+ * @Before annotation to a method to be run before each test in a class.
+ */
+ @Before
+ public void setUp() {
+ // initialization code (before each test).
+ }
+
+ /**
+ * @After annotation to a method to be run after each test in a class.
+ */
+ @After
+ public void tearDown() {
+ // cleanup code (after each test).
+ }
+
+ /**
+ * Test symbolic link
+ */
+ @Test
+ public void tesSymbolicLink() {
+ // Check if symlink capable
+ if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
+
+ String target = "/usr/bin";
+ String link = "/tmp/user-bin-" + getRandomInt();
+
+ // Create symbolic link
+ Object path = SymbolicLinkHelper.createSymbolicLink(link, target);
+
+ boolean isSymlink = SymbolicLinkHelper.isSymbolicLink(path
+ .toString());
+ assertTrue(isSymlink);
+
+ File file = new File(path.toString());
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+ }
+
+}
diff --git a/p4java/r18-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java b/p4java/r18-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
index 955735f4..75e9be6e 100644
--- a/p4java/r18-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
+++ b/p4java/r18-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
@@ -1,118 +1,118 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
-import com.perforce.p4java.io.apple.AppleFileData;
-import com.perforce.p4java.io.apple.AppleFileDecoder;
-
-/**
- * Helper class for handling Apple files.
- */
-public class AppleFileHelper {
-
- /**
- * Extract the data fork and the resource fork from the Apple file.
- *
- * @param file the Apple file
- */
- public static void extractFile(RpcPerforceFile file) {
- if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
- FileOutputStream fosData = null;
- FileOutputStream fosResource = null;
- try {
- byte[] data = AppleFileHelper.getBytesFromFile(file);
- AppleFileData fileData = new AppleFileData(data);
- AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
- appleFile.extract();
- fosData = new FileOutputStream(file);
- AppleFileData forkData = appleFile.getDataFork();
- if (forkData != AppleFileData.EMPTY_FILE_DATA) {
- fosData.write(forkData.getBytes());
- }
- String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
- RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
- fosResource = new FileOutputStream(targetResourceFile);
- AppleFileData forkResource = appleFile.getResourceFork();
- if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
- fosResource.write(forkResource.getBytes());
- }
- } catch (IOException e) {
- Log.error("Problem handling the Apple file: " + file.getName());
- } catch (FileDecoderException e) {
- Log.error("Problem decoding the Apple file: " + file.getName());
- } finally {
- if (fosData != null) {
- try {
- fosData.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- if (fosResource != null) {
- try {
- fosResource.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- }
- }
- }
-
- /**
- * Gets the bytes from file.
- *
- * @param file
- * the file
- * @return the bytes from file
- * @throws IOException
- * Signals that an I/O exception has occurred.
- */
- public static byte[] getBytesFromFile(File file) throws IOException {
- InputStream is = new FileInputStream(file);
-
- long length = file.length();
- if (length > Integer.MAX_VALUE) {
- // File is too large
- throw new IOException("Apple file too large for decoding.");
- }
-
- byte[] bytes = new byte[(int) length];
- int offset = 0;
- int numRead = 0;
-
- try {
- while (offset < bytes.length
- && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
- offset += numRead;
- }
- // Ensure all the bytes have been read in
- if (offset < bytes.length) {
- throw new IOException(
- "Could not completely read the Apple file "
- + file.getName());
- }
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- // Do nothing
- }
- }
- }
-
- return bytes;
- }
-}
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
+import com.perforce.p4java.io.apple.AppleFileData;
+import com.perforce.p4java.io.apple.AppleFileDecoder;
+
+/**
+ * Helper class for handling Apple files.
+ */
+public class AppleFileHelper {
+
+ /**
+ * Extract the data fork and the resource fork from the Apple file.
+ *
+ * @param file the Apple file
+ */
+ public static void extractFile(RpcPerforceFile file) {
+ if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
+ FileOutputStream fosData = null;
+ FileOutputStream fosResource = null;
+ try {
+ byte[] data = AppleFileHelper.getBytesFromFile(file);
+ AppleFileData fileData = new AppleFileData(data);
+ AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
+ appleFile.extract();
+ fosData = new FileOutputStream(file);
+ AppleFileData forkData = appleFile.getDataFork();
+ if (forkData != AppleFileData.EMPTY_FILE_DATA) {
+ fosData.write(forkData.getBytes());
+ }
+ String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
+ RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
+ fosResource = new FileOutputStream(targetResourceFile);
+ AppleFileData forkResource = appleFile.getResourceFork();
+ if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
+ fosResource.write(forkResource.getBytes());
+ }
+ } catch (IOException e) {
+ Log.error("Problem handling the Apple file: " + file.getName());
+ } catch (FileDecoderException e) {
+ Log.error("Problem decoding the Apple file: " + file.getName());
+ } finally {
+ if (fosData != null) {
+ try {
+ fosData.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ if (fosResource != null) {
+ try {
+ fosResource.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the bytes from file.
+ *
+ * @param file
+ * the file
+ * @return the bytes from file
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+
+ long length = file.length();
+ if (length > Integer.MAX_VALUE) {
+ // File is too large
+ throw new IOException("Apple file too large for decoding.");
+ }
+
+ byte[] bytes = new byte[(int) length];
+ int offset = 0;
+ int numRead = 0;
+
+ try {
+ while (offset < bytes.length
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException(
+ "Could not completely read the Apple file "
+ + file.getName());
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+
+ return bytes;
+ }
+}
diff --git a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
index 5b89f33a..615bfcc9 100644
--- a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
+++ b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
@@ -1,735 +1,735 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This abstract class handles AppleSingle/Double files. It contains a common
- * method to verify the Apple file, and figure out if it is an AppleSingle or
- * AppleDouble formatted file.
- *
- *
- * The AppleSingle format is a representation of Macintosh files as one
- * consecutive stream of bytes. AppleSingle combines the data fork, resource
- * fork and the related Finder meta-file information into a single file.
- *
- *
- * The AppleDouble format stores the data fork, resource fork as two separate
- * files. AppleDouble leaves the data fork in its original format, and the
- * resource fork and Finder information were combined into a second file.
- *
- *
- * Apple defined the magic number for the AppleSingle format as 0x00051600, and
- * the magic number for the AppleDouble format as 0x00051607.
- *
- *
- * AppleSingle file header:
- *
- * Field Length
- * ----- ------
- * Magic number ------- 4 bytes
- * Version number ------ 4 bytes
- * Filler ------------- 16 bytes
- * Number of entries ----- 2 bytes
- *
- * Entry descriptor for each entry:
- * Entry ID ------ 4 bytes
- * Offset -------- 4 bytes
- * Length -------- 4 bytes
- *
- * Apple reserved entry IDs:
- *
- * Data Fork -------- 1 Data fork
- * Resource Fork ----- 2 Resource fork
- * Real Name -------- 3 File's name as created on home file system
- * Comment --------- 4 Standard Macintosh comment
- * Icon, B&W -------- 5 Standard Macintosh black and white icon
- * Icon, Color -------- 6 Macintosh color icon
- * File Dates Info ------8 File creation date, modification date, and so on
- * Finder Info -------- 9 Standard Macintosh Finder information
- * Macintosh File Info ---10 Macintosh file information, attributes, and so on
- * ProDOS File Info -----11 ProDOS file information, attributes, and so on
- * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
- * Short Name --------13 AFP short name
- * AFP File Info ------- 14 AFP file information, attributes, and so on
- * Directory ID --------15 AFP directory ID
- *
- *
- * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
- */
-public abstract class AppleFile {
-
- /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
- protected FileFormat format = FileFormat.UNKNOWN;
-
- /** The raw Apple file. */
- protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 1: Data fork. */
- protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 2: Resource fork. */
- protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 3: File's name as created on home file system. */
- protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 4: Standard Macintosh comment. */
- protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 5: Standard Macintosh black and white icon. */
- protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 6: Macintosh color icon. */
- protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 8: File creation date, modification date, and so on. */
- protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** The file dates info entry. */
- protected FileDatesInfoEntry fileDatesInfoEntry = null;
-
- /** Entry 9: Standard Macintosh Finder information. */
- protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 10: Macintosh file information, attributes, and so on. */
- protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 11: ProDOS file information, attributes, and so on. */
- protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 12: MS-DOS file information, attributes, and so on. */
- protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 13: AFP short name. */
- protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 14: AFP file information, attributes, and so on. */
- protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 15: AFP directory ID. */
- protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
-
- /** The num entries. */
- protected int numEntries = 0;
-
- /**
- * The Apple file format.
- */
- public enum FileFormat {
-
- APPLE_SINGLE,
- APPLE_DOUBLE,
- UNKNOWN;
-
- /**
- * Return a suitable Apple file format as inferred from the passed-in
- * string. Otherwise return the UNKNOWN file format.
- *
- * @param fileFormat
- * the file format
- * @return the FileFormat
- */
- public static FileFormat fromString(String fileFormat) {
- if (fileFormat == null) {
- return null;
- }
-
- try {
- return FileFormat.valueOf(fileFormat.toUpperCase());
- } catch (IllegalArgumentException iae) {
- Log.error("Bad conversion attempt in FileFormat.fromString; string: "
- + fileFormat + "; message: " + iae.getMessage());
- Log.exception(iae);
- return UNKNOWN;
- }
- }
- };
-
- /**
- * This class represents the file dates.
- */
- public class FileDatesInfoEntry {
-
- /** The create time. */
- private int createTime = Integer.MIN_VALUE;
-
- /** The modify time. */
- private int modifyTime = Integer.MIN_VALUE;
-
- /** The backup time. */
- private int backupTime = Integer.MIN_VALUE;
-
- /** The access time. */
- private int accessTime = Integer.MIN_VALUE;
-
- /**
- * Instantiates a new file dates info entry.
- */
- public FileDatesInfoEntry() {
-
- }
-
- /**
- * Gets the creates the time.
- *
- * @return the creates the time
- */
- public int getCreateTime() {
- return createTime;
- }
-
- /**
- * Sets the creates the time.
- *
- * @param createTime
- * the new creates the time
- */
- public void setCreateTime(int createTime) {
- this.createTime = createTime;
- }
-
- /**
- * Gets the modify time.
- *
- * @return the modify time
- */
- public int getModifyTime() {
- return modifyTime;
- }
-
- /**
- * Sets the modify time.
- *
- * @param modifyTime
- * the new modify time
- */
- public void setModifyTime(int modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- /**
- * Gets the backup time.
- *
- * @return the backup time
- */
- public int getBackupTime() {
- return backupTime;
- }
-
- /**
- * Sets the backup time.
- *
- * @param backupTime
- * the new backup time
- */
- public void setBackupTime(int backupTime) {
- this.backupTime = backupTime;
- }
-
- /**
- * Gets the access time.
- *
- * @return the access time
- */
- public int getAccessTime() {
- return accessTime;
- }
-
- /**
- * Sets the access time.
- *
- * @param accessTime
- * the new access time
- */
- public void setAccessTime(int accessTime) {
- this.accessTime = accessTime;
- }
- }
-
- /**
- * Sets the num entries.
- *
- * @param numEntries
- * the new num entries
- */
- public void setNumEntries(int numEntries) {
- this.numEntries = numEntries;
- }
-
- /**
- * Verify the validity of the Apple file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- protected void verify() throws FileDecoderException {
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int position = offset;
- if (length < 26) {
- throw new FileDecoderException("File is too short");
- }
-
- /* Magic number */
- int magic = 0;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
-
- /* Check Apple file format: AppleSingle or AppleDobule */
- if (magic == 0x00051600) {
- this.format = FileFormat.APPLE_SINGLE;
- } else if (magic == 0x00051607) {
- this.format = FileFormat.APPLE_DOUBLE;
- } else {
- throw new FileDecoderException("Invalid Apple file magic number.");
- }
-
- /* Version number */
- int version = 0;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- if (version != 0x00020000) {
- throw new FileDecoderException("Unknown Apple file version");
- }
-
- /* Filler */
- position += 16;
-
- /* Number of entries */
- this.numEntries = 0;
- this.numEntries |= data[(position++)] & 0xFF;
- this.numEntries <<= 8;
- this.numEntries |= data[(position++)] & 0xFF;
- if (length < 26 + 12 * this.numEntries) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
-
- /* Check entries */
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- int contentPosition = 26 + 12 * this.numEntries;
- for (int i = 0; i < this.numEntries; i++) {
- position = 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
- if ((entryOffset < contentPosition)
- || (length < entryOffset + entryLength)) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
- }
- }
-
- /**
- * Extract file dates.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- protected void extractFileDates(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
-
- int position = offset;
-
- int createTime = 0;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- int modifyTime = 0;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- int backupTime = 0;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- int accessTime = 0;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
-
- this.fileDatesInfoEntry = new FileDatesInfoEntry();
- fileDatesInfoEntry.setCreateTime(createTime);
- fileDatesInfoEntry.setModifyTime(modifyTime);
- fileDatesInfoEntry.setBackupTime(backupTime);
- fileDatesInfoEntry.setAccessTime(accessTime);
- }
-
- /**
- * Gets the format.
- *
- * @return the format
- */
- public FileFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the format.
- *
- * @param format
- * the new format
- */
- public void setFormat(FileFormat format) {
- this.format = format;
- }
-
- /**
- * Gets the file data.
- *
- * @return the file data
- */
- public AppleFileData getFileData() {
- return fileData;
- }
-
- /**
- * Sets the file data.
- *
- * @param fileData
- * the new file data
- */
- public void setFileData(AppleFileData fileData) {
- this.fileData = fileData;
- }
-
- /**
- * Gets the data fork.
- *
- * @return the data fork
- */
- public AppleFileData getDataFork() {
- return dataFork;
- }
-
- /**
- * Sets the data fork.
- *
- * @param dataFork
- * the new data fork
- */
- public void setDataFork(AppleFileData dataFork) {
- this.dataFork = dataFork;
- }
-
- /**
- * Gets the resource fork.
- *
- * @return the resource fork
- */
- public AppleFileData getResourceFork() {
- return resourceFork;
- }
-
- /**
- * Sets the resource fork.
- *
- * @param resourceFork
- * the new resource fork
- */
- public void setResourceFork(AppleFileData resourceFork) {
- this.resourceFork = resourceFork;
- }
-
- /**
- * Gets the real name.
- *
- * @return the real name
- */
- public AppleFileData getRealName() {
- return realName;
- }
-
- /**
- * Sets the real name.
- *
- * @param realName
- * the new real name
- */
- public void setRealName(AppleFileData realName) {
- this.realName = realName;
- }
-
- /**
- * Gets the comment.
- *
- * @return the comment
- */
- public AppleFileData getComment() {
- return comment;
- }
-
- /**
- * Sets the comment.
- *
- * @param comment
- * the new comment
- */
- public void setComment(AppleFileData comment) {
- this.comment = comment;
- }
-
- /**
- * Gets the icon bw.
- *
- * @return the icon bw
- */
- public AppleFileData getIconBW() {
- return iconBW;
- }
-
- /**
- * Sets the icon bw.
- *
- * @param iconBW
- * the new icon bw
- */
- public void setIconBW(AppleFileData iconBW) {
- this.iconBW = iconBW;
- }
-
- /**
- * Gets the icon color.
- *
- * @return the icon color
- */
- public AppleFileData getIconColor() {
- return iconColor;
- }
-
- /**
- * Sets the icon color.
- *
- * @param iconColor
- * the new icon color
- */
- public void setIconColor(AppleFileData iconColor) {
- this.iconColor = iconColor;
- }
-
- /**
- * Gets the file dates info.
- *
- * @return the file dates info
- */
- public AppleFileData getFileDatesInfo() {
- return fileDatesInfo;
- }
-
- /**
- * Sets the file dates info.
- *
- * @param fileDatesInfo
- * the new file dates info
- */
- public void setFileDatesInfo(AppleFileData fileDatesInfo) {
- this.fileDatesInfo = fileDatesInfo;
- }
-
- /**
- * Gets the finder info.
- *
- * @return the finder info
- */
- public AppleFileData getFinderInfo() {
- return finderInfo;
- }
-
- /**
- * Sets the finder info.
- *
- * @param finderInfo
- * the new finder info
- */
- public void setFinderInfo(AppleFileData finderInfo) {
- this.finderInfo = finderInfo;
- }
-
- /**
- * Gets the macintosh info.
- *
- * @return the macintosh info
- */
- public AppleFileData getMacintoshInfo() {
- return macintoshInfo;
- }
-
- /**
- * Sets the macintosh info.
- *
- * @param macintoshInfo
- * the new macintosh info
- */
- public void setMacintoshInfo(AppleFileData macintoshInfo) {
- this.macintoshInfo = macintoshInfo;
- }
-
- /**
- * Gets the pro dos file info.
- *
- * @return the pro dos file info
- */
- public AppleFileData getProDOSFileInfo() {
- return proDOSFileInfo;
- }
-
- /**
- * Sets the pro dos file info.
- *
- * @param proDOSFileInfo
- * the new pro dos file info
- */
- public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
- this.proDOSFileInfo = proDOSFileInfo;
- }
-
- /**
- * Gets the ms dos file info.
- *
- * @return the ms dos file info
- */
- public AppleFileData getMsDOSFileInfo() {
- return msDOSFileInfo;
- }
-
- /**
- * Sets the ms dos file info.
- *
- * @param msDOSFileInfo
- * the new ms dos file info
- */
- public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
- this.msDOSFileInfo = msDOSFileInfo;
- }
-
- /**
- * Gets the short name.
- *
- * @return the short name
- */
- public AppleFileData getShortName() {
- return shortName;
- }
-
- /**
- * Sets the short name.
- *
- * @param shortName
- * the new short name
- */
- public void setShortName(AppleFileData shortName) {
- this.shortName = shortName;
- }
-
- /**
- * Gets the afp file info.
- *
- * @return the afp file info
- */
- public AppleFileData getAfpFileInfo() {
- return afpFileInfo;
- }
-
- /**
- * Sets the afp file info.
- *
- * @param afpFileInfo
- * the new afp file info
- */
- public void setAfpFileInfo(AppleFileData afpFileInfo) {
- this.afpFileInfo = afpFileInfo;
- }
-
- /**
- * Gets the directory id.
- *
- * @return the directory id
- */
- public AppleFileData getDirectoryID() {
- return directoryID;
- }
-
- /**
- * Sets the directory id.
- *
- * @param directoryID
- * the new directory id
- */
- public void setDirectoryID(AppleFileData directoryID) {
- this.directoryID = directoryID;
- }
-
- /**
- * Gets the num entries.
- *
- * @return the num entries
- */
- public int getNumEntries() {
- return numEntries;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This abstract class handles AppleSingle/Double files. It contains a common
+ * method to verify the Apple file, and figure out if it is an AppleSingle or
+ * AppleDouble formatted file.
+ *
+ *
+ * The AppleSingle format is a representation of Macintosh files as one
+ * consecutive stream of bytes. AppleSingle combines the data fork, resource
+ * fork and the related Finder meta-file information into a single file.
+ *
+ *
+ * The AppleDouble format stores the data fork, resource fork as two separate
+ * files. AppleDouble leaves the data fork in its original format, and the
+ * resource fork and Finder information were combined into a second file.
+ *
+ *
+ * Apple defined the magic number for the AppleSingle format as 0x00051600, and
+ * the magic number for the AppleDouble format as 0x00051607.
+ *
+ *
+ * AppleSingle file header:
+ *
+ * Field Length
+ * ----- ------
+ * Magic number ------- 4 bytes
+ * Version number ------ 4 bytes
+ * Filler ------------- 16 bytes
+ * Number of entries ----- 2 bytes
+ *
+ * Entry descriptor for each entry:
+ * Entry ID ------ 4 bytes
+ * Offset -------- 4 bytes
+ * Length -------- 4 bytes
+ *
+ * Apple reserved entry IDs:
+ *
+ * Data Fork -------- 1 Data fork
+ * Resource Fork ----- 2 Resource fork
+ * Real Name -------- 3 File's name as created on home file system
+ * Comment --------- 4 Standard Macintosh comment
+ * Icon, B&W -------- 5 Standard Macintosh black and white icon
+ * Icon, Color -------- 6 Macintosh color icon
+ * File Dates Info ------8 File creation date, modification date, and so on
+ * Finder Info -------- 9 Standard Macintosh Finder information
+ * Macintosh File Info ---10 Macintosh file information, attributes, and so on
+ * ProDOS File Info -----11 ProDOS file information, attributes, and so on
+ * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
+ * Short Name --------13 AFP short name
+ * AFP File Info ------- 14 AFP file information, attributes, and so on
+ * Directory ID --------15 AFP directory ID
+ *
+ *
+ * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
+ */
+public abstract class AppleFile {
+
+ /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
+ protected FileFormat format = FileFormat.UNKNOWN;
+
+ /** The raw Apple file. */
+ protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 1: Data fork. */
+ protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 2: Resource fork. */
+ protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 3: File's name as created on home file system. */
+ protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 4: Standard Macintosh comment. */
+ protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 5: Standard Macintosh black and white icon. */
+ protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 6: Macintosh color icon. */
+ protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 8: File creation date, modification date, and so on. */
+ protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The file dates info entry. */
+ protected FileDatesInfoEntry fileDatesInfoEntry = null;
+
+ /** Entry 9: Standard Macintosh Finder information. */
+ protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 10: Macintosh file information, attributes, and so on. */
+ protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 11: ProDOS file information, attributes, and so on. */
+ protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 12: MS-DOS file information, attributes, and so on. */
+ protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 13: AFP short name. */
+ protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 14: AFP file information, attributes, and so on. */
+ protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 15: AFP directory ID. */
+ protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The num entries. */
+ protected int numEntries = 0;
+
+ /**
+ * The Apple file format.
+ */
+ public enum FileFormat {
+
+ APPLE_SINGLE,
+ APPLE_DOUBLE,
+ UNKNOWN;
+
+ /**
+ * Return a suitable Apple file format as inferred from the passed-in
+ * string. Otherwise return the UNKNOWN file format.
+ *
+ * @param fileFormat
+ * the file format
+ * @return the FileFormat
+ */
+ public static FileFormat fromString(String fileFormat) {
+ if (fileFormat == null) {
+ return null;
+ }
+
+ try {
+ return FileFormat.valueOf(fileFormat.toUpperCase());
+ } catch (IllegalArgumentException iae) {
+ Log.error("Bad conversion attempt in FileFormat.fromString; string: "
+ + fileFormat + "; message: " + iae.getMessage());
+ Log.exception(iae);
+ return UNKNOWN;
+ }
+ }
+ };
+
+ /**
+ * This class represents the file dates.
+ */
+ public class FileDatesInfoEntry {
+
+ /** The create time. */
+ private int createTime = Integer.MIN_VALUE;
+
+ /** The modify time. */
+ private int modifyTime = Integer.MIN_VALUE;
+
+ /** The backup time. */
+ private int backupTime = Integer.MIN_VALUE;
+
+ /** The access time. */
+ private int accessTime = Integer.MIN_VALUE;
+
+ /**
+ * Instantiates a new file dates info entry.
+ */
+ public FileDatesInfoEntry() {
+
+ }
+
+ /**
+ * Gets the creates the time.
+ *
+ * @return the creates the time
+ */
+ public int getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * Sets the creates the time.
+ *
+ * @param createTime
+ * the new creates the time
+ */
+ public void setCreateTime(int createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * Gets the modify time.
+ *
+ * @return the modify time
+ */
+ public int getModifyTime() {
+ return modifyTime;
+ }
+
+ /**
+ * Sets the modify time.
+ *
+ * @param modifyTime
+ * the new modify time
+ */
+ public void setModifyTime(int modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ /**
+ * Gets the backup time.
+ *
+ * @return the backup time
+ */
+ public int getBackupTime() {
+ return backupTime;
+ }
+
+ /**
+ * Sets the backup time.
+ *
+ * @param backupTime
+ * the new backup time
+ */
+ public void setBackupTime(int backupTime) {
+ this.backupTime = backupTime;
+ }
+
+ /**
+ * Gets the access time.
+ *
+ * @return the access time
+ */
+ public int getAccessTime() {
+ return accessTime;
+ }
+
+ /**
+ * Sets the access time.
+ *
+ * @param accessTime
+ * the new access time
+ */
+ public void setAccessTime(int accessTime) {
+ this.accessTime = accessTime;
+ }
+ }
+
+ /**
+ * Sets the num entries.
+ *
+ * @param numEntries
+ * the new num entries
+ */
+ public void setNumEntries(int numEntries) {
+ this.numEntries = numEntries;
+ }
+
+ /**
+ * Verify the validity of the Apple file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ protected void verify() throws FileDecoderException {
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int position = offset;
+ if (length < 26) {
+ throw new FileDecoderException("File is too short");
+ }
+
+ /* Magic number */
+ int magic = 0;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+
+ /* Check Apple file format: AppleSingle or AppleDobule */
+ if (magic == 0x00051600) {
+ this.format = FileFormat.APPLE_SINGLE;
+ } else if (magic == 0x00051607) {
+ this.format = FileFormat.APPLE_DOUBLE;
+ } else {
+ throw new FileDecoderException("Invalid Apple file magic number.");
+ }
+
+ /* Version number */
+ int version = 0;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ if (version != 0x00020000) {
+ throw new FileDecoderException("Unknown Apple file version");
+ }
+
+ /* Filler */
+ position += 16;
+
+ /* Number of entries */
+ this.numEntries = 0;
+ this.numEntries |= data[(position++)] & 0xFF;
+ this.numEntries <<= 8;
+ this.numEntries |= data[(position++)] & 0xFF;
+ if (length < 26 + 12 * this.numEntries) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+
+ /* Check entries */
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ int contentPosition = 26 + 12 * this.numEntries;
+ for (int i = 0; i < this.numEntries; i++) {
+ position = 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+ if ((entryOffset < contentPosition)
+ || (length < entryOffset + entryLength)) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+ }
+ }
+
+ /**
+ * Extract file dates.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ protected void extractFileDates(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+
+ int position = offset;
+
+ int createTime = 0;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ int modifyTime = 0;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ int backupTime = 0;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ int accessTime = 0;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+
+ this.fileDatesInfoEntry = new FileDatesInfoEntry();
+ fileDatesInfoEntry.setCreateTime(createTime);
+ fileDatesInfoEntry.setModifyTime(modifyTime);
+ fileDatesInfoEntry.setBackupTime(backupTime);
+ fileDatesInfoEntry.setAccessTime(accessTime);
+ }
+
+ /**
+ * Gets the format.
+ *
+ * @return the format
+ */
+ public FileFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Sets the format.
+ *
+ * @param format
+ * the new format
+ */
+ public void setFormat(FileFormat format) {
+ this.format = format;
+ }
+
+ /**
+ * Gets the file data.
+ *
+ * @return the file data
+ */
+ public AppleFileData getFileData() {
+ return fileData;
+ }
+
+ /**
+ * Sets the file data.
+ *
+ * @param fileData
+ * the new file data
+ */
+ public void setFileData(AppleFileData fileData) {
+ this.fileData = fileData;
+ }
+
+ /**
+ * Gets the data fork.
+ *
+ * @return the data fork
+ */
+ public AppleFileData getDataFork() {
+ return dataFork;
+ }
+
+ /**
+ * Sets the data fork.
+ *
+ * @param dataFork
+ * the new data fork
+ */
+ public void setDataFork(AppleFileData dataFork) {
+ this.dataFork = dataFork;
+ }
+
+ /**
+ * Gets the resource fork.
+ *
+ * @return the resource fork
+ */
+ public AppleFileData getResourceFork() {
+ return resourceFork;
+ }
+
+ /**
+ * Sets the resource fork.
+ *
+ * @param resourceFork
+ * the new resource fork
+ */
+ public void setResourceFork(AppleFileData resourceFork) {
+ this.resourceFork = resourceFork;
+ }
+
+ /**
+ * Gets the real name.
+ *
+ * @return the real name
+ */
+ public AppleFileData getRealName() {
+ return realName;
+ }
+
+ /**
+ * Sets the real name.
+ *
+ * @param realName
+ * the new real name
+ */
+ public void setRealName(AppleFileData realName) {
+ this.realName = realName;
+ }
+
+ /**
+ * Gets the comment.
+ *
+ * @return the comment
+ */
+ public AppleFileData getComment() {
+ return comment;
+ }
+
+ /**
+ * Sets the comment.
+ *
+ * @param comment
+ * the new comment
+ */
+ public void setComment(AppleFileData comment) {
+ this.comment = comment;
+ }
+
+ /**
+ * Gets the icon bw.
+ *
+ * @return the icon bw
+ */
+ public AppleFileData getIconBW() {
+ return iconBW;
+ }
+
+ /**
+ * Sets the icon bw.
+ *
+ * @param iconBW
+ * the new icon bw
+ */
+ public void setIconBW(AppleFileData iconBW) {
+ this.iconBW = iconBW;
+ }
+
+ /**
+ * Gets the icon color.
+ *
+ * @return the icon color
+ */
+ public AppleFileData getIconColor() {
+ return iconColor;
+ }
+
+ /**
+ * Sets the icon color.
+ *
+ * @param iconColor
+ * the new icon color
+ */
+ public void setIconColor(AppleFileData iconColor) {
+ this.iconColor = iconColor;
+ }
+
+ /**
+ * Gets the file dates info.
+ *
+ * @return the file dates info
+ */
+ public AppleFileData getFileDatesInfo() {
+ return fileDatesInfo;
+ }
+
+ /**
+ * Sets the file dates info.
+ *
+ * @param fileDatesInfo
+ * the new file dates info
+ */
+ public void setFileDatesInfo(AppleFileData fileDatesInfo) {
+ this.fileDatesInfo = fileDatesInfo;
+ }
+
+ /**
+ * Gets the finder info.
+ *
+ * @return the finder info
+ */
+ public AppleFileData getFinderInfo() {
+ return finderInfo;
+ }
+
+ /**
+ * Sets the finder info.
+ *
+ * @param finderInfo
+ * the new finder info
+ */
+ public void setFinderInfo(AppleFileData finderInfo) {
+ this.finderInfo = finderInfo;
+ }
+
+ /**
+ * Gets the macintosh info.
+ *
+ * @return the macintosh info
+ */
+ public AppleFileData getMacintoshInfo() {
+ return macintoshInfo;
+ }
+
+ /**
+ * Sets the macintosh info.
+ *
+ * @param macintoshInfo
+ * the new macintosh info
+ */
+ public void setMacintoshInfo(AppleFileData macintoshInfo) {
+ this.macintoshInfo = macintoshInfo;
+ }
+
+ /**
+ * Gets the pro dos file info.
+ *
+ * @return the pro dos file info
+ */
+ public AppleFileData getProDOSFileInfo() {
+ return proDOSFileInfo;
+ }
+
+ /**
+ * Sets the pro dos file info.
+ *
+ * @param proDOSFileInfo
+ * the new pro dos file info
+ */
+ public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
+ this.proDOSFileInfo = proDOSFileInfo;
+ }
+
+ /**
+ * Gets the ms dos file info.
+ *
+ * @return the ms dos file info
+ */
+ public AppleFileData getMsDOSFileInfo() {
+ return msDOSFileInfo;
+ }
+
+ /**
+ * Sets the ms dos file info.
+ *
+ * @param msDOSFileInfo
+ * the new ms dos file info
+ */
+ public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
+ this.msDOSFileInfo = msDOSFileInfo;
+ }
+
+ /**
+ * Gets the short name.
+ *
+ * @return the short name
+ */
+ public AppleFileData getShortName() {
+ return shortName;
+ }
+
+ /**
+ * Sets the short name.
+ *
+ * @param shortName
+ * the new short name
+ */
+ public void setShortName(AppleFileData shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * Gets the afp file info.
+ *
+ * @return the afp file info
+ */
+ public AppleFileData getAfpFileInfo() {
+ return afpFileInfo;
+ }
+
+ /**
+ * Sets the afp file info.
+ *
+ * @param afpFileInfo
+ * the new afp file info
+ */
+ public void setAfpFileInfo(AppleFileData afpFileInfo) {
+ this.afpFileInfo = afpFileInfo;
+ }
+
+ /**
+ * Gets the directory id.
+ *
+ * @return the directory id
+ */
+ public AppleFileData getDirectoryID() {
+ return directoryID;
+ }
+
+ /**
+ * Sets the directory id.
+ *
+ * @param directoryID
+ * the new directory id
+ */
+ public void setDirectoryID(AppleFileData directoryID) {
+ this.directoryID = directoryID;
+ }
+
+ /**
+ * Gets the num entries.
+ *
+ * @return the num entries
+ */
+ public int getNumEntries() {
+ return numEntries;
+ }
}
\ No newline at end of file
diff --git a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
index f28c979a..d89471e2 100644
--- a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
+++ b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
@@ -1,91 +1,91 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-/**
- * This class is for representing the AppleSingle/Double file or its file forks
- * (data fork and resource fork) and the related Finder meta-file information.
- */
-public final class AppleFileData {
-
- public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
- private byte[] data;
- private int offset;
- private int length;
-
- /**
- * Instantiates a new apple file data.
- */
- public AppleFileData() {
- this.data = new byte[0];
- this.offset = 0;
- this.length = 0;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- */
- public AppleFileData(byte[] data) {
- this.data = data;
- this.offset = 0;
- this.length = data.length;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- public AppleFileData(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- /**
- * Gets the bytes.
- *
- * @return the bytes
- */
- public byte[] getBytes() {
- byte[] data = new byte[this.length];
- System.arraycopy(this.data, this.offset, data, 0, this.length);
- return data;
- }
-
- /**
- * Gets the data.
- *
- * @return the data
- */
- public byte[] getData() {
- return this.data;
- }
-
- /**
- * Gets the offset.
- *
- * @return the offset
- */
- public int getOffset() {
- return this.offset;
- }
-
- /**
- * Gets the length.
- *
- * @return the length
- */
- public int getLength() {
- return this.length;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+/**
+ * This class is for representing the AppleSingle/Double file or its file forks
+ * (data fork and resource fork) and the related Finder meta-file information.
+ */
+public final class AppleFileData {
+
+ public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
+ private byte[] data;
+ private int offset;
+ private int length;
+
+ /**
+ * Instantiates a new apple file data.
+ */
+ public AppleFileData() {
+ this.data = new byte[0];
+ this.offset = 0;
+ this.length = 0;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ */
+ public AppleFileData(byte[] data) {
+ this.data = data;
+ this.offset = 0;
+ this.length = data.length;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ public AppleFileData(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the bytes.
+ *
+ * @return the bytes
+ */
+ public byte[] getBytes() {
+ byte[] data = new byte[this.length];
+ System.arraycopy(this.data, this.offset, data, 0, this.length);
+ return data;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * Gets the offset.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ /**
+ * Gets the length.
+ *
+ * @return the length
+ */
+ public int getLength() {
+ return this.length;
+ }
}
\ No newline at end of file
diff --git a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
index 3248f85d..aa7b0363 100644
--- a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
+++ b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
@@ -1,143 +1,143 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This class handles the extraction of the data fork, resource fork and other
- * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
- * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
- * file type is a compressed AppleDouble (Mac resource fork) file.
- */
-public class AppleFileDecoder extends AppleFile {
-
- /**
- * Instantiates a new apple file decoder.
- *
- * @param fileData
- * the file data
- */
- public AppleFileDecoder(AppleFileData fileData) {
- if (fileData != null) {
- this.fileData = fileData;
- }
- }
-
- /**
- * Extract the data fork, resource fork and other entries from the Apple
- * file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- public void extract() throws FileDecoderException {
- // Verify the validity of the Apple file
- verify();
-
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int contentPosition = 0;
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- for (int i = 0; i < this.numEntries; i++) {
- contentPosition = offset + 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
-
- switch (entryId) {
- case 1:
- this.dataFork = new AppleFileData(data, offset + entryOffset,
- entryLength);
- break;
- case 2:
- this.resourceFork = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 3:
- this.realName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 4:
- this.comment = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 5:
- this.iconBW = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 6:
- this.iconColor = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 8:
- this.fileDatesInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- extractFileDates(data, offset + entryOffset, entryLength);
- break;
- case 9:
- this.finderInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 10:
- this.macintoshInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 11:
- this.proDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 12:
- this.msDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 13:
- this.shortName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 14:
- this.afpFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 15:
- this.directoryID = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- default:
- Log.warn("Apple file entry ID: " + entryId + " is not handled.");
-
- }
- }
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This class handles the extraction of the data fork, resource fork and other
+ * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
+ * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
+ * file type is a compressed AppleDouble (Mac resource fork) file.
+ */
+public class AppleFileDecoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @param fileData
+ * the file data
+ */
+ public AppleFileDecoder(AppleFileData fileData) {
+ if (fileData != null) {
+ this.fileData = fileData;
+ }
+ }
+
+ /**
+ * Extract the data fork, resource fork and other entries from the Apple
+ * file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ public void extract() throws FileDecoderException {
+ // Verify the validity of the Apple file
+ verify();
+
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int contentPosition = 0;
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ for (int i = 0; i < this.numEntries; i++) {
+ contentPosition = offset + 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+
+ switch (entryId) {
+ case 1:
+ this.dataFork = new AppleFileData(data, offset + entryOffset,
+ entryLength);
+ break;
+ case 2:
+ this.resourceFork = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 3:
+ this.realName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 4:
+ this.comment = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 5:
+ this.iconBW = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 6:
+ this.iconColor = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 8:
+ this.fileDatesInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ extractFileDates(data, offset + entryOffset, entryLength);
+ break;
+ case 9:
+ this.finderInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 10:
+ this.macintoshInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 11:
+ this.proDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 12:
+ this.msDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 13:
+ this.shortName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 14:
+ this.afpFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 15:
+ this.directoryID = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ default:
+ Log.warn("Apple file entry ID: " + entryId + " is not handled.");
+
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
index 7c5d0a04..abdfed59 100644
--- a/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
+++ b/p4java/r18-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
@@ -1,300 +1,300 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.exception.FileEncoderException;
-
-/**
- * This class handles the combination of the data fork, resource fork and other
- * entries into an AppleSingle/Double file.
- *
+ *
+ * Note that if it is an AppleDouble, the data fork is a separate file external
+ * to this file.
+ */
+public class AppleFileEncoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @throws FileEncoderException
+ */
+ public AppleFileEncoder(FileFormat fileFormat) throws FileEncoderException {
+ if (fileFormat == null) {
+ throw new FileEncoderException("Null file format passed to the AppleFileEncoder constructor.");
+ }
+ if (fileFormat == FileFormat.UNKNOWN) {
+ throw new FileEncoderException("Unknown file format passed to the AppleFileEncoder constructor.");
+ }
+ }
+
+ /**
+ * Combine the data fork, resource fork and other entries into an
+ * AppleSingle/Double file.
+ *
+ * @throws FileEncoderException
+ * the file encoder exception
+ */
+ @SuppressWarnings("unused")
+ public void combine() throws FileEncoderException {
+
+ boolean isAppleSingle = (this.format == FileFormat.APPLE_SINGLE);
+ boolean isAppleDouble = (this.format == FileFormat.APPLE_DOUBLE);
+
+ boolean hasDataFork = (this.dataFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasResourceFork = (this.resourceFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasRealName = (this.realName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasComment = (this.comment != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconBW = (this.iconBW != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconColor = (this.iconColor != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasFileDatesInfo = (this.fileDatesInfoEntry != null);
+ boolean hasFinderInfo = (this.finderInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMacintoshInfo = (this.macintoshInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasProDOSFileInfo = (this.proDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMsDOSFileInfo = (this.msDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasShortName = (this.shortName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasAfpFileInfo = (this.afpFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasDirectoryID = (this.directoryID != AppleFileData.EMPTY_FILE_DATA);
+
+ this.fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ int length = 90 + this.realName.getLength()
+ + this.resourceFork.getLength();
+
+ /* AppleSingle includes the data fork */
+ if (isAppleSingle) {
+ length += this.dataFork.getLength();
+ }
+
+ byte[] data = new byte[length];
+ int position = 0;
+
+ /* Magic number for AppleSingle or AppleDouble */
+ if (isAppleDouble) {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 0;
+ } else {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 7;
+ }
+
+ /* Version number */
+ data[(position++)] = 0;
+ data[(position++)] = 2;
+ data[(position++)] = 0;
+ data[(position++)] = 0;
+
+ /* Filler */
+
+ for (int k = 0; k < 16; k++) {
+ data[(position++)] = 0;
+ }
+
+ /* Number of entries */
+ this.numEntries = 0;
+ if (hasRealName) {
+ this.numEntries += 1;
+ }
+ if (hasFileDatesInfo) {
+ this.numEntries += 1;
+ }
+ if (hasResourceFork) {
+ this.numEntries += 1;
+ }
+ if ((hasDataFork) && (isAppleSingle)) {
+ this.numEntries += 1;
+ }
+ data[(position++)] = ((byte) (this.numEntries >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.numEntries & 0xFF));
+
+ /* Header information for the entries */
+
+ /* Real name entry header */
+ int realNamePosition = 0;
+ if (hasRealName) {
+ int realNameEntryId = 3;
+ int realNameEntryOffset = 0;
+ int realNameEntryLength = this.realName.getLength();
+ data[(position++)] = ((byte) (realNameEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 0 & 0xFF));
+ realNamePosition = position;
+ data[(position++)] = ((byte) (realNameEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 0 & 0xFF));
+ }
+
+ /* File dates info entry header */
+ int fileDatesInfoPosition = 0;
+ if (hasFileDatesInfo) {
+ int fileDatesInfoEntryId = 8;
+ int fileDatesInfoEntryOffset = 0;
+ int fileDatesInfoEntryLength = 16;
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 0 & 0xFF));
+ fileDatesInfoPosition = position;
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 0 & 0xFF));
+ }
+
+ /* Resource fork entry header */
+ int resourceForkPosition = 0;
+ if (hasResourceFork) {
+ int resourceForkEntryId = 2;
+ int resourceForkEntryOffset = 0;
+ int resourceFokrEntryLength = this.resourceFork.getLength();
+ data[(position++)] = ((byte) (resourceForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 0 & 0xFF));
+ resourceForkPosition = position;
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 0 & 0xFF));
+ }
+
+ /* Data fork entry header */
+ int dataForkPosition = 0;
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkEntryId = 1;
+ int dataForkEntryOffset = 0;
+ int dataForkEntryLength = this.dataFork.getLength();
+ data[(position++)] = ((byte) (dataForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 0 & 0xFF));
+ dataForkPosition = position;
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 0 & 0xFF));
+ }
+
+ /* Content for the entries */
+
+ /* Real name content */
+ if (hasRealName) {
+ int realNamePositionCurrent = position;
+ position = realNamePosition;
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 0 & 0xFF));
+ position = realNamePositionCurrent;
+ byte[] realNameData = this.realName.getData();
+ int realNameOffset = this.realName.getOffset();
+ int realNameLength = this.realName.getLength();
+ System.arraycopy(realNameData, realNameOffset, data, position,
+ realNameLength);
+ position += realNameLength;
+ }
+
+ /* File dates info content */
+ if (hasFileDatesInfo) {
+ int fileDatesInfoPositionCurrent = position;
+ position = fileDatesInfoPosition;
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 0 & 0xFF));
+ position = fileDatesInfoPositionCurrent;
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 0 & 0xFF));
+ }
+
+ /* Resource fork content */
+ if (hasResourceFork) {
+ int resourceForkPositionCurrent = position;
+ position = resourceForkPosition;
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 0 & 0xFF));
+ position = resourceForkPositionCurrent;
+ byte[] resourceForkData = this.resourceFork.getData();
+ int resourceForkOffset = this.resourceFork.getOffset();
+ int resourceForkLength = this.resourceFork.getLength();
+ System.arraycopy(resourceForkData, resourceForkOffset, data,
+ position, resourceForkLength);
+ position += resourceForkLength;
+ }
+
+ /* Data fork content */
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkPosition2 = position;
+ position = dataForkPosition;
+ data[(position++)] = ((byte) (dataForkPosition2 >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 0 & 0xFF));
+ position = dataForkPosition2;
+ byte[] dataForkData = this.dataFork.getData();
+ int dataForkOffset = this.dataFork.getOffset();
+ int dataForkLength = this.dataFork.getLength();
+ System.arraycopy(dataForkData, dataForkOffset, data, position,
+ dataForkLength);
+ position += dataForkLength;
+ }
+
+ /* Create the Apple file data */
+ this.fileData = new AppleFileData(data, 0, position);
+ }
}
\ No newline at end of file
diff --git a/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java b/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java
index 59a9a133..1c224364 100644
--- a/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java
+++ b/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/bug/r132/CreateSymbolicLinkTest.java
@@ -1,54 +1,54 @@
-package com.perforce.p4java.tests.dev.unit.bug.r132;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-
-import org.junit.jupiter.api.Test;
-import org.junit.platform.runner.JUnitPlatform;
-import org.junit.runner.RunWith;
-
-import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
-import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
-
-/**
- * Test create symbolic link with non-existing target.
- */
-@RunWith(JUnitPlatform.class)
-public class CreateSymbolicLinkTest extends P4JavaTestCase {
- /**
- * Test create symbolic link with non-existing target.
- */
- @Test
- public void testCreateSymbolicLink() throws IOException {
- // Check if symlink capable (JDK 7 or above)
- if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
- String target = File.createTempFile("link-to-me", ".tmp").getAbsolutePath();
- String link = System.getProperty("java.io.tmpdir") + "/p4java-bin-" + getRandomInt();
-
- // Create symbolic link
- debugPrint("Creating link " + link + " to " + target);
- String path = SymbolicLinkHelper.createSymbolicLink(link, target);
- assertNotNull("Failed to create a symbolic link from " + link + " to " + target);
- assertTrue(path + " is not a symbolic link", SymbolicLinkHelper.isSymbolicLink(path));
-
- debugPrint("Creating a new file object for " + path);
- File file = new File(path);
- assertTrue("A new File object to " + path + " is not reported as a symbolic link.",
- Files.isSymbolicLink(file.toPath()));
- assertTrue("A new File object to " + path + " is not reported as not existing.",
- file.exists());
-
- debugPrint("Checking the parent path " + path);
- String parentPath = file.getParent();
- assertNotNull(file + " has not parent path.", parentPath);
-
- debugPrint("Deleting " + file);
- assertTrue("Failed to delete " + file.toPath(), Files.deleteIfExists(file.toPath()));
- }
- }
-
-}
+package com.perforce.p4java.tests.dev.unit.bug.r132;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import org.junit.jupiter.api.Test;
+import org.junit.platform.runner.JUnitPlatform;
+import org.junit.runner.RunWith;
+
+import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
+import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
+
+/**
+ * Test create symbolic link with non-existing target.
+ */
+@RunWith(JUnitPlatform.class)
+public class CreateSymbolicLinkTest extends P4JavaTestCase {
+ /**
+ * Test create symbolic link with non-existing target.
+ */
+ @Test
+ public void testCreateSymbolicLink() throws IOException {
+ // Check if symlink capable (JDK 7 or above)
+ if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
+ String target = File.createTempFile("link-to-me", ".tmp").getAbsolutePath();
+ String link = System.getProperty("java.io.tmpdir") + "/p4java-bin-" + getRandomInt();
+
+ // Create symbolic link
+ debugPrint("Creating link " + link + " to " + target);
+ String path = SymbolicLinkHelper.createSymbolicLink(link, target);
+ assertNotNull("Failed to create a symbolic link from " + link + " to " + target);
+ assertTrue(path + " is not a symbolic link", SymbolicLinkHelper.isSymbolicLink(path));
+
+ debugPrint("Creating a new file object for " + path);
+ File file = new File(path);
+ assertTrue("A new File object to " + path + " is not reported as a symbolic link.",
+ Files.isSymbolicLink(file.toPath()));
+ assertTrue("A new File object to " + path + " is not reported as not existing.",
+ file.exists());
+
+ debugPrint("Checking the parent path " + path);
+ String parentPath = file.getParent();
+ assertNotNull(file + " has not parent path.", parentPath);
+
+ debugPrint("Deleting " + file);
+ assertTrue("Failed to delete " + file.toPath(), Files.deleteIfExists(file.toPath()));
+ }
+ }
+
+}
diff --git a/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java b/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
index bab7e806..978db638 100644
--- a/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
+++ b/p4java/r18-1/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
@@ -1,83 +1,83 @@
-/**
- * Copyright (c) 2012 Perforce Software. All rights reserved.
- */
-package com.perforce.p4java.tests.dev.unit.features123;
-
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
-import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
-
-/**
- * Test symbolic link helper (JDK 7 or above)
- */
-public class SymbolicLinkHelperTest extends P4JavaTestCase {
-
- /**
- * @BeforeClass annotation to a method to be run before all the tests in a
- * class.
- */
- @BeforeClass
- public static void oneTimeSetUp() {
- // one-time initialization code (before all the tests).
- }
-
- /**
- * @AfterClass annotation to a method to be run after all the tests in a
- * class.
- */
- @AfterClass
- public static void oneTimeTearDown() {
- // one-time cleanup code (after all the tests).
- }
-
- /**
- * @Before annotation to a method to be run before each test in a class.
- */
- @Before
- public void setUp() {
- // initialization code (before each test).
- }
-
- /**
- * @After annotation to a method to be run after each test in a class.
- */
- @After
- public void tearDown() {
- // cleanup code (after each test).
- }
-
- /**
- * Test symbolic link
- */
- @Test
- public void tesSymbolicLink() {
- // Check if symlink capable
- if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
-
- String target = "/usr/bin";
- String link = "/tmp/user-bin-" + getRandomInt();
-
- // Create symbolic link
- Object path = SymbolicLinkHelper.createSymbolicLink(link, target);
-
- boolean isSymlink = SymbolicLinkHelper.isSymbolicLink(path
- .toString());
- assertTrue(isSymlink);
-
- File file = new File(path.toString());
- if (file.exists()) {
- file.delete();
- }
- }
- }
-
-}
+/**
+ * Copyright (c) 2012 Perforce Software. All rights reserved.
+ */
+package com.perforce.p4java.tests.dev.unit.features123;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
+import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
+
+/**
+ * Test symbolic link helper (JDK 7 or above)
+ */
+public class SymbolicLinkHelperTest extends P4JavaTestCase {
+
+ /**
+ * @BeforeClass annotation to a method to be run before all the tests in a
+ * class.
+ */
+ @BeforeClass
+ public static void oneTimeSetUp() {
+ // one-time initialization code (before all the tests).
+ }
+
+ /**
+ * @AfterClass annotation to a method to be run after all the tests in a
+ * class.
+ */
+ @AfterClass
+ public static void oneTimeTearDown() {
+ // one-time cleanup code (after all the tests).
+ }
+
+ /**
+ * @Before annotation to a method to be run before each test in a class.
+ */
+ @Before
+ public void setUp() {
+ // initialization code (before each test).
+ }
+
+ /**
+ * @After annotation to a method to be run after each test in a class.
+ */
+ @After
+ public void tearDown() {
+ // cleanup code (after each test).
+ }
+
+ /**
+ * Test symbolic link
+ */
+ @Test
+ public void tesSymbolicLink() {
+ // Check if symlink capable
+ if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
+
+ String target = "/usr/bin";
+ String link = "/tmp/user-bin-" + getRandomInt();
+
+ // Create symbolic link
+ Object path = SymbolicLinkHelper.createSymbolicLink(link, target);
+
+ boolean isSymlink = SymbolicLinkHelper.isSymbolicLink(path
+ .toString());
+ assertTrue(isSymlink);
+
+ File file = new File(path.toString());
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+ }
+
+}
diff --git a/p4java/r19-1/LICENSE.txt b/p4java/r19-1/LICENSE.txt
index 5309eefb..d67531fa 100644
--- a/p4java/r19-1/LICENSE.txt
+++ b/p4java/r19-1/LICENSE.txt
@@ -1,282 +1,282 @@
-Copyright (c) 2009-2016, Perforce Software, Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-License of included (com.jcraft) jzlib library:
-------------------------------------------------------------------------------
-
-Copyright (c) 2000-2016 ymnk, JCraft,Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the distribution.
-
- 3. The names of the authors may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
-INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
-OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-License of included (org.apache.commons) commons-lang3:
-License of included (commons-io) commons-io:
-------------------------------------------------------------------------------
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
-License of included (com.google.code.findbugs) jsr305
-------------------------------------------------------------------------------
-
-The JSR-305 reference implementation (lib/jsr305.jar) is
-distributed under the terms of the New BSD license:
-
- http://www.opensource.org/licenses/bsd-license.php
-
-See the JSR-305 home page for more information:
-
- http://code.google.com/p/jsr-305/
-
-
-License of included (com.google.code.findbugs) jsr305
-------------------------------------------------------------------------------
-
-Copyright (c) 2005 Brian Goetz
-Released under the Creative Commons Attribution License
- (http://creativecommons.org/licenses/by/2.5)
-Official home: http://www.jcip.net
-
+Copyright (c) 2009-2016, Perforce Software, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+License of included (com.jcraft) jzlib library:
+------------------------------------------------------------------------------
+
+Copyright (c) 2000-2016 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+License of included (org.apache.commons) commons-lang3:
+License of included (commons-io) commons-io:
+------------------------------------------------------------------------------
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+License of included (com.google.code.findbugs) jsr305
+------------------------------------------------------------------------------
+
+The JSR-305 reference implementation (lib/jsr305.jar) is
+distributed under the terms of the New BSD license:
+
+ http://www.opensource.org/licenses/bsd-license.php
+
+See the JSR-305 home page for more information:
+
+ http://code.google.com/p/jsr-305/
+
+
+License of included (com.google.code.findbugs) jsr305
+------------------------------------------------------------------------------
+
+Copyright (c) 2005 Brian Goetz
+Released under the Creative Commons Attribution License
+ (http://creativecommons.org/licenses/by/2.5)
+Official home: http://www.jcip.net
+
diff --git a/p4java/r19-1/pom.xml b/p4java/r19-1/pom.xml
index ef41cf03..86ca474b 100644
--- a/p4java/r19-1/pom.xml
+++ b/p4java/r19-1/pom.xml
@@ -1,126 +1,126 @@
-
- 4.0.0
- com.perforce
- p4java
- jar
- 2019.1.1939255
- Perforce Java API
- http://www.perforce.com
-
-
- Perforce Software
- http://www.perforce.com
-
-
-
- P4Java, the Perforce Java API is a Java-native API for accessing Perforce SCM services from
- within Java applications, servlets, plug-ins, and other Java contexts.
-
-
-
-
- Perforce Software
- LICENSE.txt
- repo
-
-
-
-
- scm:perforce:workshop.perforce.com:1666//guest/perforce_software/p4java
-
-
- scm:perforce:workshop.perforce.com:1666//guest/perforce_software/p4java
-
- https://swarm.workshop.perforce.com/files/guest/perforce_software/p4java
-
-
-
-
- p4java
- Perforce Software
- support+java@perforce.com
-
-
-
-
- 1.7
- 1.7
- UTF-8
- 0
- releases
- 1.6.5
- 4.12
- 5.0.0-M2
- 4.12.0-M2
- 1.0.0-M2
-
-
-
-
- com.jcraft
- jzlib
- 1.1.3
-
-
- org.apache.commons
- commons-lang3
- 3.4
-
-
- org.apache.commons
- commons-exec
- 1.3
-
-
- commons-codec
- commons-codec
- 1.13
-
-
- commons-io
- commons-io
- 2.5
-
-
- com.google.code.findbugs
- jsr305
- 3.0.1
-
-
- org.slf4j
- slf4j-api
- 1.7.24
-
-
- org.slf4j
- slf4j-simple
- 1.7.24
-
-
- org.apache.commons
- commons-compress
- 1.9
- test
-
-
- junit
- junit
- ${junit.version}
- test
-
-
- org.mockito
- mockito-core
- 2.7.12
- test
-
-
- com.googlecode.java-diff-utils
- diffutils
- 1.3.0
- test
-
-
-
+
+ 4.0.0
+ com.perforce
+ p4java
+ jar
+ 2019.1.1939255
+ Perforce Java API
+ http://www.perforce.com
+
+
+ Perforce Software
+ http://www.perforce.com
+
+
+
+ P4Java, the Perforce Java API is a Java-native API for accessing Perforce SCM services from
+ within Java applications, servlets, plug-ins, and other Java contexts.
+
+
+
+
+ Perforce Software
+ LICENSE.txt
+ repo
+
+
+
+
+ scm:perforce:workshop.perforce.com:1666//guest/perforce_software/p4java
+
+
+ scm:perforce:workshop.perforce.com:1666//guest/perforce_software/p4java
+
+ https://swarm.workshop.perforce.com/files/guest/perforce_software/p4java
+
+
+
+
+ p4java
+ Perforce Software
+ support+java@perforce.com
+
+
+
+
+ 1.7
+ 1.7
+ UTF-8
+ 0
+ releases
+ 1.6.5
+ 4.12
+ 5.0.0-M2
+ 4.12.0-M2
+ 1.0.0-M2
+
+
+
+
+ com.jcraft
+ jzlib
+ 1.1.3
+
+
+ org.apache.commons
+ commons-lang3
+ 3.4
+
+
+ org.apache.commons
+ commons-exec
+ 1.3
+
+
+ commons-codec
+ commons-codec
+ 1.13
+
+
+ commons-io
+ commons-io
+ 2.5
+
+
+ com.google.code.findbugs
+ jsr305
+ 3.0.1
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.24
+
+
+ org.slf4j
+ slf4j-simple
+ 1.7.24
+
+
+ org.apache.commons
+ commons-compress
+ 1.9
+ test
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+ org.mockito
+ mockito-core
+ 2.7.12
+ test
+
+
+ com.googlecode.java-diff-utils
+ diffutils
+ 1.3.0
+ test
+
+
+
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/.project b/p4java/r19-1/src/main/java/com/perforce/p4java/.project
index c34e3af2..145b7c98 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/.project
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/.project
@@ -1,11 +1,11 @@
-
-
- p4java
-
-
-
-
-
-
-
-
+
+
+ p4java
+
+
+
+
+
+
+
+
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/client/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/client/package.html
index f505bba5..83a680a3 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/client/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/client/package.html
@@ -1,12 +1,12 @@
-
-
-
-
-
-Provides interfaces for accessing and manipulating Perforce client workspaces and associated objects.
-
-The com.perforce.p4j.client package publicly defines Perforce client workspaces and the various
-associated interfaces and operations. Perforce client workspaces (a.k.a. "clients" where
-this usage isn't ambiguous) are defined in detail in the main Perforce documentation.
-
+
+
+
+
+
+Provides interfaces for accessing and manipulating Perforce client workspaces and associated objects.
+
+The com.perforce.p4j.client package publicly defines Perforce client workspaces and the various
+associated interfaces and operations. Perforce client workspaces (a.k.a. "clients" where
+this usage isn't ambiguous) are defined in detail in the main Perforce documentation.
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/core/file/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/core/file/package.html
index 51f991b8..4085f9e7 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/core/file/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/core/file/package.html
@@ -1,8 +1,8 @@
-
-
-
-
-
-Provides interfaces and classes for defining and accessing Perforce depot and workspace files.
-
+
+
+
+
+
+Provides interfaces and classes for defining and accessing Perforce depot and workspace files.
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/core/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/core/package.html
index 507047c0..f209af70 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/core/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/core/package.html
@@ -1,10 +1,10 @@
-
-
-
-
-
-Provides interfaces and classes for defining and accessing Perforce objects
-such as jobs, changelists, etc., and, through the file sub-package, Perforce
-files.
-
+
+
+
+
+
+Provides interfaces and classes for defining and accessing Perforce objects
+such as jobs, changelists, etc., and, through the file sub-package, Perforce
+files.
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/exception/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/exception/package.html
index f6c27bad..5f833c07 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/exception/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/exception/package.html
@@ -1,19 +1,19 @@
-
-
-
-
-
-Provides exception and error classes for signaling and handling user, internal, and Perforce server errors.
-
-P4Java uses a fairly standard set of extensions to java.lang.Exception to signal recoverable errors,
-but it also uses extensions to java.lang.Error to signal unrecoverable errors that it's detected itself
-(such as null pointers or out-of-range values). Since they're defined as extensions to Error, they're
-not typically declared in method "throws" clauses, which means users are free to ignore them in the same
-way that they can ignore non-P4Java Error throwables.
-
-However, if you wish to keep control in the face of all possible errors,
-it's probably a good idea to keep an outer catch block for P4JError catching as well as other exceptions
-and throwables — P4Java does not throw such errors lightly, only for conditions that
-show a serious programming error (either internally or by the user).
-
+
+
+
+
+
+Provides exception and error classes for signaling and handling user, internal, and Perforce server errors.
+
+P4Java uses a fairly standard set of extensions to java.lang.Exception to signal recoverable errors,
+but it also uses extensions to java.lang.Error to signal unrecoverable errors that it's detected itself
+(such as null pointers or out-of-range values). Since they're defined as extensions to Error, they're
+not typically declared in method "throws" clauses, which means users are free to ignore them in the same
+way that they can ignore non-P4Java Error throwables.
+
+However, if you wish to keep control in the face of all possible errors,
+it's probably a good idea to keep an outer catch block for P4JError catching as well as other exceptions
+and throwables — P4Java does not throw such errors lightly, only for conditions that
+show a serious programming error (either internally or by the user).
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/client/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/client/package.html
index a656eba1..1e9876a1 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/client/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/client/package.html
@@ -1,12 +1,12 @@
-
-
-
-
-
-Provides standard implementation classes for the com.perforce.p4java.client interfaces.
-Users are free to use implementations defined here for their own purposes, but such use
-is not mandatory, and nor should users rely on these implementations always being
-returned by the associated interfaces (P4Java reserves the right to change or extend
-implementations under the covers).
-
+
+
+
+
+
+Provides standard implementation classes for the com.perforce.p4java.client interfaces.
+Users are free to use implementations defined here for their own purposes, but such use
+is not mandatory, and nor should users rely on these implementations always being
+returned by the associated interfaces (P4Java reserves the right to change or extend
+implementations under the covers).
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/file/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/file/package.html
index 707a7478..00ee6844 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/file/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/file/package.html
@@ -1,12 +1,12 @@
-
-
-
-
-
-Provides standard implementation classes for the com.perforce.p4java.core.file interfaces.
-Users are free to use implementations defined here for their own purposes, but such use
-is not mandatory, and nor should users rely on these implementations always being
-returned by the associated interfaces (P4Java reserves the right to change or extend
-implementations under the covers).
-
+
+
+
+
+
+Provides standard implementation classes for the com.perforce.p4java.core.file interfaces.
+Users are free to use implementations defined here for their own purposes, but such use
+is not mandatory, and nor should users rely on these implementations always being
+returned by the associated interfaces (P4Java reserves the right to change or extend
+implementations under the covers).
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/package.html
index ad16efc8..99e0b3d8 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/core/package.html
@@ -1,12 +1,12 @@
-
-
-
-
-
-Provides standard implementation classes for the com.perforce.p4java.core interfaces.
-Users are free to use implementations defined here for their own purposes, but such use
-is not mandatory, and nor should users rely on these implementations always being
-returned by the associated interfaces (P4Java reserves the right to change or extend
-implementations under the covers).
-
+
+
+
+
+
+Provides standard implementation classes for the com.perforce.p4java.core interfaces.
+Users are free to use implementations defined here for their own purposes, but such use
+is not mandatory, and nor should users rely on these implementations always being
+returned by the associated interfaces (P4Java reserves the right to change or extend
+implementations under the covers).
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/package.html
index 5d4d58cd..c3b1ca6b 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/package.html
@@ -1,14 +1,14 @@
-
-
-
-
-
-Provides generic and / or canonical implementation classes for many of the standard
-P4Java client, server, and core interfaces.
-
-Users are free to use implementations defined here for their own purposes, but such use
-is not mandatory, and nor should users rely on these implementations always being
-returned by the associated interfaces (P4Java reserves the right to change or extend
-implementations under the covers).
-
+
+
+
+
+
+Provides generic and / or canonical implementation classes for many of the standard
+P4Java client, server, and core interfaces.
+
+Users are free to use implementations defined here for their own purposes, but such use
+is not mandatory, and nor should users rely on these implementations always being
+returned by the associated interfaces (P4Java reserves the right to change or extend
+implementations under the covers).
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/sys/package.html b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/sys/package.html
index cf50e533..1e754a94 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/sys/package.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/generic/sys/package.html
@@ -1,10 +1,10 @@
-
-
-
-
-
-Provides one or more "helper" and other classes to assist P4Java with
-typical operating system operations that can not always be done efficiently (or at all)
-in Java.
-
+
+
+
+
+
+Provides one or more "helper" and other classes to assist P4Java with
+typical operating system operations that can not always be done efficiently (or at all)
+in Java.
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
index 955735f4..75e9be6e 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/impl/mapbased/rpc/sys/helper/AppleFileHelper.java
@@ -1,118 +1,118 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
-import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
-import com.perforce.p4java.io.apple.AppleFileData;
-import com.perforce.p4java.io.apple.AppleFileDecoder;
-
-/**
- * Helper class for handling Apple files.
- */
-public class AppleFileHelper {
-
- /**
- * Extract the data fork and the resource fork from the Apple file.
- *
- * @param file the Apple file
- */
- public static void extractFile(RpcPerforceFile file) {
- if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
- FileOutputStream fosData = null;
- FileOutputStream fosResource = null;
- try {
- byte[] data = AppleFileHelper.getBytesFromFile(file);
- AppleFileData fileData = new AppleFileData(data);
- AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
- appleFile.extract();
- fosData = new FileOutputStream(file);
- AppleFileData forkData = appleFile.getDataFork();
- if (forkData != AppleFileData.EMPTY_FILE_DATA) {
- fosData.write(forkData.getBytes());
- }
- String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
- RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
- fosResource = new FileOutputStream(targetResourceFile);
- AppleFileData forkResource = appleFile.getResourceFork();
- if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
- fosResource.write(forkResource.getBytes());
- }
- } catch (IOException e) {
- Log.error("Problem handling the Apple file: " + file.getName());
- } catch (FileDecoderException e) {
- Log.error("Problem decoding the Apple file: " + file.getName());
- } finally {
- if (fosData != null) {
- try {
- fosData.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- if (fosResource != null) {
- try {
- fosResource.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- }
- }
- }
-
- /**
- * Gets the bytes from file.
- *
- * @param file
- * the file
- * @return the bytes from file
- * @throws IOException
- * Signals that an I/O exception has occurred.
- */
- public static byte[] getBytesFromFile(File file) throws IOException {
- InputStream is = new FileInputStream(file);
-
- long length = file.length();
- if (length > Integer.MAX_VALUE) {
- // File is too large
- throw new IOException("Apple file too large for decoding.");
- }
-
- byte[] bytes = new byte[(int) length];
- int offset = 0;
- int numRead = 0;
-
- try {
- while (offset < bytes.length
- && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
- offset += numRead;
- }
- // Ensure all the bytes have been read in
- if (offset < bytes.length) {
- throw new IOException(
- "Could not completely read the Apple file "
- + file.getName());
- }
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- // Do nothing
- }
- }
- }
-
- return bytes;
- }
-}
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.impl.mapbased.rpc.sys.helper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFile;
+import com.perforce.p4java.impl.mapbased.rpc.sys.RpcPerforceFileType;
+import com.perforce.p4java.io.apple.AppleFileData;
+import com.perforce.p4java.io.apple.AppleFileDecoder;
+
+/**
+ * Helper class for handling Apple files.
+ */
+public class AppleFileHelper {
+
+ /**
+ * Extract the data fork and the resource fork from the Apple file.
+ *
+ * @param file the Apple file
+ */
+ public static void extractFile(RpcPerforceFile file) {
+ if (file.getFileType() == RpcPerforceFileType.FST_APPLEFILE) {
+ FileOutputStream fosData = null;
+ FileOutputStream fosResource = null;
+ try {
+ byte[] data = AppleFileHelper.getBytesFromFile(file);
+ AppleFileData fileData = new AppleFileData(data);
+ AppleFileDecoder appleFile = new AppleFileDecoder(fileData);
+ appleFile.extract();
+ fosData = new FileOutputStream(file);
+ AppleFileData forkData = appleFile.getDataFork();
+ if (forkData != AppleFileData.EMPTY_FILE_DATA) {
+ fosData.write(forkData.getBytes());
+ }
+ String resourceFilePath = file.getParent() + File.separator + "%" + file.getName();
+ RpcPerforceFile targetResourceFile = new RpcPerforceFile(resourceFilePath, file.getFileType());
+ fosResource = new FileOutputStream(targetResourceFile);
+ AppleFileData forkResource = appleFile.getResourceFork();
+ if (forkResource != AppleFileData.EMPTY_FILE_DATA) {
+ fosResource.write(forkResource.getBytes());
+ }
+ } catch (IOException e) {
+ Log.error("Problem handling the Apple file: " + file.getName());
+ } catch (FileDecoderException e) {
+ Log.error("Problem decoding the Apple file: " + file.getName());
+ } finally {
+ if (fosData != null) {
+ try {
+ fosData.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ if (fosResource != null) {
+ try {
+ fosResource.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the bytes from file.
+ *
+ * @param file
+ * the file
+ * @return the bytes from file
+ * @throws IOException
+ * Signals that an I/O exception has occurred.
+ */
+ public static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+
+ long length = file.length();
+ if (length > Integer.MAX_VALUE) {
+ // File is too large
+ throw new IOException("Apple file too large for decoding.");
+ }
+
+ byte[] bytes = new byte[(int) length];
+ int offset = 0;
+ int numRead = 0;
+
+ try {
+ while (offset < bytes.length
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException(
+ "Could not completely read the Apple file "
+ + file.getName());
+ }
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ }
+ }
+
+ return bytes;
+ }
+}
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
index 5b89f33a..615bfcc9 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFile.java
@@ -1,735 +1,735 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This abstract class handles AppleSingle/Double files. It contains a common
- * method to verify the Apple file, and figure out if it is an AppleSingle or
- * AppleDouble formatted file.
- *
- *
- * The AppleSingle format is a representation of Macintosh files as one
- * consecutive stream of bytes. AppleSingle combines the data fork, resource
- * fork and the related Finder meta-file information into a single file.
- *
- *
- * The AppleDouble format stores the data fork, resource fork as two separate
- * files. AppleDouble leaves the data fork in its original format, and the
- * resource fork and Finder information were combined into a second file.
- *
- *
- * Apple defined the magic number for the AppleSingle format as 0x00051600, and
- * the magic number for the AppleDouble format as 0x00051607.
- *
- *
- * AppleSingle file header:
- *
- * Field Length
- * ----- ------
- * Magic number ------- 4 bytes
- * Version number ------ 4 bytes
- * Filler ------------- 16 bytes
- * Number of entries ----- 2 bytes
- *
- * Entry descriptor for each entry:
- * Entry ID ------ 4 bytes
- * Offset -------- 4 bytes
- * Length -------- 4 bytes
- *
- * Apple reserved entry IDs:
- *
- * Data Fork -------- 1 Data fork
- * Resource Fork ----- 2 Resource fork
- * Real Name -------- 3 File's name as created on home file system
- * Comment --------- 4 Standard Macintosh comment
- * Icon, B&W -------- 5 Standard Macintosh black and white icon
- * Icon, Color -------- 6 Macintosh color icon
- * File Dates Info ------8 File creation date, modification date, and so on
- * Finder Info -------- 9 Standard Macintosh Finder information
- * Macintosh File Info ---10 Macintosh file information, attributes, and so on
- * ProDOS File Info -----11 ProDOS file information, attributes, and so on
- * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
- * Short Name --------13 AFP short name
- * AFP File Info ------- 14 AFP file information, attributes, and so on
- * Directory ID --------15 AFP directory ID
- *
- *
- * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
- */
-public abstract class AppleFile {
-
- /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
- protected FileFormat format = FileFormat.UNKNOWN;
-
- /** The raw Apple file. */
- protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 1: Data fork. */
- protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 2: Resource fork. */
- protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 3: File's name as created on home file system. */
- protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 4: Standard Macintosh comment. */
- protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 5: Standard Macintosh black and white icon. */
- protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 6: Macintosh color icon. */
- protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 8: File creation date, modification date, and so on. */
- protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** The file dates info entry. */
- protected FileDatesInfoEntry fileDatesInfoEntry = null;
-
- /** Entry 9: Standard Macintosh Finder information. */
- protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 10: Macintosh file information, attributes, and so on. */
- protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 11: ProDOS file information, attributes, and so on. */
- protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 12: MS-DOS file information, attributes, and so on. */
- protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 13: AFP short name. */
- protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 14: AFP file information, attributes, and so on. */
- protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 15: AFP directory ID. */
- protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
-
- /** The num entries. */
- protected int numEntries = 0;
-
- /**
- * The Apple file format.
- */
- public enum FileFormat {
-
- APPLE_SINGLE,
- APPLE_DOUBLE,
- UNKNOWN;
-
- /**
- * Return a suitable Apple file format as inferred from the passed-in
- * string. Otherwise return the UNKNOWN file format.
- *
- * @param fileFormat
- * the file format
- * @return the FileFormat
- */
- public static FileFormat fromString(String fileFormat) {
- if (fileFormat == null) {
- return null;
- }
-
- try {
- return FileFormat.valueOf(fileFormat.toUpperCase());
- } catch (IllegalArgumentException iae) {
- Log.error("Bad conversion attempt in FileFormat.fromString; string: "
- + fileFormat + "; message: " + iae.getMessage());
- Log.exception(iae);
- return UNKNOWN;
- }
- }
- };
-
- /**
- * This class represents the file dates.
- */
- public class FileDatesInfoEntry {
-
- /** The create time. */
- private int createTime = Integer.MIN_VALUE;
-
- /** The modify time. */
- private int modifyTime = Integer.MIN_VALUE;
-
- /** The backup time. */
- private int backupTime = Integer.MIN_VALUE;
-
- /** The access time. */
- private int accessTime = Integer.MIN_VALUE;
-
- /**
- * Instantiates a new file dates info entry.
- */
- public FileDatesInfoEntry() {
-
- }
-
- /**
- * Gets the creates the time.
- *
- * @return the creates the time
- */
- public int getCreateTime() {
- return createTime;
- }
-
- /**
- * Sets the creates the time.
- *
- * @param createTime
- * the new creates the time
- */
- public void setCreateTime(int createTime) {
- this.createTime = createTime;
- }
-
- /**
- * Gets the modify time.
- *
- * @return the modify time
- */
- public int getModifyTime() {
- return modifyTime;
- }
-
- /**
- * Sets the modify time.
- *
- * @param modifyTime
- * the new modify time
- */
- public void setModifyTime(int modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- /**
- * Gets the backup time.
- *
- * @return the backup time
- */
- public int getBackupTime() {
- return backupTime;
- }
-
- /**
- * Sets the backup time.
- *
- * @param backupTime
- * the new backup time
- */
- public void setBackupTime(int backupTime) {
- this.backupTime = backupTime;
- }
-
- /**
- * Gets the access time.
- *
- * @return the access time
- */
- public int getAccessTime() {
- return accessTime;
- }
-
- /**
- * Sets the access time.
- *
- * @param accessTime
- * the new access time
- */
- public void setAccessTime(int accessTime) {
- this.accessTime = accessTime;
- }
- }
-
- /**
- * Sets the num entries.
- *
- * @param numEntries
- * the new num entries
- */
- public void setNumEntries(int numEntries) {
- this.numEntries = numEntries;
- }
-
- /**
- * Verify the validity of the Apple file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- protected void verify() throws FileDecoderException {
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int position = offset;
- if (length < 26) {
- throw new FileDecoderException("File is too short");
- }
-
- /* Magic number */
- int magic = 0;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
-
- /* Check Apple file format: AppleSingle or AppleDobule */
- if (magic == 0x00051600) {
- this.format = FileFormat.APPLE_SINGLE;
- } else if (magic == 0x00051607) {
- this.format = FileFormat.APPLE_DOUBLE;
- } else {
- throw new FileDecoderException("Invalid Apple file magic number.");
- }
-
- /* Version number */
- int version = 0;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- if (version != 0x00020000) {
- throw new FileDecoderException("Unknown Apple file version");
- }
-
- /* Filler */
- position += 16;
-
- /* Number of entries */
- this.numEntries = 0;
- this.numEntries |= data[(position++)] & 0xFF;
- this.numEntries <<= 8;
- this.numEntries |= data[(position++)] & 0xFF;
- if (length < 26 + 12 * this.numEntries) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
-
- /* Check entries */
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- int contentPosition = 26 + 12 * this.numEntries;
- for (int i = 0; i < this.numEntries; i++) {
- position = 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
- if ((entryOffset < contentPosition)
- || (length < entryOffset + entryLength)) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
- }
- }
-
- /**
- * Extract file dates.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- protected void extractFileDates(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
-
- int position = offset;
-
- int createTime = 0;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- int modifyTime = 0;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- int backupTime = 0;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- int accessTime = 0;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
-
- this.fileDatesInfoEntry = new FileDatesInfoEntry();
- fileDatesInfoEntry.setCreateTime(createTime);
- fileDatesInfoEntry.setModifyTime(modifyTime);
- fileDatesInfoEntry.setBackupTime(backupTime);
- fileDatesInfoEntry.setAccessTime(accessTime);
- }
-
- /**
- * Gets the format.
- *
- * @return the format
- */
- public FileFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the format.
- *
- * @param format
- * the new format
- */
- public void setFormat(FileFormat format) {
- this.format = format;
- }
-
- /**
- * Gets the file data.
- *
- * @return the file data
- */
- public AppleFileData getFileData() {
- return fileData;
- }
-
- /**
- * Sets the file data.
- *
- * @param fileData
- * the new file data
- */
- public void setFileData(AppleFileData fileData) {
- this.fileData = fileData;
- }
-
- /**
- * Gets the data fork.
- *
- * @return the data fork
- */
- public AppleFileData getDataFork() {
- return dataFork;
- }
-
- /**
- * Sets the data fork.
- *
- * @param dataFork
- * the new data fork
- */
- public void setDataFork(AppleFileData dataFork) {
- this.dataFork = dataFork;
- }
-
- /**
- * Gets the resource fork.
- *
- * @return the resource fork
- */
- public AppleFileData getResourceFork() {
- return resourceFork;
- }
-
- /**
- * Sets the resource fork.
- *
- * @param resourceFork
- * the new resource fork
- */
- public void setResourceFork(AppleFileData resourceFork) {
- this.resourceFork = resourceFork;
- }
-
- /**
- * Gets the real name.
- *
- * @return the real name
- */
- public AppleFileData getRealName() {
- return realName;
- }
-
- /**
- * Sets the real name.
- *
- * @param realName
- * the new real name
- */
- public void setRealName(AppleFileData realName) {
- this.realName = realName;
- }
-
- /**
- * Gets the comment.
- *
- * @return the comment
- */
- public AppleFileData getComment() {
- return comment;
- }
-
- /**
- * Sets the comment.
- *
- * @param comment
- * the new comment
- */
- public void setComment(AppleFileData comment) {
- this.comment = comment;
- }
-
- /**
- * Gets the icon bw.
- *
- * @return the icon bw
- */
- public AppleFileData getIconBW() {
- return iconBW;
- }
-
- /**
- * Sets the icon bw.
- *
- * @param iconBW
- * the new icon bw
- */
- public void setIconBW(AppleFileData iconBW) {
- this.iconBW = iconBW;
- }
-
- /**
- * Gets the icon color.
- *
- * @return the icon color
- */
- public AppleFileData getIconColor() {
- return iconColor;
- }
-
- /**
- * Sets the icon color.
- *
- * @param iconColor
- * the new icon color
- */
- public void setIconColor(AppleFileData iconColor) {
- this.iconColor = iconColor;
- }
-
- /**
- * Gets the file dates info.
- *
- * @return the file dates info
- */
- public AppleFileData getFileDatesInfo() {
- return fileDatesInfo;
- }
-
- /**
- * Sets the file dates info.
- *
- * @param fileDatesInfo
- * the new file dates info
- */
- public void setFileDatesInfo(AppleFileData fileDatesInfo) {
- this.fileDatesInfo = fileDatesInfo;
- }
-
- /**
- * Gets the finder info.
- *
- * @return the finder info
- */
- public AppleFileData getFinderInfo() {
- return finderInfo;
- }
-
- /**
- * Sets the finder info.
- *
- * @param finderInfo
- * the new finder info
- */
- public void setFinderInfo(AppleFileData finderInfo) {
- this.finderInfo = finderInfo;
- }
-
- /**
- * Gets the macintosh info.
- *
- * @return the macintosh info
- */
- public AppleFileData getMacintoshInfo() {
- return macintoshInfo;
- }
-
- /**
- * Sets the macintosh info.
- *
- * @param macintoshInfo
- * the new macintosh info
- */
- public void setMacintoshInfo(AppleFileData macintoshInfo) {
- this.macintoshInfo = macintoshInfo;
- }
-
- /**
- * Gets the pro dos file info.
- *
- * @return the pro dos file info
- */
- public AppleFileData getProDOSFileInfo() {
- return proDOSFileInfo;
- }
-
- /**
- * Sets the pro dos file info.
- *
- * @param proDOSFileInfo
- * the new pro dos file info
- */
- public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
- this.proDOSFileInfo = proDOSFileInfo;
- }
-
- /**
- * Gets the ms dos file info.
- *
- * @return the ms dos file info
- */
- public AppleFileData getMsDOSFileInfo() {
- return msDOSFileInfo;
- }
-
- /**
- * Sets the ms dos file info.
- *
- * @param msDOSFileInfo
- * the new ms dos file info
- */
- public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
- this.msDOSFileInfo = msDOSFileInfo;
- }
-
- /**
- * Gets the short name.
- *
- * @return the short name
- */
- public AppleFileData getShortName() {
- return shortName;
- }
-
- /**
- * Sets the short name.
- *
- * @param shortName
- * the new short name
- */
- public void setShortName(AppleFileData shortName) {
- this.shortName = shortName;
- }
-
- /**
- * Gets the afp file info.
- *
- * @return the afp file info
- */
- public AppleFileData getAfpFileInfo() {
- return afpFileInfo;
- }
-
- /**
- * Sets the afp file info.
- *
- * @param afpFileInfo
- * the new afp file info
- */
- public void setAfpFileInfo(AppleFileData afpFileInfo) {
- this.afpFileInfo = afpFileInfo;
- }
-
- /**
- * Gets the directory id.
- *
- * @return the directory id
- */
- public AppleFileData getDirectoryID() {
- return directoryID;
- }
-
- /**
- * Sets the directory id.
- *
- * @param directoryID
- * the new directory id
- */
- public void setDirectoryID(AppleFileData directoryID) {
- this.directoryID = directoryID;
- }
-
- /**
- * Gets the num entries.
- *
- * @return the num entries
- */
- public int getNumEntries() {
- return numEntries;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This abstract class handles AppleSingle/Double files. It contains a common
+ * method to verify the Apple file, and figure out if it is an AppleSingle or
+ * AppleDouble formatted file.
+ *
+ *
+ * The AppleSingle format is a representation of Macintosh files as one
+ * consecutive stream of bytes. AppleSingle combines the data fork, resource
+ * fork and the related Finder meta-file information into a single file.
+ *
+ *
+ * The AppleDouble format stores the data fork, resource fork as two separate
+ * files. AppleDouble leaves the data fork in its original format, and the
+ * resource fork and Finder information were combined into a second file.
+ *
+ *
+ * Apple defined the magic number for the AppleSingle format as 0x00051600, and
+ * the magic number for the AppleDouble format as 0x00051607.
+ *
+ *
+ * AppleSingle file header:
+ *
+ * Field Length
+ * ----- ------
+ * Magic number ------- 4 bytes
+ * Version number ------ 4 bytes
+ * Filler ------------- 16 bytes
+ * Number of entries ----- 2 bytes
+ *
+ * Entry descriptor for each entry:
+ * Entry ID ------ 4 bytes
+ * Offset -------- 4 bytes
+ * Length -------- 4 bytes
+ *
+ * Apple reserved entry IDs:
+ *
+ * Data Fork -------- 1 Data fork
+ * Resource Fork ----- 2 Resource fork
+ * Real Name -------- 3 File's name as created on home file system
+ * Comment --------- 4 Standard Macintosh comment
+ * Icon, B&W -------- 5 Standard Macintosh black and white icon
+ * Icon, Color -------- 6 Macintosh color icon
+ * File Dates Info ------8 File creation date, modification date, and so on
+ * Finder Info -------- 9 Standard Macintosh Finder information
+ * Macintosh File Info ---10 Macintosh file information, attributes, and so on
+ * ProDOS File Info -----11 ProDOS file information, attributes, and so on
+ * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
+ * Short Name --------13 AFP short name
+ * AFP File Info ------- 14 AFP file information, attributes, and so on
+ * Directory ID --------15 AFP directory ID
+ *
+ *
+ * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
+ */
+public abstract class AppleFile {
+
+ /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
+ protected FileFormat format = FileFormat.UNKNOWN;
+
+ /** The raw Apple file. */
+ protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 1: Data fork. */
+ protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 2: Resource fork. */
+ protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 3: File's name as created on home file system. */
+ protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 4: Standard Macintosh comment. */
+ protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 5: Standard Macintosh black and white icon. */
+ protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 6: Macintosh color icon. */
+ protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 8: File creation date, modification date, and so on. */
+ protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The file dates info entry. */
+ protected FileDatesInfoEntry fileDatesInfoEntry = null;
+
+ /** Entry 9: Standard Macintosh Finder information. */
+ protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 10: Macintosh file information, attributes, and so on. */
+ protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 11: ProDOS file information, attributes, and so on. */
+ protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 12: MS-DOS file information, attributes, and so on. */
+ protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 13: AFP short name. */
+ protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 14: AFP file information, attributes, and so on. */
+ protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 15: AFP directory ID. */
+ protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The num entries. */
+ protected int numEntries = 0;
+
+ /**
+ * The Apple file format.
+ */
+ public enum FileFormat {
+
+ APPLE_SINGLE,
+ APPLE_DOUBLE,
+ UNKNOWN;
+
+ /**
+ * Return a suitable Apple file format as inferred from the passed-in
+ * string. Otherwise return the UNKNOWN file format.
+ *
+ * @param fileFormat
+ * the file format
+ * @return the FileFormat
+ */
+ public static FileFormat fromString(String fileFormat) {
+ if (fileFormat == null) {
+ return null;
+ }
+
+ try {
+ return FileFormat.valueOf(fileFormat.toUpperCase());
+ } catch (IllegalArgumentException iae) {
+ Log.error("Bad conversion attempt in FileFormat.fromString; string: "
+ + fileFormat + "; message: " + iae.getMessage());
+ Log.exception(iae);
+ return UNKNOWN;
+ }
+ }
+ };
+
+ /**
+ * This class represents the file dates.
+ */
+ public class FileDatesInfoEntry {
+
+ /** The create time. */
+ private int createTime = Integer.MIN_VALUE;
+
+ /** The modify time. */
+ private int modifyTime = Integer.MIN_VALUE;
+
+ /** The backup time. */
+ private int backupTime = Integer.MIN_VALUE;
+
+ /** The access time. */
+ private int accessTime = Integer.MIN_VALUE;
+
+ /**
+ * Instantiates a new file dates info entry.
+ */
+ public FileDatesInfoEntry() {
+
+ }
+
+ /**
+ * Gets the creates the time.
+ *
+ * @return the creates the time
+ */
+ public int getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * Sets the creates the time.
+ *
+ * @param createTime
+ * the new creates the time
+ */
+ public void setCreateTime(int createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * Gets the modify time.
+ *
+ * @return the modify time
+ */
+ public int getModifyTime() {
+ return modifyTime;
+ }
+
+ /**
+ * Sets the modify time.
+ *
+ * @param modifyTime
+ * the new modify time
+ */
+ public void setModifyTime(int modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ /**
+ * Gets the backup time.
+ *
+ * @return the backup time
+ */
+ public int getBackupTime() {
+ return backupTime;
+ }
+
+ /**
+ * Sets the backup time.
+ *
+ * @param backupTime
+ * the new backup time
+ */
+ public void setBackupTime(int backupTime) {
+ this.backupTime = backupTime;
+ }
+
+ /**
+ * Gets the access time.
+ *
+ * @return the access time
+ */
+ public int getAccessTime() {
+ return accessTime;
+ }
+
+ /**
+ * Sets the access time.
+ *
+ * @param accessTime
+ * the new access time
+ */
+ public void setAccessTime(int accessTime) {
+ this.accessTime = accessTime;
+ }
+ }
+
+ /**
+ * Sets the num entries.
+ *
+ * @param numEntries
+ * the new num entries
+ */
+ public void setNumEntries(int numEntries) {
+ this.numEntries = numEntries;
+ }
+
+ /**
+ * Verify the validity of the Apple file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ protected void verify() throws FileDecoderException {
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int position = offset;
+ if (length < 26) {
+ throw new FileDecoderException("File is too short");
+ }
+
+ /* Magic number */
+ int magic = 0;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+
+ /* Check Apple file format: AppleSingle or AppleDobule */
+ if (magic == 0x00051600) {
+ this.format = FileFormat.APPLE_SINGLE;
+ } else if (magic == 0x00051607) {
+ this.format = FileFormat.APPLE_DOUBLE;
+ } else {
+ throw new FileDecoderException("Invalid Apple file magic number.");
+ }
+
+ /* Version number */
+ int version = 0;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ if (version != 0x00020000) {
+ throw new FileDecoderException("Unknown Apple file version");
+ }
+
+ /* Filler */
+ position += 16;
+
+ /* Number of entries */
+ this.numEntries = 0;
+ this.numEntries |= data[(position++)] & 0xFF;
+ this.numEntries <<= 8;
+ this.numEntries |= data[(position++)] & 0xFF;
+ if (length < 26 + 12 * this.numEntries) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+
+ /* Check entries */
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ int contentPosition = 26 + 12 * this.numEntries;
+ for (int i = 0; i < this.numEntries; i++) {
+ position = 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+ if ((entryOffset < contentPosition)
+ || (length < entryOffset + entryLength)) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+ }
+ }
+
+ /**
+ * Extract file dates.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ protected void extractFileDates(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+
+ int position = offset;
+
+ int createTime = 0;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ int modifyTime = 0;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ int backupTime = 0;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ int accessTime = 0;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+
+ this.fileDatesInfoEntry = new FileDatesInfoEntry();
+ fileDatesInfoEntry.setCreateTime(createTime);
+ fileDatesInfoEntry.setModifyTime(modifyTime);
+ fileDatesInfoEntry.setBackupTime(backupTime);
+ fileDatesInfoEntry.setAccessTime(accessTime);
+ }
+
+ /**
+ * Gets the format.
+ *
+ * @return the format
+ */
+ public FileFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Sets the format.
+ *
+ * @param format
+ * the new format
+ */
+ public void setFormat(FileFormat format) {
+ this.format = format;
+ }
+
+ /**
+ * Gets the file data.
+ *
+ * @return the file data
+ */
+ public AppleFileData getFileData() {
+ return fileData;
+ }
+
+ /**
+ * Sets the file data.
+ *
+ * @param fileData
+ * the new file data
+ */
+ public void setFileData(AppleFileData fileData) {
+ this.fileData = fileData;
+ }
+
+ /**
+ * Gets the data fork.
+ *
+ * @return the data fork
+ */
+ public AppleFileData getDataFork() {
+ return dataFork;
+ }
+
+ /**
+ * Sets the data fork.
+ *
+ * @param dataFork
+ * the new data fork
+ */
+ public void setDataFork(AppleFileData dataFork) {
+ this.dataFork = dataFork;
+ }
+
+ /**
+ * Gets the resource fork.
+ *
+ * @return the resource fork
+ */
+ public AppleFileData getResourceFork() {
+ return resourceFork;
+ }
+
+ /**
+ * Sets the resource fork.
+ *
+ * @param resourceFork
+ * the new resource fork
+ */
+ public void setResourceFork(AppleFileData resourceFork) {
+ this.resourceFork = resourceFork;
+ }
+
+ /**
+ * Gets the real name.
+ *
+ * @return the real name
+ */
+ public AppleFileData getRealName() {
+ return realName;
+ }
+
+ /**
+ * Sets the real name.
+ *
+ * @param realName
+ * the new real name
+ */
+ public void setRealName(AppleFileData realName) {
+ this.realName = realName;
+ }
+
+ /**
+ * Gets the comment.
+ *
+ * @return the comment
+ */
+ public AppleFileData getComment() {
+ return comment;
+ }
+
+ /**
+ * Sets the comment.
+ *
+ * @param comment
+ * the new comment
+ */
+ public void setComment(AppleFileData comment) {
+ this.comment = comment;
+ }
+
+ /**
+ * Gets the icon bw.
+ *
+ * @return the icon bw
+ */
+ public AppleFileData getIconBW() {
+ return iconBW;
+ }
+
+ /**
+ * Sets the icon bw.
+ *
+ * @param iconBW
+ * the new icon bw
+ */
+ public void setIconBW(AppleFileData iconBW) {
+ this.iconBW = iconBW;
+ }
+
+ /**
+ * Gets the icon color.
+ *
+ * @return the icon color
+ */
+ public AppleFileData getIconColor() {
+ return iconColor;
+ }
+
+ /**
+ * Sets the icon color.
+ *
+ * @param iconColor
+ * the new icon color
+ */
+ public void setIconColor(AppleFileData iconColor) {
+ this.iconColor = iconColor;
+ }
+
+ /**
+ * Gets the file dates info.
+ *
+ * @return the file dates info
+ */
+ public AppleFileData getFileDatesInfo() {
+ return fileDatesInfo;
+ }
+
+ /**
+ * Sets the file dates info.
+ *
+ * @param fileDatesInfo
+ * the new file dates info
+ */
+ public void setFileDatesInfo(AppleFileData fileDatesInfo) {
+ this.fileDatesInfo = fileDatesInfo;
+ }
+
+ /**
+ * Gets the finder info.
+ *
+ * @return the finder info
+ */
+ public AppleFileData getFinderInfo() {
+ return finderInfo;
+ }
+
+ /**
+ * Sets the finder info.
+ *
+ * @param finderInfo
+ * the new finder info
+ */
+ public void setFinderInfo(AppleFileData finderInfo) {
+ this.finderInfo = finderInfo;
+ }
+
+ /**
+ * Gets the macintosh info.
+ *
+ * @return the macintosh info
+ */
+ public AppleFileData getMacintoshInfo() {
+ return macintoshInfo;
+ }
+
+ /**
+ * Sets the macintosh info.
+ *
+ * @param macintoshInfo
+ * the new macintosh info
+ */
+ public void setMacintoshInfo(AppleFileData macintoshInfo) {
+ this.macintoshInfo = macintoshInfo;
+ }
+
+ /**
+ * Gets the pro dos file info.
+ *
+ * @return the pro dos file info
+ */
+ public AppleFileData getProDOSFileInfo() {
+ return proDOSFileInfo;
+ }
+
+ /**
+ * Sets the pro dos file info.
+ *
+ * @param proDOSFileInfo
+ * the new pro dos file info
+ */
+ public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
+ this.proDOSFileInfo = proDOSFileInfo;
+ }
+
+ /**
+ * Gets the ms dos file info.
+ *
+ * @return the ms dos file info
+ */
+ public AppleFileData getMsDOSFileInfo() {
+ return msDOSFileInfo;
+ }
+
+ /**
+ * Sets the ms dos file info.
+ *
+ * @param msDOSFileInfo
+ * the new ms dos file info
+ */
+ public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
+ this.msDOSFileInfo = msDOSFileInfo;
+ }
+
+ /**
+ * Gets the short name.
+ *
+ * @return the short name
+ */
+ public AppleFileData getShortName() {
+ return shortName;
+ }
+
+ /**
+ * Sets the short name.
+ *
+ * @param shortName
+ * the new short name
+ */
+ public void setShortName(AppleFileData shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * Gets the afp file info.
+ *
+ * @return the afp file info
+ */
+ public AppleFileData getAfpFileInfo() {
+ return afpFileInfo;
+ }
+
+ /**
+ * Sets the afp file info.
+ *
+ * @param afpFileInfo
+ * the new afp file info
+ */
+ public void setAfpFileInfo(AppleFileData afpFileInfo) {
+ this.afpFileInfo = afpFileInfo;
+ }
+
+ /**
+ * Gets the directory id.
+ *
+ * @return the directory id
+ */
+ public AppleFileData getDirectoryID() {
+ return directoryID;
+ }
+
+ /**
+ * Sets the directory id.
+ *
+ * @param directoryID
+ * the new directory id
+ */
+ public void setDirectoryID(AppleFileData directoryID) {
+ this.directoryID = directoryID;
+ }
+
+ /**
+ * Gets the num entries.
+ *
+ * @return the num entries
+ */
+ public int getNumEntries() {
+ return numEntries;
+ }
}
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
index f28c979a..d89471e2 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
@@ -1,91 +1,91 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-/**
- * This class is for representing the AppleSingle/Double file or its file forks
- * (data fork and resource fork) and the related Finder meta-file information.
- */
-public final class AppleFileData {
-
- public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
- private byte[] data;
- private int offset;
- private int length;
-
- /**
- * Instantiates a new apple file data.
- */
- public AppleFileData() {
- this.data = new byte[0];
- this.offset = 0;
- this.length = 0;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- */
- public AppleFileData(byte[] data) {
- this.data = data;
- this.offset = 0;
- this.length = data.length;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- public AppleFileData(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- /**
- * Gets the bytes.
- *
- * @return the bytes
- */
- public byte[] getBytes() {
- byte[] data = new byte[this.length];
- System.arraycopy(this.data, this.offset, data, 0, this.length);
- return data;
- }
-
- /**
- * Gets the data.
- *
- * @return the data
- */
- public byte[] getData() {
- return this.data;
- }
-
- /**
- * Gets the offset.
- *
- * @return the offset
- */
- public int getOffset() {
- return this.offset;
- }
-
- /**
- * Gets the length.
- *
- * @return the length
- */
- public int getLength() {
- return this.length;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+/**
+ * This class is for representing the AppleSingle/Double file or its file forks
+ * (data fork and resource fork) and the related Finder meta-file information.
+ */
+public final class AppleFileData {
+
+ public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
+ private byte[] data;
+ private int offset;
+ private int length;
+
+ /**
+ * Instantiates a new apple file data.
+ */
+ public AppleFileData() {
+ this.data = new byte[0];
+ this.offset = 0;
+ this.length = 0;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ */
+ public AppleFileData(byte[] data) {
+ this.data = data;
+ this.offset = 0;
+ this.length = data.length;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ public AppleFileData(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the bytes.
+ *
+ * @return the bytes
+ */
+ public byte[] getBytes() {
+ byte[] data = new byte[this.length];
+ System.arraycopy(this.data, this.offset, data, 0, this.length);
+ return data;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * Gets the offset.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ /**
+ * Gets the length.
+ *
+ * @return the length
+ */
+ public int getLength() {
+ return this.length;
+ }
}
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
index 3248f85d..aa7b0363 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
@@ -1,143 +1,143 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This class handles the extraction of the data fork, resource fork and other
- * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
- * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
- * file type is a compressed AppleDouble (Mac resource fork) file.
- */
-public class AppleFileDecoder extends AppleFile {
-
- /**
- * Instantiates a new apple file decoder.
- *
- * @param fileData
- * the file data
- */
- public AppleFileDecoder(AppleFileData fileData) {
- if (fileData != null) {
- this.fileData = fileData;
- }
- }
-
- /**
- * Extract the data fork, resource fork and other entries from the Apple
- * file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- public void extract() throws FileDecoderException {
- // Verify the validity of the Apple file
- verify();
-
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int contentPosition = 0;
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- for (int i = 0; i < this.numEntries; i++) {
- contentPosition = offset + 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
-
- switch (entryId) {
- case 1:
- this.dataFork = new AppleFileData(data, offset + entryOffset,
- entryLength);
- break;
- case 2:
- this.resourceFork = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 3:
- this.realName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 4:
- this.comment = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 5:
- this.iconBW = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 6:
- this.iconColor = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 8:
- this.fileDatesInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- extractFileDates(data, offset + entryOffset, entryLength);
- break;
- case 9:
- this.finderInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 10:
- this.macintoshInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 11:
- this.proDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 12:
- this.msDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 13:
- this.shortName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 14:
- this.afpFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 15:
- this.directoryID = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- default:
- Log.warn("Apple file entry ID: " + entryId + " is not handled.");
-
- }
- }
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This class handles the extraction of the data fork, resource fork and other
+ * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
+ * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
+ * file type is a compressed AppleDouble (Mac resource fork) file.
+ */
+public class AppleFileDecoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @param fileData
+ * the file data
+ */
+ public AppleFileDecoder(AppleFileData fileData) {
+ if (fileData != null) {
+ this.fileData = fileData;
+ }
+ }
+
+ /**
+ * Extract the data fork, resource fork and other entries from the Apple
+ * file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ public void extract() throws FileDecoderException {
+ // Verify the validity of the Apple file
+ verify();
+
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int contentPosition = 0;
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ for (int i = 0; i < this.numEntries; i++) {
+ contentPosition = offset + 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+
+ switch (entryId) {
+ case 1:
+ this.dataFork = new AppleFileData(data, offset + entryOffset,
+ entryLength);
+ break;
+ case 2:
+ this.resourceFork = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 3:
+ this.realName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 4:
+ this.comment = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 5:
+ this.iconBW = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 6:
+ this.iconColor = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 8:
+ this.fileDatesInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ extractFileDates(data, offset + entryOffset, entryLength);
+ break;
+ case 9:
+ this.finderInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 10:
+ this.macintoshInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 11:
+ this.proDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 12:
+ this.msDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 13:
+ this.shortName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 14:
+ this.afpFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 15:
+ this.directoryID = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ default:
+ Log.warn("Apple file entry ID: " + entryId + " is not handled.");
+
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
index 7c5d0a04..abdfed59 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
@@ -1,300 +1,300 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.exception.FileEncoderException;
-
-/**
- * This class handles the combination of the data fork, resource fork and other
- * entries into an AppleSingle/Double file.
- *
-
-
-Provides a series of classes that implement P4Java-wide server, client, and other class method
-options definitions and processing.
-
-Package com.perforce.p4java.options and its changelist, client, and server sub-packages were introduced
-with the 2010.1 release to make it easier for users and developers to ensure forwards and backwards
-binary compatibility. Please see the Perforce knowledge base article linked to here (TBD) for the
-full semantics and usage details.
-
+
+
+
+
+
+Provides a series of classes that implement P4Java-wide server, client, and other class method
+options definitions and processing.
+
+Package com.perforce.p4java.options and its changelist, client, and server sub-packages were introduced
+with the 2010.1 release to make it easier for users and developers to ensure forwards and backwards
+binary compatibility. Please see the Perforce knowledge base article linked to here (TBD) for the
+full semantics and usage details.
+
\ No newline at end of file
diff --git a/p4java/r19-1/src/main/java/com/perforce/p4java/overview.html b/p4java/r19-1/src/main/java/com/perforce/p4java/overview.html
index 55c0eefd..c687ca12 100644
--- a/p4java/r19-1/src/main/java/com/perforce/p4java/overview.html
+++ b/p4java/r19-1/src/main/java/com/perforce/p4java/overview.html
@@ -1,34 +1,34 @@
-
-
-
-
-
-Perforce's P4Java is a Java-native API for accessing Perforce's SCM services in a Java-natural
-and Java-native way.
-
-P4Java presents Perforce services and Perforce-managed resources and files as first-class Java interfaces,
-classes, methods, and objects, rather than as simple strings or command-line-like functions. This approach
-reduces the impedance mismatch between Java and Perforce, and makes it easier to integrate the API into
-Java applications and tools; it is particularly useful for integrating into model-view-controller (MVC)
-contexts and workflows.
-
-P4Java is aimed mostly at the following types of Java development:
-
-
-Standalone applications that need to access Perforce services from within the application;
-
-Plug-ins for Java tools such as Eclipse, ant, cruise control, etc., that need to communicate
-with one or more Perforce servers; and,
-
-J2EE apps, where P4Java can be embedded within a servlet and / or presented as a web service or (e.g.)
-an Ajax binding for client-side use.
-
-P4Java is aimed at JDK 6 and later environments, but will work with some limitations against a JDK 5 installation
-(see the related P4Java User Guide for details)..
-
Related Documentation
-
-
The P4Java User Guide (available as a PDF within the main P4Java distribution zip file) — contains
-a less-formal overview and guide to using P4Java.
-
-
+
+
+
+
+
+Perforce's P4Java is a Java-native API for accessing Perforce's SCM services in a Java-natural
+and Java-native way.
+
+P4Java presents Perforce services and Perforce-managed resources and files as first-class Java interfaces,
+classes, methods, and objects, rather than as simple strings or command-line-like functions. This approach
+reduces the impedance mismatch between Java and Perforce, and makes it easier to integrate the API into
+Java applications and tools; it is particularly useful for integrating into model-view-controller (MVC)
+contexts and workflows.
+
+P4Java is aimed mostly at the following types of Java development:
+
+
+Standalone applications that need to access Perforce services from within the application;
+
+Plug-ins for Java tools such as Eclipse, ant, cruise control, etc., that need to communicate
+with one or more Perforce servers; and,
+
+J2EE apps, where P4Java can be embedded within a servlet and / or presented as a web service or (e.g.)
+an Ajax binding for client-side use.
+
+P4Java is aimed at JDK 6 and later environments, but will work with some limitations against a JDK 5 installation
+(see the related P4Java User Guide for details)..
+
Related Documentation
+
+
The P4Java User Guide (available as a PDF within the main P4Java distribution zip file) — contains
+a less-formal overview and guide to using P4Java.
+
- *
- * The AppleSingle format is a representation of Macintosh files as one
- * consecutive stream of bytes. AppleSingle combines the data fork, resource
- * fork and the related Finder meta-file information into a single file.
- *
- *
- * The AppleDouble format stores the data fork, resource fork as two separate
- * files. AppleDouble leaves the data fork in its original format, and the
- * resource fork and Finder information were combined into a second file.
- *
- *
- * Apple defined the magic number for the AppleSingle format as 0x00051600, and
- * the magic number for the AppleDouble format as 0x00051607.
- *
- *
- * AppleSingle file header:
- *
- * Field Length
- * ----- ------
- * Magic number ------- 4 bytes
- * Version number ------ 4 bytes
- * Filler ------------- 16 bytes
- * Number of entries ----- 2 bytes
- *
- * Entry descriptor for each entry:
- * Entry ID ------ 4 bytes
- * Offset -------- 4 bytes
- * Length -------- 4 bytes
- *
- * Apple reserved entry IDs:
- *
- * Data Fork -------- 1 Data fork
- * Resource Fork ----- 2 Resource fork
- * Real Name -------- 3 File's name as created on home file system
- * Comment --------- 4 Standard Macintosh comment
- * Icon, B&W -------- 5 Standard Macintosh black and white icon
- * Icon, Color -------- 6 Macintosh color icon
- * File Dates Info ------8 File creation date, modification date, and so on
- * Finder Info -------- 9 Standard Macintosh Finder information
- * Macintosh File Info ---10 Macintosh file information, attributes, and so on
- * ProDOS File Info -----11 ProDOS file information, attributes, and so on
- * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
- * Short Name --------13 AFP short name
- * AFP File Info ------- 14 AFP file information, attributes, and so on
- * Directory ID --------15 AFP directory ID
- *
- *
- * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
- */
-public abstract class AppleFile {
-
- /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
- protected FileFormat format = FileFormat.UNKNOWN;
-
- /** The raw Apple file. */
- protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 1: Data fork. */
- protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 2: Resource fork. */
- protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 3: File's name as created on home file system. */
- protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 4: Standard Macintosh comment. */
- protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 5: Standard Macintosh black and white icon. */
- protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 6: Macintosh color icon. */
- protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 8: File creation date, modification date, and so on. */
- protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** The file dates info entry. */
- protected FileDatesInfoEntry fileDatesInfoEntry = null;
-
- /** Entry 9: Standard Macintosh Finder information. */
- protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 10: Macintosh file information, attributes, and so on. */
- protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 11: ProDOS file information, attributes, and so on. */
- protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 12: MS-DOS file information, attributes, and so on. */
- protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 13: AFP short name. */
- protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 14: AFP file information, attributes, and so on. */
- protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
-
- /** Entry 15: AFP directory ID. */
- protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
-
- /** The num entries. */
- protected int numEntries = 0;
-
- /**
- * The Apple file format.
- */
- public enum FileFormat {
-
- APPLE_SINGLE,
- APPLE_DOUBLE,
- UNKNOWN;
-
- /**
- * Return a suitable Apple file format as inferred from the passed-in
- * string. Otherwise return the UNKNOWN file format.
- *
- * @param fileFormat
- * the file format
- * @return the FileFormat
- */
- public static FileFormat fromString(String fileFormat) {
- if (fileFormat == null) {
- return null;
- }
-
- try {
- return FileFormat.valueOf(fileFormat.toUpperCase());
- } catch (IllegalArgumentException iae) {
- Log.error("Bad conversion attempt in FileFormat.fromString; string: "
- + fileFormat + "; message: " + iae.getMessage());
- Log.exception(iae);
- return UNKNOWN;
- }
- }
- };
-
- /**
- * This class represents the file dates.
- */
- public class FileDatesInfoEntry {
-
- /** The create time. */
- private int createTime = Integer.MIN_VALUE;
-
- /** The modify time. */
- private int modifyTime = Integer.MIN_VALUE;
-
- /** The backup time. */
- private int backupTime = Integer.MIN_VALUE;
-
- /** The access time. */
- private int accessTime = Integer.MIN_VALUE;
-
- /**
- * Instantiates a new file dates info entry.
- */
- public FileDatesInfoEntry() {
-
- }
-
- /**
- * Gets the creates the time.
- *
- * @return the creates the time
- */
- public int getCreateTime() {
- return createTime;
- }
-
- /**
- * Sets the creates the time.
- *
- * @param createTime
- * the new creates the time
- */
- public void setCreateTime(int createTime) {
- this.createTime = createTime;
- }
-
- /**
- * Gets the modify time.
- *
- * @return the modify time
- */
- public int getModifyTime() {
- return modifyTime;
- }
-
- /**
- * Sets the modify time.
- *
- * @param modifyTime
- * the new modify time
- */
- public void setModifyTime(int modifyTime) {
- this.modifyTime = modifyTime;
- }
-
- /**
- * Gets the backup time.
- *
- * @return the backup time
- */
- public int getBackupTime() {
- return backupTime;
- }
-
- /**
- * Sets the backup time.
- *
- * @param backupTime
- * the new backup time
- */
- public void setBackupTime(int backupTime) {
- this.backupTime = backupTime;
- }
-
- /**
- * Gets the access time.
- *
- * @return the access time
- */
- public int getAccessTime() {
- return accessTime;
- }
-
- /**
- * Sets the access time.
- *
- * @param accessTime
- * the new access time
- */
- public void setAccessTime(int accessTime) {
- this.accessTime = accessTime;
- }
- }
-
- /**
- * Sets the num entries.
- *
- * @param numEntries
- * the new num entries
- */
- public void setNumEntries(int numEntries) {
- this.numEntries = numEntries;
- }
-
- /**
- * Verify the validity of the Apple file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- protected void verify() throws FileDecoderException {
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int position = offset;
- if (length < 26) {
- throw new FileDecoderException("File is too short");
- }
-
- /* Magic number */
- int magic = 0;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
- magic <<= 8;
- magic |= data[(position++)] & 0xFF;
-
- /* Check Apple file format: AppleSingle or AppleDobule */
- if (magic == 0x00051600) {
- this.format = FileFormat.APPLE_SINGLE;
- } else if (magic == 0x00051607) {
- this.format = FileFormat.APPLE_DOUBLE;
- } else {
- throw new FileDecoderException("Invalid Apple file magic number.");
- }
-
- /* Version number */
- int version = 0;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- version <<= 8;
- version |= data[(position++)] & 0xFF;
- if (version != 0x00020000) {
- throw new FileDecoderException("Unknown Apple file version");
- }
-
- /* Filler */
- position += 16;
-
- /* Number of entries */
- this.numEntries = 0;
- this.numEntries |= data[(position++)] & 0xFF;
- this.numEntries <<= 8;
- this.numEntries |= data[(position++)] & 0xFF;
- if (length < 26 + 12 * this.numEntries) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
-
- /* Check entries */
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- int contentPosition = 26 + 12 * this.numEntries;
- for (int i = 0; i < this.numEntries; i++) {
- position = 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(position++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(position++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(position++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
- if ((entryOffset < contentPosition)
- || (length < entryOffset + entryLength)) {
- throw new FileDecoderException("Corrupt Apple file data.");
- }
- }
- }
-
- /**
- * Extract file dates.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- protected void extractFileDates(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
-
- int position = offset;
-
- int createTime = 0;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- createTime <<= 8;
- createTime |= data[(position++)] & 0xFF;
- int modifyTime = 0;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- modifyTime <<= 8;
- modifyTime |= data[(position++)] & 0xFF;
- int backupTime = 0;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- backupTime <<= 8;
- backupTime |= data[(position++)] & 0xFF;
- int accessTime = 0;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
- accessTime <<= 8;
- accessTime |= data[(position++)] & 0xFF;
-
- this.fileDatesInfoEntry = new FileDatesInfoEntry();
- fileDatesInfoEntry.setCreateTime(createTime);
- fileDatesInfoEntry.setModifyTime(modifyTime);
- fileDatesInfoEntry.setBackupTime(backupTime);
- fileDatesInfoEntry.setAccessTime(accessTime);
- }
-
- /**
- * Gets the format.
- *
- * @return the format
- */
- public FileFormat getFormat() {
- return format;
- }
-
- /**
- * Sets the format.
- *
- * @param format
- * the new format
- */
- public void setFormat(FileFormat format) {
- this.format = format;
- }
-
- /**
- * Gets the file data.
- *
- * @return the file data
- */
- public AppleFileData getFileData() {
- return fileData;
- }
-
- /**
- * Sets the file data.
- *
- * @param fileData
- * the new file data
- */
- public void setFileData(AppleFileData fileData) {
- this.fileData = fileData;
- }
-
- /**
- * Gets the data fork.
- *
- * @return the data fork
- */
- public AppleFileData getDataFork() {
- return dataFork;
- }
-
- /**
- * Sets the data fork.
- *
- * @param dataFork
- * the new data fork
- */
- public void setDataFork(AppleFileData dataFork) {
- this.dataFork = dataFork;
- }
-
- /**
- * Gets the resource fork.
- *
- * @return the resource fork
- */
- public AppleFileData getResourceFork() {
- return resourceFork;
- }
-
- /**
- * Sets the resource fork.
- *
- * @param resourceFork
- * the new resource fork
- */
- public void setResourceFork(AppleFileData resourceFork) {
- this.resourceFork = resourceFork;
- }
-
- /**
- * Gets the real name.
- *
- * @return the real name
- */
- public AppleFileData getRealName() {
- return realName;
- }
-
- /**
- * Sets the real name.
- *
- * @param realName
- * the new real name
- */
- public void setRealName(AppleFileData realName) {
- this.realName = realName;
- }
-
- /**
- * Gets the comment.
- *
- * @return the comment
- */
- public AppleFileData getComment() {
- return comment;
- }
-
- /**
- * Sets the comment.
- *
- * @param comment
- * the new comment
- */
- public void setComment(AppleFileData comment) {
- this.comment = comment;
- }
-
- /**
- * Gets the icon bw.
- *
- * @return the icon bw
- */
- public AppleFileData getIconBW() {
- return iconBW;
- }
-
- /**
- * Sets the icon bw.
- *
- * @param iconBW
- * the new icon bw
- */
- public void setIconBW(AppleFileData iconBW) {
- this.iconBW = iconBW;
- }
-
- /**
- * Gets the icon color.
- *
- * @return the icon color
- */
- public AppleFileData getIconColor() {
- return iconColor;
- }
-
- /**
- * Sets the icon color.
- *
- * @param iconColor
- * the new icon color
- */
- public void setIconColor(AppleFileData iconColor) {
- this.iconColor = iconColor;
- }
-
- /**
- * Gets the file dates info.
- *
- * @return the file dates info
- */
- public AppleFileData getFileDatesInfo() {
- return fileDatesInfo;
- }
-
- /**
- * Sets the file dates info.
- *
- * @param fileDatesInfo
- * the new file dates info
- */
- public void setFileDatesInfo(AppleFileData fileDatesInfo) {
- this.fileDatesInfo = fileDatesInfo;
- }
-
- /**
- * Gets the finder info.
- *
- * @return the finder info
- */
- public AppleFileData getFinderInfo() {
- return finderInfo;
- }
-
- /**
- * Sets the finder info.
- *
- * @param finderInfo
- * the new finder info
- */
- public void setFinderInfo(AppleFileData finderInfo) {
- this.finderInfo = finderInfo;
- }
-
- /**
- * Gets the macintosh info.
- *
- * @return the macintosh info
- */
- public AppleFileData getMacintoshInfo() {
- return macintoshInfo;
- }
-
- /**
- * Sets the macintosh info.
- *
- * @param macintoshInfo
- * the new macintosh info
- */
- public void setMacintoshInfo(AppleFileData macintoshInfo) {
- this.macintoshInfo = macintoshInfo;
- }
-
- /**
- * Gets the pro dos file info.
- *
- * @return the pro dos file info
- */
- public AppleFileData getProDOSFileInfo() {
- return proDOSFileInfo;
- }
-
- /**
- * Sets the pro dos file info.
- *
- * @param proDOSFileInfo
- * the new pro dos file info
- */
- public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
- this.proDOSFileInfo = proDOSFileInfo;
- }
-
- /**
- * Gets the ms dos file info.
- *
- * @return the ms dos file info
- */
- public AppleFileData getMsDOSFileInfo() {
- return msDOSFileInfo;
- }
-
- /**
- * Sets the ms dos file info.
- *
- * @param msDOSFileInfo
- * the new ms dos file info
- */
- public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
- this.msDOSFileInfo = msDOSFileInfo;
- }
-
- /**
- * Gets the short name.
- *
- * @return the short name
- */
- public AppleFileData getShortName() {
- return shortName;
- }
-
- /**
- * Sets the short name.
- *
- * @param shortName
- * the new short name
- */
- public void setShortName(AppleFileData shortName) {
- this.shortName = shortName;
- }
-
- /**
- * Gets the afp file info.
- *
- * @return the afp file info
- */
- public AppleFileData getAfpFileInfo() {
- return afpFileInfo;
- }
-
- /**
- * Sets the afp file info.
- *
- * @param afpFileInfo
- * the new afp file info
- */
- public void setAfpFileInfo(AppleFileData afpFileInfo) {
- this.afpFileInfo = afpFileInfo;
- }
-
- /**
- * Gets the directory id.
- *
- * @return the directory id
- */
- public AppleFileData getDirectoryID() {
- return directoryID;
- }
-
- /**
- * Sets the directory id.
- *
- * @param directoryID
- * the new directory id
- */
- public void setDirectoryID(AppleFileData directoryID) {
- this.directoryID = directoryID;
- }
-
- /**
- * Gets the num entries.
- *
- * @return the num entries
- */
- public int getNumEntries() {
- return numEntries;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This abstract class handles AppleSingle/Double files. It contains a common
+ * method to verify the Apple file, and figure out if it is an AppleSingle or
+ * AppleDouble formatted file.
+ *
+ *
+ * The AppleSingle format is a representation of Macintosh files as one
+ * consecutive stream of bytes. AppleSingle combines the data fork, resource
+ * fork and the related Finder meta-file information into a single file.
+ *
+ *
+ * The AppleDouble format stores the data fork, resource fork as two separate
+ * files. AppleDouble leaves the data fork in its original format, and the
+ * resource fork and Finder information were combined into a second file.
+ *
+ *
+ * Apple defined the magic number for the AppleSingle format as 0x00051600, and
+ * the magic number for the AppleDouble format as 0x00051607.
+ *
+ *
+ * AppleSingle file header:
+ *
+ * Field Length
+ * ----- ------
+ * Magic number ------- 4 bytes
+ * Version number ------ 4 bytes
+ * Filler ------------- 16 bytes
+ * Number of entries ----- 2 bytes
+ *
+ * Entry descriptor for each entry:
+ * Entry ID ------ 4 bytes
+ * Offset -------- 4 bytes
+ * Length -------- 4 bytes
+ *
+ * Apple reserved entry IDs:
+ *
+ * Data Fork -------- 1 Data fork
+ * Resource Fork ----- 2 Resource fork
+ * Real Name -------- 3 File's name as created on home file system
+ * Comment --------- 4 Standard Macintosh comment
+ * Icon, B&W -------- 5 Standard Macintosh black and white icon
+ * Icon, Color -------- 6 Macintosh color icon
+ * File Dates Info ------8 File creation date, modification date, and so on
+ * Finder Info -------- 9 Standard Macintosh Finder information
+ * Macintosh File Info ---10 Macintosh file information, attributes, and so on
+ * ProDOS File Info -----11 ProDOS file information, attributes, and so on
+ * MS-DOS File Info ----12 MS-DOS file information, attributes, and so on
+ * Short Name --------13 AFP short name
+ * AFP File Info ------- 14 AFP file information, attributes, and so on
+ * Directory ID --------15 AFP directory ID
+ *
+ *
+ * See RFC 1740 for reference: http://tools.ietf.org/html/rfc1740
+ */
+public abstract class AppleFile {
+
+ /** The Apple file format: AppleSingle, AppleDouble, default to unknown. */
+ protected FileFormat format = FileFormat.UNKNOWN;
+
+ /** The raw Apple file. */
+ protected AppleFileData fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 1: Data fork. */
+ protected AppleFileData dataFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 2: Resource fork. */
+ protected AppleFileData resourceFork = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 3: File's name as created on home file system. */
+ protected AppleFileData realName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 4: Standard Macintosh comment. */
+ protected AppleFileData comment = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 5: Standard Macintosh black and white icon. */
+ protected AppleFileData iconBW = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 6: Macintosh color icon. */
+ protected AppleFileData iconColor = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 8: File creation date, modification date, and so on. */
+ protected AppleFileData fileDatesInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The file dates info entry. */
+ protected FileDatesInfoEntry fileDatesInfoEntry = null;
+
+ /** Entry 9: Standard Macintosh Finder information. */
+ protected AppleFileData finderInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 10: Macintosh file information, attributes, and so on. */
+ protected AppleFileData macintoshInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 11: ProDOS file information, attributes, and so on. */
+ protected AppleFileData proDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 12: MS-DOS file information, attributes, and so on. */
+ protected AppleFileData msDOSFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 13: AFP short name. */
+ protected AppleFileData shortName = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 14: AFP file information, attributes, and so on. */
+ protected AppleFileData afpFileInfo = AppleFileData.EMPTY_FILE_DATA;
+
+ /** Entry 15: AFP directory ID. */
+ protected AppleFileData directoryID = AppleFileData.EMPTY_FILE_DATA;
+
+ /** The num entries. */
+ protected int numEntries = 0;
+
+ /**
+ * The Apple file format.
+ */
+ public enum FileFormat {
+
+ APPLE_SINGLE,
+ APPLE_DOUBLE,
+ UNKNOWN;
+
+ /**
+ * Return a suitable Apple file format as inferred from the passed-in
+ * string. Otherwise return the UNKNOWN file format.
+ *
+ * @param fileFormat
+ * the file format
+ * @return the FileFormat
+ */
+ public static FileFormat fromString(String fileFormat) {
+ if (fileFormat == null) {
+ return null;
+ }
+
+ try {
+ return FileFormat.valueOf(fileFormat.toUpperCase());
+ } catch (IllegalArgumentException iae) {
+ Log.error("Bad conversion attempt in FileFormat.fromString; string: "
+ + fileFormat + "; message: " + iae.getMessage());
+ Log.exception(iae);
+ return UNKNOWN;
+ }
+ }
+ };
+
+ /**
+ * This class represents the file dates.
+ */
+ public class FileDatesInfoEntry {
+
+ /** The create time. */
+ private int createTime = Integer.MIN_VALUE;
+
+ /** The modify time. */
+ private int modifyTime = Integer.MIN_VALUE;
+
+ /** The backup time. */
+ private int backupTime = Integer.MIN_VALUE;
+
+ /** The access time. */
+ private int accessTime = Integer.MIN_VALUE;
+
+ /**
+ * Instantiates a new file dates info entry.
+ */
+ public FileDatesInfoEntry() {
+
+ }
+
+ /**
+ * Gets the creates the time.
+ *
+ * @return the creates the time
+ */
+ public int getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * Sets the creates the time.
+ *
+ * @param createTime
+ * the new creates the time
+ */
+ public void setCreateTime(int createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * Gets the modify time.
+ *
+ * @return the modify time
+ */
+ public int getModifyTime() {
+ return modifyTime;
+ }
+
+ /**
+ * Sets the modify time.
+ *
+ * @param modifyTime
+ * the new modify time
+ */
+ public void setModifyTime(int modifyTime) {
+ this.modifyTime = modifyTime;
+ }
+
+ /**
+ * Gets the backup time.
+ *
+ * @return the backup time
+ */
+ public int getBackupTime() {
+ return backupTime;
+ }
+
+ /**
+ * Sets the backup time.
+ *
+ * @param backupTime
+ * the new backup time
+ */
+ public void setBackupTime(int backupTime) {
+ this.backupTime = backupTime;
+ }
+
+ /**
+ * Gets the access time.
+ *
+ * @return the access time
+ */
+ public int getAccessTime() {
+ return accessTime;
+ }
+
+ /**
+ * Sets the access time.
+ *
+ * @param accessTime
+ * the new access time
+ */
+ public void setAccessTime(int accessTime) {
+ this.accessTime = accessTime;
+ }
+ }
+
+ /**
+ * Sets the num entries.
+ *
+ * @param numEntries
+ * the new num entries
+ */
+ public void setNumEntries(int numEntries) {
+ this.numEntries = numEntries;
+ }
+
+ /**
+ * Verify the validity of the Apple file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ protected void verify() throws FileDecoderException {
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int position = offset;
+ if (length < 26) {
+ throw new FileDecoderException("File is too short");
+ }
+
+ /* Magic number */
+ int magic = 0;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+ magic <<= 8;
+ magic |= data[(position++)] & 0xFF;
+
+ /* Check Apple file format: AppleSingle or AppleDobule */
+ if (magic == 0x00051600) {
+ this.format = FileFormat.APPLE_SINGLE;
+ } else if (magic == 0x00051607) {
+ this.format = FileFormat.APPLE_DOUBLE;
+ } else {
+ throw new FileDecoderException("Invalid Apple file magic number.");
+ }
+
+ /* Version number */
+ int version = 0;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ version <<= 8;
+ version |= data[(position++)] & 0xFF;
+ if (version != 0x00020000) {
+ throw new FileDecoderException("Unknown Apple file version");
+ }
+
+ /* Filler */
+ position += 16;
+
+ /* Number of entries */
+ this.numEntries = 0;
+ this.numEntries |= data[(position++)] & 0xFF;
+ this.numEntries <<= 8;
+ this.numEntries |= data[(position++)] & 0xFF;
+ if (length < 26 + 12 * this.numEntries) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+
+ /* Check entries */
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ int contentPosition = 26 + 12 * this.numEntries;
+ for (int i = 0; i < this.numEntries; i++) {
+ position = 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(position++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(position++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(position++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+ if ((entryOffset < contentPosition)
+ || (length < entryOffset + entryLength)) {
+ throw new FileDecoderException("Corrupt Apple file data.");
+ }
+ }
+ }
+
+ /**
+ * Extract file dates.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ protected void extractFileDates(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+
+ int position = offset;
+
+ int createTime = 0;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ createTime <<= 8;
+ createTime |= data[(position++)] & 0xFF;
+ int modifyTime = 0;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ modifyTime <<= 8;
+ modifyTime |= data[(position++)] & 0xFF;
+ int backupTime = 0;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ backupTime <<= 8;
+ backupTime |= data[(position++)] & 0xFF;
+ int accessTime = 0;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+ accessTime <<= 8;
+ accessTime |= data[(position++)] & 0xFF;
+
+ this.fileDatesInfoEntry = new FileDatesInfoEntry();
+ fileDatesInfoEntry.setCreateTime(createTime);
+ fileDatesInfoEntry.setModifyTime(modifyTime);
+ fileDatesInfoEntry.setBackupTime(backupTime);
+ fileDatesInfoEntry.setAccessTime(accessTime);
+ }
+
+ /**
+ * Gets the format.
+ *
+ * @return the format
+ */
+ public FileFormat getFormat() {
+ return format;
+ }
+
+ /**
+ * Sets the format.
+ *
+ * @param format
+ * the new format
+ */
+ public void setFormat(FileFormat format) {
+ this.format = format;
+ }
+
+ /**
+ * Gets the file data.
+ *
+ * @return the file data
+ */
+ public AppleFileData getFileData() {
+ return fileData;
+ }
+
+ /**
+ * Sets the file data.
+ *
+ * @param fileData
+ * the new file data
+ */
+ public void setFileData(AppleFileData fileData) {
+ this.fileData = fileData;
+ }
+
+ /**
+ * Gets the data fork.
+ *
+ * @return the data fork
+ */
+ public AppleFileData getDataFork() {
+ return dataFork;
+ }
+
+ /**
+ * Sets the data fork.
+ *
+ * @param dataFork
+ * the new data fork
+ */
+ public void setDataFork(AppleFileData dataFork) {
+ this.dataFork = dataFork;
+ }
+
+ /**
+ * Gets the resource fork.
+ *
+ * @return the resource fork
+ */
+ public AppleFileData getResourceFork() {
+ return resourceFork;
+ }
+
+ /**
+ * Sets the resource fork.
+ *
+ * @param resourceFork
+ * the new resource fork
+ */
+ public void setResourceFork(AppleFileData resourceFork) {
+ this.resourceFork = resourceFork;
+ }
+
+ /**
+ * Gets the real name.
+ *
+ * @return the real name
+ */
+ public AppleFileData getRealName() {
+ return realName;
+ }
+
+ /**
+ * Sets the real name.
+ *
+ * @param realName
+ * the new real name
+ */
+ public void setRealName(AppleFileData realName) {
+ this.realName = realName;
+ }
+
+ /**
+ * Gets the comment.
+ *
+ * @return the comment
+ */
+ public AppleFileData getComment() {
+ return comment;
+ }
+
+ /**
+ * Sets the comment.
+ *
+ * @param comment
+ * the new comment
+ */
+ public void setComment(AppleFileData comment) {
+ this.comment = comment;
+ }
+
+ /**
+ * Gets the icon bw.
+ *
+ * @return the icon bw
+ */
+ public AppleFileData getIconBW() {
+ return iconBW;
+ }
+
+ /**
+ * Sets the icon bw.
+ *
+ * @param iconBW
+ * the new icon bw
+ */
+ public void setIconBW(AppleFileData iconBW) {
+ this.iconBW = iconBW;
+ }
+
+ /**
+ * Gets the icon color.
+ *
+ * @return the icon color
+ */
+ public AppleFileData getIconColor() {
+ return iconColor;
+ }
+
+ /**
+ * Sets the icon color.
+ *
+ * @param iconColor
+ * the new icon color
+ */
+ public void setIconColor(AppleFileData iconColor) {
+ this.iconColor = iconColor;
+ }
+
+ /**
+ * Gets the file dates info.
+ *
+ * @return the file dates info
+ */
+ public AppleFileData getFileDatesInfo() {
+ return fileDatesInfo;
+ }
+
+ /**
+ * Sets the file dates info.
+ *
+ * @param fileDatesInfo
+ * the new file dates info
+ */
+ public void setFileDatesInfo(AppleFileData fileDatesInfo) {
+ this.fileDatesInfo = fileDatesInfo;
+ }
+
+ /**
+ * Gets the finder info.
+ *
+ * @return the finder info
+ */
+ public AppleFileData getFinderInfo() {
+ return finderInfo;
+ }
+
+ /**
+ * Sets the finder info.
+ *
+ * @param finderInfo
+ * the new finder info
+ */
+ public void setFinderInfo(AppleFileData finderInfo) {
+ this.finderInfo = finderInfo;
+ }
+
+ /**
+ * Gets the macintosh info.
+ *
+ * @return the macintosh info
+ */
+ public AppleFileData getMacintoshInfo() {
+ return macintoshInfo;
+ }
+
+ /**
+ * Sets the macintosh info.
+ *
+ * @param macintoshInfo
+ * the new macintosh info
+ */
+ public void setMacintoshInfo(AppleFileData macintoshInfo) {
+ this.macintoshInfo = macintoshInfo;
+ }
+
+ /**
+ * Gets the pro dos file info.
+ *
+ * @return the pro dos file info
+ */
+ public AppleFileData getProDOSFileInfo() {
+ return proDOSFileInfo;
+ }
+
+ /**
+ * Sets the pro dos file info.
+ *
+ * @param proDOSFileInfo
+ * the new pro dos file info
+ */
+ public void setProDOSFileInfo(AppleFileData proDOSFileInfo) {
+ this.proDOSFileInfo = proDOSFileInfo;
+ }
+
+ /**
+ * Gets the ms dos file info.
+ *
+ * @return the ms dos file info
+ */
+ public AppleFileData getMsDOSFileInfo() {
+ return msDOSFileInfo;
+ }
+
+ /**
+ * Sets the ms dos file info.
+ *
+ * @param msDOSFileInfo
+ * the new ms dos file info
+ */
+ public void setMsDOSFileInfo(AppleFileData msDOSFileInfo) {
+ this.msDOSFileInfo = msDOSFileInfo;
+ }
+
+ /**
+ * Gets the short name.
+ *
+ * @return the short name
+ */
+ public AppleFileData getShortName() {
+ return shortName;
+ }
+
+ /**
+ * Sets the short name.
+ *
+ * @param shortName
+ * the new short name
+ */
+ public void setShortName(AppleFileData shortName) {
+ this.shortName = shortName;
+ }
+
+ /**
+ * Gets the afp file info.
+ *
+ * @return the afp file info
+ */
+ public AppleFileData getAfpFileInfo() {
+ return afpFileInfo;
+ }
+
+ /**
+ * Sets the afp file info.
+ *
+ * @param afpFileInfo
+ * the new afp file info
+ */
+ public void setAfpFileInfo(AppleFileData afpFileInfo) {
+ this.afpFileInfo = afpFileInfo;
+ }
+
+ /**
+ * Gets the directory id.
+ *
+ * @return the directory id
+ */
+ public AppleFileData getDirectoryID() {
+ return directoryID;
+ }
+
+ /**
+ * Sets the directory id.
+ *
+ * @param directoryID
+ * the new directory id
+ */
+ public void setDirectoryID(AppleFileData directoryID) {
+ this.directoryID = directoryID;
+ }
+
+ /**
+ * Gets the num entries.
+ *
+ * @return the num entries
+ */
+ public int getNumEntries() {
+ return numEntries;
+ }
}
\ No newline at end of file
diff --git a/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java b/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
index f28c979a..d89471e2 100644
--- a/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
+++ b/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileData.java
@@ -1,91 +1,91 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-/**
- * This class is for representing the AppleSingle/Double file or its file forks
- * (data fork and resource fork) and the related Finder meta-file information.
- */
-public final class AppleFileData {
-
- public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
- private byte[] data;
- private int offset;
- private int length;
-
- /**
- * Instantiates a new apple file data.
- */
- public AppleFileData() {
- this.data = new byte[0];
- this.offset = 0;
- this.length = 0;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- */
- public AppleFileData(byte[] data) {
- this.data = data;
- this.offset = 0;
- this.length = data.length;
- }
-
- /**
- * Instantiates a new apple file data.
- *
- * @param data the data
- * @param offset the offset
- * @param length the length
- */
- public AppleFileData(byte[] data, int offset, int length) {
- if ((0 > offset) || (offset > data.length))
- throw new IndexOutOfBoundsException();
- if ((0 > length) || (length > data.length - offset))
- throw new IndexOutOfBoundsException();
- this.data = data;
- this.offset = offset;
- this.length = length;
- }
-
- /**
- * Gets the bytes.
- *
- * @return the bytes
- */
- public byte[] getBytes() {
- byte[] data = new byte[this.length];
- System.arraycopy(this.data, this.offset, data, 0, this.length);
- return data;
- }
-
- /**
- * Gets the data.
- *
- * @return the data
- */
- public byte[] getData() {
- return this.data;
- }
-
- /**
- * Gets the offset.
- *
- * @return the offset
- */
- public int getOffset() {
- return this.offset;
- }
-
- /**
- * Gets the length.
- *
- * @return the length
- */
- public int getLength() {
- return this.length;
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+/**
+ * This class is for representing the AppleSingle/Double file or its file forks
+ * (data fork and resource fork) and the related Finder meta-file information.
+ */
+public final class AppleFileData {
+
+ public static final AppleFileData EMPTY_FILE_DATA = new AppleFileData();
+ private byte[] data;
+ private int offset;
+ private int length;
+
+ /**
+ * Instantiates a new apple file data.
+ */
+ public AppleFileData() {
+ this.data = new byte[0];
+ this.offset = 0;
+ this.length = 0;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ */
+ public AppleFileData(byte[] data) {
+ this.data = data;
+ this.offset = 0;
+ this.length = data.length;
+ }
+
+ /**
+ * Instantiates a new apple file data.
+ *
+ * @param data the data
+ * @param offset the offset
+ * @param length the length
+ */
+ public AppleFileData(byte[] data, int offset, int length) {
+ if ((0 > offset) || (offset > data.length))
+ throw new IndexOutOfBoundsException();
+ if ((0 > length) || (length > data.length - offset))
+ throw new IndexOutOfBoundsException();
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Gets the bytes.
+ *
+ * @return the bytes
+ */
+ public byte[] getBytes() {
+ byte[] data = new byte[this.length];
+ System.arraycopy(this.data, this.offset, data, 0, this.length);
+ return data;
+ }
+
+ /**
+ * Gets the data.
+ *
+ * @return the data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * Gets the offset.
+ *
+ * @return the offset
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+
+ /**
+ * Gets the length.
+ *
+ * @return the length
+ */
+ public int getLength() {
+ return this.length;
+ }
}
\ No newline at end of file
diff --git a/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java b/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
index 3248f85d..aa7b0363 100644
--- a/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
+++ b/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileDecoder.java
@@ -1,143 +1,143 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.Log;
-import com.perforce.p4java.exception.FileDecoderException;
-
-/**
- * This class handles the extraction of the data fork, resource fork and other
- * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
- * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
- * file type is a compressed AppleDouble (Mac resource fork) file.
- */
-public class AppleFileDecoder extends AppleFile {
-
- /**
- * Instantiates a new apple file decoder.
- *
- * @param fileData
- * the file data
- */
- public AppleFileDecoder(AppleFileData fileData) {
- if (fileData != null) {
- this.fileData = fileData;
- }
- }
-
- /**
- * Extract the data fork, resource fork and other entries from the Apple
- * file.
- *
- * @throws FileDecoderException
- * the file decoder exception
- */
- @SuppressWarnings("unused")
- public void extract() throws FileDecoderException {
- // Verify the validity of the Apple file
- verify();
-
- byte[] data = this.fileData.getData();
- int offset = this.fileData.getOffset();
- int length = this.fileData.getLength();
- int contentPosition = 0;
- int entryId = 0;
- int entryOffset = 0;
- int entryLength = 0;
- for (int i = 0; i < this.numEntries; i++) {
- contentPosition = offset + 26 + i * 12;
- /* Entry ID */
- entryId = 0;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
- entryId <<= 8;
- entryId |= data[(contentPosition++)] & 0xFF;
-
- /* Entry offset */
- entryOffset = 0;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset <<= 8;
- entryOffset |= data[(contentPosition++)] & 0xFF;
- entryOffset &= 0x7FFFFFFF;
-
- /* Entry length */
- entryLength = 0;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength <<= 8;
- entryLength |= data[(contentPosition++)] & 0xFF;
- entryLength &= 0x7FFFFFFF;
-
- switch (entryId) {
- case 1:
- this.dataFork = new AppleFileData(data, offset + entryOffset,
- entryLength);
- break;
- case 2:
- this.resourceFork = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 3:
- this.realName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 4:
- this.comment = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 5:
- this.iconBW = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 6:
- this.iconColor = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 8:
- this.fileDatesInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- extractFileDates(data, offset + entryOffset, entryLength);
- break;
- case 9:
- this.finderInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 10:
- this.macintoshInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 11:
- this.proDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 12:
- this.msDOSFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- case 13:
- this.shortName = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 14:
- this.afpFileInfo = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- case 15:
- this.directoryID = new AppleFileData(data, offset
- + entryOffset, entryLength);
- break;
- default:
- Log.warn("Apple file entry ID: " + entryId + " is not handled.");
-
- }
- }
- }
+/**
+ * Copyright 2012 Perforce Software Inc., All Rights Reserved.
+ */
+package com.perforce.p4java.io.apple;
+
+import com.perforce.p4java.Log;
+import com.perforce.p4java.exception.FileDecoderException;
+
+/**
+ * This class handles the extraction of the data fork, resource fork and other
+ * entries from an AppleSingle/Double file. The Perforce 'apple' file type is a
+ * compressed AppleSingle (Mac resource + data) file. The Perforce 'resource'
+ * file type is a compressed AppleDouble (Mac resource fork) file.
+ */
+public class AppleFileDecoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @param fileData
+ * the file data
+ */
+ public AppleFileDecoder(AppleFileData fileData) {
+ if (fileData != null) {
+ this.fileData = fileData;
+ }
+ }
+
+ /**
+ * Extract the data fork, resource fork and other entries from the Apple
+ * file.
+ *
+ * @throws FileDecoderException
+ * the file decoder exception
+ */
+ @SuppressWarnings("unused")
+ public void extract() throws FileDecoderException {
+ // Verify the validity of the Apple file
+ verify();
+
+ byte[] data = this.fileData.getData();
+ int offset = this.fileData.getOffset();
+ int length = this.fileData.getLength();
+ int contentPosition = 0;
+ int entryId = 0;
+ int entryOffset = 0;
+ int entryLength = 0;
+ for (int i = 0; i < this.numEntries; i++) {
+ contentPosition = offset + 26 + i * 12;
+ /* Entry ID */
+ entryId = 0;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+ entryId <<= 8;
+ entryId |= data[(contentPosition++)] & 0xFF;
+
+ /* Entry offset */
+ entryOffset = 0;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset <<= 8;
+ entryOffset |= data[(contentPosition++)] & 0xFF;
+ entryOffset &= 0x7FFFFFFF;
+
+ /* Entry length */
+ entryLength = 0;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength <<= 8;
+ entryLength |= data[(contentPosition++)] & 0xFF;
+ entryLength &= 0x7FFFFFFF;
+
+ switch (entryId) {
+ case 1:
+ this.dataFork = new AppleFileData(data, offset + entryOffset,
+ entryLength);
+ break;
+ case 2:
+ this.resourceFork = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 3:
+ this.realName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 4:
+ this.comment = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 5:
+ this.iconBW = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 6:
+ this.iconColor = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 8:
+ this.fileDatesInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ extractFileDates(data, offset + entryOffset, entryLength);
+ break;
+ case 9:
+ this.finderInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 10:
+ this.macintoshInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 11:
+ this.proDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 12:
+ this.msDOSFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ case 13:
+ this.shortName = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 14:
+ this.afpFileInfo = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ case 15:
+ this.directoryID = new AppleFileData(data, offset
+ + entryOffset, entryLength);
+ break;
+ default:
+ Log.warn("Apple file entry ID: " + entryId + " is not handled.");
+
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java b/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
index 7c5d0a04..abdfed59 100644
--- a/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
+++ b/p4java/src/main/java/com/perforce/p4java/io/apple/AppleFileEncoder.java
@@ -1,300 +1,300 @@
-/**
- * Copyright 2012 Perforce Software Inc., All Rights Reserved.
- */
-package com.perforce.p4java.io.apple;
-
-import com.perforce.p4java.exception.FileEncoderException;
-
-/**
- * This class handles the combination of the data fork, resource fork and other
- * entries into an AppleSingle/Double file.
- *
+ *
+ * Note that if it is an AppleDouble, the data fork is a separate file external
+ * to this file.
+ */
+public class AppleFileEncoder extends AppleFile {
+
+ /**
+ * Instantiates a new apple file decoder.
+ *
+ * @throws FileEncoderException
+ */
+ public AppleFileEncoder(FileFormat fileFormat) throws FileEncoderException {
+ if (fileFormat == null) {
+ throw new FileEncoderException("Null file format passed to the AppleFileEncoder constructor.");
+ }
+ if (fileFormat == FileFormat.UNKNOWN) {
+ throw new FileEncoderException("Unknown file format passed to the AppleFileEncoder constructor.");
+ }
+ }
+
+ /**
+ * Combine the data fork, resource fork and other entries into an
+ * AppleSingle/Double file.
+ *
+ * @throws FileEncoderException
+ * the file encoder exception
+ */
+ @SuppressWarnings("unused")
+ public void combine() throws FileEncoderException {
+
+ boolean isAppleSingle = (this.format == FileFormat.APPLE_SINGLE);
+ boolean isAppleDouble = (this.format == FileFormat.APPLE_DOUBLE);
+
+ boolean hasDataFork = (this.dataFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasResourceFork = (this.resourceFork != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasRealName = (this.realName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasComment = (this.comment != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconBW = (this.iconBW != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasIconColor = (this.iconColor != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasFileDatesInfo = (this.fileDatesInfoEntry != null);
+ boolean hasFinderInfo = (this.finderInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMacintoshInfo = (this.macintoshInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasProDOSFileInfo = (this.proDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasMsDOSFileInfo = (this.msDOSFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasShortName = (this.shortName != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasAfpFileInfo = (this.afpFileInfo != AppleFileData.EMPTY_FILE_DATA);
+ boolean hasDirectoryID = (this.directoryID != AppleFileData.EMPTY_FILE_DATA);
+
+ this.fileData = AppleFileData.EMPTY_FILE_DATA;
+
+ int length = 90 + this.realName.getLength()
+ + this.resourceFork.getLength();
+
+ /* AppleSingle includes the data fork */
+ if (isAppleSingle) {
+ length += this.dataFork.getLength();
+ }
+
+ byte[] data = new byte[length];
+ int position = 0;
+
+ /* Magic number for AppleSingle or AppleDouble */
+ if (isAppleDouble) {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 0;
+ } else {
+ data[(position++)] = 0;
+ data[(position++)] = 5;
+ data[(position++)] = 22;
+ data[(position++)] = 7;
+ }
+
+ /* Version number */
+ data[(position++)] = 0;
+ data[(position++)] = 2;
+ data[(position++)] = 0;
+ data[(position++)] = 0;
+
+ /* Filler */
+
+ for (int k = 0; k < 16; k++) {
+ data[(position++)] = 0;
+ }
+
+ /* Number of entries */
+ this.numEntries = 0;
+ if (hasRealName) {
+ this.numEntries += 1;
+ }
+ if (hasFileDatesInfo) {
+ this.numEntries += 1;
+ }
+ if (hasResourceFork) {
+ this.numEntries += 1;
+ }
+ if ((hasDataFork) && (isAppleSingle)) {
+ this.numEntries += 1;
+ }
+ data[(position++)] = ((byte) (this.numEntries >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.numEntries & 0xFF));
+
+ /* Header information for the entries */
+
+ /* Real name entry header */
+ int realNamePosition = 0;
+ if (hasRealName) {
+ int realNameEntryId = 3;
+ int realNameEntryOffset = 0;
+ int realNameEntryLength = this.realName.getLength();
+ data[(position++)] = ((byte) (realNameEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryId >> 0 & 0xFF));
+ realNamePosition = position;
+ data[(position++)] = ((byte) (realNameEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNameEntryLength >> 0 & 0xFF));
+ }
+
+ /* File dates info entry header */
+ int fileDatesInfoPosition = 0;
+ if (hasFileDatesInfo) {
+ int fileDatesInfoEntryId = 8;
+ int fileDatesInfoEntryOffset = 0;
+ int fileDatesInfoEntryLength = 16;
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryId >> 0 & 0xFF));
+ fileDatesInfoPosition = position;
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoEntryLength >> 0 & 0xFF));
+ }
+
+ /* Resource fork entry header */
+ int resourceForkPosition = 0;
+ if (hasResourceFork) {
+ int resourceForkEntryId = 2;
+ int resourceForkEntryOffset = 0;
+ int resourceFokrEntryLength = this.resourceFork.getLength();
+ data[(position++)] = ((byte) (resourceForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryId >> 0 & 0xFF));
+ resourceForkPosition = position;
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceFokrEntryLength >> 0 & 0xFF));
+ }
+
+ /* Data fork entry header */
+ int dataForkPosition = 0;
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkEntryId = 1;
+ int dataForkEntryOffset = 0;
+ int dataForkEntryLength = this.dataFork.getLength();
+ data[(position++)] = ((byte) (dataForkEntryId >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryId >> 0 & 0xFF));
+ dataForkPosition = position;
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryOffset >> 0 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkEntryLength >> 0 & 0xFF));
+ }
+
+ /* Content for the entries */
+
+ /* Real name content */
+ if (hasRealName) {
+ int realNamePositionCurrent = position;
+ position = realNamePosition;
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (realNamePositionCurrent >> 0 & 0xFF));
+ position = realNamePositionCurrent;
+ byte[] realNameData = this.realName.getData();
+ int realNameOffset = this.realName.getOffset();
+ int realNameLength = this.realName.getLength();
+ System.arraycopy(realNameData, realNameOffset, data, position,
+ realNameLength);
+ position += realNameLength;
+ }
+
+ /* File dates info content */
+ if (hasFileDatesInfo) {
+ int fileDatesInfoPositionCurrent = position;
+ position = fileDatesInfoPosition;
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (fileDatesInfoPositionCurrent >> 0 & 0xFF));
+ position = fileDatesInfoPositionCurrent;
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getCreateTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getModifyTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getBackupTime() >> 0 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 24 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 16 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 8 & 0xFF));
+ data[(position++)] = ((byte) (this.fileDatesInfoEntry
+ .getAccessTime() >> 0 & 0xFF));
+ }
+
+ /* Resource fork content */
+ if (hasResourceFork) {
+ int resourceForkPositionCurrent = position;
+ position = resourceForkPosition;
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 24 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 16 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 8 & 0xFF));
+ data[(position++)] = ((byte) (resourceForkPositionCurrent >> 0 & 0xFF));
+ position = resourceForkPositionCurrent;
+ byte[] resourceForkData = this.resourceFork.getData();
+ int resourceForkOffset = this.resourceFork.getOffset();
+ int resourceForkLength = this.resourceFork.getLength();
+ System.arraycopy(resourceForkData, resourceForkOffset, data,
+ position, resourceForkLength);
+ position += resourceForkLength;
+ }
+
+ /* Data fork content */
+ if ((hasDataFork) && (isAppleSingle)) {
+ int dataForkPosition2 = position;
+ position = dataForkPosition;
+ data[(position++)] = ((byte) (dataForkPosition2 >> 24 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 16 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 8 & 0xFF));
+ data[(position++)] = ((byte) (dataForkPosition2 >> 0 & 0xFF));
+ position = dataForkPosition2;
+ byte[] dataForkData = this.dataFork.getData();
+ int dataForkOffset = this.dataFork.getOffset();
+ int dataForkLength = this.dataFork.getLength();
+ System.arraycopy(dataForkData, dataForkOffset, data, position,
+ dataForkLength);
+ position += dataForkLength;
+ }
+
+ /* Create the Apple file data */
+ this.fileData = new AppleFileData(data, 0, position);
+ }
}
\ No newline at end of file
diff --git a/p4java/src/main/java/com/perforce/p4java/server/IServerMessage.java b/p4java/src/main/java/com/perforce/p4java/server/IServerMessage.java
index 8ee5d3a1..89913cb0 100644
--- a/p4java/src/main/java/com/perforce/p4java/server/IServerMessage.java
+++ b/p4java/src/main/java/com/perforce/p4java/server/IServerMessage.java
@@ -1,79 +1,79 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.perforce.p4java.server;
-
-import com.perforce.p4java.impl.generic.core.file.FilePath;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import java.io.UnsupportedEncodingException;
-import java.util.Map;
-
-/**
- * Represents a message from the server, along with the localized version of it.
- * The message can contain multiple problems. The top level message represents
- * the highest severity message.
- *
- * To create this, see {@link com.perforce.p4java.impl.mapbased.server.cmd.ResultMapParser#toServerMessage(Map)}
- */
-public interface IServerMessage extends ISingleServerMessage {
- @Nonnull
- Iterable getAllMessages();
-
- /**
- * @return the list of messages that had at least the minimum severity.
- */
- @Nonnull
- Iterable getForSeverity(int minimum);
-
- /**
- * @return the list of messages that had at least the minimum severity.
- */
- @Nonnull
- Iterable getForExactSeverity(int minimum);
-
- boolean hasSeverity(int minimum);
-
- /**
- * @return true if the message is an informative message (info, error, fatal, etc.)
- */
- boolean isInfoOrError();
-
- boolean isInfo();
-
- boolean isWarning();
-
- boolean isError();
-
- @Nonnull
- String getFirstInfoString();
-
- @Nonnull
- String getAllInfoStrings();
-
- @Nonnull
- String getAllInfoStrings(@Nonnull String separator);
-
- byte[] getBytes(String charsetName) throws UnsupportedEncodingException;
-
- /**
- * Returns the raw string that the server call to getErrorOrInfoStr originally returned.
- * This is for writing data back to the RPC output stream.
- *
- * @return raw info string
- */
- @Nullable
- String getErrorOrInfoStr();
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.perforce.p4java.server;
+
+import com.perforce.p4java.impl.generic.core.file.FilePath;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+/**
+ * Represents a message from the server, along with the localized version of it.
+ * The message can contain multiple problems. The top level message represents
+ * the highest severity message.
+ *
+ * To create this, see {@link com.perforce.p4java.impl.mapbased.server.cmd.ResultMapParser#toServerMessage(Map)}
+ */
+public interface IServerMessage extends ISingleServerMessage {
+ @Nonnull
+ Iterable getAllMessages();
+
+ /**
+ * @return the list of messages that had at least the minimum severity.
+ */
+ @Nonnull
+ Iterable getForSeverity(int minimum);
+
+ /**
+ * @return the list of messages that had at least the minimum severity.
+ */
+ @Nonnull
+ Iterable getForExactSeverity(int minimum);
+
+ boolean hasSeverity(int minimum);
+
+ /**
+ * @return true if the message is an informative message (info, error, fatal, etc.)
+ */
+ boolean isInfoOrError();
+
+ boolean isInfo();
+
+ boolean isWarning();
+
+ boolean isError();
+
+ @Nonnull
+ String getFirstInfoString();
+
+ @Nonnull
+ String getAllInfoStrings();
+
+ @Nonnull
+ String getAllInfoStrings(@Nonnull String separator);
+
+ byte[] getBytes(String charsetName) throws UnsupportedEncodingException;
+
+ /**
+ * Returns the raw string that the server call to getErrorOrInfoStr originally returned.
+ * This is for writing data back to the RPC output stream.
+ *
+ * @return raw info string
+ */
+ @Nullable
+ String getErrorOrInfoStr();
+}
diff --git a/p4java/src/main/java/com/perforce/p4java/server/ISingleServerMessage.java b/p4java/src/main/java/com/perforce/p4java/server/ISingleServerMessage.java
index 50320fc3..c16ab123 100644
--- a/p4java/src/main/java/com/perforce/p4java/server/ISingleServerMessage.java
+++ b/p4java/src/main/java/com/perforce/p4java/server/ISingleServerMessage.java
@@ -1,91 +1,91 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.perforce.p4java.server;
-
-/**
- * Represents a message from the server, along with the localized version of it.
- */
-public interface ISingleServerMessage {
- /**
- * Localized message with argument replacements.
- *
- * @return localized message
- */
- String getLocalizedMessage();
-
- /**
- * The localized message format text, without argument replacements.
- *
- * @return localized format for the message text.
- */
- String getMessageFormat();
-
- /**
- *
- * @return the documented severity level of the message.
- * @see com.perforce.p4java.exception.MessageSeverityCode
- */
- int getSeverity();
-
- /**
- *
- * @return subsystem message code
- * @see com.perforce.p4java.exception.MessageSubsystemCode
- */
- int getSubSystem();
-
- /**
- *
- * @return the documented generic code for the message.
- * @see com.perforce.p4java.exception.MessageGenericCode
- */
- int getGeneric();
-
- /**
- * The unique code for the message. Nearly the same as the raw code.
- *
- * @return the unique code
- */
- int getUniqueCode();
-
- /**
- *
- * @return the sub-code
- * @see IServerMessageCode
- */
- int getSubCode();
-
- /**
- *
- * @return the raw, unparsed code.
- */
- int getRawCode();
-
- /**
- * Checks if the given string fragment is in the message.
- *
- * @param fragment
- * @return true if the fragment is in the message.
- * @deprecated here until the string matching is eliminated
- */
- boolean hasMessageFragment(String fragment);
-
- /**
- *
- * @return string version of the status code
- */
- String getCode();
-
-}
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.perforce.p4java.server;
+
+/**
+ * Represents a message from the server, along with the localized version of it.
+ */
+public interface ISingleServerMessage {
+ /**
+ * Localized message with argument replacements.
+ *
+ * @return localized message
+ */
+ String getLocalizedMessage();
+
+ /**
+ * The localized message format text, without argument replacements.
+ *
+ * @return localized format for the message text.
+ */
+ String getMessageFormat();
+
+ /**
+ *
+ * @return the documented severity level of the message.
+ * @see com.perforce.p4java.exception.MessageSeverityCode
+ */
+ int getSeverity();
+
+ /**
+ *
+ * @return subsystem message code
+ * @see com.perforce.p4java.exception.MessageSubsystemCode
+ */
+ int getSubSystem();
+
+ /**
+ *
+ * @return the documented generic code for the message.
+ * @see com.perforce.p4java.exception.MessageGenericCode
+ */
+ int getGeneric();
+
+ /**
+ * The unique code for the message. Nearly the same as the raw code.
+ *
+ * @return the unique code
+ */
+ int getUniqueCode();
+
+ /**
+ *
+ * @return the sub-code
+ * @see IServerMessageCode
+ */
+ int getSubCode();
+
+ /**
+ *
+ * @return the raw, unparsed code.
+ */
+ int getRawCode();
+
+ /**
+ * Checks if the given string fragment is in the message.
+ *
+ * @param fragment
+ * @return true if the fragment is in the message.
+ * @deprecated here until the string matching is eliminated
+ */
+ boolean hasMessageFragment(String fragment);
+
+ /**
+ *
+ * @return string version of the status code
+ */
+ String getCode();
+
+}
diff --git a/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java b/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
index ce3a3b73..68456034 100644
--- a/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
+++ b/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features123/SymbolicLinkHelperTest.java
@@ -1,95 +1,95 @@
-/**
- * Copyright (c) 2012 Perforce Software. All rights reserved.
- */
-package com.perforce.p4java.tests.dev.unit.features123;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-
-import com.perforce.p4java.tests.dev.UnitTestDevServerManager;
-import com.perforce.p4java.tests.ignoreRule.ConditionallyIgnoreClassRule;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Test;
-
-import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
-import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
-
-/**
- * Test symbolic link helper (JDK 7 or above)
- */
-public class SymbolicLinkHelperTest extends P4JavaTestCase {
-
- @ClassRule
- public static ConditionallyIgnoreClassRule ignoreWindows = ConditionallyIgnoreClassRule.ifWindows(
- "Creates paths that can't be used on Windows");
-
- /**
- * @BeforeClass annotation to a method to be run before all the tests in a
- * class.
- */
- @BeforeClass
- public static void oneTimeSetUp() {
- // one-time initialization code (before all the tests).
- // p4ic4idea: use local server
- UnitTestDevServerManager.INSTANCE.startTestClass("unicode");
- }
-
- /**
- * @AfterClass annotation to a method to be run after all the tests in a
- * class.
- */
- @AfterClass
- public static void oneTimeTearDown() {
- // one-time cleanup code (after all the tests).
- // p4ic4idea: use local server
- UnitTestDevServerManager.INSTANCE.endTestClass("unicode");
- }
-
- /**
- * @Before annotation to a method to be run before each test in a class.
- */
- @Before
- public void setUp() {
- // initialization code (before each test).
- }
-
- /**
- * @After annotation to a method to be run after each test in a class.
- */
- @After
- public void tearDown() {
- // cleanup code (after each test).
- }
-
- /**
- * Test symbolic link
- */
- @Test
- public void tesSymbolicLink() {
- // Check if symlink capable
- if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
-
- String target = "/usr/bin";
- String link = "/tmp/user-bin-" + getRandomInt();
-
- // Create symbolic link
- String path = SymbolicLinkHelper.createSymbolicLink(link, target);
- assertNotNull(path);
-
- boolean isSymlink = SymbolicLinkHelper.isSymbolicLink(path);
- assertTrue(isSymlink);
-
- File file = new File(path);
- if (file.exists()) {
- assertTrue(file.delete());
- }
- }
- }
-
-}
+/**
+ * Copyright (c) 2012 Perforce Software. All rights reserved.
+ */
+package com.perforce.p4java.tests.dev.unit.features123;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import com.perforce.p4java.tests.dev.UnitTestDevServerManager;
+import com.perforce.p4java.tests.ignoreRule.ConditionallyIgnoreClassRule;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import com.perforce.p4java.impl.mapbased.rpc.sys.helper.SymbolicLinkHelper;
+import com.perforce.p4java.tests.dev.unit.P4JavaTestCase;
+
+/**
+ * Test symbolic link helper (JDK 7 or above)
+ */
+public class SymbolicLinkHelperTest extends P4JavaTestCase {
+
+ @ClassRule
+ public static ConditionallyIgnoreClassRule ignoreWindows = ConditionallyIgnoreClassRule.ifWindows(
+ "Creates paths that can't be used on Windows");
+
+ /**
+ * @BeforeClass annotation to a method to be run before all the tests in a
+ * class.
+ */
+ @BeforeClass
+ public static void oneTimeSetUp() {
+ // one-time initialization code (before all the tests).
+ // p4ic4idea: use local server
+ UnitTestDevServerManager.INSTANCE.startTestClass("unicode");
+ }
+
+ /**
+ * @AfterClass annotation to a method to be run after all the tests in a
+ * class.
+ */
+ @AfterClass
+ public static void oneTimeTearDown() {
+ // one-time cleanup code (after all the tests).
+ // p4ic4idea: use local server
+ UnitTestDevServerManager.INSTANCE.endTestClass("unicode");
+ }
+
+ /**
+ * @Before annotation to a method to be run before each test in a class.
+ */
+ @Before
+ public void setUp() {
+ // initialization code (before each test).
+ }
+
+ /**
+ * @After annotation to a method to be run after each test in a class.
+ */
+ @After
+ public void tearDown() {
+ // cleanup code (after each test).
+ }
+
+ /**
+ * Test symbolic link
+ */
+ @Test
+ public void tesSymbolicLink() {
+ // Check if symlink capable
+ if (SymbolicLinkHelper.isSymbolicLinkCapable()) {
+
+ String target = "/usr/bin";
+ String link = "/tmp/user-bin-" + getRandomInt();
+
+ // Create symbolic link
+ String path = SymbolicLinkHelper.createSymbolicLink(link, target);
+ assertNotNull(path);
+
+ boolean isSymlink = SymbolicLinkHelper.isSymbolicLink(path);
+ assertTrue(isSymlink);
+
+ File file = new File(path);
+ if (file.exists()) {
+ assertTrue(file.delete());
+ }
+ }
+ }
+
+}
diff --git a/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features132/ClientCompressSyncTest.java b/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features132/ClientCompressSyncTest.java
index 1e538a28..3210b4c8 100644
--- a/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features132/ClientCompressSyncTest.java
+++ b/p4java/src/test/java/com/perforce/p4java/tests/dev/unit/features132/ClientCompressSyncTest.java
@@ -1,131 +1,131 @@
-/**
- * Copyright (c) 2013 Perforce Software. All rights reserved.
- */
-package com.perforce.p4java.tests.dev.unit.features132;
-
-import com.perforce.p4java.exception.AccessException;
-import com.perforce.p4java.exception.ConnectionException;
-import com.perforce.p4java.exception.P4JavaException;
-import com.perforce.p4java.exception.RequestException;
-import com.perforce.p4java.server.CmdSpec;
-import com.perforce.p4java.tests.UnicodeServerRule;
-import com.perforce.p4java.tests.dev.annotations.Jobs;
-import com.perforce.p4java.tests.dev.annotations.TestId;
-import com.perforce.p4java.tests.dev.unit.P4JavaRshTestCase;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/**
- * Test P4Java sync using JZlib with client compression mode.
- */
-@Jobs({ "job066779" })
-@TestId("Dev132_ClientCompressSyncTest")
-public class ClientCompressSyncTest extends P4JavaRshTestCase {
-
- @ClassRule
- public static UnicodeServerRule p4d = new UnicodeServerRule("r16.1", ClientCompressSyncTest.class.getSimpleName());
-
- String serverMessage = null;
- long completedTime = 0;
-
- /**
- * @Before annotation to a method to be run before each test in a class.
- */
- @Before
- public void setUp() {
- try {
- final String depotName = this.getRandomName(false, "p4TestUserWSCompress-depot");
- final String clientName = "p4TestUserWSCompress";
- final String clientDescription = "temp stream client for test";
- final String clientRoot = Paths.get("").toAbsolutePath().toString();
- final String[] clientViews = {"//" + depotName + "/... //" + clientName + "/..."};
-
- Properties props = new Properties();
- props.put("sockPerfPrefs", "3, 2, 1");
- props.put("sockSoTimeout", 0);
-
- setupServer(p4d.getRSHURL(), userName, password,true, props);
- setupUtf8(server);
- createLocalDepot(depotName, server);
-
- client = createClient(server, clientName, clientDescription, clientRoot, clientViews);
- } catch (Exception e) {
- fail("Unexpected exception: " + e.getLocalizedMessage());
- }
- }
-
- /**
- * @After annotation to a method to be run after each test in a class.
- */
- @After
- public void tearDown() {
- // cleanup code (after each test).
- if (server != null) {
- endServerSession(server);
- }
- }
-
- /**
- * Test "p4 sync" using Process.exec("p4 sync")
- */
- @Test
- @Ignore("Seems pointless to run this in shell immediately before the same in java")
- public void testCmdSync() {
-
- try {
- String[] command = new String[] {"/bin/sh", "-c", "/opt/perforce/p4/p4 -p"
- + server.getServerInfo().getServerAddress() + " -u"
- + userName + " -P" + server.getAuthTicket() + " -c"
- + client.getName() + " sync -f //depot/..."};
-
- ProcessBuilder builder = new ProcessBuilder(command);
-
- final Process process = builder.start();
- process.waitFor();
- System.out.println("Program terminated!");
-
- } catch (IOException e) {
- fail("Unexpected exception: " + e.getLocalizedMessage());
- } catch (ConnectionException e) {
- fail("Unexpected exception: " + e.getLocalizedMessage());
- } catch (RequestException e) {
- fail("Unexpected exception: " + e.getLocalizedMessage());
- } catch (AccessException e) {
- fail("Unexpected exception: " + e.getLocalizedMessage());
- } catch (InterruptedException e) {
- fail("Unexpected exception: " + e.getLocalizedMessage());
- }
- }
-
- /**
- * Test "p4 sync" using execMapCmd
- */
- @Test
- public void testExecMapCmdSync() {
-
- try {
- /** Limited to /depot/basic/... to reduce the memory load. */
- List