< prev index next >

src/jdk.dev/share/classes/jdk/tools/jimage/JImageTask.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2014, 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 --- 1,7 ---- /* ! * Copyright (c) 2014, 2015, 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
*** 23,167 **** * questions. */ package jdk.tools.jimage; - import java.io.BufferedOutputStream; - import java.io.DataOutputStream; import java.io.File; import java.io.IOException; - import java.io.OutputStream; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; ! import java.text.MessageFormat; ! import java.util.ArrayList; import java.util.LinkedList; import java.util.List; - import java.util.Locale; - import java.util.MissingResourceException; - import java.util.ResourceBundle; - import java.util.stream.Collectors; - import java.util.stream.Stream; import jdk.internal.jimage.BasicImageReader; - import jdk.internal.jimage.BasicImageWriter; import jdk.internal.jimage.ImageHeader; import jdk.internal.jimage.ImageLocation; ! import jdk.internal.jimage.PackageModuleMap; class JImageTask { - static class BadArgs extends Exception { - static final long serialVersionUID = 8765093759964640723L; // ## re-generate - final String key; - final Object[] args; - boolean showUsage; ! BadArgs(String key, Object... args) { ! super(JImageTask.getMessage(key, args)); ! this.key = key; ! this.args = args; ! } ! ! BadArgs showUsage(boolean b) { ! showUsage = b; ! return this; ! } ! } ! ! static abstract class Option { ! final boolean hasArg; ! final String[] aliases; ! ! Option(boolean hasArg, String... aliases) { ! this.hasArg = hasArg; ! this.aliases = aliases; ! } ! ! boolean isHidden() { ! return false; ! } ! ! boolean matches(String opt) { ! for (String a : aliases) { ! if (a.equals(opt)) { ! return true; ! } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { ! return true; ! } ! } ! return false; ! } ! ! boolean ignoreRest() { ! return false; ! } ! ! abstract void process(JImageTask task, String opt, String arg) throws BadArgs; ! } ! ! static abstract class HiddenOption extends Option { ! HiddenOption(boolean hasArg, String... aliases) { ! super(hasArg, aliases); ! } ! ! @Override ! boolean isHidden() { ! return true; ! } ! } ! ! static Option[] recognizedOptions = { ! new Option(true, "--dir") { @Override ! void process(JImageTask task, String opt, String arg) throws BadArgs { task.options.directory = arg; } }, ! new HiddenOption(false, "--fullversion") { @Override ! void process(JImageTask task, String opt, String arg) { task.options.fullVersion = true; } }, ! new Option(false, "--help") { @Override ! void process(JImageTask task, String opt, String arg) { task.options.help = true; } }, ! new Option(false, "--verbose") { @Override ! void process(JImageTask task, String opt, String arg) throws BadArgs { task.options.verbose = true; } }, ! new Option(false, "--version") { @Override ! void process(JImageTask task, String opt, String arg) { task.options.version = true; } }, }; ! static class Options { Task task = Task.LIST; String directory = "."; boolean fullVersion; boolean help; boolean verbose; boolean version; List<File> jimages = new LinkedList<>(); } private static final String PROGNAME = "jimage"; ! private final Options options = new Options(); enum Task { - RECREATE, EXTRACT, INFO, LIST, VERIFY }; private String pad(String string, int width, boolean justifyRight) { int length = string.length(); --- 23,124 ---- * questions. */ package jdk.tools.jimage; import java.io.File; import java.io.IOException; import java.io.PrintWriter; + import java.nio.ByteBuffer; + import java.nio.ByteOrder; + import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; ! import static java.nio.file.StandardOpenOption.READ; ! import static java.nio.file.StandardOpenOption.WRITE; import java.util.LinkedList; import java.util.List; import jdk.internal.jimage.BasicImageReader; import jdk.internal.jimage.ImageHeader; + import static jdk.internal.jimage.ImageHeader.MAGIC; + import static jdk.internal.jimage.ImageHeader.MAJOR_VERSION; + import static jdk.internal.jimage.ImageHeader.MINOR_VERSION; import jdk.internal.jimage.ImageLocation; ! import jdk.internal.jimage.ImageModuleData; ! import jdk.internal.jimage.ImageResourcesTree; ! import jdk.tools.jimage.TaskHelper.BadArgs; ! import jdk.tools.jimage.TaskHelper.HiddenOption; ! import jdk.tools.jimage.TaskHelper.Option; ! import jdk.tools.jimage.TaskHelper.OptionsHelper; class JImageTask { ! static final Option<?>[] recognizedOptions = { ! new Option<JImageTask>(true, "--dir") { @Override ! protected void process(JImageTask task, String opt, String arg) throws BadArgs { task.options.directory = arg; } }, ! new HiddenOption<JImageTask>(false, "--fullversion") { @Override ! protected void process(JImageTask task, String opt, String arg) { task.options.fullVersion = true; } }, ! new Option<JImageTask>(false, "--help") { @Override ! protected void process(JImageTask task, String opt, String arg) { task.options.help = true; } }, ! ! new Option<JImageTask>(true, "--flags") { ! @Override ! protected void process(JImageTask task, String opt, String arg) { ! task.options.flags = arg; ! } ! }, ! ! new Option<JImageTask>(false, "--verbose") { @Override ! protected void process(JImageTask task, String opt, String arg) throws BadArgs { task.options.verbose = true; } }, ! new Option<JImageTask>(false, "--version") { @Override ! protected void process(JImageTask task, String opt, String arg) { task.options.version = true; } }, }; + private static final TaskHelper taskHelper + = new TaskHelper("jdk.tools.jimage.resources.jimage"); + private static final OptionsHelper<JImageTask> optionsHelper + = taskHelper.newOptionsHelper(JImageTask.class, recognizedOptions); ! static class OptionsValues { Task task = Task.LIST; String directory = "."; boolean fullVersion; boolean help; + String flags; boolean verbose; boolean version; List<File> jimages = new LinkedList<>(); } private static final String PROGNAME = "jimage"; ! private final OptionsValues options = new OptionsValues(); enum Task { EXTRACT, INFO, LIST, + RECREATE, + SET, VERIFY }; private String pad(String string, int width, boolean justifyRight) { int length = string.length();
*** 208,336 **** private static final int EXIT_SYSERR = 3; // System error or resource exhaustion. private static final int EXIT_ABNORMAL = 4; // Terminated abnormally. int run(String[] args) { if (log == null) { ! log = new PrintWriter(System.out); } try { ! handleOptions(args); if (options.help) { ! showHelp(); } if (options.version || options.fullVersion) { ! showVersion(options.fullVersion); } boolean ok = run(); return ok ? EXIT_OK : EXIT_ERROR; } catch (BadArgs e) { ! reportError(e.key, e.args); if (e.showUsage) { ! log.println(getMessage("main.usage.summary", PROGNAME)); } return EXIT_CMDERR; } catch (Exception x) { x.printStackTrace(); return EXIT_ABNORMAL; } finally { log.flush(); } } - static final String MODULES_ENTRY = PackageModuleMap.MODULES_ENTRY; - static final String PACKAGES_ENTRY = "/" + PackageModuleMap.PACKAGES_ENTRY; - private void recreate() throws IOException, BadArgs { File directory = new File(options.directory); - Path dirPath = directory.toPath(); - int chop = dirPath.toString().length() + 1; - if (!directory.isDirectory()) { ! throw new BadArgs("err.not.a.dir", directory.getAbsolutePath()); } ! if (options.jimages.isEmpty()) { ! throw new BadArgs("err.jimage.not.specified"); } else if (options.jimages.size() != 1) { ! throw new BadArgs("err.only.one.jimage"); ! } ! ! File jimage = options.jimages.get(0); ! final List<File> files = new ArrayList<>(); ! final BasicImageWriter writer = new BasicImageWriter(); ! final Long longZero = 0L; ! ! // Note: code sensitive to Netbeans parser crashing. ! long total = Files.walk(dirPath).reduce(longZero, (Long offset, Path path) -> { ! long size = 0; ! String pathString = path.toString(); ! ! if (pathString.length() < chop || pathString.startsWith(".")) { ! return 0L; } ! File file = path.toFile(); ! ! if (file.isFile()) { ! String name = pathString.substring(chop).replace(File.separatorChar, '/'); ! ! if (options.verbose) { ! log.println(name); ! } ! if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) { ! try { ! try (Stream<String> lines = Files.lines(path)) { ! size = lines.peek(s -> writer.addString(s)).count() * 4; ! } ! } catch (IOException ex) { ! // Caught again when writing file. ! size = 0; ! } } else { ! size = file.length(); } - - writer.addLocation(name, offset, 0L, size); - files.add(file); - } - - return offset + size; - }, - (Long offsetL, Long offsetR) -> { return longZero; } ); - - if (jimage.createNewFile()) { - try (OutputStream os = Files.newOutputStream(jimage.toPath()); - BufferedOutputStream bos = new BufferedOutputStream(os); - DataOutputStream out = new DataOutputStream(bos)) { - - byte[] index = writer.getBytes(); - out.write(index, 0, index.length); - - for (File file : files) { - try { - Path path = file.toPath(); - String name = path.toString().replace(File.separatorChar, '/'); - - if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) { - for (String line: Files.readAllLines(path)) { - int off = writer.addString(line); - out.writeInt(off); - } - } else { - Files.copy(path, out); - } - } catch (IOException ex) { - throw new BadArgs("err.cannot.read.file", file.getName()); - } - } - } - } else { - throw new BadArgs("err.jimage.already.exists", jimage.getName()); - } - } private void title(File file, BasicImageReader reader) { log.println("jimage: " + file.getName()); } --- 165,227 ---- private static final int EXIT_SYSERR = 3; // System error or resource exhaustion. private static final int EXIT_ABNORMAL = 4; // Terminated abnormally. int run(String[] args) { if (log == null) { ! setLog(new PrintWriter(System.out)); } try { ! List<String> unhandled = optionsHelper.handleOptions(this, args); ! if(!unhandled.isEmpty()) { ! options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase()); ! for(int i = 1; i < unhandled.size(); i++) { ! options.jimages.add(new File(unhandled.get(i))); ! } ! } if (options.help) { ! optionsHelper.showHelp(PROGNAME, "recreate only options:"); } if (options.version || options.fullVersion) { ! taskHelper.showVersion(options.fullVersion); } boolean ok = run(); return ok ? EXIT_OK : EXIT_ERROR; } catch (BadArgs e) { ! taskHelper.reportError(e.key, e.args); if (e.showUsage) { ! log.println(taskHelper.getMessage("main.usage.summary", PROGNAME)); } return EXIT_CMDERR; } catch (Exception x) { x.printStackTrace(); return EXIT_ABNORMAL; } finally { log.flush(); } } private void recreate() throws IOException, BadArgs { File directory = new File(options.directory); if (!directory.isDirectory()) { ! throw taskHelper.newBadArgs("err.not.a.dir", directory.getAbsolutePath()); } ! Path dirPath = directory.toPath(); if (options.jimages.isEmpty()) { ! throw taskHelper.newBadArgs("err.jimage.not.specified"); } else if (options.jimages.size() != 1) { ! throw taskHelper.newBadArgs("err.only.one.jimage"); } ! Path jimage = options.jimages.get(0).toPath(); ! if (jimage.toFile().createNewFile()) { ! ExtractedImage img = new ExtractedImage(dirPath, log, options.verbose); ! img.recreateJImage(jimage); } else { ! throw taskHelper.newBadArgs("err.jimage.already.exists", jimage.getFileName()); } } private void title(File file, BasicImageReader reader) { log.println("jimage: " + file.getName()); }
*** 349,384 **** private interface JImageAction { public void apply(File file, BasicImageReader reader) throws IOException, BadArgs; } private interface ResourceAction { ! public void apply(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs; } ! private void extract(BasicImageReader reader, String name, ImageLocation location) throws IOException, BadArgs { File directory = new File(options.directory); byte[] bytes = reader.getResource(location); File resource = new File(directory, name); File parent = resource.getParentFile(); if (parent.exists()) { if (!parent.isDirectory()) { ! throw new BadArgs("err.cannot.create.dir", parent.getAbsolutePath()); } } else if (!parent.mkdirs()) { ! throw new BadArgs("err.cannot.create.dir", parent.getAbsolutePath()); } ! if (name.endsWith(MODULES_ENTRY) || name.endsWith(PACKAGES_ENTRY)) { ! List<String> names = reader.getNames(bytes); ! Files.write(resource.toPath(), names); } else { Files.write(resource.toPath(), bytes); } } - private static final int NAME_WIDTH = 40; private static final int NUMBER_WIDTH = 12; private static final int OFFSET_WIDTH = NUMBER_WIDTH; private static final int SIZE_WIDTH = NUMBER_WIDTH; private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH; --- 240,279 ---- private interface JImageAction { public void apply(File file, BasicImageReader reader) throws IOException, BadArgs; } private interface ResourceAction { ! public void apply(BasicImageReader reader, String name, ! ImageLocation location) throws IOException, BadArgs; } ! private void extract(BasicImageReader reader, String name, ! ImageLocation location) throws IOException, BadArgs { File directory = new File(options.directory); byte[] bytes = reader.getResource(location); File resource = new File(directory, name); File parent = resource.getParentFile(); if (parent.exists()) { if (!parent.isDirectory()) { ! throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath()); } } else if (!parent.mkdirs()) { ! throw taskHelper.newBadArgs("err.cannot.create.dir", parent.getAbsolutePath()); } ! if (name.endsWith(ImageModuleData.META_DATA_EXTENSION)) { ! ImageModuleData imageModuleData = new ImageModuleData(reader, bytes); ! List<String> lines = imageModuleData.fromModulePackages(); ! Files.write(resource.toPath(), lines); } else { + if (!ImageResourcesTree.isTreeInfoResource(name)) { Files.write(resource.toPath(), bytes); } } + } private static final int NUMBER_WIDTH = 12; private static final int OFFSET_WIDTH = NUMBER_WIDTH; private static final int SIZE_WIDTH = NUMBER_WIDTH; private static final int COMPRESSEDSIZE_WIDTH = NUMBER_WIDTH;
*** 395,410 **** } else { log.println(entry); } } ! private void info(File file, BasicImageReader reader) { ImageHeader header = reader.getHeader(); log.println(" Major Version: " + header.getMajorVersion()); log.println(" Minor Version: " + header.getMinorVersion()); ! log.println(" Location Count: " + header.getLocationCount()); log.println(" Offsets Size: " + header.getOffsetsSize()); log.println(" Redirects Size: " + header.getRedirectSize()); log.println(" Locations Size: " + header.getLocationsSize()); log.println(" Strings Size: " + header.getStringsSize()); log.println(" Index Size: " + header.getIndexSize()); --- 290,307 ---- } else { log.println(entry); } } ! private void info(File file, BasicImageReader reader) throws IOException { ImageHeader header = reader.getHeader(); log.println(" Major Version: " + header.getMajorVersion()); log.println(" Minor Version: " + header.getMinorVersion()); ! log.println(" Flags: " + Integer.toHexString(header.getMinorVersion())); ! log.println(" Resource Count: " + header.getResourceCount()); ! log.println(" Table Length: " + header.getTableLength()); log.println(" Offsets Size: " + header.getOffsetsSize()); log.println(" Redirects Size: " + header.getRedirectSize()); log.println(" Locations Size: " + header.getLocationsSize()); log.println(" Strings Size: " + header.getStringsSize()); log.println(" Index Size: " + header.getIndexSize());
*** 412,430 **** private void list(BasicImageReader reader, String name, ImageLocation location) { print(reader, name); } ! void verify(BasicImageReader reader, String name, ImageLocation location) { ! if (name.endsWith(".class")) { ! byte[] bytes; try { ! bytes = reader.getResource(location); } catch (IOException ex) { ! log.println(ex); ! bytes = null; } if (bytes == null || bytes.length <= 4 || (bytes[0] & 0xFF) != 0xCA || (bytes[1] & 0xFF) != 0xFE || (bytes[2] & 0xFF) != 0xBA || --- 309,350 ---- private void list(BasicImageReader reader, String name, ImageLocation location) { print(reader, name); } ! void set(File file, BasicImageReader reader) throws BadArgs { try { ! ImageHeader oldHeader = reader.getHeader(); ! ! int value = 0; ! try { ! value = Integer.valueOf(options.flags); ! } catch (NumberFormatException ex) { ! throw taskHelper.newBadArgs("err.flags.not.int", options.flags); ! } ! ! ImageHeader newHeader = new ImageHeader(MAGIC, MAJOR_VERSION, MINOR_VERSION, ! value, ! oldHeader.getResourceCount(), oldHeader.getTableLength(), ! oldHeader.getLocationsSize(), oldHeader.getStringsSize()); ! ! ByteBuffer buffer = ByteBuffer.allocate(ImageHeader.getHeaderSize()); ! buffer.order(ByteOrder.nativeOrder()); ! newHeader.writeTo(buffer); ! buffer.rewind(); ! ! try (FileChannel channel = FileChannel.open(file.toPath(), READ, WRITE)) { ! channel.write(buffer, 0); ! } } catch (IOException ex) { ! throw taskHelper.newBadArgs("err.cannot.update.file", file.getName()); } + } + + void verify(BasicImageReader reader, String name, ImageLocation location) { + if (name.endsWith(".class")) { + byte[] bytes = reader.getResource(location); if (bytes == null || bytes.length <= 4 || (bytes[0] & 0xFF) != 0xCA || (bytes[1] & 0xFF) != 0xFE || (bytes[2] & 0xFF) != 0xBA ||
*** 433,596 **** print(reader, name); } } } ! private void iterate(JImageAction jimageAction, ResourceAction resourceAction) throws IOException, BadArgs { for (File file : options.jimages) { if (!file.exists() || !file.isFile()) { ! throw new BadArgs("err.not.a.jimage", file.getName()); } String path = file.getCanonicalPath(); BasicImageReader reader = BasicImageReader.open(path); if (jimageAction != null) { jimageAction.apply(file, reader); } if (resourceAction != null) { ! String[] entryNames = reader.getEntryNames(true); for (String name : entryNames) { ImageLocation location = reader.findLocation(name); resourceAction.apply(reader, name, location); } } } } private boolean run() throws IOException, BadArgs { switch (options.task) { - case RECREATE: - recreate(); - break; case EXTRACT: iterate(null, this::extract); break; case INFO: iterate(this::info, null); break; case LIST: iterate(this::listTitle, this::list); break; case VERIFY: iterate(this::title, this::verify); break; default: ! throw new BadArgs("err.invalid.task", options.task.name()).showUsage(true); } return true; } private PrintWriter log; void setLog(PrintWriter out) { log = out; ! } ! public void handleOptions(String[] args) throws BadArgs { ! // process options ! int first = 0; ! ! if (args.length == 0) { ! return; ! } ! ! String arg = args[first]; ! ! if (!arg.startsWith("-")) { ! try { ! options.task = Enum.valueOf(Task.class, arg.toUpperCase()); ! first++; ! } catch (IllegalArgumentException e) { ! throw new BadArgs("err.invalid.task", arg).showUsage(true); ! } ! } ! ! for (int i = first; i < args.length; i++) { ! arg = args[i]; ! ! if (arg.charAt(0) == '-') { ! Option option = getOption(arg); ! String param = null; ! ! if (option.hasArg) { ! if (arg.startsWith("--") && arg.indexOf('=') > 0) { ! param = arg.substring(arg.indexOf('=') + 1, arg.length()); ! } else if (i + 1 < args.length) { ! param = args[++i]; ! } ! ! if (param == null || param.isEmpty() || param.charAt(0) == '-') { ! throw new BadArgs("err.missing.arg", arg).showUsage(true); ! } ! } ! ! option.process(this, arg, param); ! ! if (option.ignoreRest()) { ! i = args.length; ! } ! } else { ! File file = new File(arg); ! options.jimages.add(file); ! } ! } ! } ! ! private Option getOption(String name) throws BadArgs { ! for (Option o : recognizedOptions) { ! if (o.matches(name)) { ! return o; ! } ! } ! throw new BadArgs("err.unknown.option", name).showUsage(true); ! } ! ! private void reportError(String key, Object... args) { ! log.println(getMessage("error.prefix") + " " + getMessage(key, args)); ! } ! ! private void warning(String key, Object... args) { ! log.println(getMessage("warn.prefix") + " " + getMessage(key, args)); ! } ! ! private void showHelp() { ! log.println(getMessage("main.usage", PROGNAME)); ! for (Option o : recognizedOptions) { ! String name = o.aliases[0].substring(1); // there must always be at least one name ! name = name.charAt(0) == '-' ? name.substring(1) : name; ! if (o.isHidden() || name.equals("h")) { ! continue; ! } ! log.println(getMessage("main.opt." + name)); ! } ! } ! ! private void showVersion(boolean full) { ! log.println(version(full ? "full" : "release")); ! } ! ! private String version(String key) { ! return System.getProperty("java.version"); ! } ! ! static String getMessage(String key, Object... args) { ! try { ! return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args); ! } catch (MissingResourceException e) { ! throw new InternalError("Missing message: " + key); ! } ! } ! ! private static class ResourceBundleHelper { ! static final ResourceBundle bundle; ! ! static { ! Locale locale = Locale.getDefault(); ! try { ! bundle = ResourceBundle.getBundle("jdk.tools.jimage.resources.jimage", locale); ! } catch (MissingResourceException e) { ! throw new InternalError("Cannot find jimage resource bundle for locale " + locale); ! } ! } } } --- 353,416 ---- print(reader, name); } } } ! private void iterate(JImageAction jimageAction, ! ResourceAction resourceAction) throws IOException, BadArgs { for (File file : options.jimages) { if (!file.exists() || !file.isFile()) { ! throw taskHelper.newBadArgs("err.not.a.jimage", file.getName()); } String path = file.getCanonicalPath(); BasicImageReader reader = BasicImageReader.open(path); if (jimageAction != null) { jimageAction.apply(file, reader); } if (resourceAction != null) { ! String[] entryNames = reader.getEntryNames(); for (String name : entryNames) { + if (!ImageResourcesTree.isTreeInfoResource(name)) { ImageLocation location = reader.findLocation(name); resourceAction.apply(reader, name, location); } } } } + } private boolean run() throws IOException, BadArgs { switch (options.task) { case EXTRACT: iterate(null, this::extract); break; case INFO: iterate(this::info, null); break; case LIST: iterate(this::listTitle, this::list); break; + case RECREATE: + recreate(); + break; + case SET: + iterate(this::set, null); + break; case VERIFY: iterate(this::title, this::verify); break; default: ! throw taskHelper.newBadArgs("err.invalid.task", options.task.name()).showUsage(true); } return true; } private PrintWriter log; void setLog(PrintWriter out) { log = out; ! taskHelper.setLog(log); } }
< prev index next >