content: /*
   * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  package javac.internal.jrtfs;
  
  import java.nio.file.LinkOption;
  import java.nio.file.attribute.*;
  import java.io.IOException;
  import java.util.LinkedHashMap;
  import java.util.Map;
  import java.util.Objects;
  
  /**
   * File attribute view for jrt file system.
   *
   * @implNote This class needs to maintain JDK 8 source compatibility.
   *
   * It is used internally in the JDK to implement jimage/jrtfs access,
   * but also compiled and delivered as part of the jrtfs.jar to support access
   * to the jimage file provided by the shipped JDK by tools running on JDK 8.
   */
  final class JrtFileAttributeView implements BasicFileAttributeView {
  
      private static enum AttrID {
          size,
          creationTime,
          lastAccessTime,
          lastModifiedTime,
          isDirectory,
          isRegularFile,
          isSymbolicLink,
          isOther,
          fileKey,
          compressedSize,
          extension
      };
  
      private final JrtPath path;
      private final boolean isJrtView;
      private final LinkOption[] options;
  
      private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) {
          this.path = path;
          this.isJrtView = isJrtView;
          this.options = options;
      }
  
      @SuppressWarnings("unchecked") // Cast to V
      static <V extends FileAttributeView> V get(JrtPath path, Class<V> type, LinkOption... options) {
          Objects.requireNonNull(type);
          if (type == BasicFileAttributeView.class) {
              return (V) new JrtFileAttributeView(path, false, options);
          }
          if (type == JrtFileAttributeView.class) {
              return (V) new JrtFileAttributeView(path, true, options);
          }
          return null;
      }
  
      static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) {
          Objects.requireNonNull(type);
          if (type.equals("basic")) {
              return new JrtFileAttributeView(path, false, options);
          }
          if (type.equals("jrt")) {
              return new JrtFileAttributeView(path, true, options);
          }
          return null;
      }
  
      @Override
      public String name() {
          return isJrtView ? "jrt" : "basic";
      }
  
      @Override
      public JrtFileAttributes readAttributes() throws IOException {
          return path.getAttributes(options);
      }
  
      @Override
      public void setTimes(FileTime lastModifiedTime,
                           FileTime lastAccessTime,
                           FileTime createTime) throws IOException {
          path.setTimes(lastModifiedTime, lastAccessTime, createTime);
      }
  
      static void setAttribute(JrtPath path, String attribute, Object value)
              throws IOException {
          int colonPos = attribute.indexOf(':');
          if (colonPos != -1) {    // type = "basic", if no ":"
              String type = attribute.substring(0, colonPos++);
              if (!type.equals("basic") && !type.equals("jrt")) {
                  throw new UnsupportedOperationException(
                      "view <" + type + "> is not supported");
              }
              attribute = attribute.substring(colonPos);
          }
          try {
              AttrID id = AttrID.valueOf(attribute);
              if (id == AttrID.lastModifiedTime) {
                  path.setTimes((FileTime) value, null, null);
              } else if (id == AttrID.lastAccessTime) {
                  path.setTimes(null, (FileTime) value, null);
              } else if (id == AttrID.creationTime) {
                  path.setTimes(null, null, (FileTime) value);
              }
              return;
          } catch (IllegalArgumentException x) {}
          throw new UnsupportedOperationException("'" + attribute
                  + "' is unknown or read-only attribute");
      }
  
      static Map<String, Object> readAttributes(JrtPath path, String attributes,
                                                LinkOption... options)
              throws IOException {
          int colonPos = attributes.indexOf(':');
          boolean isJrtView = false;
          if (colonPos != -1) {    // type = "basic", if no ":"
              String type = attributes.substring(0, colonPos++);
              if (!type.equals("basic") && !type.equals("jrt")) {
                  throw new UnsupportedOperationException("view <" + type +
                                                          "> is not supported");
              }
              isJrtView = true;
              attributes = attributes.substring(colonPos);
          }
          JrtFileAttributes jrtfas = path.getAttributes();
          LinkedHashMap<String, Object> map = new LinkedHashMap<>();
          if ("*".equals(attributes)) {
              for (AttrID id : AttrID.values()) {
                  map.put(id.name(), attribute(id, jrtfas, isJrtView));
              }
          } else {
              String[] as = attributes.split(",");
              for (String a : as) {
                  //throw IllegalArgumentException
                  map.put(a, attribute(AttrID.valueOf(a), jrtfas, isJrtView));
              }
          }
          return map;
      }
  
      static Object attribute(AttrID id, JrtFileAttributes jrtfas, boolean isJrtView) {
          switch (id) {
              case size:
                  return jrtfas.size();
              case creationTime:
                  return jrtfas.creationTime();
              case lastAccessTime:
                  return jrtfas.lastAccessTime();
              case lastModifiedTime:
                  return jrtfas.lastModifiedTime();
              case isDirectory:
                  return jrtfas.isDirectory();
              case isRegularFile:
                  return jrtfas.isRegularFile();
              case isSymbolicLink:
                  return jrtfas.isSymbolicLink();
              case isOther:
                  return jrtfas.isOther();
              case fileKey:
                  return jrtfas.fileKey();
              case compressedSize:
                  if (isJrtView) {
                      return jrtfas.compressedSize();
                  }
                  break;
              case extension:
                  if (isJrtView) {
                      return jrtfas.extension();
                  }
                  break;
          }
          return null;
      }
  }
  